1/*
2 * Copyright (c) 1998-2009 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#include <IOKit/system.h>
30
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>
54
55#include <machine/pal_routines.h>
56
57#define LOG kprintf
58//#define LOG IOLog
59#define MATCH_DEBUG	0
60
61#include "IOServicePrivate.h"
62#include "IOKitKernelInternal.h"
63
64// take lockForArbitration before LOCKNOTIFY
65
66/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
67
68#define super IORegistryEntry
69
70OSDefineMetaClassAndStructors(IOService, IORegistryEntry)
71
72OSDefineMetaClassAndStructors(_IOServiceNotifier, IONotifier)
73
74OSDefineMetaClassAndStructors(_IOServiceInterestNotifier, IONotifier)
75
76OSDefineMetaClassAndStructors(_IOConfigThread, OSObject)
77
78OSDefineMetaClassAndStructors(_IOServiceJob, OSObject)
79
80OSDefineMetaClassAndStructors(IOResources, IOService)
81
82OSDefineMetaClassAndStructors(_IOOpenServiceIterator, OSIterator)
83
84OSDefineMetaClassAndAbstractStructors(IONotifier, OSObject)
85
86/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
87
88static IOPlatformExpert *	gIOPlatform;
89static class IOPMrootDomain *	gIOPMRootDomain;
90const IORegistryPlane *		gIOServicePlane;
91const IORegistryPlane *		gIOPowerPlane;
92const OSSymbol *		gIODeviceMemoryKey;
93const OSSymbol *		gIOInterruptControllersKey;
94const OSSymbol *		gIOInterruptSpecifiersKey;
95
96const OSSymbol *		gIOResourcesKey;
97const OSSymbol *		gIOResourceMatchKey;
98const OSSymbol *		gIOProviderClassKey;
99const OSSymbol * 		gIONameMatchKey;
100const OSSymbol *		gIONameMatchedKey;
101const OSSymbol *		gIOPropertyMatchKey;
102const OSSymbol *		gIOLocationMatchKey;
103const OSSymbol *		gIOParentMatchKey;
104const OSSymbol *		gIOPathMatchKey;
105const OSSymbol *		gIOMatchCategoryKey;
106const OSSymbol *		gIODefaultMatchCategoryKey;
107const OSSymbol *		gIOMatchedServiceCountKey;
108
109const OSSymbol *		gIOMapperIDKey;
110const OSSymbol *		gIOUserClientClassKey;
111const OSSymbol *		gIOKitDebugKey;
112
113const OSSymbol *		gIOCommandPoolSizeKey;
114
115const OSSymbol *		gIOConsoleLockedKey;
116const OSSymbol *		gIOConsoleUsersKey;
117const OSSymbol *		gIOConsoleSessionUIDKey;
118const OSSymbol *		gIOConsoleSessionAuditIDKey;
119const OSSymbol *		gIOConsoleUsersSeedKey;
120const OSSymbol *		gIOConsoleSessionOnConsoleKey;
121const OSSymbol *		gIOConsoleSessionLoginDoneKey;
122const OSSymbol *		gIOConsoleSessionSecureInputPIDKey;
123const OSSymbol *		gIOConsoleSessionScreenLockedTimeKey;
124
125clock_sec_t			gIOConsoleLockTime;
126static bool			gIOConsoleLoggedIn;
127static uint32_t			gIOScreenLockState;
128static IORegistryEntry *        gIOChosenEntry;
129
130static int			gIOResourceGenerationCount;
131
132const OSSymbol *		gIOServiceKey;
133const OSSymbol *		gIOPublishNotification;
134const OSSymbol *		gIOFirstPublishNotification;
135const OSSymbol *		gIOMatchedNotification;
136const OSSymbol *		gIOFirstMatchNotification;
137const OSSymbol *		gIOTerminatedNotification;
138
139const OSSymbol *		gIOGeneralInterest;
140const OSSymbol *		gIOBusyInterest;
141const OSSymbol *		gIOAppPowerStateInterest;
142const OSSymbol *		gIOPriorityPowerStateInterest;
143const OSSymbol *		gIOConsoleSecurityInterest;
144
145static OSDictionary * 		gNotifications;
146static IORecursiveLock *	gNotificationLock;
147
148static IOService *		gIOResources;
149static IOService * 		gIOServiceRoot;
150
151static OSOrderedSet *		gJobs;
152static semaphore_port_t		gJobsSemaphore;
153static IOLock *			gJobsLock;
154static int			gOutstandingJobs;
155static int			gNumConfigThreads;
156static int			gNumWaitingThreads;
157static IOLock *			gIOServiceBusyLock;
158
159static thread_t			gIOTerminateThread;
160static UInt32			gIOTerminateWork;
161static OSArray *		gIOTerminatePhase2List;
162static OSArray *		gIOStopList;
163static OSArray *		gIOStopProviderList;
164static OSArray *		gIOFinalizeList;
165
166static SInt32			gIOConsoleUsersSeed;
167static OSData *			gIOConsoleUsersSeedValue;
168
169extern const OSSymbol *		gIODTPHandleKey;
170
171const OSSymbol *		gIOPlatformSleepActionKey;
172const OSSymbol *		gIOPlatformWakeActionKey;
173const OSSymbol *		gIOPlatformQuiesceActionKey;
174const OSSymbol *		gIOPlatformActiveActionKey;
175
176const OSSymbol *		gIOPlatformFunctionHandlerSet;
177
178static IOLock *			gIOConsoleUsersLock;
179static thread_call_t		gIOConsoleLockCallout;
180
181/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
182
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 )
196
197#define randomDelay()	\
198        int del = read_processor_clock();				\
199        del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff;	\
200        IOSleep( del );
201
202/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
203
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;			\
208    } while(0)
209
210#define iterqueue(que, elt)				\
211	for (queue_entry_t elt = queue_first(que);	\
212	     !queue_end(que, elt);			\
213	     elt = queue_next(elt))
214
215#define IOMATCHDEBUG 1
216
217/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
218
219struct ArbitrationLockQueueElement {
220    queue_chain_t link;
221    IOThread      thread;
222    IOService *   service;
223    unsigned      count;
224    bool          required;
225    bool          aborted;
226};
227
228static queue_head_t gArbitrationLockQueueActive;
229static queue_head_t gArbitrationLockQueueWaiting;
230static queue_head_t gArbitrationLockQueueFree;
231static IOLock *     gArbitrationLockQueueLock;
232
233bool IOService::isInactive( void ) const
234    { return( 0 != (kIOServiceInactiveState & getState())); }
235
236/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
237
238#if defined(__i386__) || defined(__x86_64__)
239
240// Only used by the intel implementation of
241//     IOService::requireMaxBusStall(UInt32 ns)
242//     IOService::requireMaxInterruptDelay(uint32_t ns)
243struct CpuDelayEntry
244{
245    IOService * fService;
246    UInt32      fMaxDelay;
247    UInt32      fDelayType;
248};
249
250enum {
251    kCpuDelayBusStall, kCpuDelayInterrupt,
252    kCpuNumDelayTypes
253};
254
255static OSData          *sCpuDelayData = OSData::withCapacity(8 * sizeof(CpuDelayEntry));
256static IORecursiveLock *sCpuDelayLock = IORecursiveLockAlloc();
257static OSArray         *sCpuLatencyHandlers[kCpuNumDelayTypes];
258const OSSymbol         *sCPULatencyFunctionName[kCpuNumDelayTypes];
259
260static void
261requireMaxCpuDelay(IOService * service, UInt32 ns, UInt32 delayType);
262static IOReturn
263setLatencyHandler(UInt32 delayType, IOService * target, bool enable);
264
265#endif /* defined(__i386__) || defined(__x86_64__) */
266
267/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
268
269void IOService::initialize( void )
270{
271    kern_return_t	err;
272
273    gIOServicePlane	= IORegistryEntry::makePlane( kIOServicePlane );
274    gIOPowerPlane 	= IORegistryEntry::makePlane( kIOPowerPlane );
275
276    gIOProviderClassKey = OSSymbol::withCStringNoCopy( kIOProviderClassKey );
277    gIONameMatchKey	= OSSymbol::withCStringNoCopy( kIONameMatchKey );
278    gIONameMatchedKey	= OSSymbol::withCStringNoCopy( kIONameMatchedKey );
279    gIOPropertyMatchKey	= OSSymbol::withCStringNoCopy( kIOPropertyMatchKey );
280    gIOPathMatchKey 	= OSSymbol::withCStringNoCopy( kIOPathMatchKey );
281    gIOLocationMatchKey	= OSSymbol::withCStringNoCopy( kIOLocationMatchKey );
282    gIOParentMatchKey	= OSSymbol::withCStringNoCopy( kIOParentMatchKey );
283
284    gIOMatchCategoryKey	= OSSymbol::withCStringNoCopy( kIOMatchCategoryKey );
285    gIODefaultMatchCategoryKey	= OSSymbol::withCStringNoCopy(
286					kIODefaultMatchCategoryKey );
287    gIOMatchedServiceCountKey	= OSSymbol::withCStringNoCopy(
288					kIOMatchedServiceCountKey );
289
290    gIOUserClientClassKey = OSSymbol::withCStringNoCopy( kIOUserClientClassKey );
291
292    gIOResourcesKey	= OSSymbol::withCStringNoCopy( kIOResourcesClass );
293    gIOResourceMatchKey	= OSSymbol::withCStringNoCopy( kIOResourceMatchKey );
294
295    gIODeviceMemoryKey	= OSSymbol::withCStringNoCopy( "IODeviceMemory" );
296    gIOInterruptControllersKey
297	= OSSymbol::withCStringNoCopy("IOInterruptControllers");
298    gIOInterruptSpecifiersKey
299	= OSSymbol::withCStringNoCopy("IOInterruptSpecifiers");
300
301    gIOMapperIDKey = OSSymbol::withCStringNoCopy(kIOMapperIDKey);
302
303    gIOKitDebugKey	= OSSymbol::withCStringNoCopy( kIOKitDebugKey );
304
305    gIOCommandPoolSizeKey	= OSSymbol::withCStringNoCopy( kIOCommandPoolSizeKey );
306
307    gIOGeneralInterest 		= OSSymbol::withCStringNoCopy( kIOGeneralInterest );
308    gIOBusyInterest   		= OSSymbol::withCStringNoCopy( kIOBusyInterest );
309    gIOAppPowerStateInterest   	= OSSymbol::withCStringNoCopy( kIOAppPowerStateInterest );
310    gIOPriorityPowerStateInterest   	= OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest );
311    gIOConsoleSecurityInterest 	= OSSymbol::withCStringNoCopy( kIOConsoleSecurityInterest );
312
313    gNotifications		= OSDictionary::withCapacity( 1 );
314    gIOPublishNotification	= OSSymbol::withCStringNoCopy(
315						 kIOPublishNotification );
316    gIOFirstPublishNotification	= OSSymbol::withCStringNoCopy(
317                                                 kIOFirstPublishNotification );
318    gIOMatchedNotification	= OSSymbol::withCStringNoCopy(
319						 kIOMatchedNotification );
320    gIOFirstMatchNotification	= OSSymbol::withCStringNoCopy(
321						 kIOFirstMatchNotification );
322    gIOTerminatedNotification	= OSSymbol::withCStringNoCopy(
323						 kIOTerminatedNotification );
324    gIOServiceKey		= OSSymbol::withCStringNoCopy( kIOServiceClass);
325
326    gIOConsoleLockedKey		= OSSymbol::withCStringNoCopy( kIOConsoleLockedKey);
327    gIOConsoleUsersKey		= OSSymbol::withCStringNoCopy( kIOConsoleUsersKey);
328    gIOConsoleSessionUIDKey	= OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey);
329    gIOConsoleSessionAuditIDKey	= OSSymbol::withCStringNoCopy( kIOConsoleSessionAuditIDKey);
330
331    gIOConsoleUsersSeedKey	         = OSSymbol::withCStringNoCopy(kIOConsoleUsersSeedKey);
332    gIOConsoleSessionOnConsoleKey        = OSSymbol::withCStringNoCopy(kIOConsoleSessionOnConsoleKey);
333    gIOConsoleSessionLoginDoneKey        = OSSymbol::withCStringNoCopy(kIOConsoleSessionLoginDoneKey);
334    gIOConsoleSessionSecureInputPIDKey   = OSSymbol::withCStringNoCopy(kIOConsoleSessionSecureInputPIDKey);
335    gIOConsoleSessionScreenLockedTimeKey = OSSymbol::withCStringNoCopy(kIOConsoleSessionScreenLockedTimeKey);
336
337    gIOConsoleUsersSeedValue	       = OSData::withBytesNoCopy(&gIOConsoleUsersSeed, sizeof(gIOConsoleUsersSeed));
338
339    gIOPlatformSleepActionKey	= OSSymbol::withCStringNoCopy(kIOPlatformSleepActionKey);
340    gIOPlatformWakeActionKey	= OSSymbol::withCStringNoCopy(kIOPlatformWakeActionKey);
341    gIOPlatformQuiesceActionKey	= OSSymbol::withCStringNoCopy(kIOPlatformQuiesceActionKey);
342    gIOPlatformActiveActionKey	= OSSymbol::withCStringNoCopy(kIOPlatformActiveActionKey);
343
344    gIOPlatformFunctionHandlerSet		= OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerSet);
345#if defined(__i386__) || defined(__x86_64__)
346    sCPULatencyFunctionName[kCpuDelayBusStall]	= OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxBusDelay);
347    sCPULatencyFunctionName[kCpuDelayInterrupt]	= OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxInterruptDelay);
348#endif
349    gNotificationLock	 	= IORecursiveLockAlloc();
350
351    assert( gIOServicePlane && gIODeviceMemoryKey
352        && gIOInterruptControllersKey && gIOInterruptSpecifiersKey
353        && gIOResourcesKey && gNotifications && gNotificationLock
354        && gIOProviderClassKey && gIONameMatchKey && gIONameMatchedKey
355	&& gIOMatchCategoryKey && gIODefaultMatchCategoryKey
356        && gIOPublishNotification && gIOMatchedNotification
357        && gIOTerminatedNotification && gIOServiceKey
358	&& gIOConsoleUsersKey && gIOConsoleSessionUIDKey
359    && gIOConsoleSessionOnConsoleKey && gIOConsoleSessionSecureInputPIDKey
360	&& gIOConsoleUsersSeedKey && gIOConsoleUsersSeedValue);
361
362    gJobsLock	= IOLockAlloc();
363    gJobs 	= OSOrderedSet::withCapacity( 10 );
364
365    gIOServiceBusyLock = IOLockAlloc();
366
367    gIOConsoleUsersLock = IOLockAlloc();
368
369    err = semaphore_create(kernel_task, &gJobsSemaphore, SYNC_POLICY_FIFO, 0);
370
371    gIOConsoleLockCallout = thread_call_allocate(&IOService::consoleLockTimer, NULL);
372
373    IORegistryEntry::getRegistryRoot()->setProperty(gIOConsoleLockedKey, kOSBooleanTrue);
374
375    assert( gIOServiceBusyLock && gJobs && gJobsLock && gIOConsoleUsersLock
376    		&& gIOConsoleLockCallout && (err == KERN_SUCCESS) );
377
378    gIOResources = IOResources::resources();
379    assert( gIOResources );
380
381    gArbitrationLockQueueLock = IOLockAlloc();
382    queue_init(&gArbitrationLockQueueActive);
383    queue_init(&gArbitrationLockQueueWaiting);
384    queue_init(&gArbitrationLockQueueFree);
385
386    assert( gArbitrationLockQueueLock );
387
388    gIOTerminatePhase2List = OSArray::withCapacity( 2 );
389    gIOStopList            = OSArray::withCapacity( 16 );
390    gIOStopProviderList    = OSArray::withCapacity( 16 );
391    gIOFinalizeList	   = OSArray::withCapacity( 16 );
392    assert( gIOTerminatePhase2List && gIOStopList && gIOStopProviderList && gIOFinalizeList );
393}
394
395/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
396
397#if IOMATCHDEBUG
398static UInt64 getDebugFlags( OSDictionary * props )
399{
400    OSNumber *	debugProp;
401    UInt64	debugFlags;
402
403    debugProp = OSDynamicCast( OSNumber,
404		props->getObject( gIOKitDebugKey ));
405    if( debugProp)
406	debugFlags = debugProp->unsigned64BitValue();
407    else
408	debugFlags = gIOKitDebug;
409
410    return( debugFlags );
411}
412#endif
413
414/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
415
416// Probe a matched service and return an instance to be started.
417// The default score is from the property table, & may be altered
418// during probe to change the start order.
419
420IOService * IOService::probe(	IOService * provider,
421				SInt32	  * score )
422{
423    return( this );
424}
425
426bool IOService::start( IOService * provider )
427{
428    return( true );
429}
430
431void IOService::stop( IOService * provider )
432{
433}
434
435void IOService::free( void )
436{
437    requireMaxBusStall(0);
438    requireMaxInterruptDelay(0);
439    if( getPropertyTable())
440        unregisterAllInterest();
441    PMfree();
442    super::free();
443}
444
445/*
446 * Attach in service plane
447 */
448bool IOService::attach( IOService * provider )
449{
450    bool	ok;
451
452    if( provider) {
453
454	if( gIOKitDebug & kIOLogAttach)
455            LOG( "%s::attach(%s)\n", getName(),
456                    provider->getName());
457
458        provider->lockForArbitration();
459        if( provider->__state[0] & kIOServiceInactiveState)
460            ok = false;
461        else
462            ok = attachToParent( provider, gIOServicePlane);
463        provider->unlockForArbitration();
464
465    } else {
466	gIOServiceRoot = this;
467	ok = attachToParent( getRegistryRoot(), gIOServicePlane);
468    }
469
470    if (ok && !__provider) (void) getProvider();
471
472    return( ok );
473}
474
475IOService * IOService::getServiceRoot( void )
476{
477    return( gIOServiceRoot );
478}
479
480void IOService::detach( IOService * provider )
481{
482    IOService * newProvider = 0;
483    SInt32	busy;
484    bool	adjParent;
485
486    if( gIOKitDebug & kIOLogAttach)
487        LOG("%s::detach(%s)\n", getName(), provider->getName());
488
489    lockForArbitration();
490
491    adjParent = ((busy = (__state[1] & kIOServiceBusyStateMask))
492               && (provider == getProvider()));
493
494    detachFromParent( provider, gIOServicePlane );
495
496    if( busy) {
497        newProvider = getProvider();
498        if( busy && (__state[1] & kIOServiceTermPhase3State) && (0 == newProvider))
499            _adjustBusy( -busy );
500    }
501
502    if (kIOServiceInactiveState & __state[0]) {
503	getMetaClass()->removeInstance(this);
504    }
505
506    unlockForArbitration();
507
508    if( newProvider) {
509        newProvider->lockForArbitration();
510        newProvider->_adjustBusy(1);
511        newProvider->unlockForArbitration();
512    }
513
514    // check for last client detach from a terminated service
515    if( provider->lockForArbitration( true )) {
516        if( adjParent)
517            provider->_adjustBusy( -1 );
518        if( (provider->__state[1] & kIOServiceTermPhase3State)
519         && (0 == provider->getClient())) {
520            provider->scheduleFinalize();
521        }
522        provider->unlockForArbitration();
523    }
524}
525
526/*
527 * Register instance - publish it for matching
528 */
529
530void IOService::registerService( IOOptionBits options )
531{
532    char *		pathBuf;
533    const char *	path;
534    char *		skip;
535    int			len;
536    enum { kMaxPathLen	= 256 };
537    enum { kMaxChars	= 63 };
538
539    IORegistryEntry * parent = this;
540    IORegistryEntry * root = getRegistryRoot();
541    while( parent && (parent != root))
542        parent = parent->getParentEntry( gIOServicePlane);
543
544    if( parent != root) {
545        IOLog("%s: not registry member at registerService()\n", getName());
546        return;
547    }
548
549    // Allow the Platform Expert to adjust this node.
550    if( gIOPlatform && (!gIOPlatform->platformAdjustService(this)))
551	return;
552
553    if( (this != gIOResources)
554     && (kIOLogRegister & gIOKitDebug)) {
555
556        pathBuf = (char *) IOMalloc( kMaxPathLen );
557
558        IOLog( "Registering: " );
559
560        len = kMaxPathLen;
561        if( pathBuf && getPath( pathBuf, &len, gIOServicePlane)) {
562
563            path = pathBuf;
564            if( len > kMaxChars) {
565                IOLog("..");
566                len -= kMaxChars;
567                path += len;
568                if( (skip = strchr( path, '/')))
569                    path = skip;
570            }
571        } else
572            path = getName();
573
574        IOLog( "%s\n", path );
575
576	if( pathBuf)
577	    IOFree( pathBuf, kMaxPathLen );
578    }
579
580    startMatching( options );
581}
582
583void IOService::startMatching( IOOptionBits options )
584{
585    IOService *	provider;
586    UInt32	prevBusy = 0;
587    bool	needConfig;
588    bool	needWake = false;
589    bool	ok;
590    bool	sync;
591    bool	waitAgain;
592
593    lockForArbitration();
594
595    sync = (options & kIOServiceSynchronous)
596	|| ((provider = getProvider())
597		&& (provider->__state[1] & kIOServiceSynchronousState));
598
599	if ( options & kIOServiceAsynchronous )
600		sync = false;
601
602    needConfig =  (0 == (__state[1] & (kIOServiceNeedConfigState | kIOServiceConfigState)))
603	       && (0 == (__state[0] & kIOServiceInactiveState));
604
605    __state[1] |= kIOServiceNeedConfigState;
606
607//    __state[0] &= ~kIOServiceInactiveState;
608
609//    if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n",
610//			OSKernelStackRemaining(), getName());
611
612    if( needConfig) {
613        needWake = (0 != (kIOServiceSyncPubState & __state[1]));
614    }
615
616    if( sync)
617	__state[1] |= kIOServiceSynchronousState;
618    else
619	__state[1] &= ~kIOServiceSynchronousState;
620
621    unlockForArbitration();
622
623    if( needConfig) {
624
625	prevBusy = _adjustBusy( 1 );
626
627        if( needWake) {
628            IOLockLock( gIOServiceBusyLock );
629            thread_wakeup( (event_t) this/*&__state[1]*/ );
630            IOLockUnlock( gIOServiceBusyLock );
631
632        } else if( !sync || (kIOServiceAsynchronous & options)) {
633
634            ok = (0 != _IOServiceJob::startJob( this, kMatchNubJob, options ));
635
636        } else do {
637
638            if( (__state[1] & kIOServiceNeedConfigState))
639                doServiceMatch( options );
640
641            lockForArbitration();
642            IOLockLock( gIOServiceBusyLock );
643
644            waitAgain = ((prevBusy < (__state[1] & kIOServiceBusyStateMask))
645				       && (0 == (__state[0] & kIOServiceInactiveState)));
646
647            if( waitAgain)
648                __state[1] |= kIOServiceSyncPubState | kIOServiceBusyWaiterState;
649            else
650                __state[1] &= ~kIOServiceSyncPubState;
651
652            unlockForArbitration();
653
654            if( waitAgain)
655                assert_wait( (event_t) this/*&__state[1]*/, THREAD_UNINT);
656
657            IOLockUnlock( gIOServiceBusyLock );
658            if( waitAgain)
659                thread_block(THREAD_CONTINUE_NULL);
660
661        } while( waitAgain );
662    }
663}
664
665IOReturn IOService::catalogNewDrivers( OSOrderedSet * newTables )
666{
667    OSDictionary *	table;
668    OSSet *	        set;
669    OSSet *	        allSet = 0;
670    IOService *		service;
671#if IOMATCHDEBUG
672    SInt32		count = 0;
673#endif
674
675    newTables->retain();
676
677    while( (table = (OSDictionary *) newTables->getFirstObject())) {
678
679        LOCKWRITENOTIFY();
680        set = (OSSet *) copyExistingServices( table,
681						kIOServiceRegisteredState,
682						kIOServiceExistingSet);
683        UNLOCKNOTIFY();
684        if( set) {
685
686#if IOMATCHDEBUG
687            count += set->getCount();
688#endif
689            if (allSet) {
690                allSet->merge((const OSSet *) set);
691                set->release();
692            }
693            else
694                allSet = set;
695        }
696
697#if IOMATCHDEBUG
698        if( getDebugFlags( table ) & kIOLogMatch)
699            LOG("Matching service count = %ld\n", (long)count);
700#endif
701        newTables->removeObject(table);
702    }
703
704    if (allSet) {
705        while( (service = (IOService *) allSet->getAnyObject())) {
706            service->startMatching(kIOServiceAsynchronous);
707            allSet->removeObject(service);
708        }
709        allSet->release();
710    }
711
712    newTables->release();
713
714    return( kIOReturnSuccess );
715}
716
717 _IOServiceJob * _IOServiceJob::startJob( IOService * nub, int type,
718						IOOptionBits options )
719{
720    _IOServiceJob *	job;
721
722    job = new _IOServiceJob;
723    if( job && !job->init()) {
724        job->release();
725        job = 0;
726    }
727
728    if( job) {
729        job->type	= type;
730        job->nub	= nub;
731	job->options	= options;
732        nub->retain();			// thread will release()
733        pingConfig( job );
734    }
735
736    return( job );
737}
738
739/*
740 * Called on a registered service to see if it matches
741 * a property table.
742 */
743
744bool IOService::matchPropertyTable( OSDictionary * table, SInt32 * score )
745{
746    return( matchPropertyTable(table) );
747}
748
749bool IOService::matchPropertyTable( OSDictionary * table )
750{
751    return( true );
752}
753
754/*
755 * Called on a matched service to allocate resources
756 * before first driver is attached.
757 */
758
759IOReturn IOService::getResources( void )
760{
761    return( kIOReturnSuccess);
762}
763
764/*
765 * Client/provider accessors
766 */
767
768IOService * IOService::getProvider( void ) const
769{
770    IOService *	self = (IOService *) this;
771    IOService *	parent;
772    SInt32	generation;
773
774    generation = getGenerationCount();
775    if( __providerGeneration == generation)
776	return( __provider );
777
778    parent = (IOService *) getParentEntry( gIOServicePlane);
779    if( parent == IORegistryEntry::getRegistryRoot())
780	/* root is not an IOService */
781	parent = 0;
782
783    self->__provider = parent;
784    //OSMemoryBarrier();
785    // save the count from before call to getParentEntry()
786    self->__providerGeneration = generation;
787
788    return( parent );
789}
790
791IOWorkLoop * IOService::getWorkLoop() const
792{
793    IOService *provider = getProvider();
794
795    if (provider)
796	return provider->getWorkLoop();
797    else
798	return 0;
799}
800
801OSIterator * IOService::getProviderIterator( void ) const
802{
803    return( getParentIterator( gIOServicePlane));
804}
805
806IOService * IOService::getClient( void ) const
807{
808    return( (IOService *) getChildEntry( gIOServicePlane));
809}
810
811OSIterator * IOService::getClientIterator( void ) const
812{
813    return( getChildIterator( gIOServicePlane));
814}
815
816OSIterator * _IOOpenServiceIterator::iterator( OSIterator * _iter,
817						const IOService * client,
818						const IOService * provider )
819{
820    _IOOpenServiceIterator * inst;
821
822    if( !_iter)
823	return( 0 );
824
825    inst = new _IOOpenServiceIterator;
826
827    if( inst && !inst->init()) {
828	inst->release();
829	inst = 0;
830    }
831    if( inst) {
832	inst->iter = _iter;
833	inst->client = client;
834	inst->provider = provider;
835    }
836
837    return( inst );
838}
839
840void _IOOpenServiceIterator::free()
841{
842    iter->release();
843    if( last)
844	last->unlockForArbitration();
845    OSIterator::free();
846}
847
848OSObject * _IOOpenServiceIterator::getNextObject()
849{
850    IOService * next;
851
852    if( last)
853	last->unlockForArbitration();
854
855    while( (next = (IOService *) iter->getNextObject())) {
856
857	next->lockForArbitration();
858	if( (client && (next->isOpen( client )))
859	 || (provider && (provider->isOpen( next ))) )
860            break;
861	next->unlockForArbitration();
862    }
863
864    last = next;
865
866    return( next );
867}
868
869bool _IOOpenServiceIterator::isValid()
870{
871    return( iter->isValid() );
872}
873
874void _IOOpenServiceIterator::reset()
875{
876    if( last) {
877	last->unlockForArbitration();
878	last = 0;
879    }
880    iter->reset();
881}
882
883OSIterator * IOService::getOpenProviderIterator( void ) const
884{
885    return( _IOOpenServiceIterator::iterator( getProviderIterator(), this, 0 ));
886}
887
888OSIterator * IOService::getOpenClientIterator( void ) const
889{
890    return( _IOOpenServiceIterator::iterator( getClientIterator(), 0, this ));
891}
892
893
894IOReturn IOService::callPlatformFunction( const OSSymbol * functionName,
895					  bool waitForFunction,
896					  void *param1, void *param2,
897					  void *param3, void *param4 )
898{
899  IOReturn  result = kIOReturnUnsupported;
900  IOService *provider;
901
902  if (gIOPlatformFunctionHandlerSet == functionName)
903  {
904#if defined(__i386__) || defined(__x86_64__)
905    const OSSymbol * functionHandlerName = (const OSSymbol *) param1;
906    IOService *	     target		 = (IOService *) param2;
907    bool	     enable		 = (param3 != 0);
908
909    if (sCPULatencyFunctionName[kCpuDelayBusStall] == functionHandlerName)
910	result = setLatencyHandler(kCpuDelayBusStall, target, enable);
911    else if (sCPULatencyFunctionName[kCpuDelayInterrupt] == param1)
912	result = setLatencyHandler(kCpuDelayInterrupt, target, enable);
913#endif /* defined(__i386__) || defined(__x86_64__) */
914  }
915
916  if ((kIOReturnUnsupported == result) && (provider = getProvider())) {
917    result = provider->callPlatformFunction(functionName, waitForFunction,
918					    param1, param2, param3, param4);
919  }
920
921  return result;
922}
923
924IOReturn IOService::callPlatformFunction( const char * functionName,
925					  bool waitForFunction,
926					  void *param1, void *param2,
927					  void *param3, void *param4 )
928{
929  IOReturn result = kIOReturnNoMemory;
930  const OSSymbol *functionSymbol = OSSymbol::withCString(functionName);
931
932  if (functionSymbol != 0) {
933    result = callPlatformFunction(functionSymbol, waitForFunction,
934				  param1, param2, param3, param4);
935    functionSymbol->release();
936  }
937
938  return result;
939}
940
941
942/*
943 * Accessors for global services
944 */
945
946IOPlatformExpert * IOService::getPlatform( void )
947{
948    return( gIOPlatform);
949}
950
951class IOPMrootDomain * IOService::getPMRootDomain( void )
952{
953    return( gIOPMRootDomain);
954}
955
956IOService * IOService::getResourceService( void )
957{
958    return( gIOResources );
959}
960
961void IOService::setPlatform( IOPlatformExpert * platform)
962{
963    gIOPlatform = platform;
964    gIOResources->attachToParent( gIOServiceRoot, gIOServicePlane );
965}
966
967void IOService::setPMRootDomain( class IOPMrootDomain * rootDomain)
968{
969    gIOPMRootDomain = rootDomain;
970    publishResource("IOKit");
971}
972
973/*
974 * Stacking change
975 */
976
977bool IOService::lockForArbitration( bool isSuccessRequired )
978{
979    bool                          found;
980    bool                          success;
981    ArbitrationLockQueueElement * element;
982    ArbitrationLockQueueElement * active;
983    ArbitrationLockQueueElement * waiting;
984
985    enum { kPutOnFreeQueue, kPutOnActiveQueue, kPutOnWaitingQueue } action;
986
987    // lock global access
988    IOTakeLock( gArbitrationLockQueueLock );
989
990    // obtain an unused queue element
991    if( !queue_empty( &gArbitrationLockQueueFree )) {
992        queue_remove_first( &gArbitrationLockQueueFree,
993                            element,
994                            ArbitrationLockQueueElement *,
995                            link );
996    } else {
997        element = IONew( ArbitrationLockQueueElement, 1 );
998        assert( element );
999    }
1000
1001    // prepare the queue element
1002    element->thread   = IOThreadSelf();
1003    element->service  = this;
1004    element->count    = 1;
1005    element->required = isSuccessRequired;
1006    element->aborted  = false;
1007
1008    // determine whether this object is already locked (ie. on active queue)
1009    found = false;
1010    queue_iterate( &gArbitrationLockQueueActive,
1011                    active,
1012                    ArbitrationLockQueueElement *,
1013                    link )
1014    {
1015        if( active->service == element->service ) {
1016            found = true;
1017            break;
1018        }
1019    }
1020
1021    if( found ) { // this object is already locked
1022
1023        // determine whether it is the same or a different thread trying to lock
1024        if( active->thread != element->thread ) { // it is a different thread
1025
1026            ArbitrationLockQueueElement * victim = 0;
1027
1028            // before placing this new thread on the waiting queue, we look for
1029            // a deadlock cycle...
1030
1031            while( 1 ) {
1032                // determine whether the active thread holding the object we
1033                // want is waiting for another object to be unlocked
1034                found = false;
1035                queue_iterate( &gArbitrationLockQueueWaiting,
1036                               waiting,
1037                               ArbitrationLockQueueElement *,
1038                               link )
1039                {
1040                    if( waiting->thread == active->thread ) {
1041                        assert( false == waiting->aborted );
1042                        found = true;
1043                        break;
1044                    }
1045                }
1046
1047                if( found ) { // yes, active thread waiting for another object
1048
1049                    // this may be a candidate for rejection if the required
1050                    // flag is not set, should we detect a deadlock later on
1051                    if( false == waiting->required )
1052                        victim = waiting;
1053
1054                    // find the thread that is holding this other object, that
1055                    // is blocking the active thread from proceeding (fun :-)
1056                    found = false;
1057                    queue_iterate( &gArbitrationLockQueueActive,
1058                                   active,      // (reuse active queue element)
1059                                   ArbitrationLockQueueElement *,
1060                                   link )
1061                    {
1062                        if( active->service == waiting->service ) {
1063                            found = true;
1064                            break;
1065                        }
1066                    }
1067
1068                    // someone must be holding it or it wouldn't be waiting
1069                    assert( found );
1070
1071                    if( active->thread == element->thread ) {
1072
1073                        // doh, it's waiting for the thread that originated
1074                        // this whole lock (ie. current thread) -> deadlock
1075                        if( false == element->required ) { // willing to fail?
1076
1077                            // the originating thread doesn't have the required
1078                            // flag, so it can fail
1079                            success = false; // (fail originating lock request)
1080                            break; // (out of while)
1081
1082                        } else { // originating thread is not willing to fail
1083
1084                            // see if we came across a waiting thread that did
1085                            // not have the 'required' flag set: we'll fail it
1086                            if( victim ) {
1087
1088                                // we do have a willing victim, fail it's lock
1089                                victim->aborted = true;
1090
1091                                // take the victim off the waiting queue
1092                                queue_remove( &gArbitrationLockQueueWaiting,
1093                                              victim,
1094                                              ArbitrationLockQueueElement *,
1095                                              link );
1096
1097                                // wake the victim
1098                                IOLockWakeup( gArbitrationLockQueueLock,
1099                                              victim,
1100                                              /* one thread */ true );
1101
1102                                // allow this thread to proceed (ie. wait)
1103                                success = true; // (put request on wait queue)
1104                                break; // (out of while)
1105                            } else {
1106
1107                                // all the waiting threads we came across in
1108                                // finding this loop had the 'required' flag
1109                                // set, so we've got a deadlock we can't avoid
1110                                panic("I/O Kit: Unrecoverable deadlock.");
1111                            }
1112                        }
1113                    } else {
1114                        // repeat while loop, redefining active thread to be the
1115                        // thread holding "this other object" (see above), and
1116                        // looking for threads waiting on it; note the active
1117                        // variable points to "this other object" already... so
1118                        // there nothing to do in this else clause.
1119                    }
1120                } else { // no, active thread is not waiting for another object
1121
1122                    success = true; // (put request on wait queue)
1123                    break; // (out of while)
1124                }
1125            } // while forever
1126
1127            if( success ) { // put the request on the waiting queue?
1128                kern_return_t wait_result;
1129
1130                // place this thread on the waiting queue and put it to sleep;
1131                // we place it at the tail of the queue...
1132                queue_enter( &gArbitrationLockQueueWaiting,
1133                             element,
1134                             ArbitrationLockQueueElement *,
1135                             link );
1136
1137                // declare that this thread will wait for a given event
1138restart_sleep:  wait_result = assert_wait( element,
1139					   element->required ? THREAD_UNINT
1140					   : THREAD_INTERRUPTIBLE );
1141
1142                // unlock global access
1143                IOUnlock( gArbitrationLockQueueLock );
1144
1145                // put thread to sleep, waiting for our event to fire...
1146		if (wait_result == THREAD_WAITING)
1147		    wait_result = thread_block(THREAD_CONTINUE_NULL);
1148
1149
1150                // ...and we've been woken up; we might be in one of two states:
1151                // (a) we've been aborted and our queue element is not on
1152                //     any of the three queues, but is floating around
1153                // (b) we're allowed to proceed with the lock and we have
1154                //     already been moved from the waiting queue to the
1155                //     active queue.
1156                // ...plus a 3rd state, should the thread have been interrupted:
1157                // (c) we're still on the waiting queue
1158
1159                // determine whether we were interrupted out of our sleep
1160                if( THREAD_INTERRUPTED == wait_result ) {
1161
1162                    // re-lock global access
1163                    IOTakeLock( gArbitrationLockQueueLock );
1164
1165                    // determine whether we're still on the waiting queue
1166                    found = false;
1167                    queue_iterate( &gArbitrationLockQueueWaiting,
1168                                   waiting,     // (reuse waiting queue element)
1169                                   ArbitrationLockQueueElement *,
1170                                   link )
1171                    {
1172                        if( waiting == element ) {
1173                            found = true;
1174                            break;
1175                        }
1176                    }
1177
1178                    if( found ) { // yes, we're still on the waiting queue
1179
1180                        // determine whether we're willing to fail
1181                        if( false == element->required ) {
1182
1183                            // mark us as aborted
1184                            element->aborted = true;
1185
1186                            // take us off the waiting queue
1187                            queue_remove( &gArbitrationLockQueueWaiting,
1188                                          element,
1189                                          ArbitrationLockQueueElement *,
1190                                          link );
1191                        } else { // we are not willing to fail
1192
1193                            // ignore interruption, go back to sleep
1194                            goto restart_sleep;
1195                        }
1196                    }
1197
1198                    // unlock global access
1199                    IOUnlock( gArbitrationLockQueueLock );
1200
1201                    // proceed as though this were a normal wake up
1202                    wait_result = THREAD_AWAKENED;
1203                }
1204
1205                assert( THREAD_AWAKENED == wait_result );
1206
1207                // determine whether we've been aborted while we were asleep
1208                if( element->aborted ) {
1209                    assert( false == element->required );
1210
1211                    // re-lock global access
1212                    IOTakeLock( gArbitrationLockQueueLock );
1213
1214                    action = kPutOnFreeQueue;
1215                    success = false;
1216                } else { // we weren't aborted, so we must be ready to go :-)
1217
1218                    // we've already been moved from waiting to active queue
1219                    return true;
1220                }
1221
1222            } else { // the lock request is to be failed
1223
1224                // return unused queue element to queue
1225                action = kPutOnFreeQueue;
1226            }
1227        } else { // it is the same thread, recursive access is allowed
1228
1229            // add one level of recursion
1230            active->count++;
1231
1232            // return unused queue element to queue
1233            action = kPutOnFreeQueue;
1234            success = true;
1235        }
1236    } else { // this object is not already locked, so let this thread through
1237        action = kPutOnActiveQueue;
1238        success = true;
1239    }
1240
1241    // put the new element on a queue
1242    if( kPutOnActiveQueue == action ) {
1243        queue_enter( &gArbitrationLockQueueActive,
1244                     element,
1245                     ArbitrationLockQueueElement *,
1246                     link );
1247    } else if( kPutOnFreeQueue == action ) {
1248        queue_enter( &gArbitrationLockQueueFree,
1249                     element,
1250                     ArbitrationLockQueueElement *,
1251                     link );
1252    } else {
1253        assert( 0 ); // kPutOnWaitingQueue never occurs, handled specially above
1254    }
1255
1256    // unlock global access
1257    IOUnlock( gArbitrationLockQueueLock );
1258
1259    return( success );
1260}
1261
1262void IOService::unlockForArbitration( void )
1263{
1264    bool                          found;
1265    ArbitrationLockQueueElement * element;
1266
1267    // lock global access
1268    IOTakeLock( gArbitrationLockQueueLock );
1269
1270    // find the lock element for this object (ie. on active queue)
1271    found = false;
1272    queue_iterate( &gArbitrationLockQueueActive,
1273                    element,
1274                    ArbitrationLockQueueElement *,
1275                    link )
1276    {
1277        if( element->service == this ) {
1278            found = true;
1279            break;
1280        }
1281    }
1282
1283    assert( found );
1284
1285    // determine whether the lock has been taken recursively
1286    if( element->count > 1 ) {
1287        // undo one level of recursion
1288        element->count--;
1289
1290    } else {
1291
1292        // remove it from the active queue
1293        queue_remove( &gArbitrationLockQueueActive,
1294                      element,
1295                      ArbitrationLockQueueElement *,
1296                      link );
1297
1298        // put it on the free queue
1299        queue_enter( &gArbitrationLockQueueFree,
1300                     element,
1301                     ArbitrationLockQueueElement *,
1302                     link );
1303
1304        // determine whether a thread is waiting for object (head to tail scan)
1305        found = false;
1306        queue_iterate( &gArbitrationLockQueueWaiting,
1307                       element,
1308                       ArbitrationLockQueueElement *,
1309                       link )
1310        {
1311            if( element->service == this ) {
1312                found = true;
1313                break;
1314            }
1315        }
1316
1317        if ( found ) { // we found an interested thread on waiting queue
1318
1319            // remove it from the waiting queue
1320            queue_remove( &gArbitrationLockQueueWaiting,
1321                          element,
1322                          ArbitrationLockQueueElement *,
1323                          link );
1324
1325            // put it on the active queue
1326            queue_enter( &gArbitrationLockQueueActive,
1327                         element,
1328                         ArbitrationLockQueueElement *,
1329                         link );
1330
1331            // wake the waiting thread
1332            IOLockWakeup( gArbitrationLockQueueLock,
1333                          element,
1334                          /* one thread */ true );
1335        }
1336    }
1337
1338    // unlock global access
1339    IOUnlock( gArbitrationLockQueueLock );
1340}
1341
1342void IOService::applyToProviders( IOServiceApplierFunction applier,
1343                                  void * context )
1344{
1345    applyToParents( (IORegistryEntryApplierFunction) applier,
1346                    context, gIOServicePlane );
1347}
1348
1349void IOService::applyToClients( IOServiceApplierFunction applier,
1350                                void * context )
1351{
1352    applyToChildren( (IORegistryEntryApplierFunction) applier,
1353                     context, gIOServicePlane );
1354}
1355
1356
1357/*
1358 * Client messages
1359 */
1360
1361
1362// send a message to a client or interested party of this service
1363IOReturn IOService::messageClient( UInt32 type, OSObject * client,
1364                                   void * argument, vm_size_t argSize )
1365{
1366    IOReturn 				ret;
1367    IOService * 			service;
1368    _IOServiceInterestNotifier *	notify;
1369
1370    if( (service = OSDynamicCast( IOService, client)))
1371        ret = service->message( type, this, argument );
1372
1373    else if( (notify = OSDynamicCast( _IOServiceInterestNotifier, client))) {
1374
1375        _IOServiceNotifierInvocation invocation;
1376        bool			 willNotify;
1377
1378        invocation.thread = current_thread();
1379
1380        LOCKWRITENOTIFY();
1381        willNotify = (0 != (kIOServiceNotifyEnable & notify->state));
1382
1383        if( willNotify) {
1384            queue_enter( &notify->handlerInvocations, &invocation,
1385                            _IOServiceNotifierInvocation *, link );
1386        }
1387        UNLOCKNOTIFY();
1388
1389        if( willNotify) {
1390
1391            ret = (*notify->handler)( notify->target, notify->ref,
1392                                          type, this, argument, argSize );
1393
1394            LOCKWRITENOTIFY();
1395            queue_remove( &notify->handlerInvocations, &invocation,
1396                            _IOServiceNotifierInvocation *, link );
1397            if( kIOServiceNotifyWaiter & notify->state) {
1398                notify->state &= ~kIOServiceNotifyWaiter;
1399                WAKEUPNOTIFY( notify );
1400            }
1401            UNLOCKNOTIFY();
1402
1403        } else
1404            ret = kIOReturnSuccess;
1405
1406    } else
1407        ret = kIOReturnBadArgument;
1408
1409    return( ret );
1410}
1411
1412static void
1413applyToInterestNotifiers(const IORegistryEntry *target,
1414			 const OSSymbol * typeOfInterest,
1415			 OSObjectApplierFunction applier,
1416			 void * context )
1417{
1418    OSArray *		copyArray = 0;
1419
1420    LOCKREADNOTIFY();
1421
1422    IOCommand *notifyList =
1423	OSDynamicCast( IOCommand, target->getProperty( typeOfInterest ));
1424
1425    if( notifyList) {
1426        copyArray = OSArray::withCapacity(1);
1427
1428	// iterate over queue, entry is set to each element in the list
1429	iterqueue(&notifyList->fCommandChain, entry) {
1430	    _IOServiceInterestNotifier * notify;
1431
1432	    queue_element(entry, notify, _IOServiceInterestNotifier *, chain);
1433	    copyArray->setObject(notify);
1434	}
1435    }
1436    UNLOCKNOTIFY();
1437
1438    if( copyArray) {
1439	unsigned int	index;
1440	OSObject *	next;
1441
1442	for( index = 0; (next = copyArray->getObject( index )); index++)
1443	    (*applier)(next, context);
1444	copyArray->release();
1445    }
1446}
1447
1448void IOService::applyToInterested( const OSSymbol * typeOfInterest,
1449                                   OSObjectApplierFunction applier,
1450                                   void * context )
1451{
1452    if (gIOGeneralInterest == typeOfInterest)
1453	applyToClients( (IOServiceApplierFunction) applier, context );
1454    applyToInterestNotifiers(this, typeOfInterest, applier, context);
1455}
1456
1457struct MessageClientsContext {
1458    IOService *	service;
1459    UInt32	type;
1460    void *	argument;
1461    vm_size_t	argSize;
1462    IOReturn	ret;
1463};
1464
1465static void messageClientsApplier( OSObject * object, void * ctx )
1466{
1467    IOReturn		    ret;
1468    MessageClientsContext * context = (MessageClientsContext *) ctx;
1469
1470    ret = context->service->messageClient( context->type,
1471                                           object, context->argument, context->argSize );
1472    if( kIOReturnSuccess != ret)
1473        context->ret = ret;
1474}
1475
1476// send a message to all clients
1477IOReturn IOService::messageClients( UInt32 type,
1478                                    void * argument, vm_size_t argSize )
1479{
1480    MessageClientsContext	context;
1481
1482    context.service	= this;
1483    context.type	= type;
1484    context.argument	= argument;
1485    context.argSize	= argSize;
1486    context.ret		= kIOReturnSuccess;
1487
1488    applyToInterested( gIOGeneralInterest,
1489                       &messageClientsApplier, &context );
1490
1491    return( context.ret );
1492}
1493
1494IOReturn IOService::acknowledgeNotification( IONotificationRef notification,
1495                                              IOOptionBits response )
1496{
1497    return( kIOReturnUnsupported );
1498}
1499
1500IONotifier * IOService::registerInterest( const OSSymbol * typeOfInterest,
1501                  IOServiceInterestHandler handler, void * target, void * ref )
1502{
1503    _IOServiceInterestNotifier * notify = 0;
1504
1505    if( (typeOfInterest != gIOGeneralInterest)
1506     && (typeOfInterest != gIOBusyInterest)
1507     && (typeOfInterest != gIOAppPowerStateInterest)
1508     && (typeOfInterest != gIOConsoleSecurityInterest)
1509     && (typeOfInterest != gIOPriorityPowerStateInterest))
1510        return( 0 );
1511
1512    lockForArbitration();
1513    if( 0 == (__state[0] & kIOServiceInactiveState)) {
1514
1515        notify = new _IOServiceInterestNotifier;
1516        if( notify && !notify->init()) {
1517            notify->release();
1518            notify = 0;
1519        }
1520
1521        if( notify) {
1522            notify->handler = handler;
1523            notify->target = target;
1524            notify->ref = ref;
1525            notify->state = kIOServiceNotifyEnable;
1526            queue_init( &notify->handlerInvocations );
1527
1528            ////// queue
1529
1530            LOCKWRITENOTIFY();
1531
1532	    // Get the head of the notifier linked list
1533	    IOCommand *notifyList = (IOCommand *) getProperty( typeOfInterest );
1534	    if (!notifyList || !OSDynamicCast(IOCommand, notifyList)) {
1535		notifyList = OSTypeAlloc(IOCommand);
1536		if (notifyList) {
1537		    notifyList->init();
1538		    setProperty( typeOfInterest, notifyList);
1539		    notifyList->release();
1540		}
1541	    }
1542
1543	    if (notifyList) {
1544		enqueue(&notifyList->fCommandChain, &notify->chain);
1545		notify->retain();	// ref'ed while in list
1546	    }
1547
1548            UNLOCKNOTIFY();
1549        }
1550    }
1551    unlockForArbitration();
1552
1553    return( notify );
1554}
1555
1556static void cleanInterestList( OSObject * head )
1557{
1558    IOCommand *notifyHead = OSDynamicCast(IOCommand, head);
1559    if (!notifyHead)
1560	return;
1561
1562    LOCKWRITENOTIFY();
1563    while ( queue_entry_t entry = dequeue(&notifyHead->fCommandChain) ) {
1564	queue_next(entry) = queue_prev(entry) = 0;
1565
1566	_IOServiceInterestNotifier * notify;
1567
1568	queue_element(entry, notify, _IOServiceInterestNotifier *, chain);
1569	notify->release();
1570    }
1571    UNLOCKNOTIFY();
1572}
1573
1574void IOService::unregisterAllInterest( void )
1575{
1576    cleanInterestList( getProperty( gIOGeneralInterest ));
1577    cleanInterestList( getProperty( gIOBusyInterest ));
1578    cleanInterestList( getProperty( gIOAppPowerStateInterest ));
1579    cleanInterestList( getProperty( gIOPriorityPowerStateInterest ));
1580    cleanInterestList( getProperty( gIOConsoleSecurityInterest ));
1581}
1582
1583/*
1584 * _IOServiceInterestNotifier
1585 */
1586
1587// wait for all threads, other than the current one,
1588//  to exit the handler
1589
1590void _IOServiceInterestNotifier::wait()
1591{
1592    _IOServiceNotifierInvocation * next;
1593    bool doWait;
1594
1595    do {
1596        doWait = false;
1597        queue_iterate( &handlerInvocations, next,
1598                        _IOServiceNotifierInvocation *, link) {
1599            if( next->thread != current_thread() ) {
1600                doWait = true;
1601                break;
1602            }
1603        }
1604        if( doWait) {
1605            state |= kIOServiceNotifyWaiter;
1606	       SLEEPNOTIFY(this);
1607        }
1608
1609    } while( doWait );
1610}
1611
1612void _IOServiceInterestNotifier::free()
1613{
1614    assert( queue_empty( &handlerInvocations ));
1615    OSObject::free();
1616}
1617
1618void _IOServiceInterestNotifier::remove()
1619{
1620    LOCKWRITENOTIFY();
1621
1622    if( queue_next( &chain )) {
1623	remqueue(&chain);
1624	queue_next( &chain) = queue_prev( &chain) = 0;
1625	release();
1626    }
1627
1628    state &= ~kIOServiceNotifyEnable;
1629
1630    wait();
1631
1632    UNLOCKNOTIFY();
1633
1634    release();
1635}
1636
1637bool _IOServiceInterestNotifier::disable()
1638{
1639    bool	ret;
1640
1641    LOCKWRITENOTIFY();
1642
1643    ret = (0 != (kIOServiceNotifyEnable & state));
1644    state &= ~kIOServiceNotifyEnable;
1645    if( ret)
1646        wait();
1647
1648    UNLOCKNOTIFY();
1649
1650    return( ret );
1651}
1652
1653void _IOServiceInterestNotifier::enable( bool was )
1654{
1655    LOCKWRITENOTIFY();
1656    if( was)
1657        state |= kIOServiceNotifyEnable;
1658    else
1659        state &= ~kIOServiceNotifyEnable;
1660    UNLOCKNOTIFY();
1661}
1662
1663/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1664
1665/*
1666 * Termination
1667 */
1668
1669#define tailQ(o)		setObject(o)
1670#define headQ(o)		setObject(0, o)
1671#define TLOG(fmt, args...)  	{ if(kIOLogYield & gIOKitDebug) { IOLog("[%llx] ", thread_tid(current_thread())); IOLog(fmt, ## args); }}
1672
1673static void _workLoopAction( IOWorkLoop::Action action,
1674                             IOService * service,
1675                             void * p0 = 0, void * p1 = 0,
1676                             void * p2 = 0, void * p3 = 0 )
1677{
1678    IOWorkLoop * wl;
1679
1680    if( (wl = service->getWorkLoop())) {
1681        wl->retain();
1682        wl->runAction( action, service, p0, p1, p2, p3 );
1683        wl->release();
1684    } else
1685        (*action)( service, p0, p1, p2, p3 );
1686}
1687
1688bool IOService::requestTerminate( IOService * provider, IOOptionBits options )
1689{
1690    bool ok;
1691
1692    // if its our only provider
1693    ok = isParent( provider, gIOServicePlane, true);
1694
1695    // -- compat
1696    if( ok) {
1697        provider->terminateClient( this, options | kIOServiceRecursing );
1698        ok = (0 != (__state[1] & kIOServiceRecursing));
1699    }
1700    // --
1701
1702    return( ok );
1703}
1704
1705bool IOService::terminatePhase1( IOOptionBits options )
1706{
1707    IOService *	 victim;
1708    IOService *	 client;
1709    OSIterator * iter;
1710    OSArray *	 makeInactive;
1711	int          waitResult = THREAD_AWAKENED;
1712	bool         wait;
1713    bool		 ok;
1714    bool		 didInactive;
1715    bool		 startPhase2 = false;
1716
1717    TLOG("%s::terminatePhase1(%08llx)\n", getName(), (long long)options);
1718
1719    uint64_t regID = getRegistryEntryID();
1720    IOServiceTrace(
1721	IOSERVICE_TERMINATE_PHASE1,
1722	(uintptr_t) regID,
1723	(uintptr_t) (regID >> 32),
1724	(uintptr_t) this,
1725	(uintptr_t) options);
1726
1727    // -- compat
1728    if( options & kIOServiceRecursing) {
1729        __state[1] |= kIOServiceRecursing;
1730        return( true );
1731    }
1732    // --
1733
1734    makeInactive = OSArray::withCapacity( 16 );
1735    if( !makeInactive)
1736        return( false );
1737
1738    victim = this;
1739    victim->retain();
1740
1741    while( victim ) {
1742
1743		didInactive = victim->lockForArbitration( true );
1744        if( didInactive) {
1745            didInactive = (0 == (victim->__state[0] & kIOServiceInactiveState));
1746            if( didInactive) {
1747                victim->__state[0] |= kIOServiceInactiveState;
1748                victim->__state[0] &= ~(kIOServiceRegisteredState | kIOServiceMatchedState
1749                                        | kIOServiceFirstPublishState | kIOServiceFirstMatchState);
1750
1751				if (victim == this)
1752					victim->__state[1] |= kIOServiceTermPhase1State;
1753
1754                victim->_adjustBusy( 1 );
1755
1756            } else if (victim != this) do {
1757
1758				IOLockLock(gIOServiceBusyLock);
1759				wait = (victim->__state[1] & kIOServiceTermPhase1State);
1760				if( wait) {
1761				    TLOG("%s::waitPhase1(%s)\n", getName(), victim->getName());
1762					victim->__state[1] |= kIOServiceTerm1WaiterState;
1763					victim->unlockForArbitration();
1764					assert_wait((event_t)&victim->__state[1], THREAD_UNINT);
1765				}
1766				IOLockUnlock(gIOServiceBusyLock);
1767				if( wait) {
1768					waitResult = thread_block(THREAD_CONTINUE_NULL);
1769				    TLOG("%s::did waitPhase1(%s)\n", getName(), victim->getName());
1770					victim->lockForArbitration();
1771				}
1772			} while( wait && (waitResult != THREAD_TIMED_OUT));
1773
1774			victim->unlockForArbitration();
1775        }
1776        if( victim == this)
1777            startPhase2 = didInactive;
1778        if( didInactive) {
1779
1780            victim->deliverNotification( gIOTerminatedNotification, 0, 0xffffffff );
1781            IOUserClient::destroyUserReferences( victim );
1782
1783            iter = victim->getClientIterator();
1784            if( iter) {
1785                while( (client = (IOService *) iter->getNextObject())) {
1786                    TLOG("%s::requestTerminate(%s, %08llx)\n",
1787                            client->getName(), victim->getName(), (long long)options);
1788                    ok = client->requestTerminate( victim, options );
1789                    TLOG("%s::requestTerminate(%s, ok = %d)\n",
1790                            client->getName(), victim->getName(), ok);
1791
1792		    uint64_t regID1 = client->getRegistryEntryID();
1793		    uint64_t regID2 = victim->getRegistryEntryID();
1794		    IOServiceTrace(
1795			(ok ? IOSERVICE_TERMINATE_REQUEST_OK
1796			   : IOSERVICE_TERMINATE_REQUEST_FAIL),
1797			(uintptr_t) regID1,
1798			(uintptr_t) (regID1 >> 32),
1799			(uintptr_t) regID2,
1800			(uintptr_t) (regID2 >> 32));
1801
1802                    if( ok)
1803                        makeInactive->setObject( client );
1804                }
1805                iter->release();
1806            }
1807        }
1808        victim->release();
1809        victim = (IOService *) makeInactive->getObject(0);
1810        if( victim) {
1811            victim->retain();
1812            makeInactive->removeObject(0);
1813        }
1814    }
1815
1816    makeInactive->release();
1817
1818    if( startPhase2)
1819    {
1820		lockForArbitration();
1821		__state[1] &= ~kIOServiceTermPhase1State;
1822		if (kIOServiceTerm1WaiterState & __state[1])
1823		{
1824			__state[1] &= ~kIOServiceTerm1WaiterState;
1825			TLOG("%s::wakePhase1\n", getName());
1826			IOLockLock( gIOServiceBusyLock );
1827			thread_wakeup( (event_t) &__state[1]);
1828			IOLockUnlock( gIOServiceBusyLock );
1829		}
1830		unlockForArbitration();
1831
1832        scheduleTerminatePhase2( options );
1833    }
1834    return( true );
1835}
1836
1837void IOService::scheduleTerminatePhase2( IOOptionBits options )
1838{
1839    AbsoluteTime	deadline;
1840    int			waitResult = THREAD_AWAKENED;
1841    bool		wait, haveDeadline = false;
1842
1843    options |= kIOServiceRequired;
1844
1845    retain();
1846
1847    IOLockLock( gJobsLock );
1848
1849    if( (options & kIOServiceSynchronous)
1850        && (current_thread() != gIOTerminateThread)) {
1851
1852        do {
1853            wait = (gIOTerminateThread != 0);
1854            if( wait) {
1855                // wait to become the terminate thread
1856                IOLockSleep( gJobsLock, &gIOTerminateThread, THREAD_UNINT);
1857            }
1858        } while( wait );
1859
1860        gIOTerminateThread = current_thread();
1861        gIOTerminatePhase2List->setObject( this );
1862        gIOTerminateWork++;
1863
1864        do {
1865	    while( gIOTerminateWork )
1866		terminateWorker( options );
1867            wait = (0 != (__state[1] & kIOServiceBusyStateMask));
1868            if( wait) {
1869                // wait for the victim to go non-busy
1870                if( !haveDeadline) {
1871                    clock_interval_to_deadline( 15, kSecondScale, &deadline );
1872                    haveDeadline = true;
1873                }
1874                waitResult = IOLockSleepDeadline( gJobsLock, &gIOTerminateWork,
1875                                                  deadline, THREAD_UNINT );
1876                if( waitResult == THREAD_TIMED_OUT) {
1877                    IOLog("%s::terminate(kIOServiceSynchronous) timeout\n", getName());
1878		}
1879            }
1880        } while(gIOTerminateWork || (wait && (waitResult != THREAD_TIMED_OUT)));
1881
1882	gIOTerminateThread = 0;
1883	IOLockWakeup( gJobsLock, (event_t) &gIOTerminateThread, /* one-thread */ false);
1884
1885    } else {
1886        // ! kIOServiceSynchronous
1887
1888        gIOTerminatePhase2List->setObject( this );
1889        if( 0 == gIOTerminateWork++) {
1890	    if( !gIOTerminateThread)
1891		kernel_thread_start(&terminateThread, (void *) options, &gIOTerminateThread);
1892	    else
1893		IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false );
1894	}
1895    }
1896
1897    IOLockUnlock( gJobsLock );
1898
1899    release();
1900}
1901
1902void IOService::terminateThread( void * arg, wait_result_t waitResult )
1903{
1904    IOLockLock( gJobsLock );
1905
1906    while (gIOTerminateWork)
1907	terminateWorker( (uintptr_t) arg );
1908
1909    thread_deallocate(gIOTerminateThread);
1910    gIOTerminateThread = 0;
1911    IOLockWakeup( gJobsLock, (event_t) &gIOTerminateThread, /* one-thread */ false);
1912
1913    IOLockUnlock( gJobsLock );
1914}
1915
1916void IOService::scheduleStop( IOService * provider )
1917{
1918    TLOG("%s::scheduleStop(%s)\n", getName(), provider->getName());
1919
1920    uint64_t regID1 = getRegistryEntryID();
1921    uint64_t regID2 = provider->getRegistryEntryID();
1922    IOServiceTrace(
1923	IOSERVICE_TERMINATE_SCHEDULE_STOP,
1924	(uintptr_t) regID1,
1925	(uintptr_t) (regID1 >> 32),
1926	(uintptr_t) regID2,
1927	(uintptr_t) (regID2 >> 32));
1928
1929    IOLockLock( gJobsLock );
1930    gIOStopList->tailQ( this );
1931    gIOStopProviderList->tailQ( provider );
1932
1933    if( 0 == gIOTerminateWork++) {
1934        if( !gIOTerminateThread)
1935	    kernel_thread_start(&terminateThread, (void *) 0, &gIOTerminateThread);
1936        else
1937            IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false );
1938    }
1939
1940    IOLockUnlock( gJobsLock );
1941}
1942
1943void IOService::scheduleFinalize( void )
1944{
1945    TLOG("%s::scheduleFinalize\n", getName());
1946
1947    uint64_t regID1 = getRegistryEntryID();
1948    IOServiceTrace(
1949	IOSERVICE_TERMINATE_SCHEDULE_FINALIZE,
1950	(uintptr_t) regID1,
1951	(uintptr_t) (regID1 >> 32),
1952	0, 0);
1953
1954    IOLockLock( gJobsLock );
1955    gIOFinalizeList->tailQ( this );
1956
1957    if( 0 == gIOTerminateWork++) {
1958        if( !gIOTerminateThread)
1959	    kernel_thread_start(&terminateThread, (void *) 0, &gIOTerminateThread);
1960        else
1961            IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false );
1962    }
1963
1964    IOLockUnlock( gJobsLock );
1965}
1966
1967bool IOService::willTerminate( IOService * provider, IOOptionBits options )
1968{
1969    return( true );
1970}
1971
1972bool IOService::didTerminate( IOService * provider, IOOptionBits options, bool * defer )
1973{
1974    if( false == *defer) {
1975
1976        if( lockForArbitration( true )) {
1977            if( false == provider->handleIsOpen( this ))
1978                scheduleStop( provider );
1979            // -- compat
1980            else {
1981                message( kIOMessageServiceIsRequestingClose, provider, (void *) options );
1982                if( false == provider->handleIsOpen( this ))
1983                    scheduleStop( provider );
1984            }
1985            // --
1986            unlockForArbitration();
1987        }
1988    }
1989
1990    return( true );
1991}
1992
1993void IOService::actionWillTerminate( IOService * victim, IOOptionBits options,
1994				     OSArray * doPhase2List,
1995				     void *unused2 __unused,
1996				     void *unused3 __unused  )
1997{
1998    OSIterator * iter;
1999    IOService *	 client;
2000    bool	 ok;
2001
2002    iter = victim->getClientIterator();
2003    if( iter) {
2004        while( (client = (IOService *) iter->getNextObject())) {
2005            TLOG("%s::willTerminate(%s, %08llx)\n",
2006                    client->getName(), victim->getName(), (long long)options);
2007
2008	    uint64_t regID1 = client->getRegistryEntryID();
2009	    uint64_t regID2 = victim->getRegistryEntryID();
2010	    IOServiceTrace(
2011		IOSERVICE_TERMINATE_WILL,
2012		(uintptr_t) regID1,
2013		(uintptr_t) (regID1 >> 32),
2014		(uintptr_t) regID2,
2015		(uintptr_t) (regID2 >> 32));
2016
2017            ok = client->willTerminate( victim, options );
2018            doPhase2List->tailQ( client );
2019        }
2020        iter->release();
2021    }
2022}
2023
2024void IOService::actionDidTerminate( IOService * victim, IOOptionBits options,
2025			    void *unused1 __unused, void *unused2 __unused,
2026			    void *unused3 __unused )
2027{
2028    OSIterator * iter;
2029    IOService *	 client;
2030    bool defer = false;
2031
2032    victim->messageClients( kIOMessageServiceIsTerminated, (void *) options );
2033
2034    iter = victim->getClientIterator();
2035    if( iter) {
2036        while( (client = (IOService *) iter->getNextObject())) {
2037            TLOG("%s::didTerminate(%s, %08llx)\n",
2038                    client->getName(), victim->getName(), (long long)options);
2039            client->didTerminate( victim, options, &defer );
2040
2041	    uint64_t regID1 = client->getRegistryEntryID();
2042	    uint64_t regID2 = victim->getRegistryEntryID();
2043	    IOServiceTrace(
2044		(defer ? IOSERVICE_TERMINATE_DID_DEFER
2045		       : IOSERVICE_TERMINATE_DID),
2046		(uintptr_t) regID1,
2047		(uintptr_t) (regID1 >> 32),
2048		(uintptr_t) regID2,
2049		(uintptr_t) (regID2 >> 32));
2050
2051            TLOG("%s::didTerminate(%s, defer %d)\n",
2052                    client->getName(), victim->getName(), defer);
2053        }
2054        iter->release();
2055    }
2056}
2057
2058void IOService::actionFinalize( IOService * victim, IOOptionBits options,
2059			    void *unused1 __unused, void *unused2 __unused,
2060			    void *unused3 __unused )
2061{
2062    TLOG("%s::finalize(%08llx)\n", victim->getName(), (long long)options);
2063
2064    uint64_t regID1 = victim->getRegistryEntryID();
2065    IOServiceTrace(
2066	IOSERVICE_TERMINATE_FINALIZE,
2067	(uintptr_t) regID1,
2068	(uintptr_t) (regID1 >> 32),
2069	0, 0);
2070
2071    victim->finalize( options );
2072}
2073
2074void IOService::actionStop( IOService * provider, IOService * client,
2075			    void *unused1 __unused, void *unused2 __unused,
2076			    void *unused3 __unused )
2077{
2078    TLOG("%s::stop(%s)\n", client->getName(), provider->getName());
2079
2080    uint64_t regID1 = provider->getRegistryEntryID();
2081    uint64_t regID2 = client->getRegistryEntryID();
2082    IOServiceTrace(
2083	IOSERVICE_TERMINATE_STOP,
2084	(uintptr_t) regID1,
2085	(uintptr_t) (regID1 >> 32),
2086	(uintptr_t) regID2,
2087	(uintptr_t) (regID2 >> 32));
2088
2089    client->stop( provider );
2090    if( provider->isOpen( client ))
2091        provider->close( client );
2092    TLOG("%s::detach(%s)\n", client->getName(), provider->getName());
2093    client->detach( provider );
2094}
2095
2096void IOService::terminateWorker( IOOptionBits options )
2097{
2098    OSArray *		doPhase2List;
2099    OSArray *		didPhase2List;
2100    OSSet *		freeList;
2101    UInt32		workDone;
2102    IOService * 	victim;
2103    IOService * 	client;
2104    IOService * 	provider;
2105    unsigned int	idx;
2106    bool		moreToDo;
2107    bool		doPhase2;
2108    bool		doPhase3;
2109
2110    options |= kIOServiceRequired;
2111
2112    doPhase2List  = OSArray::withCapacity( 16 );
2113    didPhase2List = OSArray::withCapacity( 16 );
2114    freeList	  = OSSet::withCapacity( 16 );
2115    if( (0 == doPhase2List) || (0 == didPhase2List) || (0 == freeList))
2116        return;
2117
2118    do {
2119        workDone = gIOTerminateWork;
2120
2121        while( (victim = (IOService *) gIOTerminatePhase2List->getObject(0) )) {
2122
2123            victim->retain();
2124            gIOTerminatePhase2List->removeObject(0);
2125            IOLockUnlock( gJobsLock );
2126
2127            while( victim ) {
2128
2129                doPhase2 = victim->lockForArbitration( true );
2130                if( doPhase2) {
2131                    doPhase2 = (0 != (kIOServiceInactiveState & victim->__state[0]));
2132                    if( doPhase2) {
2133                        doPhase2 = (0 == (victim->__state[1] & kIOServiceTermPhase2State))
2134                                && (0 == (victim->__state[1] & kIOServiceConfigState));
2135                        if( doPhase2)
2136                            victim->__state[1] |= kIOServiceTermPhase2State;
2137                    }
2138                    victim->unlockForArbitration();
2139                }
2140                if( doPhase2) {
2141                    if( 0 == victim->getClient()) {
2142                        // no clients - will go to finalize
2143                        IOLockLock( gJobsLock );
2144                        gIOFinalizeList->tailQ( victim );
2145                        IOLockUnlock( gJobsLock );
2146                    } else {
2147                        _workLoopAction( (IOWorkLoop::Action) &actionWillTerminate,
2148                                            victim, (void *) options, (void *) doPhase2List );
2149                    }
2150                    didPhase2List->headQ( victim );
2151                }
2152                victim->release();
2153                victim = (IOService *) doPhase2List->getObject(0);
2154                if( victim) {
2155                    victim->retain();
2156                    doPhase2List->removeObject(0);
2157                }
2158            }
2159
2160            while( (victim = (IOService *) didPhase2List->getObject(0)) ) {
2161
2162                if( victim->lockForArbitration( true )) {
2163                    victim->__state[1] |= kIOServiceTermPhase3State;
2164                    victim->unlockForArbitration();
2165                }
2166                _workLoopAction( (IOWorkLoop::Action) &actionDidTerminate,
2167                                    victim, (void *) options );
2168                didPhase2List->removeObject(0);
2169            }
2170            IOLockLock( gJobsLock );
2171        }
2172
2173        // phase 3
2174        do {
2175            doPhase3 = false;
2176            // finalize leaves
2177            while( (victim = (IOService *) gIOFinalizeList->getObject(0))) {
2178
2179                IOLockUnlock( gJobsLock );
2180                _workLoopAction( (IOWorkLoop::Action) &actionFinalize,
2181                                    victim, (void *) options );
2182                IOLockLock( gJobsLock );
2183                // hold off free
2184                freeList->setObject( victim );
2185                // safe if finalize list is append only
2186                gIOFinalizeList->removeObject(0);
2187            }
2188
2189            for( idx = 0;
2190                 (!doPhase3) && (client = (IOService *) gIOStopList->getObject(idx)); ) {
2191
2192                provider = (IOService *) gIOStopProviderList->getObject(idx);
2193                assert( provider );
2194
2195                if( !provider->isChild( client, gIOServicePlane )) {
2196                    // may be multiply queued - nop it
2197                    TLOG("%s::nop stop(%s)\n", client->getName(), provider->getName());
2198
2199		    uint64_t regID1 = provider->getRegistryEntryID();
2200		    uint64_t regID2 = client->getRegistryEntryID();
2201		    IOServiceTrace(
2202			IOSERVICE_TERMINATE_STOP_NOP,
2203			(uintptr_t) regID1,
2204			(uintptr_t) (regID1 >> 32),
2205			(uintptr_t) regID2,
2206			(uintptr_t) (regID2 >> 32));
2207
2208                } else {
2209                    // a terminated client is not ready for stop if it has clients, skip it
2210                    if( (kIOServiceInactiveState & client->__state[0]) && client->getClient()) {
2211                        TLOG("%s::defer stop(%s)\n", client->getName(), provider->getName());
2212
2213			uint64_t regID1 = provider->getRegistryEntryID();
2214			uint64_t regID2 = client->getRegistryEntryID();
2215			IOServiceTrace(
2216			    IOSERVICE_TERMINATE_STOP_DEFER,
2217			    (uintptr_t) regID1,
2218			    (uintptr_t) (regID1 >> 32),
2219			    (uintptr_t) regID2,
2220			    (uintptr_t) (regID2 >> 32));
2221
2222                        idx++;
2223                        continue;
2224                    }
2225
2226                    IOLockUnlock( gJobsLock );
2227                    _workLoopAction( (IOWorkLoop::Action) &actionStop,
2228                                     provider, (void *) client );
2229                    IOLockLock( gJobsLock );
2230                    // check the finalize list now
2231                    doPhase3 = true;
2232                }
2233                // hold off free
2234                freeList->setObject( client );
2235                freeList->setObject( provider );
2236
2237                // safe if stop list is append only
2238                gIOStopList->removeObject( idx );
2239                gIOStopProviderList->removeObject( idx );
2240                idx = 0;
2241            }
2242
2243        } while( doPhase3 );
2244
2245        gIOTerminateWork -= workDone;
2246        moreToDo = (gIOTerminateWork != 0);
2247
2248        if( !moreToDo) {
2249            TLOG("iokit terminate done, %d stops remain\n", gIOStopList->getCount());
2250	    IOServiceTrace(
2251		IOSERVICE_TERMINATE_DONE,
2252		(uintptr_t) gIOStopList->getCount(), 0, 0, 0);
2253        }
2254
2255    } while( moreToDo );
2256
2257    IOLockUnlock( gJobsLock );
2258
2259    freeList->release();
2260    doPhase2List->release();
2261    didPhase2List->release();
2262
2263    IOLockLock( gJobsLock );
2264}
2265
2266bool IOService::finalize( IOOptionBits options )
2267{
2268    OSIterator *	iter;
2269    IOService *		provider;
2270
2271    iter = getProviderIterator();
2272    assert( iter );
2273
2274    if( iter) {
2275        while( (provider = (IOService *) iter->getNextObject())) {
2276
2277            // -- compat
2278            if( 0 == (__state[1] & kIOServiceTermPhase3State)) {
2279                /* we come down here on programmatic terminate */
2280                stop( provider );
2281                if( provider->isOpen( this ))
2282                    provider->close( this );
2283                detach( provider );
2284            } else {
2285            //--
2286                if( provider->lockForArbitration( true )) {
2287                    if( 0 == (provider->__state[1] & kIOServiceTermPhase3State))
2288                        scheduleStop( provider );
2289                    provider->unlockForArbitration();
2290                }
2291            }
2292        }
2293        iter->release();
2294    }
2295
2296    return( true );
2297}
2298
2299#undef tailQ
2300#undef headQ
2301
2302/*
2303 * Terminate
2304 */
2305
2306void IOService::doServiceTerminate( IOOptionBits options )
2307{
2308}
2309
2310// a method in case someone needs to override it
2311bool IOService::terminateClient( IOService * client, IOOptionBits options )
2312{
2313    bool ok;
2314
2315    if( client->isParent( this, gIOServicePlane, true))
2316        // we are the clients only provider
2317        ok = client->terminate( options );
2318    else
2319	ok = true;
2320
2321    return( ok );
2322}
2323
2324bool IOService::terminate( IOOptionBits options )
2325{
2326    options |= kIOServiceTerminate;
2327
2328    return( terminatePhase1( options ));
2329}
2330
2331/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2332
2333/*
2334 * Open & close
2335 */
2336
2337struct ServiceOpenMessageContext
2338{
2339    IOService *	 service;
2340    UInt32	 type;
2341    IOService *  excludeClient;
2342    IOOptionBits options;
2343};
2344
2345static void serviceOpenMessageApplier( OSObject * object, void * ctx )
2346{
2347    ServiceOpenMessageContext * context = (ServiceOpenMessageContext *) ctx;
2348
2349    if( object != context->excludeClient)
2350        context->service->messageClient( context->type, object, (void *) context->options );
2351}
2352
2353bool IOService::open( 	IOService *	forClient,
2354                        IOOptionBits	options,
2355                        void *		arg )
2356{
2357    bool			ok;
2358    ServiceOpenMessageContext	context;
2359
2360    context.service		= this;
2361    context.type		= kIOMessageServiceIsAttemptingOpen;
2362    context.excludeClient	= forClient;
2363    context.options		= options;
2364
2365    applyToInterested( gIOGeneralInterest,
2366                        &serviceOpenMessageApplier, &context );
2367
2368    if( false == lockForArbitration(false) )
2369        return false;
2370
2371    ok = (0 == (__state[0] & kIOServiceInactiveState));
2372    if( ok)
2373        ok = handleOpen( forClient, options, arg );
2374
2375    unlockForArbitration();
2376
2377    return( ok );
2378}
2379
2380void IOService::close( 	IOService *	forClient,
2381                        IOOptionBits	options )
2382{
2383    bool		wasClosed;
2384    bool		last = false;
2385
2386    lockForArbitration();
2387
2388    wasClosed = handleIsOpen( forClient );
2389    if( wasClosed) {
2390        handleClose( forClient, options );
2391	last = (__state[1] & kIOServiceTermPhase3State);
2392    }
2393
2394    unlockForArbitration();
2395
2396    if( last)
2397        forClient->scheduleStop( this );
2398
2399    else if( wasClosed) {
2400
2401        ServiceOpenMessageContext context;
2402
2403        context.service		= this;
2404        context.type		= kIOMessageServiceWasClosed;
2405        context.excludeClient	= forClient;
2406        context.options		= options;
2407
2408        applyToInterested( gIOGeneralInterest,
2409                            &serviceOpenMessageApplier, &context );
2410    }
2411}
2412
2413bool IOService::isOpen( const IOService * forClient ) const
2414{
2415    IOService *	self = (IOService *) this;
2416    bool ok;
2417
2418    self->lockForArbitration();
2419
2420    ok = handleIsOpen( forClient );
2421
2422    self->unlockForArbitration();
2423
2424    return( ok );
2425}
2426
2427bool IOService::handleOpen( 	IOService *	forClient,
2428                                IOOptionBits	options,
2429                                void *		arg )
2430{
2431    bool	ok;
2432
2433    ok = (0 == __owner);
2434    if( ok )
2435        __owner = forClient;
2436
2437    else if( options & kIOServiceSeize ) {
2438        ok = (kIOReturnSuccess == messageClient( kIOMessageServiceIsRequestingClose,
2439                                __owner, (void *) options ));
2440        if( ok && (0 == __owner ))
2441            __owner = forClient;
2442        else
2443            ok = false;
2444    }
2445    return( ok );
2446}
2447
2448void IOService::handleClose( 	IOService *	forClient,
2449                                IOOptionBits	options )
2450{
2451    if( __owner == forClient)
2452        __owner = 0;
2453}
2454
2455bool IOService::handleIsOpen( 	const IOService * forClient ) const
2456{
2457    if( forClient)
2458	return( __owner == forClient );
2459    else
2460	return( __owner != forClient );
2461}
2462
2463/*
2464 * Probing & starting
2465 */
2466static SInt32 IONotifyOrdering( const OSMetaClassBase * inObj1, const OSMetaClassBase * inObj2, void * ref )
2467{
2468    const _IOServiceNotifier * obj1 = (const _IOServiceNotifier *) inObj1;
2469    const _IOServiceNotifier * obj2 = (const _IOServiceNotifier *) inObj2;
2470    SInt32             val1;
2471    SInt32             val2;
2472
2473    val1 = 0;
2474    val2 = 0;
2475
2476    if ( obj1 )
2477        val1 = obj1->priority;
2478
2479    if ( obj2 )
2480        val2 = obj2->priority;
2481
2482    return ( val1 - val2 );
2483}
2484
2485static SInt32 IOServiceObjectOrder( const OSObject * entry, void * ref)
2486{
2487    OSDictionary *	dict;
2488    IOService *		service;
2489    _IOServiceNotifier * notify;
2490    OSSymbol *		key = (OSSymbol *) ref;
2491    OSNumber *		offset;
2492
2493    if( (dict = OSDynamicCast( OSDictionary, entry)))
2494        offset = OSDynamicCast(OSNumber, dict->getObject( key ));
2495    else if( (notify = OSDynamicCast( _IOServiceNotifier, entry)))
2496	return( notify->priority );
2497
2498    else if( (service = OSDynamicCast( IOService, entry)))
2499        offset = OSDynamicCast(OSNumber, service->getProperty( key ));
2500    else {
2501	assert( false );
2502	offset = 0;
2503    }
2504
2505    if( offset)
2506        return( (SInt32) offset->unsigned32BitValue());
2507    else
2508        return( kIODefaultProbeScore );
2509}
2510
2511SInt32 IOServiceOrdering( const OSMetaClassBase * inObj1, const OSMetaClassBase * inObj2, void * ref )
2512{
2513    const OSObject *	obj1 = (const OSObject *) inObj1;
2514    const OSObject *	obj2 = (const OSObject *) inObj2;
2515    SInt32               val1;
2516    SInt32               val2;
2517
2518    val1 = 0;
2519    val2 = 0;
2520
2521    if ( obj1 )
2522        val1 = IOServiceObjectOrder( obj1, ref );
2523
2524    if ( obj2 )
2525        val2 = IOServiceObjectOrder( obj2, ref );
2526
2527    return ( val1 - val2 );
2528}
2529
2530IOService * IOService::copyClientWithCategory( const OSSymbol * category )
2531{
2532    IOService *		service = 0;
2533    OSIterator *	iter;
2534    const OSSymbol *	nextCat;
2535
2536    iter = getClientIterator();
2537    if( iter) {
2538	while( (service = (IOService *) iter->getNextObject())) {
2539	    if( kIOServiceInactiveState & service->__state[0])
2540		continue;
2541            nextCat = (const OSSymbol *) OSDynamicCast( OSSymbol,
2542			service->getProperty( gIOMatchCategoryKey ));
2543	    if( category == nextCat)
2544	    {
2545		service->retain();
2546		break;
2547	    }
2548	}
2549	iter->release();
2550    }
2551    return( service );
2552}
2553
2554IOService * IOService::getClientWithCategory( const OSSymbol * category )
2555{
2556    IOService *
2557    service = copyClientWithCategory(category);
2558    if (service)
2559	service->release();
2560    return (service);
2561}
2562
2563bool IOService::invokeNotifer( _IOServiceNotifier * notify )
2564{
2565    _IOServiceNotifierInvocation invocation;
2566    bool			 willNotify;
2567    bool			 ret = true;
2568
2569    invocation.thread = current_thread();
2570
2571    LOCKWRITENOTIFY();
2572    willNotify = (0 != (kIOServiceNotifyEnable & notify->state));
2573
2574    if( willNotify) {
2575        queue_enter( &notify->handlerInvocations, &invocation,
2576                        _IOServiceNotifierInvocation *, link );
2577    }
2578    UNLOCKNOTIFY();
2579
2580    if( willNotify) {
2581
2582	ret = (*notify->handler)(notify->target, notify->ref, this, notify);
2583
2584        LOCKWRITENOTIFY();
2585        queue_remove( &notify->handlerInvocations, &invocation,
2586                        _IOServiceNotifierInvocation *, link );
2587        if( kIOServiceNotifyWaiter & notify->state) {
2588            notify->state &= ~kIOServiceNotifyWaiter;
2589            WAKEUPNOTIFY( notify );
2590        }
2591        UNLOCKNOTIFY();
2592    }
2593
2594    return( ret );
2595}
2596
2597/*
2598 * Alloc and probe matching classes,
2599 * called on the provider instance
2600 */
2601
2602void IOService::probeCandidates( OSOrderedSet * matches )
2603{
2604    OSDictionary 	*	match = 0;
2605    OSSymbol 		*	symbol;
2606    IOService 		*	inst;
2607    IOService 		*	newInst;
2608    OSDictionary 	*	props;
2609    SInt32			score;
2610    OSNumber 		*	newPri;
2611    OSOrderedSet 	*	familyMatches = 0;
2612    OSOrderedSet 	*	startList;
2613    OSDictionary	*	startDict = 0;
2614    const OSSymbol	* 	category;
2615    OSIterator		*	iter;
2616    _IOServiceNotifier 	*		notify;
2617    OSObject 		*	nextMatch = 0;
2618    bool			started;
2619    bool			needReloc = false;
2620#if IOMATCHDEBUG
2621    SInt64			debugFlags;
2622#endif
2623    IOService * client = NULL;
2624
2625
2626    assert( matches );
2627    while( !needReloc && (nextMatch = matches->getFirstObject())) {
2628
2629        nextMatch->retain();
2630        matches->removeObject(nextMatch);
2631
2632        if( (notify = OSDynamicCast( _IOServiceNotifier, nextMatch ))) {
2633
2634            lockForArbitration();
2635            if( 0 == (__state[0] & kIOServiceInactiveState))
2636                invokeNotifer( notify );
2637            unlockForArbitration();
2638            nextMatch->release();
2639            nextMatch = 0;
2640            continue;
2641
2642        } else if( !(match = OSDynamicCast( OSDictionary, nextMatch ))) {
2643            nextMatch->release();
2644            nextMatch = 0;
2645            continue;
2646	}
2647
2648	props = 0;
2649#if IOMATCHDEBUG
2650        debugFlags = getDebugFlags( match );
2651#endif
2652
2653        do {
2654            category = OSDynamicCast( OSSymbol,
2655			match->getObject( gIOMatchCategoryKey ));
2656	    if( 0 == category)
2657		category = gIODefaultMatchCategoryKey;
2658
2659	    if( (client = copyClientWithCategory(category)) ) {
2660#if IOMATCHDEBUG
2661		if( debugFlags & kIOLogMatch)
2662		    LOG("%s: match category %s exists\n", getName(),
2663				category->getCStringNoCopy());
2664#endif
2665                nextMatch->release();
2666                nextMatch = 0;
2667
2668		client->release();
2669		client = NULL;
2670
2671                continue;
2672	    }
2673
2674            // create a copy now in case its modified during matching
2675            props = OSDictionary::withDictionary( match, match->getCount());
2676            if( 0 == props)
2677                continue;
2678	    props->setCapacityIncrement(1);
2679
2680	    // check the nub matches
2681	    if( false == matchPassive(props, kIOServiceChangesOK | kIOServiceClassDone))
2682		continue;
2683
2684            // Check to see if driver reloc has been loaded.
2685            needReloc = (false == gIOCatalogue->isModuleLoaded( match ));
2686            if( needReloc) {
2687#if IOMATCHDEBUG
2688		if( debugFlags & kIOLogCatalogue)
2689		    LOG("%s: stalling for module\n", getName());
2690#endif
2691                // If reloc hasn't been loaded, exit;
2692                // reprobing will occur after reloc has been loaded.
2693                continue;
2694	    }
2695
2696            // reorder on family matchPropertyTable score.
2697            if( 0 == familyMatches)
2698                familyMatches = OSOrderedSet::withCapacity( 1,
2699                        IOServiceOrdering, (void *) gIOProbeScoreKey );
2700            if( familyMatches)
2701                familyMatches->setObject( props );
2702
2703        } while( false );
2704
2705        if (nextMatch) {
2706            nextMatch->release();
2707            nextMatch = 0;
2708        }
2709        if( props)
2710            props->release();
2711    }
2712    matches->release();
2713    matches = 0;
2714
2715    if( familyMatches) {
2716
2717        while( !needReloc
2718             && (props = (OSDictionary *) familyMatches->getFirstObject())) {
2719
2720            props->retain();
2721            familyMatches->removeObject( props );
2722
2723            inst = 0;
2724            newInst = 0;
2725#if IOMATCHDEBUG
2726            debugFlags = getDebugFlags( props );
2727#endif
2728            do {
2729                symbol = OSDynamicCast( OSSymbol,
2730                                props->getObject( gIOClassKey));
2731                if( !symbol)
2732                    continue;
2733
2734                //IOLog("%s alloc (symbol %p props %p)\n", symbol->getCStringNoCopy(), symbol, props);
2735
2736                // alloc the driver instance
2737                inst = (IOService *) OSMetaClass::allocClassWithName( symbol);
2738
2739                if( !inst) {
2740                    IOLog("Couldn't alloc class \"%s\"\n",
2741                        symbol->getCStringNoCopy());
2742                    continue;
2743                }
2744
2745                // init driver instance
2746                if( !(inst->init( props ))) {
2747#if IOMATCHDEBUG
2748                    if( debugFlags & kIOLogStart)
2749                        IOLog("%s::init fails\n", symbol->getCStringNoCopy());
2750#endif
2751                    continue;
2752                }
2753                if( __state[1] & kIOServiceSynchronousState)
2754                    inst->__state[1] |= kIOServiceSynchronousState;
2755
2756                // give the driver the default match category if not specified
2757                category = OSDynamicCast( OSSymbol,
2758                            props->getObject( gIOMatchCategoryKey ));
2759                if( 0 == category)
2760                    category = gIODefaultMatchCategoryKey;
2761                inst->setProperty( gIOMatchCategoryKey, (OSObject *) category );
2762                // attach driver instance
2763                if( !(inst->attach( this )))
2764                        continue;
2765
2766                // pass in score from property table
2767                score = familyMatches->orderObject( props );
2768
2769                // & probe the new driver instance
2770#if IOMATCHDEBUG
2771                if( debugFlags & kIOLogProbe)
2772                    LOG("%s::probe(%s)\n",
2773                        inst->getMetaClass()->getClassName(), getName());
2774#endif
2775
2776                newInst = inst->probe( this, &score );
2777                inst->detach( this );
2778                if( 0 == newInst) {
2779#if IOMATCHDEBUG
2780                    if( debugFlags & kIOLogProbe)
2781                        IOLog("%s::probe fails\n", symbol->getCStringNoCopy());
2782#endif
2783                    continue;
2784                }
2785
2786                // save the score
2787                newPri = OSNumber::withNumber( score, 32 );
2788                if( newPri) {
2789                    newInst->setProperty( gIOProbeScoreKey, newPri );
2790                    newPri->release();
2791                }
2792
2793                // add to start list for the match category
2794                if( 0 == startDict)
2795                    startDict = OSDictionary::withCapacity( 1 );
2796                assert( startDict );
2797                startList = (OSOrderedSet *)
2798                                startDict->getObject( category );
2799                if( 0 == startList) {
2800                    startList = OSOrderedSet::withCapacity( 1,
2801                            IOServiceOrdering, (void *) gIOProbeScoreKey );
2802                    if( startDict && startList) {
2803                        startDict->setObject( category, startList );
2804                        startList->release();
2805                    }
2806                }
2807                assert( startList );
2808                if( startList)
2809                    startList->setObject( newInst );
2810
2811            } while( false );
2812
2813            props->release();
2814            if( inst)
2815                inst->release();
2816        }
2817        familyMatches->release();
2818        familyMatches = 0;
2819    }
2820
2821    // start the best (until success) of each category
2822
2823    iter = OSCollectionIterator::withCollection( startDict );
2824    if( iter) {
2825	while( (category = (const OSSymbol *) iter->getNextObject())) {
2826
2827	    startList = (OSOrderedSet *) startDict->getObject( category );
2828	    assert( startList );
2829	    if( !startList)
2830		continue;
2831
2832            started = false;
2833            while( true // (!started)
2834		   && (inst = (IOService *)startList->getFirstObject())) {
2835
2836		inst->retain();
2837		startList->removeObject(inst);
2838
2839#if IOMATCHDEBUG
2840        	debugFlags = getDebugFlags( inst->getPropertyTable() );
2841
2842                if( debugFlags & kIOLogStart) {
2843                    if( started)
2844                        LOG( "match category exists, skipping " );
2845                    LOG( "%s::start(%s) <%d>\n", inst->getName(),
2846                         getName(), inst->getRetainCount());
2847                }
2848#endif
2849                if( false == started)
2850                    started = startCandidate( inst );
2851#if IOMATCHDEBUG
2852                if( (debugFlags & kIOLogStart) && (false == started))
2853                    LOG( "%s::start(%s) <%d> failed\n", inst->getName(), getName(),
2854                         inst->getRetainCount());
2855#endif
2856		inst->release();
2857            }
2858        }
2859	iter->release();
2860    }
2861
2862
2863    // adjust the busy count by +1 if matching is stalled for a module,
2864    // or -1 if a previously stalled matching is complete.
2865    lockForArbitration();
2866    SInt32 adjBusy = 0;
2867    uint64_t regID = getRegistryEntryID();
2868
2869    if( needReloc) {
2870        adjBusy = (__state[1] & kIOServiceModuleStallState) ? 0 : 1;
2871        if( adjBusy) {
2872
2873	    IOServiceTrace(
2874		IOSERVICE_MODULESTALL,
2875		(uintptr_t) regID,
2876		(uintptr_t) (regID >> 32),
2877		(uintptr_t) this,
2878		0);
2879
2880            __state[1] |= kIOServiceModuleStallState;
2881	}
2882
2883    } else if( __state[1] & kIOServiceModuleStallState) {
2884
2885	    IOServiceTrace(
2886	    IOSERVICE_MODULEUNSTALL,
2887	    (uintptr_t) regID,
2888	    (uintptr_t) (regID >> 32),
2889	    (uintptr_t) this,
2890	    0);
2891
2892        __state[1] &= ~kIOServiceModuleStallState;
2893        adjBusy = -1;
2894    }
2895    if( adjBusy)
2896        _adjustBusy( adjBusy );
2897    unlockForArbitration();
2898
2899    if( startDict)
2900	startDict->release();
2901}
2902
2903/*
2904 * Start a previously attached & probed instance,
2905 * called on exporting object instance
2906 */
2907
2908bool IOService::startCandidate( IOService * service )
2909{
2910    bool		ok;
2911
2912    ok = service->attach( this );
2913
2914    if( ok)
2915    {
2916	if (this != gIOResources)
2917	{
2918	    // stall for any nub resources
2919	    checkResources();
2920	    // stall for any driver resources
2921	    service->checkResources();
2922	}
2923
2924	AbsoluteTime startTime;
2925	AbsoluteTime endTime;
2926	UInt64       nano;
2927
2928	if (kIOLogStart & gIOKitDebug)
2929	    clock_get_uptime(&startTime);
2930
2931        ok = service->start(this);
2932
2933	if (kIOLogStart & gIOKitDebug)
2934	{
2935	    clock_get_uptime(&endTime);
2936
2937	    if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0)
2938	    {
2939		SUB_ABSOLUTETIME(&endTime, &startTime);
2940		absolutetime_to_nanoseconds(endTime, &nano);
2941		if (nano > 500000000ULL)
2942		    IOLog("%s::start took %ld ms\n", service->getName(), (long)(UInt32)(nano / 1000000ULL));
2943	    }
2944	}
2945        if( !ok)
2946            service->detach( this );
2947    }
2948    return( ok );
2949}
2950
2951void IOService::publishResource( const char * key, OSObject * value )
2952{
2953    const OSSymbol *	sym;
2954
2955    if( (sym = OSSymbol::withCString( key))) {
2956        publishResource( sym, value);
2957	sym->release();
2958    }
2959}
2960
2961void IOService::publishResource( const OSSymbol * key, OSObject * value )
2962{
2963    if( 0 == value)
2964	value = (OSObject *) gIOServiceKey;
2965
2966    gIOResources->setProperty( key, value);
2967
2968    if( IORecursiveLockHaveLock( gNotificationLock))
2969	return;
2970
2971    gIOResourceGenerationCount++;
2972    gIOResources->registerService();
2973}
2974
2975bool IOService::addNeededResource( const char * key )
2976{
2977    OSObject *	resourcesProp;
2978    OSSet *	set;
2979    OSString *	newKey;
2980    bool ret;
2981
2982    resourcesProp = getProperty( gIOResourceMatchKey );
2983
2984    newKey = OSString::withCString( key );
2985    if( (0 == resourcesProp) || (0 == newKey))
2986	return( false);
2987
2988    set = OSDynamicCast( OSSet, resourcesProp );
2989    if( !set) {
2990	set = OSSet::withCapacity( 1 );
2991	if( set)
2992            set->setObject( resourcesProp );
2993    }
2994    else
2995        set->retain();
2996
2997    set->setObject( newKey );
2998    newKey->release();
2999    ret = setProperty( gIOResourceMatchKey, set );
3000    set->release();
3001
3002    return( ret );
3003}
3004
3005bool IOService::checkResource( OSObject * matching )
3006{
3007    OSString *		str;
3008    OSDictionary *	table;
3009
3010    if( (str = OSDynamicCast( OSString, matching ))) {
3011	if( gIOResources->getProperty( str ))
3012	    return( true );
3013    }
3014
3015    if( str)
3016	table = resourceMatching( str );
3017    else if( (table = OSDynamicCast( OSDictionary, matching )))
3018	table->retain();
3019    else {
3020	IOLog("%s: Can't match using: %s\n", getName(),
3021		matching->getMetaClass()->getClassName());
3022	/* false would stall forever */
3023	return( true );
3024    }
3025
3026    if( gIOKitDebug & kIOLogConfig)
3027        LOG("config(%p): stalling %s\n", IOThreadSelf(), getName());
3028
3029    waitForService( table );
3030
3031    if( gIOKitDebug & kIOLogConfig)
3032        LOG("config(%p): waking\n", IOThreadSelf() );
3033
3034    return( true );
3035}
3036
3037bool IOService::checkResources( void )
3038{
3039    OSObject * 		resourcesProp;
3040    OSSet *		set;
3041    OSIterator *	iter;
3042    bool		ok;
3043
3044    resourcesProp = getProperty( gIOResourceMatchKey );
3045    if( 0 == resourcesProp)
3046        return( true );
3047
3048    if( (set = OSDynamicCast( OSSet, resourcesProp ))) {
3049
3050	iter = OSCollectionIterator::withCollection( set );
3051	ok = (0 != iter);
3052        while( ok && (resourcesProp = iter->getNextObject()) )
3053            ok = checkResource( resourcesProp );
3054	if( iter)
3055	    iter->release();
3056
3057    } else
3058	ok = checkResource( resourcesProp );
3059
3060    return( ok );
3061}
3062
3063
3064void _IOConfigThread::configThread( void )
3065{
3066    _IOConfigThread * 	inst;
3067
3068    do {
3069	if( !(inst = new _IOConfigThread))
3070	    continue;
3071	if( !inst->init())
3072	    continue;
3073	thread_t unused;
3074	if (KERN_SUCCESS != kernel_thread_start(&_IOConfigThread::main, inst, &unused))
3075	    continue;
3076
3077	return;
3078
3079    } while( false);
3080
3081    if( inst)
3082	inst->release();
3083
3084    return;
3085}
3086
3087void _IOConfigThread::free( void )
3088{
3089    thread_deallocate(current_thread());
3090    OSObject::free();
3091}
3092
3093void IOService::doServiceMatch( IOOptionBits options )
3094{
3095    _IOServiceNotifier * notify;
3096    OSIterator *	iter;
3097    OSOrderedSet *	matches;
3098    SInt32		catalogGeneration;
3099    bool		keepGuessing = true;
3100    bool		reRegistered = true;
3101    bool		didRegister;
3102
3103//    job->nub->deliverNotification( gIOPublishNotification,
3104//  				kIOServiceRegisteredState, 0xffffffff );
3105
3106    while( keepGuessing ) {
3107
3108        matches = gIOCatalogue->findDrivers( this, &catalogGeneration );
3109	// the matches list should always be created by findDrivers()
3110        if( matches) {
3111
3112            lockForArbitration();
3113            if( 0 == (__state[0] & kIOServiceFirstPublishState))
3114                deliverNotification( gIOFirstPublishNotification,
3115                                     kIOServiceFirstPublishState, 0xffffffff );
3116	    LOCKREADNOTIFY();
3117            __state[1] &= ~kIOServiceNeedConfigState;
3118            __state[1] |= kIOServiceConfigState;
3119            didRegister = (0 == (kIOServiceRegisteredState & __state[0]));
3120            __state[0] |= kIOServiceRegisteredState;
3121
3122	    keepGuessing &= (0 == (__state[0] & kIOServiceInactiveState));
3123            if (reRegistered && keepGuessing) {
3124                iter = OSCollectionIterator::withCollection( (OSOrderedSet *)
3125                        gNotifications->getObject( gIOPublishNotification ) );
3126                if( iter) {
3127                    while((notify = (_IOServiceNotifier *)
3128                           iter->getNextObject())) {
3129
3130                        if( matchPassive(notify->matching, 0)
3131                         && (kIOServiceNotifyEnable & notify->state))
3132                            matches->setObject( notify );
3133                    }
3134                    iter->release();
3135                }
3136            }
3137
3138	    UNLOCKNOTIFY();
3139	    if (didRegister) {
3140		getMetaClass()->addInstance(this);
3141	    }
3142            unlockForArbitration();
3143
3144            if (keepGuessing && matches->getCount() && (kIOReturnSuccess == getResources()))
3145                probeCandidates( matches );
3146            else
3147                matches->release();
3148        }
3149
3150        lockForArbitration();
3151	reRegistered = (0 != (__state[1] & kIOServiceNeedConfigState));
3152	keepGuessing =
3153		   (reRegistered || (catalogGeneration !=
3154					gIOCatalogue->getGenerationCount()))
3155                && (0 == (__state[0] & kIOServiceInactiveState));
3156
3157	if( keepGuessing)
3158            unlockForArbitration();
3159    }
3160
3161    if( (0 == (__state[0] & kIOServiceInactiveState))
3162     && (0 == (__state[1] & kIOServiceModuleStallState)) ) {
3163        deliverNotification( gIOMatchedNotification,
3164		kIOServiceMatchedState, 0xffffffff );
3165	if( 0 == (__state[0] & kIOServiceFirstMatchState))
3166	    deliverNotification( gIOFirstMatchNotification,
3167		kIOServiceFirstMatchState, 0xffffffff );
3168    }
3169
3170    __state[1] &= ~kIOServiceConfigState;
3171    if( __state[0] & kIOServiceInactiveState)
3172        scheduleTerminatePhase2();
3173
3174    _adjustBusy( -1 );
3175    unlockForArbitration();
3176}
3177
3178UInt32 IOService::_adjustBusy( SInt32 delta )
3179{
3180    IOService * next;
3181    UInt32	count;
3182    UInt32	result;
3183    bool	wasQuiet, nowQuiet, needWake;
3184
3185    next = this;
3186    result = __state[1] & kIOServiceBusyStateMask;
3187
3188    if( delta) do {
3189        if( next != this)
3190            next->lockForArbitration();
3191        count = next->__state[1] & kIOServiceBusyStateMask;
3192        wasQuiet = (0 == count);
3193	if (((delta < 0) && wasQuiet) || ((delta > 0) && (kIOServiceBusyMax == count)))
3194	    OSReportWithBacktrace("%s: bad busy count (%d,%d)\n", next->getName(), count, delta);
3195	else
3196	    count += delta;
3197	next->__state[1] = (next->__state[1] & ~kIOServiceBusyStateMask) | count;
3198        nowQuiet = (0 == count);
3199	needWake = (0 != (kIOServiceBusyWaiterState & next->__state[1]));
3200
3201        if( needWake) {
3202            next->__state[1] &= ~kIOServiceBusyWaiterState;
3203            IOLockLock( gIOServiceBusyLock );
3204	    thread_wakeup( (event_t) next);
3205            IOLockUnlock( gIOServiceBusyLock );
3206        }
3207        if( next != this)
3208            next->unlockForArbitration();
3209
3210        if( (wasQuiet || nowQuiet) ) {
3211	    uint64_t regID = next->getRegistryEntryID();
3212
3213		IOServiceTrace(
3214		((wasQuiet/*nowBusy*/) ? IOSERVICE_BUSY : IOSERVICE_NONBUSY),
3215		(uintptr_t) regID,
3216		(uintptr_t) (regID >> 32),
3217		(uintptr_t) next,
3218		0);
3219
3220	    if (wasQuiet)
3221	    {
3222		next->__timeBusy = mach_absolute_time();
3223	    }
3224	    else
3225	    {
3226		next->__accumBusy += mach_absolute_time() - next->__timeBusy;
3227		next->__timeBusy = 0;
3228	    }
3229
3230	    MessageClientsContext context;
3231
3232	    context.service  = next;
3233	    context.type     = kIOMessageServiceBusyStateChange;
3234	    context.argument = (void *) wasQuiet;	/*nowBusy*/
3235	    context.argSize  = 0;
3236
3237	    applyToInterestNotifiers( next, gIOBusyInterest,
3238				     &messageClientsApplier, &context );
3239
3240#if !NO_KEXTD
3241            if( nowQuiet && (next == gIOServiceRoot)) {
3242                OSKext::considerUnloads();
3243                IOServiceTrace(IOSERVICE_REGISTRY_QUIET, 0, 0, 0, 0);
3244            }
3245#endif
3246        }
3247
3248        delta = nowQuiet ? -1 : +1;
3249
3250    } while( (wasQuiet || nowQuiet) && (next = next->getProvider()));
3251
3252    return( result );
3253}
3254
3255void IOService::adjustBusy( SInt32 delta )
3256{
3257    lockForArbitration();
3258    _adjustBusy( delta );
3259    unlockForArbitration();
3260}
3261
3262uint64_t IOService::getAccumulatedBusyTime( void )
3263{
3264    uint64_t accumBusy = __accumBusy;
3265    uint64_t timeBusy = __timeBusy;
3266    uint64_t nano;
3267
3268    do
3269    {
3270	accumBusy = __accumBusy;
3271	timeBusy  = __timeBusy;
3272	if (timeBusy)
3273	    accumBusy += mach_absolute_time() - timeBusy;
3274    }
3275    while (timeBusy != __timeBusy);
3276
3277    absolutetime_to_nanoseconds(*(AbsoluteTime *)&accumBusy, &nano);
3278
3279    return (nano);
3280}
3281
3282UInt32 IOService::getBusyState( void )
3283{
3284    return( __state[1] & kIOServiceBusyStateMask );
3285}
3286
3287IOReturn IOService::waitForState( UInt32 mask, UInt32 value,
3288				  mach_timespec_t * timeout )
3289{
3290    panic("waitForState");
3291    return (kIOReturnUnsupported);
3292}
3293
3294IOReturn IOService::waitForState( UInt32 mask, UInt32 value,
3295				   uint64_t timeout )
3296{
3297    bool            wait;
3298    int             waitResult = THREAD_AWAKENED;
3299    bool            computeDeadline = true;
3300    AbsoluteTime    abstime;
3301
3302    do {
3303        lockForArbitration();
3304        IOLockLock( gIOServiceBusyLock );
3305        wait = (value != (__state[1] & mask));
3306        if( wait) {
3307            __state[1] |= kIOServiceBusyWaiterState;
3308            unlockForArbitration();
3309            if( timeout != UINT64_MAX ) {
3310                if( computeDeadline ) {
3311                    AbsoluteTime  nsinterval;
3312                    nanoseconds_to_absolutetime(timeout, &nsinterval );
3313                    clock_absolutetime_interval_to_deadline(nsinterval, &abstime);
3314                    computeDeadline = false;
3315                }
3316                assert_wait_deadline((event_t)this, THREAD_UNINT, __OSAbsoluteTime(abstime));
3317            }
3318            else
3319                assert_wait((event_t)this, THREAD_UNINT );
3320        } else
3321            unlockForArbitration();
3322        IOLockUnlock( gIOServiceBusyLock );
3323        if( wait)
3324            waitResult = thread_block(THREAD_CONTINUE_NULL);
3325
3326    } while( wait && (waitResult != THREAD_TIMED_OUT));
3327
3328    if( waitResult == THREAD_TIMED_OUT)
3329        return( kIOReturnTimeout );
3330    else
3331        return( kIOReturnSuccess );
3332}
3333
3334IOReturn IOService::waitQuiet( uint64_t timeout )
3335{
3336    return( waitForState( kIOServiceBusyStateMask, 0, timeout ));
3337}
3338
3339IOReturn IOService::waitQuiet( mach_timespec_t * timeout )
3340{
3341    uint64_t    timeoutNS;
3342
3343    if (timeout)
3344    {
3345	timeoutNS = timeout->tv_sec;
3346	timeoutNS *= kSecondScale;
3347	timeoutNS += timeout->tv_nsec;
3348    }
3349    else
3350	timeoutNS = UINT64_MAX;
3351
3352    return( waitForState( kIOServiceBusyStateMask, 0, timeoutNS ));
3353}
3354
3355bool IOService::serializeProperties( OSSerialize * s ) const
3356{
3357#if 0
3358    ((IOService *)this)->setProperty( ((IOService *)this)->__state,
3359		sizeof( __state), "__state");
3360#endif
3361    return( super::serializeProperties(s) );
3362}
3363
3364
3365void _IOConfigThread::main(void * arg, wait_result_t result)
3366{
3367    _IOConfigThread * self = (_IOConfigThread *) arg;
3368    _IOServiceJob * job;
3369    IOService 	*   nub;
3370    bool	    alive = true;
3371    kern_return_t   kr;
3372    thread_precedence_policy_data_t precedence = { -1 };
3373
3374    kr = thread_policy_set(current_thread(),
3375			    THREAD_PRECEDENCE_POLICY,
3376			    (thread_policy_t) &precedence,
3377			    THREAD_PRECEDENCE_POLICY_COUNT);
3378    if (KERN_SUCCESS != kr)
3379	IOLog("thread_policy_set(%d)\n", kr);
3380
3381    do {
3382
3383//	randomDelay();
3384
3385        semaphore_wait( gJobsSemaphore );
3386
3387	IOTakeLock( gJobsLock );
3388	job = (_IOServiceJob *) gJobs->getFirstObject();
3389        job->retain();
3390        gJobs->removeObject(job);
3391	if( job) {
3392	    gOutstandingJobs--;
3393//	    gNumConfigThreads--;	// we're out of service
3394	    gNumWaitingThreads--;	// we're out of service
3395	}
3396	IOUnlock( gJobsLock );
3397
3398	if( job) {
3399
3400	  nub = job->nub;
3401
3402          if( gIOKitDebug & kIOLogConfig)
3403            LOG("config(%p): starting on %s, %d\n",
3404                        IOThreadSelf(), job->nub->getName(), job->type);
3405
3406	  switch( job->type) {
3407
3408	    case kMatchNubJob:
3409		nub->doServiceMatch( job->options );
3410		break;
3411
3412            default:
3413                LOG("config(%p): strange type (%d)\n",
3414			IOThreadSelf(), job->type );
3415		break;
3416            }
3417
3418	    nub->release();
3419            job->release();
3420
3421            IOTakeLock( gJobsLock );
3422	    alive = (gOutstandingJobs > gNumWaitingThreads);
3423	    if( alive)
3424		gNumWaitingThreads++;	// back in service
3425//		gNumConfigThreads++;
3426	    else {
3427                if( 0 == --gNumConfigThreads) {
3428//                    IOLog("MATCH IDLE\n");
3429                    IOLockWakeup( gJobsLock, (event_t) &gNumConfigThreads, /* one-thread */ false );
3430                }
3431            }
3432            IOUnlock( gJobsLock );
3433	}
3434
3435    } while( alive );
3436
3437    if( gIOKitDebug & kIOLogConfig)
3438        LOG("config(%p): terminating\n", IOThreadSelf() );
3439
3440    self->release();
3441}
3442
3443IOReturn IOService::waitMatchIdle( UInt32 msToWait )
3444{
3445    bool            wait;
3446    int             waitResult = THREAD_AWAKENED;
3447    bool            computeDeadline = true;
3448    AbsoluteTime    deadline;
3449
3450    IOLockLock( gJobsLock );
3451    do {
3452        wait = (0 != gNumConfigThreads);
3453        if( wait) {
3454            if( msToWait) {
3455                if( computeDeadline ) {
3456                    clock_interval_to_deadline(
3457                          msToWait, kMillisecondScale, &deadline );
3458                    computeDeadline = false;
3459                }
3460			  waitResult = IOLockSleepDeadline( gJobsLock, &gNumConfigThreads,
3461								deadline, THREAD_UNINT );
3462	    	   } else {
3463			  waitResult = IOLockSleep( gJobsLock, &gNumConfigThreads,
3464								THREAD_UNINT );
3465	        }
3466        }
3467    } while( wait && (waitResult != THREAD_TIMED_OUT));
3468	IOLockUnlock( gJobsLock );
3469
3470    if( waitResult == THREAD_TIMED_OUT)
3471        return( kIOReturnTimeout );
3472    else
3473        return( kIOReturnSuccess );
3474}
3475
3476void _IOServiceJob::pingConfig( _IOServiceJob * job )
3477{
3478    int		count;
3479    bool	create;
3480
3481    assert( job );
3482
3483    IOTakeLock( gJobsLock );
3484
3485    gOutstandingJobs++;
3486    gJobs->setLastObject( job );
3487
3488    count = gNumWaitingThreads;
3489//    if( gNumConfigThreads) count++;// assume we're called from a config thread
3490
3491    create = (  (gOutstandingJobs > count)
3492		&& (gNumConfigThreads < kMaxConfigThreads) );
3493    if( create) {
3494	gNumConfigThreads++;
3495	gNumWaitingThreads++;
3496    }
3497
3498    IOUnlock( gJobsLock );
3499
3500    job->release();
3501
3502    if( create) {
3503        if( gIOKitDebug & kIOLogConfig)
3504            LOG("config(%d): creating\n", gNumConfigThreads - 1);
3505        _IOConfigThread::configThread();
3506    }
3507
3508    semaphore_signal( gJobsSemaphore );
3509}
3510
3511struct IOServiceMatchContext
3512{
3513    OSDictionary * table;
3514    OSObject *     result;
3515    uint32_t	   options;
3516    uint32_t	   state;
3517    uint32_t	   count;
3518    uint32_t       done;
3519};
3520
3521bool IOService::instanceMatch(const OSObject * entry, void * context)
3522{
3523    IOServiceMatchContext * ctx = (typeof(ctx)) context;
3524    IOService *    service = (typeof(service)) entry;
3525    OSDictionary * table   = ctx->table;
3526    uint32_t	   options = ctx->options;
3527    uint32_t	   state   = ctx->state;
3528    uint32_t       done;
3529    bool           match;
3530
3531    done = 0;
3532    do
3533    {
3534	match = ((state == (state & service->__state[0]))
3535		&& (0 == (service->__state[0] & kIOServiceInactiveState)));
3536	if (!match) break;
3537	ctx->count += table->getCount();
3538        match = service->matchInternal(table, options, &done);
3539	ctx->done += done;
3540    }
3541    while (false);
3542    if (!match)
3543    	return (false);
3544
3545    if ((kIONotifyOnce & options) && (ctx->done == ctx->count))
3546    {
3547	service->retain();
3548	ctx->result = service;
3549	return (true);
3550    }
3551    else if (!ctx->result)
3552    {
3553	ctx->result = OSSet::withObjects((const OSObject **) &service, 1, 1);
3554    }
3555    else
3556    {
3557    	((OSSet *)ctx->result)->setObject(service);
3558    }
3559    return (false);
3560}
3561
3562// internal - call with gNotificationLock
3563OSObject * IOService::copyExistingServices( OSDictionary * matching,
3564		 IOOptionBits inState, IOOptionBits options )
3565{
3566    OSObject *	 current = 0;
3567    OSIterator * iter;
3568    IOService *	 service;
3569    OSObject *	 obj;
3570    OSString *   str;
3571
3572    if( !matching)
3573	return( 0 );
3574
3575#if MATCH_DEBUG
3576    OSSerialize * s = OSSerialize::withCapacity(128);
3577    matching->serialize(s);
3578#endif
3579
3580    if((obj = matching->getObject(gIOProviderClassKey))
3581      && gIOResourcesKey
3582      && gIOResourcesKey->isEqualTo(obj)
3583      && (service = gIOResources))
3584    {
3585	if( (inState == (service->__state[0] & inState))
3586	  && (0 == (service->__state[0] & kIOServiceInactiveState))
3587	  &&  service->matchPassive(matching, options))
3588	{
3589	    if( options & kIONotifyOnce)
3590	    {
3591		service->retain();
3592		current = service;
3593	    }
3594	    else
3595		current = OSSet::withObjects((const OSObject **) &service, 1, 1 );
3596	}
3597    }
3598    else
3599    {
3600    	IOServiceMatchContext ctx;
3601	ctx.table   = matching;
3602	ctx.state   = inState;
3603	ctx.count   = 0;
3604	ctx.done    = 0;
3605	ctx.options = options;
3606	ctx.result  = 0;
3607
3608	if ((str = OSDynamicCast(OSString, obj)))
3609	{
3610	    const OSSymbol * sym = OSSymbol::withString(str);
3611	    OSMetaClass::applyToInstancesOfClassName(sym, instanceMatch, &ctx);
3612	    sym->release();
3613	}
3614	else
3615	{
3616	    IOService::gMetaClass.applyToInstances(instanceMatch, &ctx);
3617	}
3618
3619
3620	current = ctx.result;
3621
3622	options |= kIOServiceInternalDone | kIOServiceClassDone;
3623	if (current && (ctx.done != ctx.count))
3624	{
3625	    OSSet *
3626	    source = OSDynamicCast(OSSet, current);
3627	    current = 0;
3628	    while ((service = (IOService *) source->getAnyObject()))
3629	    {
3630		if (service->matchPassive(matching, options))
3631		{
3632		    if( options & kIONotifyOnce)
3633		    {
3634			service->retain();
3635			current = service;
3636			break;
3637		    }
3638		    if( current)
3639		    {
3640			((OSSet *)current)->setObject( service );
3641		    }
3642		    else
3643		    {
3644			current = OSSet::withObjects(
3645					(const OSObject **) &service, 1, 1 );
3646		    }
3647		}
3648		source->removeObject(service);
3649	    }
3650	    source->release();
3651	}
3652    }
3653
3654#if MATCH_DEBUG
3655    {
3656	OSObject * _current = 0;
3657
3658	iter = IORegistryIterator::iterateOver( gIOServicePlane,
3659					    kIORegistryIterateRecursively );
3660	if( iter) {
3661	    do {
3662		iter->reset();
3663		while( (service = (IOService *) iter->getNextObject())) {
3664		    if( (inState == (service->__state[0] & inState))
3665		    && (0 == (service->__state[0] & kIOServiceInactiveState))
3666		    &&  service->matchPassive(matching, 0)) {
3667
3668			if( options & kIONotifyOnce) {
3669			    service->retain();
3670			    _current = service;
3671			    break;
3672			}
3673			if( _current)
3674			    ((OSSet *)_current)->setObject( service );
3675			else
3676			    _current = OSSet::withObjects(
3677					    (const OSObject **) &service, 1, 1 );
3678		    }
3679		}
3680	    } while( !service && !iter->isValid());
3681	    iter->release();
3682	}
3683
3684
3685	if ( ((current != 0) != (_current != 0))
3686	|| (current && _current && !current->isEqualTo(_current)))
3687	{
3688	    OSSerialize * s1 = OSSerialize::withCapacity(128);
3689	    OSSerialize * s2 = OSSerialize::withCapacity(128);
3690	    current->serialize(s1);
3691	    _current->serialize(s2);
3692	    kprintf("**mismatch** %p %p\n%s\n%s\n%s\n", current, _current, s->text(), s1->text(), s2->text());
3693	    s1->release();
3694	    s2->release();
3695	}
3696
3697	if (_current) _current->release();
3698    }
3699
3700    s->release();
3701#endif
3702
3703    if( current && (0 == (options & (kIONotifyOnce | kIOServiceExistingSet)))) {
3704	iter = OSCollectionIterator::withCollection( (OSSet *)current );
3705	current->release();
3706	current = iter;
3707    }
3708
3709    return( current );
3710}
3711
3712// public version
3713OSIterator * IOService::getMatchingServices( OSDictionary * matching )
3714{
3715    OSIterator *	iter;
3716
3717    // is a lock even needed?
3718    LOCKWRITENOTIFY();
3719
3720    iter = (OSIterator *) copyExistingServices( matching,
3721						kIOServiceMatchedState );
3722
3723    UNLOCKNOTIFY();
3724
3725    return( iter );
3726}
3727
3728IOService * IOService::copyMatchingService( OSDictionary * matching )
3729{
3730    IOService *	service;
3731
3732    // is a lock even needed?
3733    LOCKWRITENOTIFY();
3734
3735    service = (IOService *) copyExistingServices( matching,
3736						kIOServiceMatchedState, kIONotifyOnce );
3737
3738    UNLOCKNOTIFY();
3739
3740    return( service );
3741}
3742
3743struct _IOServiceMatchingNotificationHandlerRef
3744{
3745    IOServiceNotificationHandler handler;
3746    void * ref;
3747};
3748
3749static bool _IOServiceMatchingNotificationHandler( void * target, void * refCon,
3750						   IOService * newService,
3751						   IONotifier * notifier )
3752{
3753    return ((*((_IOServiceNotifier *) notifier)->compatHandler)(target, refCon, newService));
3754}
3755
3756// internal - call with gNotificationLock
3757IONotifier * IOService::setNotification(
3758	    const OSSymbol * type, OSDictionary * matching,
3759            IOServiceMatchingNotificationHandler handler, void * target, void * ref,
3760            SInt32 priority )
3761{
3762    _IOServiceNotifier * notify = 0;
3763    OSOrderedSet *	set;
3764
3765    if( !matching)
3766	return( 0 );
3767
3768    notify = new _IOServiceNotifier;
3769    if( notify && !notify->init()) {
3770        notify->release();
3771        notify = 0;
3772    }
3773
3774    if( notify) {
3775	notify->handler = handler;
3776        notify->target = target;
3777        notify->matching = matching;
3778	matching->retain();
3779	if (handler == &_IOServiceMatchingNotificationHandler)
3780	{
3781	    notify->compatHandler = ((_IOServiceMatchingNotificationHandlerRef *)ref)->handler;
3782	    notify->ref = ((_IOServiceMatchingNotificationHandlerRef *)ref)->ref;
3783	}
3784	else
3785	    notify->ref = ref;
3786        notify->priority = priority;
3787	notify->state = kIOServiceNotifyEnable;
3788        queue_init( &notify->handlerInvocations );
3789
3790        ////// queue
3791
3792        if( 0 == (set = (OSOrderedSet *) gNotifications->getObject( type ))) {
3793            set = OSOrderedSet::withCapacity( 1,
3794			IONotifyOrdering, 0 );
3795            if( set) {
3796                gNotifications->setObject( type, set );
3797                set->release();
3798            }
3799        }
3800        notify->whence = set;
3801        if( set)
3802            set->setObject( notify );
3803    }
3804
3805    return( notify );
3806}
3807
3808// internal - call with gNotificationLock
3809IONotifier * IOService::doInstallNotification(
3810			const OSSymbol * type, OSDictionary * matching,
3811			IOServiceMatchingNotificationHandler handler,
3812			void * target, void * ref,
3813			SInt32 priority, OSIterator ** existing )
3814{
3815    OSIterator *	exist;
3816    IONotifier *	notify;
3817    IOOptionBits	inState;
3818
3819    if( !matching)
3820	return( 0 );
3821
3822    if( type == gIOPublishNotification)
3823	inState = kIOServiceRegisteredState;
3824
3825    else if( type == gIOFirstPublishNotification)
3826	inState = kIOServiceFirstPublishState;
3827
3828    else if( (type == gIOMatchedNotification)
3829	  || (type == gIOFirstMatchNotification))
3830	inState = kIOServiceMatchedState;
3831    else if( type == gIOTerminatedNotification)
3832	inState = 0;
3833    else
3834        return( 0 );
3835
3836    notify = setNotification( type, matching, handler, target, ref, priority );
3837
3838    if( inState)
3839        // get the current set
3840        exist = (OSIterator *) copyExistingServices( matching, inState );
3841    else
3842	exist = 0;
3843
3844    *existing = exist;
3845
3846    return( notify );
3847}
3848
3849#if !defined(__LP64__)
3850IONotifier * IOService::installNotification(const OSSymbol * type, OSDictionary * matching,
3851					IOServiceNotificationHandler handler,
3852					void * target, void * refCon,
3853					SInt32 priority, OSIterator ** existing )
3854{
3855    IONotifier * result;
3856    _IOServiceMatchingNotificationHandlerRef ref;
3857    ref.handler = handler;
3858    ref.ref     = refCon;
3859
3860    result = (_IOServiceNotifier *) installNotification( type, matching,
3861			 &_IOServiceMatchingNotificationHandler,
3862			target, &ref, priority, existing );
3863    if (result)
3864	matching->release();
3865
3866    return (result);
3867}
3868#endif /* !defined(__LP64__) */
3869
3870
3871IONotifier * IOService::installNotification(
3872			const OSSymbol * type, OSDictionary * matching,
3873			IOServiceMatchingNotificationHandler handler,
3874			void * target, void * ref,
3875			SInt32 priority, OSIterator ** existing )
3876{
3877    IONotifier * notify;
3878
3879    LOCKWRITENOTIFY();
3880
3881    notify = doInstallNotification( type, matching, handler, target, ref,
3882		priority, existing );
3883
3884    UNLOCKNOTIFY();
3885
3886    return( notify );
3887}
3888
3889IONotifier * IOService::addNotification(
3890			const OSSymbol * type, OSDictionary * matching,
3891			IOServiceNotificationHandler handler,
3892			void * target, void * refCon,
3893			SInt32 priority )
3894{
3895    IONotifier * result;
3896    _IOServiceMatchingNotificationHandlerRef ref;
3897
3898    ref.handler = handler;
3899    ref.ref     = refCon;
3900
3901    result = addMatchingNotification(type, matching, &_IOServiceMatchingNotificationHandler,
3902			    target, &ref, priority);
3903
3904    if (result)
3905	matching->release();
3906
3907    return (result);
3908}
3909
3910IONotifier * IOService::addMatchingNotification(
3911			const OSSymbol * type, OSDictionary * matching,
3912			IOServiceMatchingNotificationHandler handler,
3913			void * target, void * ref,
3914			SInt32 priority )
3915{
3916    OSIterator *		existing = NULL;
3917    _IOServiceNotifier *	notify;
3918    IOService *			next;
3919
3920    notify = (_IOServiceNotifier *) installNotification( type, matching,
3921		handler, target, ref, priority, &existing );
3922
3923    // send notifications for existing set
3924    if( existing) {
3925
3926        notify->retain();		// in case handler remove()s
3927        while( (next = (IOService *) existing->getNextObject())) {
3928
3929	    next->lockForArbitration();
3930	    if( 0 == (next->__state[0] & kIOServiceInactiveState))
3931                next->invokeNotifer( notify );
3932	    next->unlockForArbitration();
3933	}
3934        notify->release();
3935	existing->release();
3936    }
3937
3938    return( notify );
3939}
3940
3941bool IOService::syncNotificationHandler(
3942			void * /* target */, void * ref,
3943			IOService * newService,
3944			IONotifier * notifier )
3945{
3946
3947    LOCKWRITENOTIFY();
3948    if (!*((IOService **) ref))
3949    {
3950	newService->retain();
3951	(*(IOService **) ref) = newService;
3952	WAKEUPNOTIFY(ref);
3953    }
3954    UNLOCKNOTIFY();
3955
3956    return( false );
3957}
3958
3959IOService * IOService::waitForMatchingService( OSDictionary * matching,
3960						uint64_t timeout)
3961{
3962    IONotifier *	notify = 0;
3963    // priority doesn't help us much since we need a thread wakeup
3964    SInt32		priority = 0;
3965    IOService *  	result;
3966
3967    if (!matching)
3968        return( 0 );
3969
3970    result = NULL;
3971
3972    LOCKWRITENOTIFY();
3973    do
3974    {
3975        result = (IOService *) copyExistingServices( matching,
3976                            kIOServiceMatchedState, kIONotifyOnce );
3977	if (result)
3978	    break;
3979        notify = IOService::setNotification( gIOMatchedNotification, matching,
3980                    &IOService::syncNotificationHandler, (void *) 0,
3981                    &result, priority );
3982	 if (!notify)
3983	    break;
3984        if (UINT64_MAX != timeout)
3985	{
3986	    AbsoluteTime deadline;
3987	    nanoseconds_to_absolutetime(timeout, &deadline);
3988	    clock_absolutetime_interval_to_deadline(deadline, &deadline);
3989	    SLEEPNOTIFYTO(&result, deadline);
3990	}
3991        else
3992	{
3993	    SLEEPNOTIFY(&result);
3994	}
3995    }
3996    while( false );
3997
3998    UNLOCKNOTIFY();
3999
4000    if (notify)
4001        notify->remove();	// dequeues
4002
4003    return( result );
4004}
4005
4006IOService * IOService::waitForService( OSDictionary * matching,
4007					mach_timespec_t * timeout )
4008{
4009    IOService * result;
4010    uint64_t    timeoutNS;
4011
4012    if (timeout)
4013    {
4014	timeoutNS = timeout->tv_sec;
4015	timeoutNS *= kSecondScale;
4016	timeoutNS += timeout->tv_nsec;
4017    }
4018    else
4019	timeoutNS = UINT64_MAX;
4020
4021    result = waitForMatchingService(matching, timeoutNS);
4022
4023    matching->release();
4024    if (result)
4025	result->release();
4026
4027    return (result);
4028}
4029
4030void IOService::deliverNotification( const OSSymbol * type,
4031                            IOOptionBits orNewState, IOOptionBits andNewState )
4032{
4033    _IOServiceNotifier * notify;
4034    OSIterator *	 iter;
4035    OSArray *		 willSend = 0;
4036
4037    lockForArbitration();
4038
4039    if( (0 == (__state[0] & kIOServiceInactiveState))
4040     ||	(type == gIOTerminatedNotification)) {
4041
4042	LOCKREADNOTIFY();
4043
4044        iter = OSCollectionIterator::withCollection( (OSOrderedSet *)
4045                    gNotifications->getObject( type ) );
4046
4047        if( iter) {
4048            while( (notify = (_IOServiceNotifier *) iter->getNextObject())) {
4049
4050                if( matchPassive(notify->matching, 0)
4051                  && (kIOServiceNotifyEnable & notify->state)) {
4052                    if( 0 == willSend)
4053                        willSend = OSArray::withCapacity(8);
4054                    if( willSend)
4055                        willSend->setObject( notify );
4056                }
4057            }
4058            iter->release();
4059        }
4060
4061        __state[0] = (__state[0] | orNewState) & andNewState;
4062
4063        UNLOCKNOTIFY();
4064    }
4065
4066    if( willSend) {
4067        for( unsigned int idx = 0;
4068             (notify = (_IOServiceNotifier *) willSend->getObject(idx));
4069             idx++) {
4070            invokeNotifer( notify );
4071        }
4072        willSend->release();
4073    }
4074    unlockForArbitration();
4075}
4076
4077IOOptionBits IOService::getState( void ) const
4078{
4079    return( __state[0] );
4080}
4081
4082/*
4083 * Helpers to make matching objects for simple cases
4084 */
4085
4086OSDictionary * IOService::serviceMatching( const OSString * name,
4087			OSDictionary * table )
4088{
4089
4090    const OSString *	str;
4091
4092    str = OSSymbol::withString(name);
4093    if( !str)
4094	return( 0 );
4095
4096    if( !table)
4097	table = OSDictionary::withCapacity( 2 );
4098    if( table)
4099        table->setObject(gIOProviderClassKey, (OSObject *)str );
4100    str->release();
4101
4102    return( table );
4103}
4104
4105OSDictionary * IOService::serviceMatching( const char * name,
4106			OSDictionary * table )
4107{
4108    const OSString *	str;
4109
4110    str = OSSymbol::withCString( name );
4111    if( !str)
4112	return( 0 );
4113
4114    table = serviceMatching( str, table );
4115    str->release();
4116    return( table );
4117}
4118
4119OSDictionary * IOService::nameMatching( const OSString * name,
4120			OSDictionary * table )
4121{
4122    if( !table)
4123	table = OSDictionary::withCapacity( 2 );
4124    if( table)
4125        table->setObject( gIONameMatchKey, (OSObject *)name );
4126
4127    return( table );
4128}
4129
4130OSDictionary * IOService::nameMatching( const char * name,
4131			OSDictionary * table )
4132{
4133    const OSString *	str;
4134
4135    str = OSSymbol::withCString( name );
4136    if( !str)
4137	return( 0 );
4138
4139    table = nameMatching( str, table );
4140    str->release();
4141    return( table );
4142}
4143
4144OSDictionary * IOService::resourceMatching( const OSString * str,
4145			OSDictionary * table )
4146{
4147    table = serviceMatching( gIOResourcesKey, table );
4148    if( table)
4149        table->setObject( gIOResourceMatchKey, (OSObject *) str );
4150
4151    return( table );
4152}
4153
4154OSDictionary * IOService::resourceMatching( const char * name,
4155			OSDictionary * table )
4156{
4157    const OSSymbol *	str;
4158
4159    str = OSSymbol::withCString( name );
4160    if( !str)
4161	return( 0 );
4162
4163    table = resourceMatching( str, table );
4164    str->release();
4165
4166    return( table );
4167}
4168
4169OSDictionary * IOService::propertyMatching( const OSSymbol * key, const OSObject * value,
4170			OSDictionary * table )
4171{
4172    OSDictionary * properties;
4173
4174    properties = OSDictionary::withCapacity( 2 );
4175    if( !properties)
4176	return( 0 );
4177    properties->setObject( key, value );
4178
4179    if( !table)
4180	table = OSDictionary::withCapacity( 2 );
4181    if( table)
4182        table->setObject( gIOPropertyMatchKey, properties );
4183
4184    properties->release();
4185
4186    return( table );
4187}
4188
4189OSDictionary * IOService::registryEntryIDMatching( uint64_t entryID,
4190			OSDictionary * table )
4191{
4192    OSNumber *     num;
4193
4194    num = OSNumber::withNumber( entryID, 64 );
4195    if( !num)
4196	return( 0 );
4197
4198    if( !table)
4199	table = OSDictionary::withCapacity( 2 );
4200    if( table)
4201        table->setObject( gIORegistryEntryIDKey, num );
4202
4203    if (num)
4204	num->release();
4205
4206    return( table );
4207}
4208
4209
4210/*
4211 * _IOServiceNotifier
4212 */
4213
4214// wait for all threads, other than the current one,
4215//  to exit the handler
4216
4217void _IOServiceNotifier::wait()
4218{
4219    _IOServiceNotifierInvocation * next;
4220    bool doWait;
4221
4222    do {
4223        doWait = false;
4224        queue_iterate( &handlerInvocations, next,
4225                        _IOServiceNotifierInvocation *, link) {
4226            if( next->thread != current_thread() ) {
4227                doWait = true;
4228                break;
4229            }
4230        }
4231        if( doWait) {
4232            state |= kIOServiceNotifyWaiter;
4233            SLEEPNOTIFY(this);
4234        }
4235
4236    } while( doWait );
4237}
4238
4239void _IOServiceNotifier::free()
4240{
4241    assert( queue_empty( &handlerInvocations ));
4242    OSObject::free();
4243}
4244
4245void _IOServiceNotifier::remove()
4246{
4247    LOCKWRITENOTIFY();
4248
4249    if( whence) {
4250        whence->removeObject( (OSObject *) this );
4251        whence = 0;
4252    }
4253    if( matching) {
4254        matching->release();
4255        matching = 0;
4256    }
4257
4258    state &= ~kIOServiceNotifyEnable;
4259
4260    wait();
4261
4262    UNLOCKNOTIFY();
4263
4264    release();
4265}
4266
4267bool _IOServiceNotifier::disable()
4268{
4269    bool	ret;
4270
4271    LOCKWRITENOTIFY();
4272
4273    ret = (0 != (kIOServiceNotifyEnable & state));
4274    state &= ~kIOServiceNotifyEnable;
4275    if( ret)
4276        wait();
4277
4278    UNLOCKNOTIFY();
4279
4280    return( ret );
4281}
4282
4283void _IOServiceNotifier::enable( bool was )
4284{
4285    LOCKWRITENOTIFY();
4286    if( was)
4287        state |= kIOServiceNotifyEnable;
4288    else
4289        state &= ~kIOServiceNotifyEnable;
4290    UNLOCKNOTIFY();
4291}
4292
4293/*
4294 * IOResources
4295 */
4296
4297IOService * IOResources::resources( void )
4298{
4299    IOResources *	inst;
4300
4301    inst = new IOResources;
4302    if( inst && !inst->init()) {
4303	inst->release();
4304	inst = 0;
4305    }
4306
4307    return( inst );
4308}
4309
4310bool IOResources::init( OSDictionary * dictionary )
4311{
4312    // Do super init first
4313    if ( !super::init() )
4314        return false;
4315    return true;
4316}
4317
4318IOWorkLoop * IOResources::getWorkLoop() const
4319{
4320    // If we are the resource root
4321    // then use the platform's workloop
4322    if (this == (IOResources *) gIOResources)
4323	return getPlatform()->getWorkLoop();
4324    else
4325	return IOService::getWorkLoop();
4326}
4327
4328bool IOResources::matchPropertyTable( OSDictionary * table )
4329{
4330    OSObject *		prop;
4331    OSString *		str;
4332    OSSet *		set;
4333    OSIterator *	iter;
4334    bool		ok = false;
4335
4336    prop = table->getObject( gIOResourceMatchKey );
4337    str = OSDynamicCast( OSString, prop );
4338    if( str)
4339	ok = (0 != getProperty( str ));
4340
4341    else if( (set = OSDynamicCast( OSSet, prop))) {
4342
4343	iter = OSCollectionIterator::withCollection( set );
4344	ok = (iter != 0);
4345        while( ok && (str = OSDynamicCast( OSString, iter->getNextObject()) ))
4346            ok = (0 != getProperty( str ));
4347
4348        if( iter)
4349	    iter->release();
4350    }
4351
4352    return( ok );
4353}
4354
4355void IOService::consoleLockTimer(thread_call_param_t p0, thread_call_param_t p1)
4356{
4357    IOService::updateConsoleUsers(NULL, 0);
4358}
4359
4360void IOService::updateConsoleUsers(OSArray * consoleUsers, IOMessage systemMessage)
4361{
4362    IORegistryEntry * regEntry;
4363    OSObject *        locked = kOSBooleanFalse;
4364    uint32_t          idx;
4365    bool              publish;
4366    OSDictionary *    user;
4367    static IOMessage  sSystemPower;
4368
4369    regEntry = IORegistryEntry::getRegistryRoot();
4370
4371    if (!gIOChosenEntry)
4372	gIOChosenEntry = IORegistryEntry::fromPath("/chosen", gIODTPlane);
4373
4374    IOLockLock(gIOConsoleUsersLock);
4375
4376    if (systemMessage)
4377    {
4378        sSystemPower = systemMessage;
4379#if HIBERNATION
4380	if ((kIOMessageSystemHasPoweredOn == systemMessage) && IOHibernateWasScreenLocked())
4381	{
4382	    locked = kOSBooleanTrue;
4383	}
4384#endif /* HIBERNATION */
4385    }
4386
4387    if (consoleUsers)
4388    {
4389        OSNumber * num = 0;
4390	gIOConsoleLoggedIn = false;
4391	for (idx = 0;
4392	      (user = OSDynamicCast(OSDictionary, consoleUsers->getObject(idx)));
4393	      idx++)
4394	{
4395	    gIOConsoleLoggedIn |= ((kOSBooleanTrue == user->getObject(gIOConsoleSessionOnConsoleKey))
4396	      		&& (kOSBooleanTrue == user->getObject(gIOConsoleSessionLoginDoneKey)));
4397	    if (!num)
4398	    {
4399   	        num = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionScreenLockedTimeKey));
4400	    }
4401	}
4402        gIOConsoleLockTime = num ? num->unsigned32BitValue() : 0;
4403    }
4404
4405    if (!gIOConsoleLoggedIn
4406     || (kIOMessageSystemWillSleep == sSystemPower)
4407     || (kIOMessageSystemPagingOff == sSystemPower))
4408    {
4409	locked = kOSBooleanTrue;
4410    }
4411    else if (gIOConsoleLockTime)
4412    {
4413	clock_sec_t  now;
4414	clock_usec_t microsecs;
4415
4416	clock_get_calendar_microtime(&now, &microsecs);
4417	if (gIOConsoleLockTime > now)
4418	{
4419	    AbsoluteTime deadline;
4420	    clock_interval_to_deadline(gIOConsoleLockTime - now, kSecondScale, &deadline);
4421	    thread_call_enter_delayed(gIOConsoleLockCallout, deadline);
4422	}
4423	else
4424	{
4425	    locked = kOSBooleanTrue;
4426	}
4427    }
4428
4429    publish = (consoleUsers || (locked != regEntry->getProperty(gIOConsoleLockedKey)));
4430    if (publish)
4431    {
4432	regEntry->setProperty(gIOConsoleLockedKey, locked);
4433	if (consoleUsers)
4434	{
4435	    regEntry->setProperty(gIOConsoleUsersKey, consoleUsers);
4436	}
4437	OSIncrementAtomic( &gIOConsoleUsersSeed );
4438    }
4439
4440#if HIBERNATION
4441    if (gIOChosenEntry)
4442    {
4443	uint32_t screenLockState;
4444
4445	if (locked == kOSBooleanTrue) screenLockState = kIOScreenLockLocked;
4446	else if (gIOConsoleLockTime)  screenLockState = kIOScreenLockUnlocked;
4447	else                          screenLockState = kIOScreenLockNoLock;
4448
4449	if (screenLockState != gIOScreenLockState) gIOChosenEntry->setProperty(kIOScreenLockStateKey, &screenLockState, sizeof(screenLockState));
4450	gIOScreenLockState = screenLockState;
4451    }
4452#endif /* HIBERNATION */
4453
4454    IOLockUnlock(gIOConsoleUsersLock);
4455
4456    if (publish)
4457    {
4458	publishResource( gIOConsoleUsersSeedKey, gIOConsoleUsersSeedValue );
4459
4460	MessageClientsContext context;
4461
4462	context.service  = getServiceRoot();
4463	context.type     = kIOMessageConsoleSecurityChange;
4464	context.argument = (void *) regEntry;
4465	context.argSize  = 0;
4466
4467	applyToInterestNotifiers(getServiceRoot(), gIOConsoleSecurityInterest,
4468				 &messageClientsApplier, &context );
4469    }
4470}
4471
4472IOReturn IOResources::setProperties( OSObject * properties )
4473{
4474    IOReturn			err;
4475    const OSSymbol *		key;
4476    OSDictionary *		dict;
4477    OSCollectionIterator *	iter;
4478
4479    err = IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator);
4480    if ( kIOReturnSuccess != err)
4481	return( err );
4482
4483    dict = OSDynamicCast(OSDictionary, properties);
4484    if( 0 == dict)
4485	return( kIOReturnBadArgument);
4486
4487    iter = OSCollectionIterator::withCollection( dict);
4488    if( 0 == iter)
4489	return( kIOReturnBadArgument);
4490
4491    while( (key = OSDynamicCast(OSSymbol, iter->getNextObject())))
4492    {
4493	if (gIOConsoleUsersKey == key) do
4494	{
4495	    OSArray * consoleUsers;
4496	    consoleUsers = OSDynamicCast(OSArray, dict->getObject(key));
4497	    if (!consoleUsers)
4498		continue;
4499	    IOService::updateConsoleUsers(consoleUsers, 0);
4500	}
4501	while (false);
4502
4503	publishResource( key, dict->getObject(key) );
4504    }
4505
4506    iter->release();
4507
4508    return( kIOReturnSuccess );
4509}
4510
4511/*
4512 * Helpers for matching dictionaries.
4513 * Keys existing in matching are checked in properties.
4514 * Keys may be a string or OSCollection of IOStrings
4515 */
4516
4517bool IOService::compareProperty( OSDictionary * matching,
4518                                 const char * 	key )
4519{
4520    OSObject *	value;
4521    bool	ok;
4522
4523    value = matching->getObject( key );
4524    if( value)
4525        ok = value->isEqualTo( getProperty( key ));
4526    else
4527	ok = true;
4528
4529    return( ok );
4530}
4531
4532
4533bool IOService::compareProperty( OSDictionary *   matching,
4534                                 const OSString * key )
4535{
4536    OSObject *	value;
4537    bool	ok;
4538
4539    value = matching->getObject( key );
4540    if( value)
4541        ok = value->isEqualTo( getProperty( key ));
4542    else
4543	ok = true;
4544
4545    return( ok );
4546}
4547
4548bool IOService::compareProperties( OSDictionary * matching,
4549                                   OSCollection * keys )
4550{
4551    OSCollectionIterator *	iter;
4552    const OSString *		key;
4553    bool			ok = true;
4554
4555    if( !matching || !keys)
4556	return( false );
4557
4558    iter = OSCollectionIterator::withCollection( keys );
4559
4560    if( iter) {
4561	while( ok && (key = OSDynamicCast( OSString, iter->getNextObject())))
4562	    ok = compareProperty( matching, key );
4563
4564	iter->release();
4565    }
4566    keys->release();	// !! consume a ref !!
4567
4568    return( ok );
4569}
4570
4571/* Helper to add a location matching dict to the table */
4572
4573OSDictionary * IOService::addLocation( OSDictionary * table )
4574{
4575    OSDictionary * 	dict;
4576
4577    if( !table)
4578	return( 0 );
4579
4580    dict = OSDictionary::withCapacity( 1 );
4581    if( dict) {
4582        table->setObject( gIOLocationMatchKey, dict );
4583        dict->release();
4584    }
4585
4586    return( dict );
4587}
4588
4589/*
4590 * Go looking for a provider to match a location dict.
4591 */
4592
4593IOService * IOService::matchLocation( IOService * /* client */ )
4594{
4595    IOService *	parent;
4596
4597    parent = getProvider();
4598
4599    if( parent)
4600        parent = parent->matchLocation( this );
4601
4602    return( parent );
4603}
4604
4605bool IOService::matchInternal(OSDictionary * table, uint32_t options, uint32_t * did)
4606{
4607    OSString *		matched;
4608    OSObject *		obj;
4609    OSString *		str;
4610    IORegistryEntry *	entry;
4611    OSNumber *		num;
4612    bool		match = true;
4613    bool                changesOK = (0 != (kIOServiceChangesOK & options));
4614    uint32_t            count;
4615    uint32_t            done;
4616
4617    do
4618    {
4619	count = table->getCount();
4620	done = 0;
4621	str = OSDynamicCast(OSString, table->getObject(gIOProviderClassKey));
4622	if (str) {
4623	    done++;
4624	    match = ((kIOServiceClassDone & options) || (0 != metaCast(str)));
4625#if MATCH_DEBUG
4626	    match = (0 != metaCast( str ));
4627	    if ((kIOServiceClassDone & options) && !match) panic("classDone");
4628#endif
4629	    if ((!match) || (done == count)) break;
4630	}
4631
4632	obj = table->getObject( gIONameMatchKey );
4633	if( obj) {
4634	    done++;
4635	    match = compareNames( obj, changesOK ? &matched : 0 );
4636	    if (!match)	break;
4637	    if( changesOK && matched) {
4638		// leave a hint as to which name matched
4639		table->setObject( gIONameMatchedKey, matched );
4640		matched->release();
4641	    }
4642	    if (done == count) break;
4643	}
4644
4645	str = OSDynamicCast( OSString, table->getObject( gIOLocationMatchKey ));
4646	if (str)
4647	{
4648    	    const OSSymbol * sym;
4649	    done++;
4650	    match = false;
4651	    sym = copyLocation();
4652	    if (sym) {
4653		match = sym->isEqualTo( str );
4654		sym->release();
4655	    }
4656	    if ((!match) || (done == count)) break;
4657	}
4658
4659	obj = table->getObject( gIOPropertyMatchKey );
4660	if( obj)
4661	{
4662	    OSDictionary * dict;
4663	    OSDictionary * nextDict;
4664	    OSIterator *   iter;
4665	    done++;
4666	    match = false;
4667	    dict = dictionaryWithProperties();
4668	    if( dict) {
4669		nextDict = OSDynamicCast( OSDictionary, obj);
4670		if( nextDict)
4671		    iter = 0;
4672		else
4673		    iter = OSCollectionIterator::withCollection(
4674				OSDynamicCast(OSCollection, obj));
4675
4676		while( nextDict
4677		    || (iter && (0 != (nextDict = OSDynamicCast(OSDictionary,
4678					    iter->getNextObject()))))) {
4679		    match = dict->isEqualTo( nextDict, nextDict);
4680		    if( match)
4681			break;
4682		    nextDict = 0;
4683		}
4684		dict->release();
4685		if( iter)
4686		    iter->release();
4687	    }
4688	    if ((!match) || (done == count)) break;
4689	}
4690
4691	str = OSDynamicCast( OSString, table->getObject( gIOPathMatchKey ));
4692	if( str) {
4693	    done++;
4694	    entry = IORegistryEntry::fromPath( str->getCStringNoCopy() );
4695	    match = (this == entry);
4696	    if( entry)
4697		entry->release();
4698	    if ((!match) || (done == count)) break;
4699	}
4700
4701	num = OSDynamicCast( OSNumber, table->getObject( gIORegistryEntryIDKey ));
4702	if (num) {
4703	    done++;
4704	    match = (getRegistryEntryID() == num->unsigned64BitValue());
4705	    if ((!match) || (done == count)) break;
4706	}
4707
4708	num = OSDynamicCast( OSNumber, table->getObject( gIOMatchedServiceCountKey ));
4709	if( num)
4710	{
4711	    OSIterator *	iter;
4712	    IOService *		service = 0;
4713	    UInt32		serviceCount = 0;
4714
4715	    done++;
4716	    iter = getClientIterator();
4717	    if( iter) {
4718		while( (service = (IOService *) iter->getNextObject())) {
4719		    if( kIOServiceInactiveState & service->__state[0])
4720			continue;
4721		    if( 0 == service->getProperty( gIOMatchCategoryKey ))
4722			continue;
4723		    ++serviceCount;
4724		}
4725		iter->release();
4726	    }
4727	    match = (serviceCount == num->unsigned32BitValue());
4728	    if ((!match) || (done == count)) break;
4729	}
4730
4731#define propMatch(key)					\
4732	obj = table->getObject(key);			\
4733	if (obj)					\
4734	{						\
4735	    OSObject * prop;				\
4736	    done++;					\
4737	    prop = copyProperty(key);			\
4738	    match = obj->isEqualTo(prop);		\
4739            if (prop) prop->release();			\
4740	    if ((!match) || (done == count)) break;	\
4741	}
4742	propMatch(kIOBSDNameKey)
4743	propMatch(kIOBSDMajorKey)
4744	propMatch(kIOBSDMinorKey)
4745	propMatch(kIOBSDUnitKey)
4746#undef propMatch
4747    }
4748    while (false);
4749
4750    if (did) *did = done;
4751    return (match);
4752}
4753
4754bool IOService::passiveMatch( OSDictionary * table, bool changesOK )
4755{
4756    return (matchPassive(table, changesOK ? kIOServiceChangesOK : 0));
4757}
4758
4759bool IOService::matchPassive(OSDictionary * table, uint32_t options)
4760{
4761    IOService *		where;
4762    OSDictionary *      nextTable;
4763    SInt32		score;
4764    OSNumber *		newPri;
4765    bool		match = true;
4766    bool		matchParent = false;
4767    uint32_t		count;
4768    uint32_t		done;
4769
4770    assert( table );
4771
4772#if MATCH_DEBUG
4773    OSDictionary * root = table;
4774#endif
4775
4776    where = this;
4777    do
4778    {
4779        do
4780        {
4781	    count = table->getCount();
4782	    if (!(kIOServiceInternalDone & options))
4783	    {
4784		match = where->matchInternal(table, options, &done);
4785		// don't call family if we've done all the entries in the table
4786		if ((!match) || (done == count)) break;
4787            }
4788
4789            // pass in score from property table
4790            score = IOServiceObjectOrder( table, (void *) gIOProbeScoreKey);
4791
4792            // do family specific matching
4793            match = where->matchPropertyTable( table, &score );
4794
4795            if( !match) {
4796#if IOMATCHDEBUG
4797                if( kIOLogMatch & getDebugFlags( table ))
4798                    LOG("%s: family specific matching fails\n", where->getName());
4799#endif
4800                break;
4801            }
4802
4803            if (kIOServiceChangesOK & options) {
4804                // save the score
4805                newPri = OSNumber::withNumber( score, 32 );
4806                if( newPri) {
4807                    table->setObject( gIOProbeScoreKey, newPri );
4808                    newPri->release();
4809                }
4810            }
4811
4812	    options = 0;
4813            matchParent = false;
4814
4815            nextTable = OSDynamicCast(OSDictionary,
4816                  table->getObject( gIOParentMatchKey ));
4817            if( nextTable) {
4818		// look for a matching entry anywhere up to root
4819                match = false;
4820                matchParent = true;
4821		table = nextTable;
4822                break;
4823            }
4824
4825            table = OSDynamicCast(OSDictionary,
4826                    table->getObject( gIOLocationMatchKey ));
4827            if (table) {
4828		// look for a matching entry at matchLocation()
4829                match = false;
4830                where = where->getProvider();
4831                if (where && (where = where->matchLocation(where))) continue;
4832            }
4833            break;
4834        }
4835        while (true);
4836    }
4837    while( matchParent && (!match) && (where = where->getProvider()) );
4838
4839#if MATCH_DEBUG
4840    if (where != this)
4841    {
4842	OSSerialize * s = OSSerialize::withCapacity(128);
4843	root->serialize(s);
4844	kprintf("parent match 0x%llx, %d,\n%s\n", getRegistryEntryID(), match, s->text());
4845	s->release();
4846    }
4847#endif
4848
4849    return( match );
4850}
4851
4852
4853IOReturn IOService::newUserClient( task_t owningTask, void * securityID,
4854                                    UInt32 type,  OSDictionary * properties,
4855                                    IOUserClient ** handler )
4856{
4857    const OSSymbol *userClientClass = 0;
4858    IOUserClient *client;
4859    OSObject *temp;
4860
4861    if (kIOReturnSuccess == newUserClient( owningTask, securityID, type, handler ))
4862	return kIOReturnSuccess;
4863
4864    // First try my own properties for a user client class name
4865    temp = getProperty(gIOUserClientClassKey);
4866    if (temp) {
4867	if (OSDynamicCast(OSSymbol, temp))
4868	    userClientClass = (const OSSymbol *) temp;
4869	else if (OSDynamicCast(OSString, temp)) {
4870	    userClientClass = OSSymbol::withString((OSString *) temp);
4871	    if (userClientClass)
4872		setProperty(kIOUserClientClassKey,
4873			    (OSObject *) userClientClass);
4874	}
4875    }
4876
4877    // Didn't find one so lets just bomb out now without further ado.
4878    if (!userClientClass)
4879        return kIOReturnUnsupported;
4880
4881    // This reference is consumed by the IOServiceOpen call
4882    temp = OSMetaClass::allocClassWithName(userClientClass);
4883    if (!temp)
4884        return kIOReturnNoMemory;
4885
4886    if (OSDynamicCast(IOUserClient, temp))
4887        client = (IOUserClient *) temp;
4888    else {
4889        temp->release();
4890        return kIOReturnUnsupported;
4891    }
4892
4893    if ( !client->initWithTask(owningTask, securityID, type, properties) ) {
4894        client->release();
4895        return kIOReturnBadArgument;
4896    }
4897
4898    if ( !client->attach(this) ) {
4899        client->release();
4900        return kIOReturnUnsupported;
4901    }
4902
4903    if ( !client->start(this) ) {
4904        client->detach(this);
4905        client->release();
4906        return kIOReturnUnsupported;
4907    }
4908
4909    *handler = client;
4910    return kIOReturnSuccess;
4911}
4912
4913IOReturn IOService::newUserClient( task_t owningTask, void * securityID,
4914                                    UInt32 type, IOUserClient ** handler )
4915{
4916    return( kIOReturnUnsupported );
4917}
4918
4919IOReturn IOService::requestProbe( IOOptionBits options )
4920{
4921    return( kIOReturnUnsupported);
4922}
4923
4924/*
4925 * Convert an IOReturn to text. Subclasses which add additional
4926 * IOReturn's should override this method and call
4927 * super::stringFromReturn if the desired value is not found.
4928 */
4929
4930const char * IOService::stringFromReturn( IOReturn rtn )
4931{
4932    static const IONamedValue IOReturn_values[] = {
4933        {kIOReturnSuccess,          "success"                           },
4934        {kIOReturnError,            "general error"                     },
4935        {kIOReturnNoMemory,         "memory allocation error"           },
4936        {kIOReturnNoResources,      "resource shortage"                 },
4937        {kIOReturnIPCError,         "Mach IPC failure"                  },
4938        {kIOReturnNoDevice,         "no such device"                    },
4939        {kIOReturnNotPrivileged,    "privilege violation"               },
4940        {kIOReturnBadArgument,      "invalid argument"                  },
4941        {kIOReturnLockedRead,       "device is read locked"             },
4942        {kIOReturnLockedWrite,      "device is write locked"            },
4943        {kIOReturnExclusiveAccess,  "device is exclusive access"        },
4944        {kIOReturnBadMessageID,     "bad IPC message ID"                },
4945        {kIOReturnUnsupported,      "unsupported function"              },
4946        {kIOReturnVMError,          "virtual memory error"              },
4947        {kIOReturnInternalError,    "internal driver error"             },
4948        {kIOReturnIOError,          "I/O error"                         },
4949        {kIOReturnCannotLock,       "cannot acquire lock"               },
4950        {kIOReturnNotOpen,          "device is not open"                },
4951        {kIOReturnNotReadable,      "device is not readable"            },
4952        {kIOReturnNotWritable,      "device is not writeable"           },
4953        {kIOReturnNotAligned,       "alignment error"                   },
4954        {kIOReturnBadMedia,         "media error"                       },
4955        {kIOReturnStillOpen,        "device is still open"              },
4956        {kIOReturnRLDError,         "rld failure"                       },
4957        {kIOReturnDMAError,         "DMA failure"                       },
4958        {kIOReturnBusy,             "device is busy"                    },
4959        {kIOReturnTimeout,          "I/O timeout"                       },
4960        {kIOReturnOffline,          "device is offline"                 },
4961        {kIOReturnNotReady,         "device is not ready"               },
4962        {kIOReturnNotAttached,      "device/channel is not attached"    },
4963        {kIOReturnNoChannels,       "no DMA channels available"         },
4964        {kIOReturnNoSpace,          "no space for data"                 },
4965        {kIOReturnPortExists,       "device port already exists"        },
4966        {kIOReturnCannotWire,       "cannot wire physical memory"       },
4967        {kIOReturnNoInterrupt,      "no interrupt attached"             },
4968        {kIOReturnNoFrames,         "no DMA frames enqueued"            },
4969        {kIOReturnMessageTooLarge,  "message is too large"              },
4970        {kIOReturnNotPermitted,     "operation is not permitted"        },
4971        {kIOReturnNoPower,          "device is without power"           },
4972        {kIOReturnNoMedia,          "media is not present"              },
4973        {kIOReturnUnformattedMedia, "media is not formatted"            },
4974        {kIOReturnUnsupportedMode,  "unsupported mode"                  },
4975        {kIOReturnUnderrun,         "data underrun"                     },
4976        {kIOReturnOverrun,          "data overrun"                      },
4977        {kIOReturnDeviceError,      "device error"                      },
4978        {kIOReturnNoCompletion,     "no completion routine"             },
4979        {kIOReturnAborted,          "operation was aborted"             },
4980        {kIOReturnNoBandwidth,      "bus bandwidth would be exceeded"   },
4981        {kIOReturnNotResponding,    "device is not responding"          },
4982        {kIOReturnInvalid,          "unanticipated driver error"        },
4983        {0,                         NULL                                }
4984    };
4985
4986    return IOFindNameForValue(rtn, IOReturn_values);
4987}
4988
4989/*
4990 * Convert an IOReturn to an errno.
4991 */
4992int IOService::errnoFromReturn( IOReturn rtn )
4993{
4994    switch(rtn) {
4995        // (obvious match)
4996        case kIOReturnSuccess:
4997            return(0);
4998        case kIOReturnNoMemory:
4999            return(ENOMEM);
5000        case kIOReturnNoDevice:
5001            return(ENXIO);
5002        case kIOReturnVMError:
5003            return(EFAULT);
5004        case kIOReturnNotPermitted:
5005            return(EPERM);
5006        case kIOReturnNotPrivileged:
5007            return(EACCES);
5008        case kIOReturnIOError:
5009            return(EIO);
5010        case kIOReturnNotWritable:
5011            return(EROFS);
5012        case kIOReturnBadArgument:
5013            return(EINVAL);
5014        case kIOReturnUnsupported:
5015            return(ENOTSUP);
5016        case kIOReturnBusy:
5017            return(EBUSY);
5018        case kIOReturnNoPower:
5019            return(EPWROFF);
5020        case kIOReturnDeviceError:
5021            return(EDEVERR);
5022        case kIOReturnTimeout:
5023            return(ETIMEDOUT);
5024        case kIOReturnMessageTooLarge:
5025            return(EMSGSIZE);
5026        case kIOReturnNoSpace:
5027            return(ENOSPC);
5028        case kIOReturnCannotLock:
5029            return(ENOLCK);
5030
5031        // (best match)
5032        case kIOReturnBadMessageID:
5033        case kIOReturnNoCompletion:
5034        case kIOReturnNotAligned:
5035            return(EINVAL);
5036        case kIOReturnNotReady:
5037            return(EBUSY);
5038        case kIOReturnRLDError:
5039            return(EBADMACHO);
5040        case kIOReturnPortExists:
5041        case kIOReturnStillOpen:
5042            return(EEXIST);
5043        case kIOReturnExclusiveAccess:
5044        case kIOReturnLockedRead:
5045        case kIOReturnLockedWrite:
5046        case kIOReturnNotOpen:
5047        case kIOReturnNotReadable:
5048            return(EACCES);
5049        case kIOReturnCannotWire:
5050        case kIOReturnNoResources:
5051            return(ENOMEM);
5052        case kIOReturnAborted:
5053        case kIOReturnOffline:
5054        case kIOReturnNotResponding:
5055            return(EBUSY);
5056        case kIOReturnBadMedia:
5057        case kIOReturnNoMedia:
5058        case kIOReturnNotAttached:
5059        case kIOReturnUnformattedMedia:
5060            return(ENXIO); // (media error)
5061        case kIOReturnDMAError:
5062        case kIOReturnOverrun:
5063        case kIOReturnUnderrun:
5064            return(EIO); // (transfer error)
5065        case kIOReturnNoBandwidth:
5066        case kIOReturnNoChannels:
5067        case kIOReturnNoFrames:
5068        case kIOReturnNoInterrupt:
5069            return(EIO); // (hardware error)
5070        case kIOReturnError:
5071        case kIOReturnInternalError:
5072        case kIOReturnInvalid:
5073            return(EIO); // (generic error)
5074        case kIOReturnIPCError:
5075            return(EIO); // (ipc error)
5076        default:
5077            return(EIO); // (all other errors)
5078    }
5079}
5080
5081IOReturn IOService::message( UInt32 type, IOService * provider,
5082				void * argument )
5083{
5084    /*
5085     * Generic entry point for calls from the provider.  A return value of
5086     * kIOReturnSuccess indicates that the message was received, and where
5087     * applicable, that it was successful.
5088     */
5089
5090    return kIOReturnUnsupported;
5091}
5092
5093/*
5094 * Device memory
5095 */
5096
5097IOItemCount IOService::getDeviceMemoryCount( void )
5098{
5099    OSArray *		array;
5100    IOItemCount		count;
5101
5102    array = OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey));
5103    if( array)
5104	count = array->getCount();
5105    else
5106	count = 0;
5107
5108    return( count);
5109}
5110
5111IODeviceMemory * IOService::getDeviceMemoryWithIndex( unsigned int index )
5112{
5113    OSArray *		array;
5114    IODeviceMemory *	range;
5115
5116    array = OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey));
5117    if( array)
5118	range = (IODeviceMemory *) array->getObject( index );
5119    else
5120	range = 0;
5121
5122    return( range);
5123}
5124
5125IOMemoryMap * IOService::mapDeviceMemoryWithIndex( unsigned int index,
5126						IOOptionBits options )
5127{
5128    IODeviceMemory *	range;
5129    IOMemoryMap *	map;
5130
5131    range = getDeviceMemoryWithIndex( index );
5132    if( range)
5133	map = range->map( options );
5134    else
5135	map = 0;
5136
5137    return( map );
5138}
5139
5140OSArray * IOService::getDeviceMemory( void )
5141{
5142    return( OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey)));
5143}
5144
5145
5146void IOService::setDeviceMemory( OSArray * array )
5147{
5148    setProperty( gIODeviceMemoryKey, array);
5149}
5150
5151/*
5152 * For machines where the transfers on an I/O bus can stall because
5153 * the CPU is in an idle mode, These APIs allow a driver to specify
5154 * the maximum bus stall that they can handle.  0 indicates no limit.
5155 */
5156void IOService::
5157setCPUSnoopDelay(UInt32 __unused ns)
5158{
5159#if defined(__i386__) || defined(__x86_64__)
5160    ml_set_maxsnoop(ns);
5161#endif /* defined(__i386__) || defined(__x86_64__) */
5162}
5163
5164UInt32 IOService::
5165getCPUSnoopDelay()
5166{
5167#if defined(__i386__) || defined(__x86_64__)
5168    return ml_get_maxsnoop();
5169#else
5170    return 0;
5171#endif /* defined(__i386__) || defined(__x86_64__) */
5172}
5173
5174#if defined(__i386__) || defined(__x86_64__)
5175static void
5176requireMaxCpuDelay(IOService * service, UInt32 ns, UInt32 delayType)
5177{
5178    static const UInt kNoReplace = -1U;	// Must be an illegal index
5179    UInt replace = kNoReplace;
5180    bool setCpuDelay = false;
5181
5182    IORecursiveLockLock(sCpuDelayLock);
5183
5184    UInt count = sCpuDelayData->getLength() / sizeof(CpuDelayEntry);
5185    CpuDelayEntry *entries = (CpuDelayEntry *) sCpuDelayData->getBytesNoCopy();
5186    IOService * holder = NULL;
5187
5188    if (ns) {
5189        const CpuDelayEntry ne = {service, ns, delayType};
5190	holder = service;
5191        // Set maximum delay.
5192        for (UInt i = 0; i < count; i++) {
5193            IOService *thisService = entries[i].fService;
5194            bool sameType = (delayType == entries[i].fDelayType);
5195            if ((service == thisService) && sameType)
5196                replace = i;
5197            else if (!thisService) {
5198                if (kNoReplace == replace)
5199                    replace = i;
5200            }
5201            else if (sameType) {
5202                const UInt32 thisMax = entries[i].fMaxDelay;
5203                if (thisMax < ns)
5204		{
5205                    ns = thisMax;
5206		    holder = thisService;
5207		}
5208            }
5209        }
5210
5211        setCpuDelay = true;
5212        if (kNoReplace == replace)
5213            sCpuDelayData->appendBytes(&ne, sizeof(ne));
5214        else
5215            entries[replace] = ne;
5216    }
5217    else {
5218        ns = -1U;	// Set to max unsigned, i.e. no restriction
5219
5220        for (UInt i = 0; i < count; i++) {
5221            // Clear a maximum delay.
5222            IOService *thisService = entries[i].fService;
5223            if (thisService && (delayType == entries[i].fDelayType)) {
5224                UInt32 thisMax = entries[i].fMaxDelay;
5225                if (service == thisService)
5226                    replace = i;
5227                else if (thisMax < ns) {
5228                    ns = thisMax;
5229		    holder = thisService;
5230		}
5231            }
5232        }
5233
5234        // Check if entry found
5235        if (kNoReplace != replace) {
5236            entries[replace].fService = 0;	// Null the entry
5237            setCpuDelay = true;
5238        }
5239    }
5240
5241    if (setCpuDelay)
5242    {
5243        // Must be safe to call from locked context
5244        if (delayType == kCpuDelayBusStall)
5245        {
5246            ml_set_maxbusdelay(ns);
5247        }
5248        else if (delayType == kCpuDelayInterrupt)
5249        {
5250            ml_set_maxintdelay(ns);
5251        }
5252
5253	OSArray * handlers = sCpuLatencyHandlers[delayType];
5254	IOService * target;
5255	if (handlers) for (unsigned int idx = 0;
5256			    (target = (IOService *) handlers->getObject(idx));
5257			    idx++)
5258	{
5259	    target->callPlatformFunction(sCPULatencyFunctionName[delayType], false,
5260					    (void *) (uintptr_t) ns, holder,
5261					    NULL, NULL);
5262	}
5263    }
5264
5265    IORecursiveLockUnlock(sCpuDelayLock);
5266}
5267
5268static IOReturn
5269setLatencyHandler(UInt32 delayType, IOService * target, bool enable)
5270{
5271    IOReturn result = kIOReturnNotFound;
5272    OSArray * array;
5273    unsigned int idx;
5274
5275    IORecursiveLockLock(sCpuDelayLock);
5276
5277    do
5278    {
5279	if (enable && !sCpuLatencyHandlers[delayType])
5280	    sCpuLatencyHandlers[delayType] = OSArray::withCapacity(4);
5281	array = sCpuLatencyHandlers[delayType];
5282	if (!array)
5283	    break;
5284	idx = array->getNextIndexOfObject(target, 0);
5285	if (!enable)
5286	{
5287	    if (-1U != idx)
5288	    {
5289		array->removeObject(idx);
5290		result = kIOReturnSuccess;
5291	    }
5292	}
5293	else
5294	{
5295	    if (-1U != idx) {
5296		result = kIOReturnExclusiveAccess;
5297		break;
5298	    }
5299	    array->setObject(target);
5300
5301	    UInt count = sCpuDelayData->getLength() / sizeof(CpuDelayEntry);
5302	    CpuDelayEntry *entries = (CpuDelayEntry *) sCpuDelayData->getBytesNoCopy();
5303	    UInt32 ns = -1U;	// Set to max unsigned, i.e. no restriction
5304	    IOService * holder = NULL;
5305
5306	    for (UInt i = 0; i < count; i++) {
5307		if (entries[i].fService
5308		  && (delayType == entries[i].fDelayType)
5309		  && (entries[i].fMaxDelay < ns)) {
5310		    ns = entries[i].fMaxDelay;
5311		    holder = entries[i].fService;
5312		}
5313	    }
5314	    target->callPlatformFunction(sCPULatencyFunctionName[delayType], false,
5315					    (void *) (uintptr_t) ns, holder,
5316					    NULL, NULL);
5317	    result = kIOReturnSuccess;
5318	}
5319    }
5320    while (false);
5321
5322    IORecursiveLockUnlock(sCpuDelayLock);
5323
5324    return (result);
5325}
5326
5327#endif /* defined(__i386__) || defined(__x86_64__) */
5328
5329void IOService::
5330requireMaxBusStall(UInt32 __unused ns)
5331{
5332#if defined(__i386__) || defined(__x86_64__)
5333    requireMaxCpuDelay(this, ns, kCpuDelayBusStall);
5334#endif
5335}
5336
5337void IOService::
5338requireMaxInterruptDelay(uint32_t __unused ns)
5339{
5340#if defined(__i386__) || defined(__x86_64__)
5341    requireMaxCpuDelay(this, ns, kCpuDelayInterrupt);
5342#endif
5343}
5344
5345/*
5346 * Device interrupts
5347 */
5348
5349IOReturn IOService::resolveInterrupt(IOService *nub, int source)
5350{
5351  IOInterruptController *interruptController;
5352  OSArray               *array;
5353  OSData                *data;
5354  OSSymbol              *interruptControllerName;
5355  long                  numSources;
5356  IOInterruptSource     *interruptSources;
5357
5358  // Get the parents list from the nub.
5359  array = OSDynamicCast(OSArray, nub->getProperty(gIOInterruptControllersKey));
5360  if (array == 0) return kIOReturnNoResources;
5361
5362  // Allocate space for the IOInterruptSources if needed... then return early.
5363  if (nub->_interruptSources == 0) {
5364    numSources = array->getCount();
5365    interruptSources = (IOInterruptSource *)IOMalloc(numSources * sizeof(IOInterruptSource));
5366    if (interruptSources == 0) return kIOReturnNoMemory;
5367
5368    bzero(interruptSources, numSources * sizeof(IOInterruptSource));
5369
5370    nub->_numInterruptSources = numSources;
5371    nub->_interruptSources = interruptSources;
5372    return kIOReturnSuccess;
5373  }
5374
5375  interruptControllerName = OSDynamicCast(OSSymbol,array->getObject(source));
5376  if (interruptControllerName == 0) return kIOReturnNoResources;
5377
5378  interruptController = getPlatform()->lookUpInterruptController(interruptControllerName);
5379  if (interruptController == 0) return kIOReturnNoResources;
5380
5381  // Get the interrupt numbers from the nub.
5382  array = OSDynamicCast(OSArray, nub->getProperty(gIOInterruptSpecifiersKey));
5383  if (array == 0) return kIOReturnNoResources;
5384  data = OSDynamicCast(OSData, array->getObject(source));
5385  if (data == 0) return kIOReturnNoResources;
5386
5387  // Set the interruptController and interruptSource in the nub's table.
5388  interruptSources = nub->_interruptSources;
5389  interruptSources[source].interruptController = interruptController;
5390  interruptSources[source].vectorData = data;
5391
5392  return kIOReturnSuccess;
5393}
5394
5395IOReturn IOService::lookupInterrupt(int source, bool resolve, IOInterruptController **interruptController)
5396{
5397  IOReturn ret;
5398
5399  /* Make sure the _interruptSources are set */
5400  if (_interruptSources == 0) {
5401    ret = resolveInterrupt(this, source);
5402    if (ret != kIOReturnSuccess) return ret;
5403  }
5404
5405  /* Make sure the local source number is valid */
5406  if ((source < 0) || (source >= _numInterruptSources))
5407    return kIOReturnNoInterrupt;
5408
5409  /* Look up the contoller for the local source */
5410  *interruptController = _interruptSources[source].interruptController;
5411
5412  if (*interruptController == NULL) {
5413    if (!resolve) return kIOReturnNoInterrupt;
5414
5415    /* Try to reslove the interrupt */
5416    ret = resolveInterrupt(this, source);
5417    if (ret != kIOReturnSuccess) return ret;
5418
5419    *interruptController = _interruptSources[source].interruptController;
5420  }
5421
5422  return kIOReturnSuccess;
5423}
5424
5425IOReturn IOService::registerInterrupt(int source, OSObject *target,
5426				      IOInterruptAction handler,
5427				      void *refCon)
5428{
5429  IOInterruptController *interruptController;
5430  IOReturn              ret;
5431
5432  ret = lookupInterrupt(source, true, &interruptController);
5433  if (ret != kIOReturnSuccess) return ret;
5434
5435  /* Register the source */
5436  return interruptController->registerInterrupt(this, source, target,
5437						(IOInterruptHandler)handler,
5438						refCon);
5439}
5440
5441IOReturn IOService::unregisterInterrupt(int source)
5442{
5443  IOInterruptController *interruptController;
5444  IOReturn              ret;
5445
5446  ret = lookupInterrupt(source, false, &interruptController);
5447  if (ret != kIOReturnSuccess) return ret;
5448
5449  /* Unregister the source */
5450  return interruptController->unregisterInterrupt(this, source);
5451}
5452
5453IOReturn IOService::getInterruptType(int source, int *interruptType)
5454{
5455  IOInterruptController *interruptController;
5456  IOReturn              ret;
5457
5458  ret = lookupInterrupt(source, true, &interruptController);
5459  if (ret != kIOReturnSuccess) return ret;
5460
5461  /* Return the type */
5462  return interruptController->getInterruptType(this, source, interruptType);
5463}
5464
5465IOReturn IOService::enableInterrupt(int source)
5466{
5467  IOInterruptController *interruptController;
5468  IOReturn              ret;
5469
5470  ret = lookupInterrupt(source, false, &interruptController);
5471  if (ret != kIOReturnSuccess) return ret;
5472
5473  /* Enable the source */
5474  return interruptController->enableInterrupt(this, source);
5475}
5476
5477IOReturn IOService::disableInterrupt(int source)
5478{
5479  IOInterruptController *interruptController;
5480  IOReturn              ret;
5481
5482  ret = lookupInterrupt(source, false, &interruptController);
5483  if (ret != kIOReturnSuccess) return ret;
5484
5485  /* Disable the source */
5486  return interruptController->disableInterrupt(this, source);
5487}
5488
5489IOReturn IOService::causeInterrupt(int source)
5490{
5491  IOInterruptController *interruptController;
5492  IOReturn              ret;
5493
5494  ret = lookupInterrupt(source, false, &interruptController);
5495  if (ret != kIOReturnSuccess) return ret;
5496
5497  /* Cause an interrupt for the source */
5498  return interruptController->causeInterrupt(this, source);
5499}
5500
5501#if __LP64__
5502OSMetaClassDefineReservedUnused(IOService, 0);
5503OSMetaClassDefineReservedUnused(IOService, 1);
5504OSMetaClassDefineReservedUnused(IOService, 2);
5505OSMetaClassDefineReservedUnused(IOService, 3);
5506OSMetaClassDefineReservedUnused(IOService, 4);
5507OSMetaClassDefineReservedUnused(IOService, 5);
5508#else
5509OSMetaClassDefineReservedUsed(IOService, 0);
5510OSMetaClassDefineReservedUsed(IOService, 1);
5511OSMetaClassDefineReservedUsed(IOService, 2);
5512OSMetaClassDefineReservedUsed(IOService, 3);
5513OSMetaClassDefineReservedUsed(IOService, 4);
5514OSMetaClassDefineReservedUsed(IOService, 5);
5515#endif
5516OSMetaClassDefineReservedUnused(IOService, 6);
5517OSMetaClassDefineReservedUnused(IOService, 7);
5518OSMetaClassDefineReservedUnused(IOService, 8);
5519OSMetaClassDefineReservedUnused(IOService, 9);
5520OSMetaClassDefineReservedUnused(IOService, 10);
5521OSMetaClassDefineReservedUnused(IOService, 11);
5522OSMetaClassDefineReservedUnused(IOService, 12);
5523OSMetaClassDefineReservedUnused(IOService, 13);
5524OSMetaClassDefineReservedUnused(IOService, 14);
5525OSMetaClassDefineReservedUnused(IOService, 15);
5526OSMetaClassDefineReservedUnused(IOService, 16);
5527OSMetaClassDefineReservedUnused(IOService, 17);
5528OSMetaClassDefineReservedUnused(IOService, 18);
5529OSMetaClassDefineReservedUnused(IOService, 19);
5530OSMetaClassDefineReservedUnused(IOService, 20);
5531OSMetaClassDefineReservedUnused(IOService, 21);
5532OSMetaClassDefineReservedUnused(IOService, 22);
5533OSMetaClassDefineReservedUnused(IOService, 23);
5534OSMetaClassDefineReservedUnused(IOService, 24);
5535OSMetaClassDefineReservedUnused(IOService, 25);
5536OSMetaClassDefineReservedUnused(IOService, 26);
5537OSMetaClassDefineReservedUnused(IOService, 27);
5538OSMetaClassDefineReservedUnused(IOService, 28);
5539OSMetaClassDefineReservedUnused(IOService, 29);
5540OSMetaClassDefineReservedUnused(IOService, 30);
5541OSMetaClassDefineReservedUnused(IOService, 31);
5542OSMetaClassDefineReservedUnused(IOService, 32);
5543OSMetaClassDefineReservedUnused(IOService, 33);
5544OSMetaClassDefineReservedUnused(IOService, 34);
5545OSMetaClassDefineReservedUnused(IOService, 35);
5546OSMetaClassDefineReservedUnused(IOService, 36);
5547OSMetaClassDefineReservedUnused(IOService, 37);
5548OSMetaClassDefineReservedUnused(IOService, 38);
5549OSMetaClassDefineReservedUnused(IOService, 39);
5550OSMetaClassDefineReservedUnused(IOService, 40);
5551OSMetaClassDefineReservedUnused(IOService, 41);
5552OSMetaClassDefineReservedUnused(IOService, 42);
5553OSMetaClassDefineReservedUnused(IOService, 43);
5554OSMetaClassDefineReservedUnused(IOService, 44);
5555OSMetaClassDefineReservedUnused(IOService, 45);
5556OSMetaClassDefineReservedUnused(IOService, 46);
5557OSMetaClassDefineReservedUnused(IOService, 47);
5558