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