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