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