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