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