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