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