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