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