]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOService.cpp
xnu-3248.40.184.tar.gz
[apple/xnu.git] / iokit / Kernel / IOService.cpp
1 /*
2 * Copyright (c) 1998-2014 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include <IOKit/system.h>
30
31 #include <IOKit/IOService.h>
32 #include <libkern/OSDebug.h>
33 #include <libkern/c++/OSContainers.h>
34 #include <libkern/c++/OSKext.h>
35 #include <libkern/c++/OSUnserialize.h>
36 #include <IOKit/IOCatalogue.h>
37 #include <IOKit/IOCommand.h>
38 #include <IOKit/IODeviceTreeSupport.h>
39 #include <IOKit/IODeviceMemory.h>
40 #include <IOKit/IOInterrupts.h>
41 #include <IOKit/IOInterruptController.h>
42 #include <IOKit/IOPlatformExpert.h>
43 #include <IOKit/IOMessage.h>
44 #include <IOKit/IOLib.h>
45 #include <IOKit/IOKitKeysPrivate.h>
46 #include <IOKit/IOBSD.h>
47 #include <IOKit/IOUserClient.h>
48 #include <IOKit/IOWorkLoop.h>
49 #include <IOKit/IOTimeStamp.h>
50 #include <IOKit/IOHibernatePrivate.h>
51 #include <IOKit/IOInterruptAccountingPrivate.h>
52 #include <IOKit/IOKernelReporters.h>
53 #include <IOKit/AppleKeyStoreInterface.h>
54 #include <IOKit/IOCPU.h>
55 #include <mach/sync_policy.h>
56 #include <IOKit/assert.h>
57 #include <sys/errno.h>
58 #include <sys/kdebug.h>
59 #include <string.h>
60
61 #include <machine/pal_routines.h>
62
63 #define LOG kprintf
64 //#define LOG IOLog
65 #define MATCH_DEBUG 0
66 #define OBFUSCATE(x) ((void *)(VM_KERNEL_ADDRPERM(x)))
67
68 #include "IOServicePrivate.h"
69 #include "IOKitKernelInternal.h"
70
71 // take lockForArbitration before LOCKNOTIFY
72
73 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
74
75 #define super IORegistryEntry
76
77 OSDefineMetaClassAndStructors(IOService, IORegistryEntry)
78
79 OSDefineMetaClassAndStructors(_IOServiceNotifier, IONotifier)
80
81 OSDefineMetaClassAndStructors(_IOServiceInterestNotifier, IONotifier)
82
83 OSDefineMetaClassAndStructors(_IOConfigThread, OSObject)
84
85 OSDefineMetaClassAndStructors(_IOServiceJob, OSObject)
86
87 OSDefineMetaClassAndStructors(IOResources, IOService)
88
89 OSDefineMetaClassAndStructors(_IOOpenServiceIterator, OSIterator)
90
91 OSDefineMetaClassAndAbstractStructors(IONotifier, OSObject)
92
93 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
94
95 static IOPlatformExpert * gIOPlatform;
96 static class IOPMrootDomain * gIOPMRootDomain;
97 const IORegistryPlane * gIOServicePlane;
98 const IORegistryPlane * gIOPowerPlane;
99 const OSSymbol * gIODeviceMemoryKey;
100 const OSSymbol * gIOInterruptControllersKey;
101 const OSSymbol * gIOInterruptSpecifiersKey;
102
103 const OSSymbol * gIOResourcesKey;
104 const OSSymbol * gIOResourceMatchKey;
105 const OSSymbol * gIOProviderClassKey;
106 const OSSymbol * gIONameMatchKey;
107 const OSSymbol * gIONameMatchedKey;
108 const OSSymbol * gIOPropertyMatchKey;
109 const OSSymbol * gIOLocationMatchKey;
110 const OSSymbol * gIOParentMatchKey;
111 const OSSymbol * gIOPathMatchKey;
112 const OSSymbol * gIOMatchCategoryKey;
113 const OSSymbol * gIODefaultMatchCategoryKey;
114 const OSSymbol * gIOMatchedServiceCountKey;
115
116 const OSSymbol * gIOMapperIDKey;
117 const OSSymbol * gIOUserClientClassKey;
118 const OSSymbol * gIOKitDebugKey;
119
120 const OSSymbol * gIOCommandPoolSizeKey;
121
122 const OSSymbol * gIOConsoleLockedKey;
123 const OSSymbol * gIOConsoleUsersKey;
124 const OSSymbol * gIOConsoleSessionUIDKey;
125 const OSSymbol * gIOConsoleSessionAuditIDKey;
126 const OSSymbol * gIOConsoleUsersSeedKey;
127 const OSSymbol * gIOConsoleSessionOnConsoleKey;
128 const OSSymbol * gIOConsoleSessionLoginDoneKey;
129 const OSSymbol * gIOConsoleSessionSecureInputPIDKey;
130 const OSSymbol * gIOConsoleSessionScreenLockedTimeKey;
131
132 clock_sec_t gIOConsoleLockTime;
133 static bool gIOConsoleLoggedIn;
134 #if HIBERNATION
135 static uint32_t gIOScreenLockState;
136 #endif
137 static IORegistryEntry * gIOChosenEntry;
138
139 static int gIOResourceGenerationCount;
140
141 const OSSymbol * gIOServiceKey;
142 const OSSymbol * gIOPublishNotification;
143 const OSSymbol * gIOFirstPublishNotification;
144 const OSSymbol * gIOMatchedNotification;
145 const OSSymbol * gIOFirstMatchNotification;
146 const OSSymbol * gIOTerminatedNotification;
147
148 const OSSymbol * gIOGeneralInterest;
149 const OSSymbol * gIOBusyInterest;
150 const OSSymbol * gIOAppPowerStateInterest;
151 const OSSymbol * gIOPriorityPowerStateInterest;
152 const OSSymbol * gIOConsoleSecurityInterest;
153
154 const OSSymbol * gAKSGetKey;
155 #if defined(__i386__) || defined(__x86_64__)
156 const OSSymbol * gIOCreateEFIDevicePathSymbol;
157 #endif
158
159 static OSDictionary * gNotifications;
160 static IORecursiveLock * gNotificationLock;
161
162 static IOService * gIOResources;
163 static IOService * gIOServiceRoot;
164
165 static OSOrderedSet * gJobs;
166 static semaphore_port_t gJobsSemaphore;
167 static IOLock * gJobsLock;
168 static int gOutstandingJobs;
169 static int gNumConfigThreads;
170 static int gNumWaitingThreads;
171 static IOLock * gIOServiceBusyLock;
172 static bool gCPUsRunning;
173
174 static thread_t gIOTerminateThread;
175 static UInt32 gIOTerminateWork;
176 static OSArray * gIOTerminatePhase2List;
177 static OSArray * gIOStopList;
178 static OSArray * gIOStopProviderList;
179 static OSArray * gIOFinalizeList;
180
181 static SInt32 gIOConsoleUsersSeed;
182 static OSData * gIOConsoleUsersSeedValue;
183
184 extern const OSSymbol * gIODTPHandleKey;
185
186 const OSSymbol * gIOPlatformFunctionHandlerSet;
187
188 static IOLock * gIOConsoleUsersLock;
189 static thread_call_t gIOConsoleLockCallout;
190
191 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
192
193 #define LOCKREADNOTIFY() \
194 IORecursiveLockLock( gNotificationLock )
195 #define LOCKWRITENOTIFY() \
196 IORecursiveLockLock( gNotificationLock )
197 #define LOCKWRITE2READNOTIFY()
198 #define UNLOCKNOTIFY() \
199 IORecursiveLockUnlock( gNotificationLock )
200 #define SLEEPNOTIFY(event) \
201 IORecursiveLockSleep( gNotificationLock, (void *)(event), THREAD_UNINT )
202 #define SLEEPNOTIFYTO(event, deadline) \
203 IORecursiveLockSleepDeadline( gNotificationLock, (void *)(event), deadline, THREAD_UNINT )
204 #define WAKEUPNOTIFY(event) \
205 IORecursiveLockWakeup( gNotificationLock, (void *)(event), /* wake one */ false )
206
207 #define randomDelay() \
208 int del = read_processor_clock(); \
209 del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff; \
210 IOSleep( del );
211
212 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
213
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
227 struct IOInterruptAccountingReporter {
228 IOSimpleReporter * reporter; /* Reporter responsible for communicating the statistics */
229 IOInterruptAccountingData * statistics; /* The live statistics values, if any */
230 };
231
232 struct ArbitrationLockQueueElement {
233 queue_chain_t link;
234 IOThread thread;
235 IOService * service;
236 unsigned count;
237 bool required;
238 bool aborted;
239 };
240
241 static queue_head_t gArbitrationLockQueueActive;
242 static queue_head_t gArbitrationLockQueueWaiting;
243 static queue_head_t gArbitrationLockQueueFree;
244 static IOLock * gArbitrationLockQueueLock;
245
246 bool IOService::isInactive( void ) const
247 { return( 0 != (kIOServiceInactiveState & getState())); }
248
249 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
250
251 #if defined(__i386__) || defined(__x86_64__)
252
253 // Only used by the intel implementation of
254 // IOService::requireMaxBusStall(UInt32 ns)
255 // IOService::requireMaxInterruptDelay(uint32_t ns)
256 struct CpuDelayEntry
257 {
258 IOService * fService;
259 UInt32 fMaxDelay;
260 UInt32 fDelayType;
261 };
262
263 enum {
264 kCpuDelayBusStall, kCpuDelayInterrupt,
265 kCpuNumDelayTypes
266 };
267
268 static OSData *sCpuDelayData = OSData::withCapacity(8 * sizeof(CpuDelayEntry));
269 static IORecursiveLock *sCpuDelayLock = IORecursiveLockAlloc();
270 static OSArray *sCpuLatencyHandlers[kCpuNumDelayTypes];
271 const OSSymbol *sCPULatencyFunctionName[kCpuNumDelayTypes];
272 static OSNumber * sCPULatencyHolder[kCpuNumDelayTypes];
273 static char sCPULatencyHolderName[kCpuNumDelayTypes][128];
274 static OSNumber * sCPULatencySet[kCpuNumDelayTypes];
275
276 static void
277 requireMaxCpuDelay(IOService * service, UInt32 ns, UInt32 delayType);
278 static IOReturn
279 setLatencyHandler(UInt32 delayType, IOService * target, bool enable);
280
281 #endif /* defined(__i386__) || defined(__x86_64__) */
282
283 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
284
285 void 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 );
297 gIOLocationMatchKey = OSSymbol::withCStringNoCopy( kIOLocationMatchKey );
298 gIOParentMatchKey = OSSymbol::withCStringNoCopy( kIOParentMatchKey );
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
317 gIOMapperIDKey = OSSymbol::withCStringNoCopy(kIOMapperIDKey);
318
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 );
326 gIOPriorityPowerStateInterest = OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest );
327 gIOConsoleSecurityInterest = OSSymbol::withCStringNoCopy( kIOConsoleSecurityInterest );
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
342 gIOConsoleLockedKey = OSSymbol::withCStringNoCopy( kIOConsoleLockedKey);
343 gIOConsoleUsersKey = OSSymbol::withCStringNoCopy( kIOConsoleUsersKey);
344 gIOConsoleSessionUIDKey = OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey);
345 gIOConsoleSessionAuditIDKey = OSSymbol::withCStringNoCopy( kIOConsoleSessionAuditIDKey);
346
347 gIOConsoleUsersSeedKey = OSSymbol::withCStringNoCopy(kIOConsoleUsersSeedKey);
348 gIOConsoleSessionOnConsoleKey = OSSymbol::withCStringNoCopy(kIOConsoleSessionOnConsoleKey);
349 gIOConsoleSessionLoginDoneKey = OSSymbol::withCStringNoCopy(kIOConsoleSessionLoginDoneKey);
350 gIOConsoleSessionSecureInputPIDKey = OSSymbol::withCStringNoCopy(kIOConsoleSessionSecureInputPIDKey);
351 gIOConsoleSessionScreenLockedTimeKey = OSSymbol::withCStringNoCopy(kIOConsoleSessionScreenLockedTimeKey);
352
353 gIOConsoleUsersSeedValue = OSData::withBytesNoCopy(&gIOConsoleUsersSeed, sizeof(gIOConsoleUsersSeed));
354
355 gIOPlatformFunctionHandlerSet = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerSet);
356 #if defined(__i386__) || defined(__x86_64__)
357 sCPULatencyFunctionName[kCpuDelayBusStall] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxBusDelay);
358 sCPULatencyFunctionName[kCpuDelayInterrupt] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxInterruptDelay);
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 }
366 gIOCreateEFIDevicePathSymbol = OSSymbol::withCString("CreateEFIDevicePath");
367 #endif
368 gNotificationLock = IORecursiveLockAlloc();
369
370 gAKSGetKey = OSSymbol::withCStringNoCopy(AKS_PLATFORM_FUNCTION_GETKEY);
371
372 assert( gIOServicePlane && gIODeviceMemoryKey
373 && gIOInterruptControllersKey && gIOInterruptSpecifiersKey
374 && gIOResourcesKey && gNotifications && gNotificationLock
375 && gIOProviderClassKey && gIONameMatchKey && gIONameMatchedKey
376 && gIOMatchCategoryKey && gIODefaultMatchCategoryKey
377 && gIOPublishNotification && gIOMatchedNotification
378 && gIOTerminatedNotification && gIOServiceKey
379 && gIOConsoleUsersKey && gIOConsoleSessionUIDKey
380 && gIOConsoleSessionOnConsoleKey && gIOConsoleSessionSecureInputPIDKey
381 && gIOConsoleUsersSeedKey && gIOConsoleUsersSeedValue);
382
383 gJobsLock = IOLockAlloc();
384 gJobs = OSOrderedSet::withCapacity( 10 );
385
386 gIOServiceBusyLock = IOLockAlloc();
387
388 gIOConsoleUsersLock = IOLockAlloc();
389
390 err = semaphore_create(kernel_task, &gJobsSemaphore, SYNC_POLICY_FIFO, 0);
391
392 gIOConsoleLockCallout = thread_call_allocate(&IOService::consoleLockTimer, NULL);
393
394 IORegistryEntry::getRegistryRoot()->setProperty(gIOConsoleLockedKey, kOSBooleanTrue);
395
396 assert( gIOServiceBusyLock && gJobs && gJobsLock && gIOConsoleUsersLock
397 && gIOConsoleLockCallout && (err == KERN_SUCCESS) );
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
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 );
414
415 }
416
417 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
418
419 #if defined(__i386__) || defined(__x86_64__)
420 extern "C" {
421
422 const char *getCpuDelayBusStallHolderName(void) {
423 return sCPULatencyHolderName[kCpuDelayBusStall];
424 }
425
426 }
427 #endif
428
429 #if IOMATCHDEBUG
430 static 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
452 IOService * IOService::probe( IOService * provider,
453 SInt32 * score )
454 {
455 return( this );
456 }
457
458 bool IOService::start( IOService * provider )
459 {
460 return( true );
461 }
462
463 void IOService::stop( IOService * provider )
464 {
465 }
466
467 bool IOService::init( OSDictionary * dictionary )
468 {
469 bool ret;
470
471 ret = super::init(dictionary);
472 if (!ret) return (false);
473 if (reserved) return (true);
474
475 reserved = IONew(ExpansionData, 1);
476 if (!reserved) return (false);
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();
490 if (!reserved->interruptStatisticsLock) return (false);
491
492 return (true);
493 }
494
495 bool IOService::init( IORegistryEntry * from,
496 const IORegistryPlane * inPlane )
497 {
498 bool ret;
499
500 ret = super::init(from, inPlane);
501 if (!ret) return (false);
502 if (reserved) return (true);
503
504 reserved = IONew(ExpansionData, 1);
505 if (!reserved) return (false);
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();
519 if (!reserved->interruptStatisticsLock) return (false);
520
521 return (true);
522 }
523
524 void IOService::free( void )
525 {
526 int i = 0;
527 requireMaxBusStall(0);
528 requireMaxInterruptDelay(0);
529 if( getPropertyTable())
530 unregisterAllInterest();
531 PMfree();
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
548 if (_numInterruptSources && _interruptSources)
549 {
550 IOFree(_interruptSources, _numInterruptSources * sizeof(IOInterruptSource));
551 _interruptSources = 0;
552 }
553
554 super::free();
555 }
556
557 /*
558 * Attach in service plane
559 */
560 bool 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 {
578 gIOServiceRoot = this;
579 ok = attachToParent( getRegistryRoot(), gIOServicePlane);
580 }
581
582 if (ok && !__provider) (void) getProvider();
583
584 return( ok );
585 }
586
587 IOService * IOService::getServiceRoot( void )
588 {
589 return( gIOServiceRoot );
590 }
591
592 void IOService::detach( IOService * provider )
593 {
594 IOService * newProvider = 0;
595 SInt32 busy;
596 bool adjParent;
597
598 if( gIOKitDebug & kIOLogAttach)
599 LOG("%s::detach(%s)\n", getName(), provider->getName());
600
601 lockForArbitration();
602
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
612 adjParent = ((busy = (__state[1] & kIOServiceBusyStateMask))
613 && (provider == getProvider()));
614
615 detachFromParent( provider, gIOServicePlane );
616
617 if( busy) {
618 newProvider = getProvider();
619 if( busy && (__state[1] & kIOServiceTermPhase3State) && (0 == newProvider))
620 _adjustBusy( -busy );
621 }
622
623 if (kIOServiceInactiveState & __state[0]) {
624 getMetaClass()->removeInstance(this);
625 IORemoveServicePlatformActions(this);
626 }
627
628 unlockForArbitration();
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
637 if( provider->lockForArbitration( true ))
638 {
639 if (kIOServiceStartState & __state[1])
640 {
641 provider->scheduleTerminatePhase2();
642 }
643 if( adjParent) provider->_adjustBusy( -1 );
644 if( (provider->__state[1] & kIOServiceTermPhase3State)
645 && (0 == provider->getClient())) {
646 provider->scheduleFinalize(false);
647 }
648 provider->unlockForArbitration();
649 }
650 }
651
652 /*
653 * Register instance - publish it for matching
654 */
655
656 void IOService::registerService( IOOptionBits options )
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
679 IOInstallServicePlatformActions(this);
680
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
711 void IOService::startMatching( IOOptionBits options )
712 {
713 IOService * provider;
714 UInt32 prevBusy = 0;
715 bool needConfig;
716 bool needWake = false;
717 bool ok;
718 bool sync;
719 bool waitAgain;
720
721 lockForArbitration();
722
723 sync = (options & kIOServiceSynchronous)
724 || ((provider = getProvider())
725 && (provider->__state[1] & kIOServiceSynchronousState));
726
727 if ( options & kIOServiceAsynchronous )
728 sync = false;
729
730 needConfig = (0 == (__state[1] & (kIOServiceNeedConfigState | kIOServiceConfigState)))
731 && (0 == (__state[0] & kIOServiceInactiveState));
732
733 __state[1] |= kIOServiceNeedConfigState;
734
735 // __state[0] &= ~kIOServiceInactiveState;
736
737 // if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n",
738 // OSKernelStackRemaining(), getName());
739
740 if( needConfig) {
741 needWake = (0 != (kIOServiceSyncPubState & __state[1]));
742 }
743
744 if( sync)
745 __state[1] |= kIOServiceSynchronousState;
746 else
747 __state[1] &= ~kIOServiceSynchronousState;
748
749 if( needConfig) prevBusy = _adjustBusy( 1 );
750
751 unlockForArbitration();
752
753 if( needConfig) {
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
762 ok = (0 != _IOServiceJob::startJob( this, kMatchNubJob, options ));
763
764 } else do {
765
766 if( (__state[1] & kIOServiceNeedConfigState))
767 doServiceMatch( options );
768
769 lockForArbitration();
770 IOLockLock( gIOServiceBusyLock );
771
772 waitAgain = ((prevBusy < (__state[1] & kIOServiceBusyStateMask))
773 && (0 == (__state[0] & kIOServiceInactiveState)));
774
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)
787 thread_block(THREAD_CONTINUE_NULL);
788
789 } while( waitAgain );
790 }
791 }
792
793 IOReturn IOService::catalogNewDrivers( OSOrderedSet * newTables )
794 {
795 OSDictionary * table;
796 OSSet * set;
797 OSSet * allSet = 0;
798 IOService * service;
799 #if IOMATCHDEBUG
800 SInt32 count = 0;
801 #endif
802
803 newTables->retain();
804
805 while( (table = (OSDictionary *) newTables->getFirstObject())) {
806
807 LOCKWRITENOTIFY();
808 set = (OSSet *) copyExistingServices( table,
809 kIOServiceRegisteredState,
810 kIOServiceExistingSet);
811 UNLOCKNOTIFY();
812 if( set) {
813
814 #if IOMATCHDEBUG
815 count += set->getCount();
816 #endif
817 if (allSet) {
818 allSet->merge((const OSSet *) set);
819 set->release();
820 }
821 else
822 allSet = set;
823 }
824
825 #if IOMATCHDEBUG
826 if( getDebugFlags( table ) & kIOLogMatch)
827 LOG("Matching service count = %ld\n", (long)count);
828 #endif
829 newTables->removeObject(table);
830 }
831
832 if (allSet) {
833 while( (service = (IOService *) allSet->getAnyObject())) {
834 service->startMatching(kIOServiceAsynchronous);
835 allSet->removeObject(service);
836 }
837 allSet->release();
838 }
839
840 newTables->release();
841
842 return( kIOReturnSuccess );
843 }
844
845 _IOServiceJob * _IOServiceJob::startJob( IOService * nub, int type,
846 IOOptionBits options )
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
872 bool IOService::matchPropertyTable( OSDictionary * table, SInt32 * score )
873 {
874 return( matchPropertyTable(table) );
875 }
876
877 bool 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
887 IOReturn IOService::getResources( void )
888 {
889 return( kIOReturnSuccess);
890 }
891
892 /*
893 * Client/provider accessors
894 */
895
896 IOService * IOService::getProvider( void ) const
897 {
898 IOService * self = (IOService *) this;
899 IOService * parent;
900 SInt32 generation;
901
902 generation = getGenerationCount();
903 if( __providerGeneration == generation)
904 return( __provider );
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;
912 OSMemoryBarrier();
913 // save the count from before call to getParentEntry()
914 self->__providerGeneration = generation;
915
916 return( parent );
917 }
918
919 IOWorkLoop * IOService::getWorkLoop() const
920 {
921 IOService *provider = getProvider();
922
923 if (provider)
924 return provider->getWorkLoop();
925 else
926 return 0;
927 }
928
929 OSIterator * IOService::getProviderIterator( void ) const
930 {
931 return( getParentIterator( gIOServicePlane));
932 }
933
934 IOService * IOService::getClient( void ) const
935 {
936 return( (IOService *) getChildEntry( gIOServicePlane));
937 }
938
939 OSIterator * IOService::getClientIterator( void ) const
940 {
941 return( getChildIterator( gIOServicePlane));
942 }
943
944 OSIterator * _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
968 void _IOOpenServiceIterator::free()
969 {
970 iter->release();
971 if( last)
972 last->unlockForArbitration();
973 OSIterator::free();
974 }
975
976 OSObject * _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
997 bool _IOOpenServiceIterator::isValid()
998 {
999 return( iter->isValid() );
1000 }
1001
1002 void _IOOpenServiceIterator::reset()
1003 {
1004 if( last) {
1005 last->unlockForArbitration();
1006 last = 0;
1007 }
1008 iter->reset();
1009 }
1010
1011 OSIterator * IOService::getOpenProviderIterator( void ) const
1012 {
1013 return( _IOOpenServiceIterator::iterator( getProviderIterator(), this, 0 ));
1014 }
1015
1016 OSIterator * IOService::getOpenClientIterator( void ) const
1017 {
1018 return( _IOOpenServiceIterator::iterator( getClientIterator(), 0, this ));
1019 }
1020
1021
1022 IOReturn IOService::callPlatformFunction( const OSSymbol * functionName,
1023 bool waitForFunction,
1024 void *param1, void *param2,
1025 void *param3, void *param4 )
1026 {
1027 IOReturn result = kIOReturnUnsupported;
1028 IOService *provider;
1029
1030 if (gIOPlatformFunctionHandlerSet == functionName)
1031 {
1032 #if defined(__i386__) || defined(__x86_64__)
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);
1041 #endif /* defined(__i386__) || defined(__x86_64__) */
1042 }
1043
1044 if ((kIOReturnUnsupported == result) && (provider = getProvider())) {
1045 result = provider->callPlatformFunction(functionName, waitForFunction,
1046 param1, param2, param3, param4);
1047 }
1048
1049 return result;
1050 }
1051
1052 IOReturn 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 /*
1071 * Accessors for global services
1072 */
1073
1074 IOPlatformExpert * IOService::getPlatform( void )
1075 {
1076 return( gIOPlatform);
1077 }
1078
1079 class IOPMrootDomain * IOService::getPMRootDomain( void )
1080 {
1081 return( gIOPMRootDomain);
1082 }
1083
1084 IOService * IOService::getResourceService( void )
1085 {
1086 return( gIOResources );
1087 }
1088
1089 void IOService::setPlatform( IOPlatformExpert * platform)
1090 {
1091 gIOPlatform = platform;
1092 gIOResources->attachToParent( gIOServiceRoot, gIOServicePlane );
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__) */
1112 }
1113
1114 void IOService::setPMRootDomain( class IOPMrootDomain * rootDomain)
1115 {
1116 gIOPMRootDomain = rootDomain;
1117 publishResource("IOKit");
1118 }
1119
1120 /*
1121 * Stacking change
1122 */
1123
1124 bool IOService::lockForArbitration( bool isSuccessRequired )
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
1245 IOLockWakeup( gArbitrationLockQueueLock,
1246 victim,
1247 /* one thread */ true );
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
1285 restart_sleep: wait_result = assert_wait( element,
1286 element->required ? THREAD_UNINT
1287 : THREAD_INTERRUPTIBLE );
1288
1289 // unlock global access
1290 IOUnlock( gArbitrationLockQueueLock );
1291
1292 // put thread to sleep, waiting for our event to fire...
1293 if (wait_result == THREAD_WAITING)
1294 wait_result = thread_block(THREAD_CONTINUE_NULL);
1295
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
1409 void 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
1479 IOLockWakeup( gArbitrationLockQueueLock,
1480 element,
1481 /* one thread */ true );
1482 }
1483 }
1484
1485 // unlock global access
1486 IOUnlock( gArbitrationLockQueueLock );
1487 }
1488
1489 void IOService::applyToProviders( IOServiceApplierFunction applier,
1490 void * context )
1491 {
1492 applyToParents( (IORegistryEntryApplierFunction) applier,
1493 context, gIOServicePlane );
1494 }
1495
1496 void 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
1510 IOReturn IOService::messageClient( UInt32 type, OSObject * client,
1511 void * argument, vm_size_t argSize )
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;
1546 WAKEUPNOTIFY( notify );
1547 }
1548 UNLOCKNOTIFY();
1549
1550 } else
1551 ret = kIOReturnSuccess;
1552
1553 } else
1554 ret = kIOReturnBadArgument;
1555
1556 return( ret );
1557 }
1558
1559 static void
1560 applyToInterestNotifiers(const IORegistryEntry *target,
1561 const OSSymbol * typeOfInterest,
1562 OSObjectApplierFunction applier,
1563 void * context )
1564 {
1565 OSArray * copyArray = 0;
1566
1567 LOCKREADNOTIFY();
1568
1569 IOCommand *notifyList =
1570 OSDynamicCast( IOCommand, target->getProperty( typeOfInterest ));
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 }
1593 }
1594
1595 void IOService::applyToInterested( const OSSymbol * typeOfInterest,
1596 OSObjectApplierFunction applier,
1597 void * context )
1598 {
1599 if (gIOGeneralInterest == typeOfInterest)
1600 applyToClients( (IOServiceApplierFunction) applier, context );
1601 applyToInterestNotifiers(this, typeOfInterest, applier, context);
1602 }
1603
1604 struct MessageClientsContext {
1605 IOService * service;
1606 UInt32 type;
1607 void * argument;
1608 vm_size_t argSize;
1609 IOReturn ret;
1610 };
1611
1612 static 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
1624 IOReturn IOService::messageClients( UInt32 type,
1625 void * argument, vm_size_t argSize )
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
1641 IOReturn IOService::acknowledgeNotification( IONotificationRef notification,
1642 IOOptionBits response )
1643 {
1644 return( kIOReturnUnsupported );
1645 }
1646
1647 IONotifier * IOService::registerInterest( const OSSymbol * typeOfInterest,
1648 IOServiceInterestHandler handler, void * target, void * ref )
1649 {
1650 _IOServiceInterestNotifier * notify = 0;
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
1669 IOReturn IOService::registerInterestForNotifer( IONotifier *svcNotify, const OSSymbol * typeOfInterest,
1670 IOServiceInterestHandler handler, void * target, void * ref )
1671 {
1672 IOReturn rc = kIOReturnSuccess;
1673 _IOServiceInterestNotifier *notify = 0;
1674
1675 if( (typeOfInterest != gIOGeneralInterest)
1676 && (typeOfInterest != gIOBusyInterest)
1677 && (typeOfInterest != gIOAppPowerStateInterest)
1678 && (typeOfInterest != gIOConsoleSecurityInterest)
1679 && (typeOfInterest != gIOPriorityPowerStateInterest))
1680 return( kIOReturnBadArgument );
1681
1682 if (!svcNotify || !(notify = OSDynamicCast(_IOServiceInterestNotifier, svcNotify)))
1683 return( kIOReturnBadArgument );
1684
1685 lockForArbitration();
1686 if( 0 == (__state[0] & kIOServiceInactiveState)) {
1687
1688 notify->handler = handler;
1689 notify->target = target;
1690 notify->ref = ref;
1691 notify->state = kIOServiceNotifyEnable;
1692
1693 ////// queue
1694
1695 LOCKWRITENOTIFY();
1696
1697 // Get the head of the notifier linked list
1698 IOCommand * notifyList;
1699 OSObject * obj = copyProperty( typeOfInterest );
1700 if (!(notifyList = OSDynamicCast(IOCommand, obj))) {
1701 notifyList = OSTypeAlloc(IOCommand);
1702 if (notifyList) {
1703 notifyList->init();
1704 bool ok = setProperty( typeOfInterest, notifyList);
1705 notifyList->release();
1706 if (!ok) notifyList = 0;
1707 }
1708 }
1709 if (obj) obj->release();
1710
1711 if (notifyList) {
1712 enqueue(&notifyList->fCommandChain, &notify->chain);
1713 notify->retain(); // ref'ed while in list
1714 }
1715
1716 UNLOCKNOTIFY();
1717 }
1718 else {
1719 rc = kIOReturnNotReady;
1720 }
1721 unlockForArbitration();
1722
1723 return rc;
1724 }
1725
1726 static void cleanInterestList( OSObject * head )
1727 {
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();
1740 }
1741 UNLOCKNOTIFY();
1742 }
1743
1744 void IOService::unregisterAllInterest( void )
1745 {
1746 cleanInterestList( getProperty( gIOGeneralInterest ));
1747 cleanInterestList( getProperty( gIOBusyInterest ));
1748 cleanInterestList( getProperty( gIOAppPowerStateInterest ));
1749 cleanInterestList( getProperty( gIOPriorityPowerStateInterest ));
1750 cleanInterestList( getProperty( gIOConsoleSecurityInterest ));
1751 }
1752
1753 /*
1754 * _IOServiceInterestNotifier
1755 */
1756
1757 // wait for all threads, other than the current one,
1758 // to exit the handler
1759
1760 void _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;
1776 SLEEPNOTIFY(this);
1777 }
1778
1779 } while( doWait );
1780 }
1781
1782 void _IOServiceInterestNotifier::free()
1783 {
1784 assert( queue_empty( &handlerInvocations ));
1785 OSObject::free();
1786 }
1787
1788 void _IOServiceInterestNotifier::remove()
1789 {
1790 LOCKWRITENOTIFY();
1791
1792 if( queue_next( &chain )) {
1793 remqueue(&chain);
1794 queue_next( &chain) = queue_prev( &chain) = 0;
1795 release();
1796 }
1797
1798 state &= ~kIOServiceNotifyEnable;
1799
1800 wait();
1801
1802 UNLOCKNOTIFY();
1803
1804 release();
1805 }
1806
1807 bool _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
1823 void _IOServiceInterestNotifier::enable( bool was )
1824 {
1825 LOCKWRITENOTIFY();
1826 if( was)
1827 state |= kIOServiceNotifyEnable;
1828 else
1829 state &= ~kIOServiceNotifyEnable;
1830 UNLOCKNOTIFY();
1831 }
1832
1833 bool _IOServiceInterestNotifier::init()
1834 {
1835 queue_init( &handlerInvocations );
1836 return (OSObject::init());
1837 }
1838 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1839
1840 /*
1841 * Termination
1842 */
1843
1844 #define tailQ(o) setObject(o)
1845 #define headQ(o) setObject(0, o)
1846 #define TLOG(fmt, args...) { if(kIOLogYield & gIOKitDebug) { IOLog("[%llx] ", thread_tid(current_thread())); IOLog(fmt, ## args); }}
1847
1848 static void _workLoopAction( IOWorkLoop::Action action,
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
1863 bool IOService::requestTerminate( IOService * provider, IOOptionBits options )
1864 {
1865 bool ok;
1866
1867 // if its our only provider
1868 ok = isParent( provider, gIOServicePlane, true);
1869
1870 // -- compat
1871 if( ok) {
1872 provider->terminateClient( this, options | kIOServiceRecursing );
1873 ok = (0 != (kIOServiceInactiveState & __state[0]));
1874 }
1875 // --
1876
1877 return( ok );
1878 }
1879
1880 bool IOService::terminatePhase1( IOOptionBits options )
1881 {
1882 IOService * victim;
1883 IOService * client;
1884 OSIterator * iter;
1885 OSArray * makeInactive;
1886 OSArray * waitingInactive;
1887 int waitResult = THREAD_AWAKENED;
1888 bool wait;
1889 bool ok;
1890 bool didInactive;
1891 bool startPhase2 = false;
1892
1893 TLOG("%s[0x%qx]::terminatePhase1(%08llx)\n", getName(), getRegistryEntryID(), (long long)options);
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);
1902
1903 // -- compat
1904 if( options & kIOServiceRecursing) {
1905 lockForArbitration();
1906 if (0 == (kIOServiceInactiveState & __state[0]))
1907 {
1908 __state[0] |= kIOServiceInactiveState;
1909 __state[1] |= kIOServiceRecursing | kIOServiceTermPhase1State;
1910 }
1911 unlockForArbitration();
1912
1913 return( true );
1914 }
1915 // --
1916
1917 makeInactive = OSArray::withCapacity( 16 );
1918 waitingInactive = OSArray::withCapacity( 16 );
1919 if(!makeInactive || !waitingInactive) return( false );
1920
1921 victim = this;
1922 victim->retain();
1923
1924 while( victim )
1925 {
1926 didInactive = victim->lockForArbitration( true );
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);
1935
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);
1972 if (victim == this)
1973 {
1974 if (kIOServiceTerminateNeedWillTerminate & options)
1975 {
1976 victim->__state[1] |= kIOServiceNeedWillTerminate;
1977 }
1978 }
1979 victim->_adjustBusy( 1 );
1980 }
1981 victim->unlockForArbitration();
1982 }
1983 if( victim == this) startPhase2 = didInactive;
1984 if (didInactive)
1985 {
1986 victim->deliverNotification( gIOTerminatedNotification, 0, 0xffffffff );
1987 IOUserClient::destroyUserReferences( victim );
1988
1989 iter = victim->getClientIterator();
1990 if( iter) {
1991 while( (client = (IOService *) iter->getNextObject())) {
1992 TLOG("%s[0x%qx]::requestTerminate(%s[0x%qx], %08llx)\n",
1993 client->getName(), client->getRegistryEntryID(),
1994 victim->getName(), victim->getRegistryEntryID(), (long long)options);
1995 ok = client->requestTerminate( victim, options );
1996 TLOG("%s[0x%qx]::requestTerminate(%s[0x%qx], ok = %d)\n",
1997 client->getName(), client->getRegistryEntryID(),
1998 victim->getName(), victim->getRegistryEntryID(), ok);
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
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 }
2023 makeInactive->release();
2024
2025 while ((victim = (IOService *) waitingInactive->getObject(0)))
2026 {
2027 victim->retain();
2028 waitingInactive->removeObject(0);
2029
2030 victim->lockForArbitration();
2031 victim->__state[1] &= ~kIOServiceTermPhase1State;
2032 if (kIOServiceTerm1WaiterState & victim->__state[1])
2033 {
2034 victim->__state[1] &= ~kIOServiceTerm1WaiterState;
2035 TLOG("%s[0x%qx]::wakePhase1\n", victim->getName(), victim->getRegistryEntryID());
2036 IOLockLock( gIOServiceBusyLock );
2037 thread_wakeup( (event_t) &victim->__state[1]);
2038 IOLockUnlock( gIOServiceBusyLock );
2039 }
2040 victim->unlockForArbitration();
2041 victim->release();
2042 }
2043 waitingInactive->release();
2044
2045 if( startPhase2)
2046 {
2047 retain();
2048 lockForArbitration();
2049 scheduleTerminatePhase2(options);
2050 unlockForArbitration();
2051 release();
2052 }
2053
2054 return( true );
2055 }
2056
2057 void 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();
2067 provider->scheduleTerminatePhase2();
2068 provider->unlockForArbitration();
2069 }
2070 }
2071
2072 // call with lockForArbitration
2073 void IOService::scheduleTerminatePhase2( IOOptionBits options )
2074 {
2075 AbsoluteTime deadline;
2076 uint64_t regID1;
2077 int waitResult = THREAD_AWAKENED;
2078 bool wait, haveDeadline = false;
2079
2080 if (!(__state[0] & kIOServiceInactiveState)) return;
2081
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);
2089
2090 if (__state[1] & kIOServiceTermPhase1State) return;
2091
2092 retain();
2093 unlockForArbitration();
2094 options |= kIOServiceRequired;
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
2104 IOLockSleep( gJobsLock, &gIOTerminateThread, THREAD_UNINT);
2105 }
2106 } while( wait );
2107
2108 gIOTerminateThread = current_thread();
2109 gIOTerminatePhase2List->setObject( this );
2110 gIOTerminateWork++;
2111
2112 do {
2113 while( gIOTerminateWork )
2114 terminateWorker( options );
2115 wait = (0 != (__state[1] & kIOServiceBusyStateMask));
2116 if( wait) {
2117 // wait for the victim to go non-busy
2118 if( !haveDeadline) {
2119 clock_interval_to_deadline( 15, kSecondScale, &deadline );
2120 haveDeadline = true;
2121 }
2122 waitResult = IOLockSleepDeadline( gJobsLock, &gIOTerminateWork,
2123 deadline, THREAD_UNINT );
2124 if( waitResult == THREAD_TIMED_OUT) {
2125 IOLog("%s[0x%qx]::terminate(kIOServiceSynchronous) timeout\n", getName(), getRegistryEntryID());
2126 }
2127 }
2128 } while(gIOTerminateWork || (wait && (waitResult != THREAD_TIMED_OUT)));
2129
2130 gIOTerminateThread = 0;
2131 IOLockWakeup( gJobsLock, (event_t) &gIOTerminateThread, /* one-thread */ false);
2132
2133 } else {
2134 // ! kIOServiceSynchronous
2135
2136 gIOTerminatePhase2List->setObject( this );
2137 if( 0 == gIOTerminateWork++) {
2138 if( !gIOTerminateThread)
2139 kernel_thread_start(&terminateThread, (void *)(uintptr_t) options, &gIOTerminateThread);
2140 else
2141 IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false );
2142 }
2143 }
2144
2145 IOLockUnlock( gJobsLock );
2146 lockForArbitration();
2147 release();
2148 }
2149
2150 void IOService::terminateThread( void * arg, wait_result_t waitResult )
2151 {
2152 IOLockLock( gJobsLock );
2153
2154 while (gIOTerminateWork)
2155 terminateWorker( (uintptr_t) arg );
2156
2157 thread_deallocate(gIOTerminateThread);
2158 gIOTerminateThread = 0;
2159 IOLockWakeup( gJobsLock, (event_t) &gIOTerminateThread, /* one-thread */ false);
2160
2161 IOLockUnlock( gJobsLock );
2162 }
2163
2164 void IOService::scheduleStop( IOService * provider )
2165 {
2166 uint64_t regID1 = getRegistryEntryID();
2167 uint64_t regID2 = provider->getRegistryEntryID();
2168
2169 TLOG("%s[0x%qx]::scheduleStop(%s[0x%qx])\n", getName(), regID1, provider->getName(), regID2);
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
2177 IOLockLock( gJobsLock );
2178 gIOStopList->tailQ( this );
2179 gIOStopProviderList->tailQ( provider );
2180
2181 if( 0 == gIOTerminateWork++) {
2182 if( !gIOTerminateThread)
2183 kernel_thread_start(&terminateThread, (void *) 0, &gIOTerminateThread);
2184 else
2185 IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false );
2186 }
2187
2188 IOLockUnlock( gJobsLock );
2189 }
2190
2191 void IOService::scheduleFinalize(bool now)
2192 {
2193 uint64_t regID1 = getRegistryEntryID();
2194
2195 TLOG("%s[0x%qx]::scheduleFinalize\n", getName(), regID1);
2196 IOServiceTrace(
2197 IOSERVICE_TERMINATE_SCHEDULE_FINALIZE,
2198 (uintptr_t) regID1,
2199 (uintptr_t) (regID1 >> 32),
2200 0, 0);
2201
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 );
2214 }
2215 }
2216
2217 bool IOService::willTerminate( IOService * provider, IOOptionBits options )
2218 {
2219 return( true );
2220 }
2221
2222 bool 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 {
2231 message( kIOMessageServiceIsRequestingClose, provider, (void *)(uintptr_t) options );
2232 if( false == provider->handleIsOpen( this ))
2233 scheduleStop( provider );
2234 }
2235 // --
2236 unlockForArbitration();
2237 }
2238 }
2239
2240 return( true );
2241 }
2242
2243 void IOService::actionWillTerminate( IOService * victim, IOOptionBits options,
2244 OSArray * doPhase2List,
2245 void *unused2 __unused,
2246 void *unused3 __unused )
2247 {
2248 OSIterator * iter;
2249 IOService * client;
2250 bool ok;
2251 uint64_t regID1, regID2 = victim->getRegistryEntryID();
2252
2253 iter = victim->getClientIterator();
2254 if( iter) {
2255 while( (client = (IOService *) iter->getNextObject())) {
2256
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);
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
2268 ok = client->willTerminate( victim, options );
2269 doPhase2List->tailQ( client );
2270 }
2271 iter->release();
2272 }
2273 }
2274
2275 void IOService::actionDidTerminate( IOService * victim, IOOptionBits options,
2276 void *unused1 __unused, void *unused2 __unused,
2277 void *unused3 __unused )
2278 {
2279 OSIterator * iter;
2280 IOService * client;
2281 bool defer;
2282 uint64_t regID1, regID2 = victim->getRegistryEntryID();
2283
2284 victim->messageClients( kIOMessageServiceIsTerminated, (void *)(uintptr_t) options );
2285
2286 iter = victim->getClientIterator();
2287 if( iter) {
2288 while( (client = (IOService *) iter->getNextObject())) {
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);
2294 defer = false;
2295 client->didTerminate( victim, options, &defer );
2296
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
2305 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], defer %d)\n",
2306 client->getName(), regID1,
2307 victim->getName(), regID2, defer);
2308 }
2309 iter->release();
2310 }
2311 }
2312
2313
2314 void IOService::actionWillStop( IOService * victim, IOOptionBits options,
2315 void *unused1 __unused, void *unused2 __unused,
2316 void *unused3 __unused )
2317 {
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 }
2343
2344 void 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
2380 void IOService::actionFinalize( IOService * victim, IOOptionBits options,
2381 void *unused1 __unused, void *unused2 __unused,
2382 void *unused3 __unused )
2383 {
2384 uint64_t regID1 = victim->getRegistryEntryID();
2385 TLOG("%s[0x%qx]::finalize(%08llx)\n", victim->getName(), regID1, (long long)options);
2386 IOServiceTrace(
2387 IOSERVICE_TERMINATE_FINALIZE,
2388 (uintptr_t) regID1,
2389 (uintptr_t) (regID1 >> 32),
2390 0, 0);
2391
2392 victim->finalize( options );
2393 }
2394
2395 void IOService::actionStop( IOService * provider, IOService * client,
2396 void *unused1 __unused, void *unused2 __unused,
2397 void *unused3 __unused )
2398 {
2399 uint64_t regID1 = provider->getRegistryEntryID();
2400 uint64_t regID2 = client->getRegistryEntryID();
2401
2402 TLOG("%s[0x%qx]::stop(%s[0x%qx])\n", client->getName(), regID2, provider->getName(), regID1);
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
2410 client->stop( provider );
2411 if( provider->isOpen( client ))
2412 provider->close( client );
2413
2414 TLOG("%s[0x%qx]::detach(%s[0x%qx])\n", client->getName(), regID2, provider->getName(), regID1);
2415 client->detach( provider );
2416 }
2417
2418 void IOService::terminateWorker( IOOptionBits options )
2419 {
2420 OSArray * doPhase2List;
2421 OSArray * didPhase2List;
2422 OSSet * freeList;
2423 OSIterator * iter;
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;
2432
2433 options |= kIOServiceRequired;
2434
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;
2440
2441 do {
2442 workDone = gIOTerminateWork;
2443
2444 while( (victim = (IOService *) gIOTerminatePhase2List->getObject(0) )) {
2445
2446 victim->retain();
2447 gIOTerminatePhase2List->removeObject(0);
2448 IOLockUnlock( gJobsLock );
2449
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
2458 while( victim ) {
2459
2460 doPhase2 = victim->lockForArbitration( true );
2461 if( doPhase2) {
2462 doPhase2 = (0 != (kIOServiceInactiveState & victim->__state[0]));
2463 if( doPhase2) {
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
2473 doPhase2 = (0 == (victim->__state[1] & kIOServiceTermPhase2State))
2474 && (0 == (victim->__state[1] & kIOServiceConfigState));
2475
2476 if (doPhase2 && (iter = victim->getClientIterator())) {
2477 while (doPhase2 && (client = (IOService *) iter->getNextObject())) {
2478 doPhase2 = (0 == (client->__state[1] & kIOServiceStartState));
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 }
2492 }
2493 iter->release();
2494 }
2495 if( doPhase2)
2496 victim->__state[1] |= kIOServiceTermPhase2State;
2497 }
2498 victim->unlockForArbitration();
2499 }
2500 if( doPhase2) {
2501
2502 if (kIOServiceNeedWillTerminate & victim->__state[1]) {
2503 _workLoopAction( (IOWorkLoop::Action) &actionWillStop,
2504 victim, (void *)(uintptr_t) options, NULL );
2505 }
2506
2507 if( 0 == victim->getClient()) {
2508
2509 // no clients - will go to finalize
2510 victim->scheduleFinalize(false);
2511
2512 } else {
2513 _workLoopAction( (IOWorkLoop::Action) &actionWillTerminate,
2514 victim, (void *)(uintptr_t) options, (void *)(uintptr_t) doPhase2List );
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 }
2524 }
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,
2533 victim, (void *)(uintptr_t) options );
2534 if (kIOServiceNeedWillTerminate & victim->__state[1]) {
2535 _workLoopAction( (IOWorkLoop::Action) &actionDidStop,
2536 victim, (void *)(uintptr_t) options, NULL );
2537 }
2538 didPhase2List->removeObject(0);
2539 }
2540 IOLockLock( gJobsLock );
2541 }
2542
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,
2551 victim, (void *)(uintptr_t) options );
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 );
2564
2565 uint64_t regID1 = provider->getRegistryEntryID();
2566 uint64_t regID2 = client->getRegistryEntryID();
2567
2568 if( !provider->isChild( client, gIOServicePlane )) {
2569 // may be multiply queued - nop it
2570 TLOG("%s[0x%qx]::nop stop(%s[0x%qx])\n", client->getName(), regID2, provider->getName(), regID1);
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
2578 } else {
2579 // a terminated client is not ready for stop if it has clients, skip it
2580 if( (kIOServiceInactiveState & client->__state[0]) && client->getClient()) {
2581 TLOG("%s[0x%qx]::defer stop(%s[0x%qx])\n",
2582 client->getName(), regID2,
2583 client->getClient()->getName(), client->getClient()->getRegistryEntryID());
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
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 }
2611
2612 } while( doPhase3 );
2613
2614 gIOTerminateWork -= workDone;
2615 moreToDo = (gIOTerminateWork != 0);
2616
2617 if( !moreToDo) {
2618 TLOG("iokit terminate done, %d stops remain\n", gIOStopList->getCount());
2619 IOServiceTrace(
2620 IOSERVICE_TERMINATE_DONE,
2621 (uintptr_t) gIOStopList->getCount(), 0, 0, 0);
2622 }
2623
2624 } while( moreToDo );
2625
2626 IOLockUnlock( gJobsLock );
2627
2628 freeList->release();
2629 doPhase2List->release();
2630 didPhase2List->release();
2631
2632 IOLockLock( gJobsLock );
2633 }
2634
2635 bool IOService::finalize( IOOptionBits options )
2636 {
2637 OSIterator * iter;
2638 IOService * provider;
2639 uint64_t regID1, regID2 = getRegistryEntryID();
2640
2641 iter = getProviderIterator();
2642 assert( iter );
2643
2644 if( iter) {
2645 while( (provider = (IOService *) iter->getNextObject())) {
2646
2647 // -- compat
2648 if( 0 == (__state[1] & kIOServiceTermPhase3State)) {
2649 /* we come down here on programmatic terminate */
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
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();
2674 }
2675
2676 return( true );
2677 }
2678
2679 #undef tailQ
2680 #undef headQ
2681
2682 /*
2683 * Terminate
2684 */
2685
2686 void IOService::doServiceTerminate( IOOptionBits options )
2687 {
2688 }
2689
2690 // a method in case someone needs to override it
2691 bool 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
2704 bool IOService::terminate( IOOptionBits options )
2705 {
2706 options |= kIOServiceTerminate;
2707
2708 return( terminatePhase1( options ));
2709 }
2710
2711 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2712
2713 /*
2714 * Open & close
2715 */
2716
2717 struct ServiceOpenMessageContext
2718 {
2719 IOService * service;
2720 UInt32 type;
2721 IOService * excludeClient;
2722 IOOptionBits options;
2723 };
2724
2725 static void serviceOpenMessageApplier( OSObject * object, void * ctx )
2726 {
2727 ServiceOpenMessageContext * context = (ServiceOpenMessageContext *) ctx;
2728
2729 if( object != context->excludeClient)
2730 context->service->messageClient( context->type, object, (void *)(uintptr_t) context->options );
2731 }
2732
2733 bool IOService::open( IOService * forClient,
2734 IOOptionBits options,
2735 void * arg )
2736 {
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 );
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
2760 void IOService::close( IOService * forClient,
2761 IOOptionBits options )
2762 {
2763 bool wasClosed;
2764 bool last = false;
2765
2766 lockForArbitration();
2767
2768 wasClosed = handleIsOpen( forClient );
2769 if( wasClosed) {
2770 handleClose( forClient, options );
2771 last = (__state[1] & kIOServiceTermPhase3State);
2772 }
2773
2774 unlockForArbitration();
2775
2776 if( last)
2777 forClient->scheduleStop( this );
2778
2779 else if( wasClosed) {
2780
2781 ServiceOpenMessageContext context;
2782
2783 context.service = this;
2784 context.type = kIOMessageServiceWasClosed;
2785 context.excludeClient = forClient;
2786 context.options = options;
2787
2788 applyToInterested( gIOGeneralInterest,
2789 &serviceOpenMessageApplier, &context );
2790 }
2791 }
2792
2793 bool IOService::isOpen( const IOService * forClient ) const
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
2807 bool 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,
2819 __owner, (void *)(uintptr_t) options ));
2820 if( ok && (0 == __owner ))
2821 __owner = forClient;
2822 else
2823 ok = false;
2824 }
2825 return( ok );
2826 }
2827
2828 void IOService::handleClose( IOService * forClient,
2829 IOOptionBits options )
2830 {
2831 if( __owner == forClient)
2832 __owner = 0;
2833 }
2834
2835 bool 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 */
2846 static 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
2865 static 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
2873 if( (dict = OSDynamicCast( OSDictionary, entry)))
2874 offset = OSDynamicCast(OSNumber, dict->getObject( key ));
2875 else if( (notify = OSDynamicCast( _IOServiceNotifier, entry)))
2876 return( notify->priority );
2877
2878 else if( (service = OSDynamicCast( IOService, entry)))
2879 offset = OSDynamicCast(OSNumber, service->getProperty( key ));
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
2891 SInt32 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
2910 IOService * IOService::copyClientWithCategory( const OSSymbol * category )
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)
2924 {
2925 service->retain();
2926 break;
2927 }
2928 }
2929 iter->release();
2930 }
2931 return( service );
2932 }
2933
2934 IOService * IOService::getClientWithCategory( const OSSymbol * category )
2935 {
2936 IOService *
2937 service = copyClientWithCategory(category);
2938 if (service)
2939 service->release();
2940 return (service);
2941 }
2942
2943 bool 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
2962 ret = (*notify->handler)(notify->target, notify->ref, this, notify);
2963
2964 LOCKWRITENOTIFY();
2965 queue_remove( &notify->handlerInvocations, &invocation,
2966 _IOServiceNotifierInvocation *, link );
2967 if( kIOServiceNotifyWaiter & notify->state) {
2968 notify->state &= ~kIOServiceNotifyWaiter;
2969 WAKEUPNOTIFY( notify );
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
2982 void 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
3003 IOService * client = NULL;
3004
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;
3038
3039 if( (client = copyClientWithCategory(category)) ) {
3040 #if IOMATCHDEBUG
3041 if( (debugFlags & kIOLogMatch) && (this != gIOResources))
3042 LOG("%s: match category %s exists\n", getName(),
3043 category->getCStringNoCopy());
3044 #endif
3045 nextMatch->release();
3046 nextMatch = 0;
3047
3048 client->release();
3049 client = NULL;
3050
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
3061 if( false == matchPassive(props, kIOServiceChangesOK | kIOServiceClassDone))
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
3114 //IOLog("%s alloc (symbol %p props %p)\n", symbol->getCStringNoCopy(), OBFUSCATE(symbol), OBFUSCATE(props));
3115
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 );
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
3242
3243 // adjust the busy count by +1 if matching is stalled for a module,
3244 // or -1 if a previously stalled matching is complete.
3245 lockForArbitration();
3246 SInt32 adjBusy = 0;
3247 uint64_t regID = getRegistryEntryID();
3248
3249 if( needReloc) {
3250 adjBusy = (__state[1] & kIOServiceModuleStallState) ? 0 : 1;
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
3260 __state[1] |= kIOServiceModuleStallState;
3261 }
3262
3263 } else if( __state[1] & kIOServiceModuleStallState) {
3264
3265 IOServiceTrace(
3266 IOSERVICE_MODULEUNSTALL,
3267 (uintptr_t) regID,
3268 (uintptr_t) (regID >> 32),
3269 (uintptr_t) this,
3270 0);
3271
3272 __state[1] &= ~kIOServiceModuleStallState;
3273 adjBusy = -1;
3274 }
3275 if( adjBusy)
3276 _adjustBusy( adjBusy );
3277 unlockForArbitration();
3278
3279 if( startDict)
3280 startDict->release();
3281 }
3282
3283 /*
3284 * Start a previously attached & probed instance,
3285 * called on exporting object instance
3286 */
3287
3288 bool IOService::startCandidate( IOService * service )
3289 {
3290 bool ok;
3291
3292 ok = service->attach( this );
3293
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 }
3303
3304 AbsoluteTime startTime;
3305 AbsoluteTime endTime;
3306 UInt64 nano;
3307
3308 if (kIOLogStart & gIOKitDebug)
3309 clock_get_uptime(&startTime);
3310
3311 ok = service->start(this);
3312
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)
3322 IOLog("%s::start took %ld ms\n", service->getName(), (long)(UInt32)(nano / 1000000ULL));
3323 }
3324 }
3325 if( !ok)
3326 service->detach( this );
3327 }
3328 return( ok );
3329 }
3330
3331 void IOService::publishResource( const char * key, OSObject * value )
3332 {
3333 const OSSymbol * sym;
3334
3335 if( (sym = OSSymbol::withCString( key))) {
3336 publishResource( sym, value);
3337 sym->release();
3338 }
3339 }
3340
3341 void IOService::publishResource( const OSSymbol * key, OSObject * value )
3342 {
3343 if( 0 == value)
3344 value = (OSObject *) gIOServiceKey;
3345
3346 gIOResources->setProperty( key, value);
3347
3348 if( IORecursiveLockHaveLock( gNotificationLock))
3349 return;
3350
3351 gIOResourceGenerationCount++;
3352 gIOResources->registerService();
3353 }
3354
3355 bool IOService::addNeededResource( const char * key )
3356 {
3357 OSObject * resourcesProp;
3358 OSSet * set;
3359 OSString * newKey;
3360 bool ret;
3361
3362 resourcesProp = getProperty( gIOResourceMatchKey );
3363
3364 newKey = OSString::withCString( key );
3365 if( (0 == resourcesProp) || (0 == newKey))
3366 return( false);
3367
3368 set = OSDynamicCast( OSSet, resourcesProp );
3369 if( !set) {
3370 set = OSSet::withCapacity( 1 );
3371 if( set)
3372 set->setObject( resourcesProp );
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
3385 bool 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)
3407 LOG("config(%p): stalling %s\n", OBFUSCATE(IOThreadSelf()), getName());
3408
3409 waitForService( table );
3410
3411 if( gIOKitDebug & kIOLogConfig)
3412 LOG("config(%p): waking\n", OBFUSCATE(IOThreadSelf()) );
3413
3414 return( true );
3415 }
3416
3417 bool IOService::checkResources( void )
3418 {
3419 OSObject * resourcesProp;
3420 OSSet * set;
3421 OSIterator * iter;
3422 bool ok;
3423
3424 resourcesProp = getProperty( gIOResourceMatchKey );
3425 if( 0 == resourcesProp)
3426 return( true );
3427
3428 if( (set = OSDynamicCast( OSSet, resourcesProp ))) {
3429
3430 iter = OSCollectionIterator::withCollection( set );
3431 ok = (0 != iter);
3432 while( ok && (resourcesProp = iter->getNextObject()) )
3433 ok = checkResource( resourcesProp );
3434 if( iter)
3435 iter->release();
3436
3437 } else
3438 ok = checkResource( resourcesProp );
3439
3440 return( ok );
3441 }
3442
3443
3444 void _IOConfigThread::configThread( void )
3445 {
3446 _IOConfigThread * inst;
3447
3448 do {
3449 if( !(inst = new _IOConfigThread))
3450 continue;
3451 if( !inst->init())
3452 continue;
3453 thread_t unused;
3454 if (KERN_SUCCESS != kernel_thread_start(&_IOConfigThread::main, inst, &unused))
3455 continue;
3456
3457 return;
3458
3459 } while( false);
3460
3461 if( inst)
3462 inst->release();
3463
3464 return;
3465 }
3466
3467 void _IOConfigThread::free( void )
3468 {
3469 thread_deallocate(current_thread());
3470 OSObject::free();
3471 }
3472
3473 void 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;
3481 bool didRegister;
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();
3493 if( 0 == (__state[0] & kIOServiceFirstPublishState)) {
3494 getMetaClass()->addInstance(this);
3495 deliverNotification( gIOFirstPublishNotification,
3496 kIOServiceFirstPublishState, 0xffffffff );
3497 }
3498 LOCKREADNOTIFY();
3499 __state[1] &= ~kIOServiceNeedConfigState;
3500 __state[1] |= kIOServiceConfigState;
3501 didRegister = (0 == (kIOServiceRegisteredState & __state[0]));
3502 __state[0] |= kIOServiceRegisteredState;
3503
3504 keepGuessing &= (0 == (__state[0] & kIOServiceInactiveState));
3505 if (reRegistered && keepGuessing) {
3506 iter = OSCollectionIterator::withCollection( (OSOrderedSet *)
3507 gNotifications->getObject( gIOPublishNotification ) );
3508 if( iter) {
3509 while((notify = (_IOServiceNotifier *)
3510 iter->getNextObject())) {
3511
3512 if( matchPassive(notify->matching, 0)
3513 && (kIOServiceNotifyEnable & notify->state))
3514 matches->setObject( notify );
3515 }
3516 iter->release();
3517 }
3518 }
3519
3520 UNLOCKNOTIFY();
3521 unlockForArbitration();
3522
3523 if (keepGuessing && matches->getCount() && (kIOReturnSuccess == getResources()))
3524 probeCandidates( matches );
3525 else
3526 matches->release();
3527 }
3528
3529 lockForArbitration();
3530 reRegistered = (0 != (__state[1] & kIOServiceNeedConfigState));
3531 keepGuessing =
3532 (reRegistered || (catalogGeneration !=
3533 gIOCatalogue->getGenerationCount()))
3534 && (0 == (__state[0] & kIOServiceInactiveState));
3535
3536 if( keepGuessing)
3537 unlockForArbitration();
3538 }
3539
3540 if( (0 == (__state[0] & kIOServiceInactiveState))
3541 && (0 == (__state[1] & kIOServiceModuleStallState)) ) {
3542 deliverNotification( gIOMatchedNotification,
3543 kIOServiceMatchedState, 0xffffffff );
3544 if( 0 == (__state[0] & kIOServiceFirstMatchState))
3545 deliverNotification( gIOFirstMatchNotification,
3546 kIOServiceFirstMatchState, 0xffffffff );
3547 }
3548
3549 __state[1] &= ~kIOServiceConfigState;
3550 scheduleTerminatePhase2();
3551
3552 _adjustBusy( -1 );
3553 unlockForArbitration();
3554 }
3555
3556 UInt32 IOService::_adjustBusy( SInt32 delta )
3557 {
3558 IOService * next;
3559 UInt32 count;
3560 UInt32 result;
3561 bool wasQuiet, nowQuiet, needWake;
3562
3563 next = this;
3564 result = __state[1] & kIOServiceBusyStateMask;
3565
3566 if( delta) do {
3567 if( next != this)
3568 next->lockForArbitration();
3569 count = next->__state[1] & kIOServiceBusyStateMask;
3570 wasQuiet = (0 == count);
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);
3577 needWake = (0 != (kIOServiceBusyWaiterState & next->__state[1]));
3578
3579 if( needWake) {
3580 next->__state[1] &= ~kIOServiceBusyWaiterState;
3581 IOLockLock( gIOServiceBusyLock );
3582 thread_wakeup( (event_t) next);
3583 IOLockUnlock( gIOServiceBusyLock );
3584 }
3585 if( next != this)
3586 next->unlockForArbitration();
3587
3588 if( (wasQuiet || nowQuiet) ) {
3589
3590 uint64_t regID = next->getRegistryEntryID();
3591 IOServiceTrace(
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
3608 MessageClientsContext context;
3609
3610 context.service = next;
3611 context.type = kIOMessageServiceBusyStateChange;
3612 context.argument = (void *) wasQuiet; /*nowBusy*/
3613 context.argSize = 0;
3614
3615 applyToInterestNotifiers( next, gIOBusyInterest,
3616 &messageClientsApplier, &context );
3617
3618 #if !NO_KEXTD
3619 if( nowQuiet && (next == gIOServiceRoot)) {
3620 OSKext::considerUnloads();
3621 IOServiceTrace(IOSERVICE_REGISTRY_QUIET, 0, 0, 0, 0);
3622 }
3623 #endif
3624 }
3625
3626 delta = nowQuiet ? -1 : +1;
3627
3628 } while( (wasQuiet || nowQuiet) && (next = next->getProvider()));
3629
3630 return( result );
3631 }
3632
3633 void IOService::adjustBusy( SInt32 delta )
3634 {
3635 lockForArbitration();
3636 _adjustBusy( delta );
3637 unlockForArbitration();
3638 }
3639
3640 uint64_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
3660 UInt32 IOService::getBusyState( void )
3661 {
3662 return( __state[1] & kIOServiceBusyStateMask );
3663 }
3664
3665 IOReturn IOService::waitForState( UInt32 mask, UInt32 value,
3666 mach_timespec_t * timeout )
3667 {
3668 panic("waitForState");
3669 return (kIOReturnUnsupported);
3670 }
3671
3672 IOReturn IOService::waitForState( UInt32 mask, UInt32 value,
3673 uint64_t timeout )
3674 {
3675 bool wait;
3676 int waitResult = THREAD_AWAKENED;
3677 bool computeDeadline = true;
3678 AbsoluteTime abstime;
3679
3680 do {
3681 lockForArbitration();
3682 IOLockLock( gIOServiceBusyLock );
3683 wait = (value != (__state[1] & mask));
3684 if( wait) {
3685 __state[1] |= kIOServiceBusyWaiterState;
3686 unlockForArbitration();
3687 if( timeout != UINT64_MAX ) {
3688 if( computeDeadline ) {
3689 AbsoluteTime nsinterval;
3690 nanoseconds_to_absolutetime(timeout, &nsinterval );
3691 clock_absolutetime_interval_to_deadline(nsinterval, &abstime);
3692 computeDeadline = false;
3693 }
3694 assert_wait_deadline((event_t)this, THREAD_UNINT, __OSAbsoluteTime(abstime));
3695 }
3696 else
3697 assert_wait((event_t)this, THREAD_UNINT );
3698 } else
3699 unlockForArbitration();
3700 IOLockUnlock( gIOServiceBusyLock );
3701 if( wait)
3702 waitResult = thread_block(THREAD_CONTINUE_NULL);
3703
3704 } while( wait && (waitResult != THREAD_TIMED_OUT));
3705
3706 if( waitResult == THREAD_TIMED_OUT)
3707 return( kIOReturnTimeout );
3708 else
3709 return( kIOReturnSuccess );
3710 }
3711
3712 IOReturn IOService::waitQuiet( uint64_t timeout )
3713 {
3714 IOReturn ret;
3715 ret = waitForState( kIOServiceBusyStateMask, 0, timeout );
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)
3734 {
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 }
3758 }
3759 panic("busy timeout(%llds): %s", timeout / 1000000000ULL, string ? string : "");
3760 }
3761 return (ret);
3762 }
3763
3764 IOReturn 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
3777 return (waitQuiet(timeoutNS));
3778 }
3779
3780 bool 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
3790 void _IOConfigThread::main(void * arg, wait_result_t result)
3791 {
3792 _IOConfigThread * self = (_IOConfigThread *) arg;
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);
3805
3806 do {
3807
3808 // randomDelay();
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--;
3818 // gNumConfigThreads--; // we're out of service
3819 gNumWaitingThreads--; // we're out of service
3820 }
3821 IOUnlock( gJobsLock );
3822
3823 if( job) {
3824
3825 nub = job->nub;
3826
3827 if( gIOKitDebug & kIOLogConfig)
3828 LOG("config(%p): starting on %s, %d\n",
3829 OBFUSCATE(IOThreadSelf()), job->nub->getName(), job->type);
3830
3831 switch( job->type) {
3832
3833 case kMatchNubJob:
3834 nub->doServiceMatch( job->options );
3835 break;
3836
3837 default:
3838 LOG("config(%p): strange type (%d)\n",
3839 OBFUSCATE(IOThreadSelf()), job->type );
3840 break;
3841 }
3842
3843 nub->release();
3844 job->release();
3845
3846 IOTakeLock( gJobsLock );
3847 alive = (gOutstandingJobs > gNumWaitingThreads);
3848 if( alive)
3849 gNumWaitingThreads++; // back in service
3850 // gNumConfigThreads++;
3851 else {
3852 if( 0 == --gNumConfigThreads) {
3853 // IOLog("MATCH IDLE\n");
3854 IOLockWakeup( gJobsLock, (event_t) &gNumConfigThreads, /* one-thread */ false );
3855 }
3856 }
3857 IOUnlock( gJobsLock );
3858 }
3859
3860 } while( alive );
3861
3862 if( gIOKitDebug & kIOLogConfig)
3863 LOG("config(%p): terminating\n", OBFUSCATE(IOThreadSelf()) );
3864
3865 self->release();
3866 }
3867
3868 IOReturn IOService::waitMatchIdle( UInt32 msToWait )
3869 {
3870 bool wait;
3871 int waitResult = THREAD_AWAKENED;
3872 bool computeDeadline = true;
3873 AbsoluteTime deadline;
3874
3875 IOLockLock( gJobsLock );
3876 do {
3877 wait = (0 != gNumConfigThreads);
3878 if( wait) {
3879 if( msToWait) {
3880 if( computeDeadline ) {
3881 clock_interval_to_deadline(
3882 msToWait, kMillisecondScale, &deadline );
3883 computeDeadline = false;
3884 }
3885 waitResult = IOLockSleepDeadline( gJobsLock, &gNumConfigThreads,
3886 deadline, THREAD_UNINT );
3887 } else {
3888 waitResult = IOLockSleep( gJobsLock, &gNumConfigThreads,
3889 THREAD_UNINT );
3890 }
3891 }
3892 } while( wait && (waitResult != THREAD_TIMED_OUT));
3893 IOLockUnlock( gJobsLock );
3894
3895 if( waitResult == THREAD_TIMED_OUT)
3896 return( kIOReturnTimeout );
3897 else
3898 return( kIOReturnSuccess );
3899 }
3900
3901 void IOService::cpusRunning(void)
3902 {
3903 gCPUsRunning = true;
3904 }
3905
3906 void _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)
3922 && ((gNumConfigThreads < kMaxConfigThreads)
3923 || (job->nub == gIOResources)
3924 || !gCPUsRunning));
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
3943 struct 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
3953 bool 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
3994 // internal - call with gNotificationLock
3995 OSObject * IOService::copyExistingServices( OSDictionary * matching,
3996 IOOptionBits inState, IOOptionBits options )
3997 {
3998 OSObject * current = 0;
3999 OSIterator * iter;
4000 IOService * service;
4001 OSObject * obj;
4002 OSString * str;
4003
4004 if( !matching)
4005 return( 0 );
4006
4007 #if MATCH_DEBUG
4008 OSSerialize * s = OSSerialize::withCapacity(128);
4009 matching->serialize(s);
4010 #endif
4011
4012 if((obj = matching->getObject(gIOProviderClassKey))
4013 && gIOResourcesKey
4014 && gIOResourcesKey->isEqualTo(obj)
4015 && (service = gIOResources))
4016 {
4017 if( (inState == (service->__state[0] & inState))
4018 && (0 == (service->__state[0] & kIOServiceInactiveState))
4019 && service->matchPassive(matching, options))
4020 {
4021 if( options & kIONotifyOnce)
4022 {
4023 service->retain();
4024 current = service;
4025 }
4026 else
4027 current = OSSet::withObjects((const OSObject **) &service, 1, 1 );
4028 }
4029 }
4030 else
4031 {
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
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))
4098 && service->matchPassive(matching, 0)) {
4099
4100 if( options & kIONotifyOnce) {
4101 service->retain();
4102 _current = service;
4103 break;
4104 }
4105 if( _current)
4106 ((OSSet *)_current)->setObject( service );
4107 else
4108 _current = OSSet::withObjects(
4109 (const OSObject **) &service, 1, 1 );
4110 }
4111 }
4112 } while( !service && !iter->isValid());
4113 iter->release();
4114 }
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);
4124 kprintf("**mismatch** %p %p\n%s\n%s\n%s\n", OBFUSCATE(current),
4125 OBFUSCATE(_current), s->text(), s1->text(), s2->text());
4126 s1->release();
4127 s2->release();
4128 }
4129
4130 if (_current) _current->release();
4131 }
4132
4133 s->release();
4134 #endif
4135
4136 if( current && (0 == (options & (kIONotifyOnce | kIOServiceExistingSet)))) {
4137 iter = OSCollectionIterator::withCollection( (OSSet *)current );
4138 current->release();
4139 current = iter;
4140 }
4141
4142 return( current );
4143 }
4144
4145 // public version
4146 OSIterator * IOService::getMatchingServices( OSDictionary * matching )
4147 {
4148 OSIterator * iter;
4149
4150 // is a lock even needed?
4151 LOCKWRITENOTIFY();
4152
4153 iter = (OSIterator *) copyExistingServices( matching,
4154 kIOServiceMatchedState );
4155
4156 UNLOCKNOTIFY();
4157
4158 return( iter );
4159 }
4160
4161 IOService * 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
4176 struct _IOServiceMatchingNotificationHandlerRef
4177 {
4178 IOServiceNotificationHandler handler;
4179 void * ref;
4180 };
4181
4182 static bool _IOServiceMatchingNotificationHandler( void * target, void * refCon,
4183 IOService * newService,
4184 IONotifier * notifier )
4185 {
4186 return ((*((_IOServiceNotifier *) notifier)->compatHandler)(target, refCon, newService));
4187 }
4188
4189 // internal - call with gNotificationLock
4190 IONotifier * IOService::setNotification(
4191 const OSSymbol * type, OSDictionary * matching,
4192 IOServiceMatchingNotificationHandler handler, void * target, void * ref,
4193 SInt32 priority )
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) {
4208 notify->handler = handler;
4209 notify->target = target;
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;
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
4242 IONotifier * IOService::doInstallNotification(
4243 const OSSymbol * type, OSDictionary * matching,
4244 IOServiceMatchingNotificationHandler handler,
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
4255 if( type == gIOPublishNotification)
4256 inState = kIOServiceRegisteredState;
4257
4258 else if( type == gIOFirstPublishNotification)
4259 inState = kIOServiceFirstPublishState;
4260
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
4273 exist = (OSIterator *) copyExistingServices( matching, inState );
4274 else
4275 exist = 0;
4276
4277 *existing = exist;
4278
4279 return( notify );
4280 }
4281
4282 #if !defined(__LP64__)
4283 IONotifier * 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
4303
4304 IONotifier * IOService::installNotification(
4305 const OSSymbol * type, OSDictionary * matching,
4306 IOServiceMatchingNotificationHandler handler,
4307 void * target, void * ref,
4308 SInt32 priority, OSIterator ** existing )
4309 {
4310 IONotifier * notify;
4311
4312 LOCKWRITENOTIFY();
4313
4314 notify = doInstallNotification( type, matching, handler, target, ref,
4315 priority, existing );
4316
4317 UNLOCKNOTIFY();
4318
4319 return( notify );
4320 }
4321
4322 IONotifier * IOService::addNotification(
4323 const OSSymbol * type, OSDictionary * matching,
4324 IOServiceNotificationHandler handler,
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
4343 IONotifier * IOService::addMatchingNotification(
4344 const OSSymbol * type, OSDictionary * matching,
4345 IOServiceMatchingNotificationHandler handler,
4346 void * target, void * ref,
4347 SInt32 priority )
4348 {
4349 OSIterator * existing = NULL;
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
4374 bool IOService::syncNotificationHandler(
4375 void * /* target */, void * ref,
4376 IOService * newService,
4377 IONotifier * notifier )
4378 {
4379
4380 LOCKWRITENOTIFY();
4381 if (!*((IOService **) ref))
4382 {
4383 newService->retain();
4384 (*(IOService **) ref) = newService;
4385 WAKEUPNOTIFY(ref);
4386 }
4387 UNLOCKNOTIFY();
4388
4389 return( false );
4390 }
4391
4392 IOService * IOService::waitForMatchingService( OSDictionary * matching,
4393 uint64_t timeout)
4394 {
4395 IONotifier * notify = 0;
4396 // priority doesn't help us much since we need a thread wakeup
4397 SInt32 priority = 0;
4398 IOService * result;
4399
4400 if (!matching)
4401 return( 0 );
4402
4403 result = NULL;
4404
4405 LOCKWRITENOTIFY();
4406 do
4407 {
4408 result = (IOService *) copyExistingServices( matching,
4409 kIOServiceMatchedState, kIONotifyOnce );
4410 if (result)
4411 break;
4412 notify = IOService::setNotification( gIOMatchedNotification, matching,
4413 &IOService::syncNotificationHandler, (void *) 0,
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 }
4424 else
4425 {
4426 SLEEPNOTIFY(&result);
4427 }
4428 }
4429 while( false );
4430
4431 UNLOCKNOTIFY();
4432
4433 if (notify)
4434 notify->remove(); // dequeues
4435
4436 return( result );
4437 }
4438
4439 IOService * 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 }
4451 else
4452 timeoutNS = UINT64_MAX;
4453
4454 result = waitForMatchingService(matching, timeoutNS);
4455
4456 matching->release();
4457 if (result)
4458 result->release();
4459
4460 return (result);
4461 }
4462
4463 void 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
4483 if( matchPassive(notify->matching, 0)
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
4510 IOOptionBits IOService::getState( void ) const
4511 {
4512 return( __state[0] );
4513 }
4514
4515 /*
4516 * Helpers to make matching objects for simple cases
4517 */
4518
4519 OSDictionary * IOService::serviceMatching( const OSString * name,
4520 OSDictionary * table )
4521 {
4522
4523 const OSString * str;
4524
4525 str = OSSymbol::withString(name);
4526 if( !str)
4527 return( 0 );
4528
4529 if( !table)
4530 table = OSDictionary::withCapacity( 2 );
4531 if( table)
4532 table->setObject(gIOProviderClassKey, (OSObject *)str );
4533 str->release();
4534
4535 return( table );
4536 }
4537
4538 OSDictionary * IOService::serviceMatching( const char * name,
4539 OSDictionary * table )
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
4552 OSDictionary * IOService::nameMatching( const OSString * name,
4553 OSDictionary * table )
4554 {
4555 if( !table)
4556 table = OSDictionary::withCapacity( 2 );
4557 if( table)
4558 table->setObject( gIONameMatchKey, (OSObject *)name );
4559
4560 return( table );
4561 }
4562
4563 OSDictionary * IOService::nameMatching( const char * name,
4564 OSDictionary * table )
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
4577 OSDictionary * IOService::resourceMatching( const OSString * str,
4578 OSDictionary * table )
4579 {
4580 table = serviceMatching( gIOResourcesKey, table );
4581 if( table)
4582 table->setObject( gIOResourceMatchKey, (OSObject *) str );
4583
4584 return( table );
4585 }
4586
4587 OSDictionary * IOService::resourceMatching( const char * name,
4588 OSDictionary * table )
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
4602 OSDictionary * 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
4622 OSDictionary * 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
4643 /*
4644 * _IOServiceNotifier
4645 */
4646
4647 // wait for all threads, other than the current one,
4648 // to exit the handler
4649
4650 void _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;
4666 SLEEPNOTIFY(this);
4667 }
4668
4669 } while( doWait );
4670 }
4671
4672 void _IOServiceNotifier::free()
4673 {
4674 assert( queue_empty( &handlerInvocations ));
4675 OSObject::free();
4676 }
4677
4678 void _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
4700 bool _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
4716 void _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
4730 IOService * 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
4743 bool 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
4771 IOReturn IOResources::newUserClient(task_t owningTask, void * securityID,
4772 UInt32 type, OSDictionary * properties,
4773 IOUserClient ** handler)
4774 {
4775 return( kIOReturnUnsupported );
4776 }
4777
4778 IOWorkLoop * IOResources::getWorkLoop() const
4779 {
4780 // If we are the resource root
4781 // then use the platform's workloop
4782 if (this == (IOResources *) gIOResources)
4783 return getPlatform()->getWorkLoop();
4784 else
4785 return IOService::getWorkLoop();
4786 }
4787
4788 bool IOResources::matchPropertyTable( OSDictionary * table )
4789 {
4790 OSObject * prop;
4791 OSString * str;
4792 OSSet * set;
4793 OSIterator * iter;
4794 bool ok = true;
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
4815 void IOService::consoleLockTimer(thread_call_param_t p0, thread_call_param_t p1)
4816 {
4817 IOService::updateConsoleUsers(NULL, 0);
4818 }
4819
4820 void 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
4831 if (!gIOChosenEntry)
4832 gIOChosenEntry = IORegistryEntry::fromPath("/chosen", gIODTPlane);
4833
4834 IOLockLock(gIOConsoleUsersLock);
4835
4836 if (systemMessage)
4837 {
4838 sSystemPower = systemMessage;
4839 #if HIBERNATION
4840 if ((kIOMessageSystemHasPoweredOn == systemMessage) && IOHibernateWasScreenLocked())
4841 {
4842 locked = kOSBooleanTrue;
4843 }
4844 #endif /* HIBERNATION */
4845 }
4846
4847 if (consoleUsers)
4848 {
4849 OSNumber * num = 0;
4850 gIOConsoleLoggedIn = false;
4851 for (idx = 0;
4852 (user = OSDynamicCast(OSDictionary, consoleUsers->getObject(idx)));
4853 idx++)
4854 {
4855 gIOConsoleLoggedIn |= ((kOSBooleanTrue == user->getObject(gIOConsoleSessionOnConsoleKey))
4856 && (kOSBooleanTrue == user->getObject(gIOConsoleSessionLoginDoneKey)));
4857 if (!num)
4858 {
4859 num = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionScreenLockedTimeKey));
4860 }
4861 }
4862 gIOConsoleLockTime = num ? num->unsigned32BitValue() : 0;
4863 }
4864
4865 if (!gIOConsoleLoggedIn
4866 || (kIOMessageSystemWillSleep == sSystemPower)
4867 || (kIOMessageSystemPagingOff == sSystemPower))
4868 {
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 }
4883 else
4884 {
4885 locked = kOSBooleanTrue;
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
4900 #if HIBERNATION
4901 if (gIOChosenEntry)
4902 {
4903 if (locked == kOSBooleanTrue) gIOScreenLockState = kIOScreenLockLocked;
4904 else if (gIOConsoleLockTime) gIOScreenLockState = kIOScreenLockUnlocked;
4905 else gIOScreenLockState = kIOScreenLockNoLock;
4906 gIOChosenEntry->setProperty(kIOScreenLockStateKey, &gIOScreenLockState, sizeof(gIOScreenLockState));
4907 }
4908 #endif /* HIBERNATION */
4909
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
4928 IOReturn 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
4947 while( (key = OSDynamicCast(OSSymbol, iter->getNextObject())))
4948 {
4949 if (gIOConsoleUsersKey == key) do
4950 {
4951 OSArray * consoleUsers;
4952 consoleUsers = OSDynamicCast(OSArray, dict->getObject(key));
4953 if (!consoleUsers)
4954 continue;
4955 IOService::updateConsoleUsers(consoleUsers, 0);
4956 }
4957 while (false);
4958
4959 publishResource( key, dict->getObject(key) );
4960 }
4961
4962 iter->release();
4963
4964 return( kIOReturnSuccess );
4965 }
4966
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
4973 bool 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
4989 bool 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
5004 bool 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
5029 OSDictionary * 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
5049 IOService * 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
5061 bool IOService::matchInternal(OSDictionary * table, uint32_t options, uint32_t * did)
5062 {
5063 OSString * matched;
5064 OSObject * obj;
5065 OSString * str;
5066 IORegistryEntry * entry;
5067 OSNumber * num;
5068 bool match = true;
5069 bool changesOK = (0 != (kIOServiceChangesOK & options));
5070 uint32_t count;
5071 uint32_t done;
5072
5073 do
5074 {
5075 count = table->getCount();
5076 done = 0;
5077 str = OSDynamicCast(OSString, table->getObject(gIOProviderClassKey));
5078
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 }
5088
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 }
5101
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 }
5115
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 }
5147
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 }
5157
5158 num = OSDynamicCast( OSNumber, table->getObject( gIORegistryEntryIDKey ));
5159 if (num) {
5160 done++;
5161 match = (getRegistryEntryID() == num->unsigned64BitValue());
5162 if ((!match) || (done == count)) break;
5163 }
5164
5165 num = OSDynamicCast( OSNumber, table->getObject( gIOMatchedServiceCountKey ));
5166 if( num)
5167 {
5168 OSIterator * iter;
5169 IOService * service = 0;
5170 UInt32 serviceCount = 0;
5171
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 }
5187
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);
5206
5207 if (did) *did = done;
5208 return (match);
5209 }
5210
5211 bool IOService::passiveMatch( OSDictionary * table, bool changesOK )
5212 {
5213 return (matchPassive(table, changesOK ? kIOServiceChangesOK : 0));
5214 }
5215
5216 bool 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;
5226
5227 assert( table );
5228
5229 OSArray* aliasServiceRegIds = NULL;
5230 IOService* foundAlternateService = NULL;
5231
5232 #if MATCH_DEBUG
5233 OSDictionary * root = table;
5234 #endif
5235
5236 where = this;
5237 do
5238 {
5239 do
5240 {
5241 count = table->getCount();
5242
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;
5248 }
5249
5250 // pass in score from property table
5251 score = IOServiceObjectOrder( table, (void *) gIOProbeScoreKey);
5252
5253 // do family specific matching
5254 match = where->matchPropertyTable( table, &score );
5255
5256 if( !match) {
5257 #if IOMATCHDEBUG
5258 if( kIOLogMatch & getDebugFlags( table ))
5259 LOG("%s: family specific matching fails\n", where->getName());
5260 #endif
5261 break;
5262 }
5263
5264 if (kIOServiceChangesOK & options) {
5265 // save the score
5266 newPri = OSNumber::withNumber( score, 32 );
5267 if( newPri) {
5268 table->setObject( gIOProbeScoreKey, newPri );
5269 newPri->release();
5270 }
5271 }
5272
5273 options = 0;
5274 matchParent = false;
5275
5276 nextTable = OSDynamicCast(OSDictionary,
5277 table->getObject( gIOParentMatchKey ));
5278 if(nextTable) {
5279 // look for a matching entry anywhere up to root
5280 match = false;
5281 matchParent = true;
5282 table = nextTable;
5283 break;
5284 }
5285
5286 table = OSDynamicCast(OSDictionary,
5287 table->getObject( gIOLocationMatchKey ));
5288 if (table) {
5289 // look for a matching entry at matchLocation()
5290 match = false;
5291 where = where->getProvider();
5292 if (where && (where = where->matchLocation(where))) continue;
5293 }
5294 break;
5295 }
5296 while (true);
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 }
5339 }
5340 while( where != NULL );
5341
5342 OSSafeRelease(foundAlternateService);
5343 OSSafeRelease(aliasServiceRegIds);
5344
5345 #if MATCH_DEBUG
5346 if (where != this)
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
5354
5355 return( match );
5356 }
5357
5358
5359 IOReturn 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
5367 if (kIOReturnSuccess == newUserClient( owningTask, securityID, type, handler ))
5368 return kIOReturnSuccess;
5369
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
5387 // This reference is consumed by the IOServiceOpen call
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
5419 IOReturn IOService::newUserClient( task_t owningTask, void * securityID,
5420 UInt32 type, IOUserClient ** handler )
5421 {
5422 return( kIOReturnUnsupported );
5423 }
5424
5425 IOReturn 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
5436 const 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 */
5498 int IOService::errnoFromReturn( IOReturn rtn )
5499 {
5500 if (unix_err(err_get_code(rtn)) == rtn)
5501 return err_get_code(rtn);
5502
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:
5524 return(ENOTSUP);
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:
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:
5567 case kIOReturnNotAttached:
5568 case kIOReturnUnformattedMedia:
5569 return(ENXIO); // (media error)
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
5590 IOReturn 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
5606 IOItemCount 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
5620 IODeviceMemory * 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
5634 IOMemoryMap * IOService::mapDeviceMemoryWithIndex( unsigned int index,
5635 IOOptionBits options )
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
5649 OSArray * IOService::getDeviceMemory( void )
5650 {
5651 return( OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey)));
5652 }
5653
5654
5655 void IOService::setDeviceMemory( OSArray * array )
5656 {
5657 setProperty( gIODeviceMemoryKey, array);
5658 }
5659
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 */
5665 void IOService::
5666 setCPUSnoopDelay(UInt32 __unused ns)
5667 {
5668 #if defined(__i386__) || defined(__x86_64__)
5669 ml_set_maxsnoop(ns);
5670 #endif /* defined(__i386__) || defined(__x86_64__) */
5671 }
5672
5673 UInt32 IOService::
5674 getCPUSnoopDelay()
5675 {
5676 #if defined(__i386__) || defined(__x86_64__)
5677 return ml_get_maxsnoop();
5678 #else
5679 return 0;
5680 #endif /* defined(__i386__) || defined(__x86_64__) */
5681 }
5682
5683 #if defined(__i386__) || defined(__x86_64__)
5684 static void
5685 requireMaxCpuDelay(IOService * service, UInt32 ns, UInt32 delayType)
5686 {
5687 static const UInt kNoReplace = -1U; // Must be an illegal index
5688 UInt replace = kNoReplace;
5689 bool setCpuDelay = false;
5690
5691 IORecursiveLockLock(sCpuDelayLock);
5692
5693 UInt count = sCpuDelayData->getLength() / sizeof(CpuDelayEntry);
5694 CpuDelayEntry *entries = (CpuDelayEntry *) sCpuDelayData->getBytesNoCopy();
5695 IOService * holder = NULL;
5696
5697 if (ns) {
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;
5725 }
5726 else {
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 {
5752 if (holder && debug_boot_arg) {
5753 strlcpy(sCPULatencyHolderName[delayType], holder->getName(), sizeof(sCPULatencyHolderName[delayType]));
5754 }
5755
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 }
5765 sCPULatencyHolder[delayType]->setValue(holder ? holder->getRegistryEntryID() : 0);
5766 sCPULatencySet [delayType]->setValue(ns);
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);
5777 }
5778 }
5779
5780 IORecursiveLockUnlock(sCpuDelayLock);
5781 }
5782
5783 static IOReturn
5784 setLatencyHandler(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;
5833 }
5834 }
5835 while (false);
5836
5837 IORecursiveLockUnlock(sCpuDelayLock);
5838
5839 return (result);
5840 }
5841
5842 #endif /* defined(__i386__) || defined(__x86_64__) */
5843
5844 void IOService::
5845 requireMaxBusStall(UInt32 __unused ns)
5846 {
5847 #if defined(__i386__) || defined(__x86_64__)
5848 requireMaxCpuDelay(this, ns, kCpuDelayBusStall);
5849 #endif
5850 }
5851
5852 void IOService::
5853 requireMaxInterruptDelay(uint32_t __unused ns)
5854 {
5855 #if defined(__i386__) || defined(__x86_64__)
5856 requireMaxCpuDelay(this, ns, kCpuDelayInterrupt);
5857 #endif
5858 }
5859
5860 /*
5861 * Device interrupts
5862 */
5863
5864 IOReturn IOService::resolveInterrupt(IOService *nub, int source)
5865 {
5866 IOInterruptController *interruptController;
5867 OSArray *array;
5868 OSData *data;
5869 OSSymbol *interruptControllerName;
5870 long numSources;
5871 IOInterruptSource *interruptSources;
5872
5873 // Get the parents list from the nub.
5874 array = OSDynamicCast(OSArray, nub->getProperty(gIOInterruptControllersKey));
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
5896 // Get the interrupt numbers from the nub.
5897 array = OSDynamicCast(OSArray, nub->getProperty(gIOInterruptSpecifiersKey));
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
5910 IOReturn 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
5940 IOReturn 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
5956 IOReturn 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
5968 IOReturn IOService::addInterruptStatistics(IOInterruptAccountingData * statistics, int source)
5969 {
5970 IOReportLegend * legend = NULL;
5971 IOInterruptAccountingData * oldValue = NULL;
5972 IOInterruptAccountingReporter * newArray = NULL;
5973 char subgroupName[64];
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 */
6051 reserved->interruptStatisticsArray[source].reporter = IOSimpleReporter::with(this, kIOReportCategoryPower, kIOReportUnitNone);
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
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);
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
6121 IOReturn 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
6166 IOReturn 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
6178 IOReturn 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
6190 IOReturn 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
6202 IOReturn 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
6214 IOReturn 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
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
6250 return kIOReturnSuccess;
6251 }
6252
6253 IOReturn 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
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
6289 return kIOReturnSuccess;
6290 }
6291
6292 uint64_t IOService::getAuthorizationID( void )
6293 {
6294 return reserved->authorizationID;
6295 }
6296
6297 IOReturn 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
6327 #if __LP64__
6328 OSMetaClassDefineReservedUsed(IOService, 0);
6329 OSMetaClassDefineReservedUsed(IOService, 1);
6330 OSMetaClassDefineReservedUnused(IOService, 2);
6331 OSMetaClassDefineReservedUnused(IOService, 3);
6332 OSMetaClassDefineReservedUnused(IOService, 4);
6333 OSMetaClassDefineReservedUnused(IOService, 5);
6334 OSMetaClassDefineReservedUnused(IOService, 6);
6335 OSMetaClassDefineReservedUnused(IOService, 7);
6336 #else
6337 OSMetaClassDefineReservedUsed(IOService, 0);
6338 OSMetaClassDefineReservedUsed(IOService, 1);
6339 OSMetaClassDefineReservedUsed(IOService, 2);
6340 OSMetaClassDefineReservedUsed(IOService, 3);
6341 OSMetaClassDefineReservedUsed(IOService, 4);
6342 OSMetaClassDefineReservedUsed(IOService, 5);
6343 OSMetaClassDefineReservedUsed(IOService, 6);
6344 OSMetaClassDefineReservedUsed(IOService, 7);
6345 #endif
6346 OSMetaClassDefineReservedUnused(IOService, 8);
6347 OSMetaClassDefineReservedUnused(IOService, 9);
6348 OSMetaClassDefineReservedUnused(IOService, 10);
6349 OSMetaClassDefineReservedUnused(IOService, 11);
6350 OSMetaClassDefineReservedUnused(IOService, 12);
6351 OSMetaClassDefineReservedUnused(IOService, 13);
6352 OSMetaClassDefineReservedUnused(IOService, 14);
6353 OSMetaClassDefineReservedUnused(IOService, 15);
6354 OSMetaClassDefineReservedUnused(IOService, 16);
6355 OSMetaClassDefineReservedUnused(IOService, 17);
6356 OSMetaClassDefineReservedUnused(IOService, 18);
6357 OSMetaClassDefineReservedUnused(IOService, 19);
6358 OSMetaClassDefineReservedUnused(IOService, 20);
6359 OSMetaClassDefineReservedUnused(IOService, 21);
6360 OSMetaClassDefineReservedUnused(IOService, 22);
6361 OSMetaClassDefineReservedUnused(IOService, 23);
6362 OSMetaClassDefineReservedUnused(IOService, 24);
6363 OSMetaClassDefineReservedUnused(IOService, 25);
6364 OSMetaClassDefineReservedUnused(IOService, 26);
6365 OSMetaClassDefineReservedUnused(IOService, 27);
6366 OSMetaClassDefineReservedUnused(IOService, 28);
6367 OSMetaClassDefineReservedUnused(IOService, 29);
6368 OSMetaClassDefineReservedUnused(IOService, 30);
6369 OSMetaClassDefineReservedUnused(IOService, 31);
6370 OSMetaClassDefineReservedUnused(IOService, 32);
6371 OSMetaClassDefineReservedUnused(IOService, 33);
6372 OSMetaClassDefineReservedUnused(IOService, 34);
6373 OSMetaClassDefineReservedUnused(IOService, 35);
6374 OSMetaClassDefineReservedUnused(IOService, 36);
6375 OSMetaClassDefineReservedUnused(IOService, 37);
6376 OSMetaClassDefineReservedUnused(IOService, 38);
6377 OSMetaClassDefineReservedUnused(IOService, 39);
6378 OSMetaClassDefineReservedUnused(IOService, 40);
6379 OSMetaClassDefineReservedUnused(IOService, 41);
6380 OSMetaClassDefineReservedUnused(IOService, 42);
6381 OSMetaClassDefineReservedUnused(IOService, 43);
6382 OSMetaClassDefineReservedUnused(IOService, 44);
6383 OSMetaClassDefineReservedUnused(IOService, 45);
6384 OSMetaClassDefineReservedUnused(IOService, 46);
6385 OSMetaClassDefineReservedUnused(IOService, 47);