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