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