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