1/*
2 * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*
29 * Copyright (c) 1998 Apple Computer, Inc.  All rights reserved.
30 *
31 * HISTORY
32 * 12 Nov 98 sdouglas created.
33 *
34 */
35
36#include <IOKit/IORegistryEntry.h>
37#include <libkern/c++/OSContainers.h>
38#include <IOKit/IOService.h>
39#include <IOKit/IOKitKeys.h>
40
41#include <IOKit/IOLib.h>
42
43#include <IOKit/assert.h>
44
45/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
46
47#define super OSObject
48
49OSDefineMetaClassAndStructors(IORegistryEntry, OSObject)
50
51/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
52
53#define kIORegPlaneParentSuffix		"ParentLinks"
54#define kIORegPlaneChildSuffix		"ChildLinks"
55#define kIORegPlaneNameSuffix		"Name"
56#define kIORegPlaneLocationSuffix	"Location"
57
58#define kIORegPlaneParentSuffixLen	(sizeof(kIORegPlaneParentSuffix) - 1)
59#define kIORegPlaneChildSuffixLen	(sizeof(kIORegPlaneChildSuffix) - 1)
60#define kIORegPlaneNameSuffixLen	(sizeof(kIORegPlaneNameSuffix) - 1)
61#define kIORegPlaneLocationSuffixLen	(sizeof(kIORegPlaneLocationSuffix) - 1)
62
63#define KASLR_IOREG_DEBUG 0
64
65static IORegistryEntry * gRegistryRoot;
66static OSDictionary * 	 gIORegistryPlanes;
67
68const OSSymbol * 	gIONameKey;
69const OSSymbol * 	gIOLocationKey;
70const OSSymbol * 	gIORegistryEntryIDKey;
71
72enum {
73    kParentSetIndex	= 0,
74    kChildSetIndex	= 1,
75    kNumSetIndex
76};
77enum {
78    kIOMaxPlaneName	= 32
79};
80
81enum { kIORegistryIDReserved = (1ULL << 32) + 255 };
82
83static uint64_t gIORegistryLastID = kIORegistryIDReserved;
84
85class IORegistryPlane : public OSObject {
86
87    friend class IORegistryEntry;
88
89    OSDeclareAbstractStructors(IORegistryPlane)
90
91    const OSSymbol *	nameKey;
92    const OSSymbol *	keys[ kNumSetIndex ];
93    const OSSymbol *	pathNameKey;
94    const OSSymbol *	pathLocationKey;
95    int			reserved[2];
96
97public:
98    virtual bool serialize(OSSerialize *s) const;
99};
100
101OSDefineMetaClassAndStructors(IORegistryPlane, OSObject)
102
103
104static IORecursiveLock *	gPropertiesLock;
105static SInt32			gIORegistryGenerationCount;
106
107#define UNLOCK	lck_rw_done( &gIORegistryLock )
108#define RLOCK	lck_rw_lock_shared( &gIORegistryLock )
109#define WLOCK	lck_rw_lock_exclusive( &gIORegistryLock );	\
110		gIORegistryGenerationCount++
111		// make atomic
112
113#define PUNLOCK	IORecursiveLockUnlock( gPropertiesLock )
114#define PLOCK	IORecursiveLockLock( gPropertiesLock )
115
116#define IOREGSPLITTABLES
117
118#ifdef IOREGSPLITTABLES
119#define registryTable()	fRegistryTable
120#else
121#define registryTable()	fPropertyTable
122#endif
123
124#define DEBUG_FREE	1
125
126/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
127
128lck_rw_t	gIORegistryLock;
129lck_grp_t       *gIORegistryLockGrp;
130lck_grp_attr_t  *gIORegistryLockGrpAttr;
131lck_attr_t      *gIORegistryLockAttr;
132
133
134/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
135
136IORegistryEntry * IORegistryEntry::initialize( void )
137{
138   bool			ok;
139
140    if( !gRegistryRoot) {
141
142
143	gIORegistryLockGrpAttr = lck_grp_attr_alloc_init();
144	//lck_grp_attr_setstat(gIORegistryLockGrpAttr);
145	gIORegistryLockGrp = lck_grp_alloc_init("IORegistryLock",  gIORegistryLockGrpAttr);
146	gIORegistryLockAttr = lck_attr_alloc_init();
147	lck_attr_rw_shared_priority(gIORegistryLockAttr);
148	//lck_attr_setdebug(gIORegistryLockAttr);
149	lck_rw_init( &gIORegistryLock, gIORegistryLockGrp, gIORegistryLockAttr);
150
151	gRegistryRoot = new IORegistryEntry;
152	gPropertiesLock = IORecursiveLockAlloc();
153	gIORegistryPlanes = OSDictionary::withCapacity( 1 );
154
155	assert( gRegistryRoot && gPropertiesLock
156		&& gIORegistryPlanes );
157        ok = gRegistryRoot->init();
158
159	if (ok)
160	    gRegistryRoot->reserved->fRegistryEntryID = ++gIORegistryLastID;
161
162	gIONameKey = OSSymbol::withCStringNoCopy( "IOName" );
163	gIOLocationKey = OSSymbol::withCStringNoCopy( "IOLocation" );
164	gIORegistryEntryIDKey = OSSymbol::withCStringNoCopy( kIORegistryEntryIDKey );
165
166	assert( ok && gIONameKey && gIOLocationKey );
167
168	gRegistryRoot->setName( "Root" );
169        gRegistryRoot->setProperty( kIORegistryPlanesKey, gIORegistryPlanes );
170    }
171
172    return( gRegistryRoot );
173}
174
175IORegistryEntry * IORegistryEntry::getRegistryRoot( void )
176{
177    return( gRegistryRoot );
178}
179
180SInt32 IORegistryEntry::getGenerationCount( void )
181{
182    return( gIORegistryGenerationCount );
183}
184
185
186const IORegistryPlane * IORegistryEntry::makePlane( const char * name )
187{
188    IORegistryPlane *	plane;
189    const OSSymbol *	nameKey;
190    const OSSymbol *	parentKey;
191    const OSSymbol *	childKey;
192    const OSSymbol *	pathNameKey;
193    const OSSymbol *	pathLocationKey;
194    char		key[ kIOMaxPlaneName + 16 ];
195    char *		end;
196
197    strlcpy( key, name, kIOMaxPlaneName + 1 );
198    end = key + strlen( key );
199
200    nameKey = OSSymbol::withCString( key);
201
202    strlcpy( end, kIORegPlaneParentSuffix, kIORegPlaneParentSuffixLen + 1 );
203    parentKey = OSSymbol::withCString( key);
204
205    strlcpy( end, kIORegPlaneChildSuffix, kIORegPlaneChildSuffixLen + 1 );
206    childKey = OSSymbol::withCString( key);
207
208    strlcpy( end, kIORegPlaneNameSuffix, kIORegPlaneNameSuffixLen + 1 );
209    pathNameKey = OSSymbol::withCString( key);
210
211    strlcpy( end, kIORegPlaneLocationSuffix, kIORegPlaneLocationSuffixLen + 1 );
212    pathLocationKey = OSSymbol::withCString( key);
213
214    plane = new IORegistryPlane;
215
216    if( plane && plane->init()
217	&& nameKey && parentKey && childKey
218	&& pathNameKey && pathLocationKey ) {
219
220	plane->nameKey = nameKey;
221	plane->keys[ kParentSetIndex ] = parentKey;
222	plane->keys[ kChildSetIndex ] = childKey;
223	plane->pathNameKey = pathNameKey;
224	plane->pathLocationKey = pathLocationKey;
225
226	WLOCK;
227        gIORegistryPlanes->setObject( nameKey, plane );
228	UNLOCK;
229
230    } else {
231
232	if( plane)
233	    plane->release();
234	if( pathLocationKey)
235	    pathLocationKey->release();
236	if( pathNameKey)
237	    pathNameKey->release();
238	if( parentKey)
239	    parentKey->release();
240	if( childKey)
241	    childKey->release();
242	if( nameKey)
243	    nameKey->release();
244	plane = 0;
245    }
246
247    return( plane);
248}
249
250const IORegistryPlane * IORegistryEntry::getPlane( const char * name )
251{
252    const IORegistryPlane *	plane;
253
254    RLOCK;
255    plane = (const IORegistryPlane *) gIORegistryPlanes->getObject( name );
256    UNLOCK;
257
258    return( plane );
259}
260
261bool IORegistryPlane::serialize(OSSerialize *s) const
262{
263    return( nameKey->serialize(s) );
264}
265
266enum { kIORegCapacityIncrement = 4 };
267
268bool IORegistryEntry::init( OSDictionary * dict )
269{
270    OSString *	prop;
271
272    if( !super::init())
273	return( false);
274
275    if (!reserved)
276    {
277	reserved = IONew(ExpansionData, 1);
278	if (!reserved)
279	    return (false);
280	bzero(reserved, sizeof(ExpansionData));
281    }
282    if( dict) {
283	if (OSCollection::kImmutable & dict->setOptions(0, 0)) {
284	    dict = (OSDictionary *) dict->copyCollection();
285	    if (!dict)
286           	return (false);
287	} else
288	    dict->retain();
289	if( fPropertyTable)
290	    fPropertyTable->release();
291	fPropertyTable = dict;
292
293    } else if( !fPropertyTable) {
294        fPropertyTable = OSDictionary::withCapacity( kIORegCapacityIncrement );
295	if( fPropertyTable)
296            fPropertyTable->setCapacityIncrement( kIORegCapacityIncrement );
297    }
298
299    if( !fPropertyTable)
300        return( false);
301
302#ifdef IOREGSPLITTABLES
303    if( !fRegistryTable) {
304	fRegistryTable = OSDictionary::withCapacity( kIORegCapacityIncrement );
305	if( fRegistryTable)
306	    fRegistryTable->setCapacityIncrement( kIORegCapacityIncrement );
307    }
308
309    if( (prop = OSDynamicCast( OSString, getProperty( gIONameKey)))) {
310        OSSymbol * sym = (OSSymbol *)OSSymbol::withString( prop);
311        // ok for OSSymbol too
312        setName( sym);
313        sym->release();
314    }
315
316#endif /* IOREGSPLITTABLES */
317
318    return( true);
319}
320
321bool IORegistryEntry::init( IORegistryEntry * old,
322				const IORegistryPlane * plane )
323{
324    OSArray *		all;
325    IORegistryEntry *		next;
326    unsigned int	index;
327
328    if( !super::init())
329	return( false);
330
331    WLOCK;
332
333    reserved = old->reserved;
334    old->reserved = NULL;
335
336    fPropertyTable = old->getPropertyTable();
337    fPropertyTable->retain();
338#ifdef IOREGSPLITTABLES
339    fRegistryTable = old->fRegistryTable;
340    old->fRegistryTable = OSDictionary::withDictionary( fRegistryTable );
341#endif /* IOREGSPLITTABLES */
342
343    old->registryTable()->removeObject( plane->keys[ kParentSetIndex ] );
344    old->registryTable()->removeObject( plane->keys[ kChildSetIndex ] );
345
346    all = getParentSetReference( plane );
347    if( all) for( index = 0;
348              (next = (IORegistryEntry *) all->getObject(index));
349              index++ ) {
350	    next->makeLink( this, kChildSetIndex, plane );
351            next->breakLink( old, kChildSetIndex, plane );
352    }
353
354    all = getChildSetReference( plane );
355    if( all) for( index = 0;
356              (next = (IORegistryEntry *) all->getObject(index));
357              index++ ) {
358	    next->makeLink( this, kParentSetIndex, plane );
359            next->breakLink( old, kParentSetIndex, plane );
360    }
361
362    UNLOCK;
363
364    return( true );
365}
366
367void IORegistryEntry::free( void )
368{
369#if DEBUG_FREE
370    if( registryTable() && gIOServicePlane) {
371        if( getParentSetReference( gIOServicePlane )
372            || getChildSetReference( gIOServicePlane )) {
373            panic("%s: attached at free()", getName());
374        }
375    }
376#endif
377
378    if( getPropertyTable())
379        getPropertyTable()->release();
380
381#ifdef IOREGSPLITTABLES
382    if( registryTable())
383        registryTable()->release();
384#endif /* IOREGSPLITTABLES */
385
386    if (reserved)
387	IODelete(reserved, ExpansionData, 1);
388
389    super::free();
390}
391
392void IORegistryEntry::setPropertyTable( OSDictionary * dict )
393{
394    if( fPropertyTable)
395	fPropertyTable->release();
396    if( dict)
397	dict->retain();
398    fPropertyTable = dict;
399}
400
401/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
402
403/* Wrappers to synchronize property table */
404
405#define wrap2(type, constant)						\
406OSObject *								\
407IORegistryEntry::copyProperty( type * aKey) constant			\
408{									\
409    OSObject *	obj;							\
410									\
411    PLOCK;								\
412    obj = getProperty( aKey );						\
413    if( obj)								\
414        obj->retain();							\
415    PUNLOCK;								\
416									\
417    return( obj );							\
418}
419
420#define wrap4(type,constant) \
421OSObject * \
422IORegistryEntry::getProperty( type *                  aKey, \
423                              const IORegistryPlane * plane, \
424                              IOOptionBits            options ) constant \
425{ \
426    OSObject * obj = getProperty( aKey ); \
427    \
428    if ( (0 == obj) && plane && (options & kIORegistryIterateRecursively) ) { \
429        IORegistryEntry * entry = (IORegistryEntry *) this; \
430        IORegistryIterator * iter; \
431        iter = IORegistryIterator::iterateOver( entry, plane, options ); \
432        \
433        if(iter) { \
434            while ( (0 == obj) && (entry = iter->getNextObject()) ) { \
435                obj = entry->getProperty( aKey ); \
436            } \
437            iter->release(); \
438        } \
439    } \
440    \
441    return( obj ); \
442}
443
444#define wrap5(type,constant) \
445OSObject * \
446IORegistryEntry::copyProperty( type *                  aKey, \
447                              const IORegistryPlane * plane, \
448                              IOOptionBits            options ) constant \
449{ \
450    OSObject * obj = copyProperty( aKey ); \
451    \
452    if ( (0 == obj) && plane && (options & kIORegistryIterateRecursively) ) { \
453        IORegistryEntry * entry = (IORegistryEntry *) this; \
454        IORegistryIterator * iter; \
455        iter = IORegistryIterator::iterateOver( entry, plane, options ); \
456        \
457        if(iter) { \
458            while ( (0 == obj) && (entry = iter->getNextObject()) ) { \
459                obj = entry->copyProperty( aKey ); \
460            } \
461            iter->release(); \
462        } \
463    } \
464    \
465    return( obj ); \
466}
467
468bool IORegistryEntry::serializeProperties( OSSerialize * s ) const
469{
470//    setProperty( getRetainCount(), 32, "__retain" );
471
472    PLOCK;
473    OSCollection *snapshotProperties = getPropertyTable()->copyCollection();
474    PUNLOCK;
475
476    bool ok =  snapshotProperties->serialize( s );
477    snapshotProperties->release();
478    return( ok );
479}
480
481OSDictionary * IORegistryEntry::dictionaryWithProperties( void ) const
482{
483    OSDictionary *	dict;
484
485    PLOCK;
486    dict = OSDictionary::withDictionary( getPropertyTable(),
487                            getPropertyTable()->getCapacity() );
488    PUNLOCK;
489
490    return( dict );
491}
492
493IOReturn IORegistryEntry::setProperties( OSObject * properties )
494{
495    return( kIOReturnUnsupported );
496}
497
498wrap2(const OSSymbol, const)       // copyProperty() definition
499wrap2(const OSString, const)       // copyProperty() definition
500wrap2(const char, const)      	   // copyProperty() definition
501
502wrap4(const OSSymbol, const)       // getProperty() w/plane definition
503wrap4(const OSString, const)       // getProperty() w/plane definition
504wrap4(const char, const)           // getProperty() w/plane definition
505
506wrap5(const OSSymbol, const)       // copyProperty() w/plane definition
507wrap5(const OSString, const)       // copyProperty() w/plane definition
508wrap5(const char, const)           // copyProperty() w/plane definition
509
510
511OSObject *
512IORegistryEntry::getProperty( const OSSymbol * aKey) const
513{
514    OSObject * obj;
515
516    PLOCK;
517    obj = getPropertyTable()->getObject( aKey );
518    PUNLOCK;
519
520    return( obj );
521}
522
523void
524IORegistryEntry::removeProperty( const OSSymbol * aKey)
525{
526    PLOCK;
527    getPropertyTable()->removeObject( aKey );
528    PUNLOCK;
529}
530
531#if KASLR_IOREG_DEBUG
532extern "C" {
533
534bool ScanForAddrInObject(OSObject * theObject,
535                         int indent);
536
537}; /* extern "C" */
538#endif
539
540bool
541IORegistryEntry::setProperty( const OSSymbol * aKey, OSObject * anObject)
542{
543    bool ret = false;
544
545    // If we are inserting a collection class and the current entry
546    // is attached into the registry (inPlane()) then mark the collection
547    // as immutable.
548    OSCollection *coll = OSDynamicCast(OSCollection, anObject);
549    bool makeImmutable = (coll && inPlane());
550
551    PLOCK;
552    if( makeImmutable )
553	coll->setOptions( OSCollection::kMASK, OSCollection::kImmutable );
554
555    ret = getPropertyTable()->setObject( aKey, anObject );
556    PUNLOCK;
557
558#if KASLR_IOREG_DEBUG
559    if ( anObject && strcmp(kIOKitDiagnosticsKey, aKey->getCStringNoCopy()) != 0 ) {
560        if (ScanForAddrInObject(anObject, 0)) {
561            IOLog("%s: IORegistryEntry name %s with key \"%s\" \n",
562                  __FUNCTION__,
563                  getName(0),
564                  aKey->getCStringNoCopy() );
565        }
566    }
567#endif
568
569    return ret;
570}
571
572IOReturn IORegistryEntry::
573runPropertyAction(Action inAction, OSObject *target,
574	void *arg0, void *arg1, void *arg2, void *arg3)
575{
576    IOReturn res;
577
578    // closeGate is recursive so don't worry if we already hold the lock.
579    PLOCK;
580    res = (*inAction)(target, arg0, arg1, arg2, arg3);
581    PUNLOCK;
582
583    return res;
584}
585
586OSObject *
587IORegistryEntry::getProperty( const OSString * aKey) const
588{
589    const OSSymbol * tmpKey = OSSymbol::withString( aKey );
590    OSObject * obj = getProperty( tmpKey );
591
592    tmpKey->release();
593    return( obj );
594}
595
596OSObject *
597IORegistryEntry::getProperty( const char * aKey) const
598{
599    const OSSymbol * tmpKey = OSSymbol::withCString( aKey );
600    OSObject * obj = getProperty( tmpKey );
601
602    tmpKey->release();
603    return( obj );
604}
605
606
607void
608IORegistryEntry::removeProperty( const OSString * aKey)
609{
610    const OSSymbol * tmpKey = OSSymbol::withString( aKey );
611    removeProperty( tmpKey );
612    tmpKey->release();
613}
614
615void
616IORegistryEntry::removeProperty( const char * aKey)
617{
618    const OSSymbol * tmpKey = OSSymbol::withCString( aKey );
619    removeProperty( tmpKey );
620    tmpKey->release();
621}
622
623bool
624IORegistryEntry::setProperty( const OSString * aKey, OSObject * anObject)
625{
626    const OSSymbol * tmpKey = OSSymbol::withString( aKey );
627    bool ret = setProperty( tmpKey, anObject );
628
629    tmpKey->release();
630    return ret;
631}
632
633bool
634IORegistryEntry::setProperty( const char * aKey,  OSObject * anObject)
635{
636    const OSSymbol * tmpKey = OSSymbol::withCString( aKey );
637    bool ret = setProperty( tmpKey, anObject );
638
639    tmpKey->release();
640    return ret;
641}
642
643bool
644IORegistryEntry::setProperty(const char * aKey, const char * aString)
645{
646    bool ret = false;
647    OSSymbol * aSymbol = (OSSymbol *) OSSymbol::withCString( aString );
648
649    if( aSymbol) {
650        const OSSymbol * tmpKey = OSSymbol::withCString( aKey );
651        ret = setProperty( tmpKey, aSymbol );
652
653        tmpKey->release();
654        aSymbol->release();
655    }
656    return( ret );
657}
658
659bool
660IORegistryEntry::setProperty(const char * aKey, bool aBoolean)
661{
662    bool ret = false;
663    OSBoolean * aBooleanObj = OSBoolean::withBoolean( aBoolean );
664
665    if( aBooleanObj) {
666        const OSSymbol * tmpKey = OSSymbol::withCString( aKey );
667        ret = setProperty( tmpKey, aBooleanObj );
668
669        tmpKey->release();
670        aBooleanObj->release();
671    }
672    return( ret );
673}
674
675bool
676IORegistryEntry::setProperty( const char *       aKey,
677                              unsigned long long aValue,
678                              unsigned int       aNumberOfBits)
679{
680    bool ret = false;
681    OSNumber * anOffset = OSNumber::withNumber( aValue, aNumberOfBits );
682
683    if( anOffset) {
684        const OSSymbol * tmpKey = OSSymbol::withCString( aKey );
685        ret = setProperty( tmpKey, anOffset );
686
687        tmpKey->release();
688        anOffset->release();
689    }
690    return( ret );
691}
692
693bool
694IORegistryEntry::setProperty( const char *      aKey,
695                              void *		bytes,
696                              unsigned int      length)
697{
698    bool ret = false;
699    OSData * data = OSData::withBytes( bytes, length );
700
701    if( data) {
702        const OSSymbol * tmpKey = OSSymbol::withCString( aKey );
703        ret = setProperty( tmpKey, data );
704
705        tmpKey->release();
706        data->release();
707    }
708    return( ret );
709}
710
711/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
712
713/* Name, location, paths */
714
715const char * IORegistryEntry::getName( const IORegistryPlane * plane ) const
716{
717    OSSymbol *		sym = 0;
718
719    RLOCK;
720    if( plane)
721	sym = (OSSymbol *) registryTable()->getObject( plane->pathNameKey );
722    if( !sym)
723	sym = (OSSymbol *) registryTable()->getObject( gIONameKey );
724    UNLOCK;
725
726    if( sym)
727	return( sym->getCStringNoCopy());
728    else
729        return( (getMetaClass())->getClassName());
730}
731
732const OSSymbol * IORegistryEntry::copyName(
733			const IORegistryPlane * plane ) const
734{
735    OSSymbol *		sym = 0;
736
737    RLOCK;
738    if( plane)
739	sym = (OSSymbol *) registryTable()->getObject( plane->pathNameKey );
740    if( !sym)
741	sym = (OSSymbol *) registryTable()->getObject( gIONameKey );
742    if( sym)
743	sym->retain();
744    UNLOCK;
745
746    if( sym)
747	return( sym );
748    else
749        return( OSSymbol::withCString((getMetaClass())->getClassName()) );
750}
751
752const OSSymbol * IORegistryEntry::copyLocation(
753			const IORegistryPlane * plane ) const
754{
755    OSSymbol *		sym = 0;
756
757    RLOCK;
758    if( plane)
759	sym = (OSSymbol *) registryTable()->getObject( plane->pathLocationKey );
760    if( !sym)
761	sym = (OSSymbol *) registryTable()->getObject( gIOLocationKey );
762    if( sym)
763	sym->retain();
764    UNLOCK;
765
766    return( sym );
767}
768
769const char * IORegistryEntry::getLocation( const IORegistryPlane * plane ) const
770{
771    const OSSymbol *	sym = copyLocation( plane );
772    const char *	result = 0;
773
774    if( sym) {
775	result = sym->getCStringNoCopy();
776	sym->release();
777    }
778
779    return( result );
780}
781
782void IORegistryEntry::setName( const OSSymbol * name,
783                            const IORegistryPlane * plane )
784{
785    const OSSymbol *	key;
786
787    if( name) {
788        if( plane)
789            key = plane->pathNameKey;
790        else
791            key = gIONameKey;
792
793	WLOCK;
794        registryTable()->setObject( key, (OSObject *) name);
795	UNLOCK;
796    }
797}
798
799void IORegistryEntry::setName( const char * name,
800                            const IORegistryPlane * plane )
801{
802    OSSymbol * sym = (OSSymbol *)OSSymbol::withCString( name );
803    if ( sym ) {
804        setName( sym, plane );
805        sym->release();
806    }
807}
808
809void IORegistryEntry::setLocation( const OSSymbol * location,
810                            const IORegistryPlane * plane )
811{
812    const OSSymbol *	key;
813
814    if( location) {
815        if( plane)
816            key = plane->pathLocationKey;
817        else
818            key = gIOLocationKey;
819
820	WLOCK;
821        registryTable()->setObject( key, (OSObject *) location);
822	UNLOCK;
823    }
824}
825
826void IORegistryEntry::setLocation( const char * location,
827                            const IORegistryPlane * plane )
828{
829    OSSymbol * sym = (OSSymbol *)OSSymbol::withCString( location );
830    if ( sym ) {
831        setLocation( sym, plane );
832        sym->release();
833    }
834}
835
836bool
837IORegistryEntry::compareName( OSString * name, OSString ** matched ) const
838{
839    const OSSymbol *	sym = copyName();
840    bool		isEqual;
841
842    isEqual = sym->isEqualTo( name );
843
844    if( isEqual && matched) {
845	name->retain();
846	*matched = name;
847    }
848
849    if( sym)
850	sym->release();
851
852    return( isEqual );
853}
854
855bool
856IORegistryEntry::compareNames( OSObject * names, OSString ** matched ) const
857{
858    OSString *		string;
859    OSCollection *	collection;
860    OSIterator *	iter = 0;
861    bool		result = false;
862
863    if( (collection = OSDynamicCast( OSCollection, names))) {
864	iter = OSCollectionIterator::withCollection( collection );
865	string = 0;
866    } else
867	string = OSDynamicCast( OSString, names);
868
869    do {
870	if( string)
871            result = compareName( string, matched );
872
873    } while( (false == result)
874	&& iter && (string = OSDynamicCast( OSString, iter->getNextObject())));
875
876    if( iter)
877	iter->release();
878
879    return( result);
880}
881
882
883bool IORegistryEntry::getPath(	char * path, int * length,
884				const IORegistryPlane * plane ) const
885{
886    OSArray *		stack;
887    IORegistryEntry *	root;
888    const IORegistryEntry * entry;
889    IORegistryEntry *	parent;
890    const OSSymbol *	alias;
891    int			index;
892    int			len, maxLength, compLen, aliasLen;
893    char *		nextComp;
894    bool		ok;
895
896   if( !path || !length || !plane)
897	return( false);
898
899    len = 0;
900    maxLength = *length - 2;
901    nextComp = path;
902
903    len = plane->nameKey->getLength();
904    if( len >= maxLength)
905	return( false);
906    strlcpy( nextComp, plane->nameKey->getCStringNoCopy(), len + 1);
907    nextComp[ len++ ] = ':';
908    nextComp += len;
909
910    if( (alias = hasAlias( plane ))) {
911	aliasLen = alias->getLength();
912	len += aliasLen;
913	ok = (maxLength > len);
914	*length = len;
915	if( ok)
916	    strlcpy( nextComp, alias->getCStringNoCopy(), aliasLen + 1);
917	return( ok );
918    }
919
920    entry = this;
921    parent = entry->getParentEntry( plane );
922    if( !parent)
923	// Error if not attached in plane
924	return( false);
925
926    stack = OSArray::withCapacity( getDepth( plane ));
927    if( !stack)
928	return( false);
929
930    RLOCK;
931
932    root = gRegistryRoot->getChildEntry( plane );
933    while( parent && (entry != root)) {
934	// stop below root
935	stack->setObject( (OSObject *) entry );
936	entry = parent;
937	parent = entry->getParentEntry( plane );
938    }
939
940    index = stack->getCount();
941    ok = true;
942
943    if( 0 == index) {
944
945        *nextComp++ = '/';
946        *nextComp = 0;
947        len++;
948
949    } else while( ok && ((--index) >= 0)) {
950
951        entry = (IORegistryEntry *) stack->getObject((unsigned int) index );
952        assert( entry );
953
954        if( (alias = entry->hasAlias( plane ))) {
955            len = plane->nameKey->getLength() + 1;
956            nextComp = path + len;
957
958            compLen = alias->getLength();
959            ok = (maxLength > (len + compLen));
960            if( ok)
961                strlcpy( nextComp, alias->getCStringNoCopy(), compLen + 1);
962        } else {
963            compLen = maxLength - len;
964            ok = entry->getPathComponent( nextComp + 1, &compLen, plane );
965
966            if( ok && compLen) {
967                compLen++;
968                *nextComp = '/';
969            }
970        }
971
972        if( ok) {
973            len += compLen;
974            nextComp += compLen;
975        }
976    }
977    *length = len;
978
979    UNLOCK;
980
981    stack->release();
982
983    return( ok );
984}
985
986bool IORegistryEntry::getPathComponent( char * path, int * length,
987                                        const IORegistryPlane * plane ) const
988{
989    int			len, locLen, maxLength;
990    const char *	compName;
991    const char *	loc;
992    bool		ok;
993
994    maxLength = *length;
995
996    compName = getName( plane );
997    len = strlen( compName );
998    if( (loc = getLocation( plane )))
999	locLen = 1 + strlen( loc );
1000    else
1001	locLen = 0;
1002
1003    ok = ((len + locLen + 1) < maxLength);
1004    if( ok) {
1005        strlcpy( path, compName, len + 1 );
1006	if( loc) {
1007            path += len;
1008            len += locLen;
1009            *path++ = '@';
1010            strlcpy( path, loc, locLen );
1011	}
1012        *length = len;
1013    }
1014
1015    return( ok );
1016}
1017
1018const char * IORegistryEntry::matchPathLocation( const char * cmp,
1019				const IORegistryPlane * plane )
1020{
1021    const char	*	str;
1022    const char	*	result = 0;
1023    u_quad_t		num1, num2;
1024    char		lastPathChar, lastLocationChar;
1025
1026    str = getLocation( plane );
1027    if( str) {
1028	lastPathChar = cmp[0];
1029	lastLocationChar = str[0];
1030	do {
1031            if( lastPathChar) {
1032                num1 = strtouq( cmp, (char **) &cmp, 16 );
1033                lastPathChar = *cmp++;
1034	    } else
1035                num1 = 0;
1036
1037            if( lastLocationChar) {
1038                num2 = strtouq( str, (char **) &str, 16 );
1039                lastLocationChar = *str++;
1040	    } else
1041                num2 = 0;
1042
1043            if( num1 != num2)
1044                break;
1045
1046	    if (!lastPathChar && !lastLocationChar) {
1047                result = cmp - 1;
1048                break;
1049            }
1050
1051            if( (',' != lastPathChar) && (':' != lastPathChar))
1052		lastPathChar = 0;
1053
1054	    if (lastPathChar && lastLocationChar && (lastPathChar != lastLocationChar))
1055                break;
1056
1057        } while( true);
1058    }
1059
1060    return( result );
1061}
1062
1063IORegistryEntry * IORegistryEntry::getChildFromComponent( const char ** opath,
1064				const IORegistryPlane * plane )
1065{
1066    IORegistryEntry *	entry = 0;
1067    OSArray *		set;
1068    unsigned int	index;
1069    const char *	path;
1070    const char *	cmp = 0;
1071    char		c;
1072    size_t		len;
1073    const char *	str;
1074
1075    set = getChildSetReference( plane );
1076    if( set) {
1077
1078	path = *opath;
1079
1080	for( index = 0;
1081             (entry = (IORegistryEntry *) set->getObject(index));
1082             index++ ) {
1083
1084            cmp = path;
1085
1086            if( *cmp != '@') {
1087                str = entry->getName( plane );
1088                len = strlen( str );
1089                if( strncmp( str, cmp, len ))
1090                    continue;
1091                cmp += len;
1092
1093                c = *cmp;
1094                if( (c == 0) || (c == '/') || (c == ':'))
1095                    break;
1096                if( c != '@')
1097                    continue;
1098            }
1099            cmp++;
1100            if( (cmp = entry->matchPathLocation( cmp, plane )))
1101                break;
1102        }
1103        if( entry)
1104            *opath = cmp;
1105    }
1106
1107    return( entry );
1108}
1109
1110const OSSymbol * IORegistryEntry::hasAlias( const IORegistryPlane * plane,
1111				char * opath, int * length ) const
1112{
1113    IORegistryEntry *	entry;
1114    IORegistryEntry *	entry2;
1115    const OSSymbol *	key;
1116    const OSSymbol *	bestKey = 0;
1117    OSIterator *	iter;
1118    OSData *		data;
1119    const char * 	path = "/aliases";
1120
1121    entry = IORegistryEntry::fromPath( path, plane );
1122    if( entry) {
1123        RLOCK;
1124        if( (iter = OSCollectionIterator::withCollection(
1125				entry->getPropertyTable() ))) {
1126
1127            while( (key = (OSSymbol *) iter->getNextObject())) {
1128
1129                data = (OSData *) entry->getProperty( key );
1130                path = (const char *) data->getBytesNoCopy();
1131                if( (entry2 = IORegistryEntry::fromPath( path, plane,
1132						opath, length ))) {
1133                    if( this == entry2) {
1134                        if( !bestKey
1135			 || (bestKey->getLength() > key->getLength()))
1136                            // pick the smallest alias
1137                            bestKey = key;
1138                    }
1139		    entry2->release();
1140		}
1141            }
1142            iter->release();
1143        }
1144	entry->release();
1145	UNLOCK;
1146    }
1147    return( bestKey );
1148}
1149
1150const char * IORegistryEntry::dealiasPath(
1151			const char ** 		opath,
1152			const IORegistryPlane *	plane )
1153{
1154    IORegistryEntry *	entry;
1155    OSData *		data;
1156    const char * 	path = *opath;
1157    const char * 	rpath = 0;
1158    const char * 	end;
1159    char		c;
1160    char		temp[ kIOMaxPlaneName + 1 ];
1161
1162    if( path[0] == '/')
1163	return( rpath );
1164
1165    // check for alias
1166    end = path;
1167    while( (c = *end++) && (c != '/') && (c != ':'))
1168        {}
1169    end--;
1170    if( (end - path) < kIOMaxPlaneName) {
1171        strlcpy( temp, path, end - path + 1 );
1172
1173        RLOCK;
1174        entry = IORegistryEntry::fromPath( "/aliases", plane );
1175        if( entry) {
1176            data = (OSData *) entry->getProperty( temp );
1177            if( data ) {
1178                rpath = (const char *) data->getBytesNoCopy();
1179                if( rpath)
1180                    *opath = end;
1181            }
1182	    entry->release();
1183        }
1184        UNLOCK;
1185    }
1186
1187    return( rpath );
1188}
1189
1190IORegistryEntry * IORegistryEntry::fromPath(
1191                        const char * 		path,
1192                        const IORegistryPlane * plane,
1193                        char *			opath,
1194			int * 			length,
1195                        IORegistryEntry * 	fromEntry )
1196{
1197    IORegistryEntry *	where = 0;
1198    IORegistryEntry *	aliasEntry = 0;
1199    IORegistryEntry *	next;
1200    const char *	alias;
1201    const char *	end;
1202    int			len = 0;
1203    int			len2;
1204    char		c;
1205    char		temp[ kIOMaxPlaneName + 1 ];
1206
1207    if( 0 == path)
1208	return( 0 );
1209
1210    if( 0 == plane) {
1211	// get plane name
1212        end = strchr( path, ':' );
1213	if( end && ((end - path) < kIOMaxPlaneName)) {
1214	    strlcpy( temp, path, end - path + 1 );
1215            plane = getPlane( temp );
1216	    path = end + 1;
1217	}
1218    }
1219    if( 0 == plane)
1220	return( 0 );
1221
1222    // check for alias
1223    end = path;
1224    if( (alias = dealiasPath( &end, plane))) {
1225        if( length)
1226            len = *length;
1227        aliasEntry = IORegistryEntry::fromPath( alias, plane,
1228                                    opath, &len, fromEntry );
1229        where = aliasEntry;
1230        if( where)
1231            path = end;
1232        else
1233            len = 0;
1234    }
1235
1236    RLOCK;
1237
1238    do {
1239        if( 0 == where) {
1240            if( (0 == fromEntry) && (*path++ == '/'))
1241                fromEntry = gRegistryRoot->getChildEntry( plane );
1242            where = fromEntry;
1243            if( 0 == where)
1244                break;
1245        } else {
1246            c = *path++;
1247            if( c != '/') {
1248                if( c && (c != ':'))	// check valid terminator
1249                    where = 0;
1250                break;
1251            }
1252        }
1253        next = where->getChildFromComponent( &path, plane );
1254        if( next)
1255            where = next;
1256    } while( next );
1257
1258    if( where) {
1259	// check residual path
1260	if( where != fromEntry)
1261            path--;
1262
1263	if( opath && length) {
1264            // copy out residual path
1265	    len2 = strlen( path );
1266	    if( (len + len2) < *length)
1267                strlcpy( opath + len, path, len2 + 1 );
1268	    *length = (len + len2);
1269
1270	} else if( path[0])
1271	    // no residual path => must be no tail for success
1272            where = 0;
1273    }
1274
1275    if( where)
1276	where->retain();
1277    if( aliasEntry)
1278        aliasEntry->release();
1279
1280    UNLOCK;
1281
1282    return( where );
1283}
1284
1285IORegistryEntry * IORegistryEntry::childFromPath(
1286			const char *		path,
1287                        const IORegistryPlane * plane,
1288                        char *			opath,
1289                        int *			len )
1290{
1291    return( IORegistryEntry::fromPath( path, plane, opath, len, this ));
1292}
1293
1294/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1295
1296#define IOLinkIterator OSCollectionIterator
1297
1298#undef super
1299#define super OSObject
1300
1301inline bool IORegistryEntry::arrayMember( OSArray * set,
1302					  const IORegistryEntry * member,
1303					unsigned int * index ) const
1304{
1305    int		i;
1306    OSObject *	probeObject;
1307
1308    for( i = 0; (probeObject = set->getObject(i)); i++) {
1309        if (probeObject == (OSObject *) member) {
1310	    if( index)
1311                *index = i;
1312            return( true );
1313	}
1314    }
1315    return( false );
1316}
1317
1318bool IORegistryEntry::makeLink( IORegistryEntry * to,
1319                                unsigned int relation,
1320                                const IORegistryPlane * plane ) const
1321{
1322    OSArray *	links;
1323    bool	result = false;
1324
1325    if( (links = (OSArray *)
1326		registryTable()->getObject( plane->keys[ relation ] ))) {
1327
1328	result = arrayMember( links, to );
1329	if( !result)
1330            result = links->setObject( to );
1331
1332    } else {
1333
1334	links = OSArray::withObjects( (const OSObject **) &to, 1, 1 );
1335	result = (links != 0);
1336	if( result) {
1337	    result = registryTable()->setObject( plane->keys[ relation ],
1338                                          links );
1339            links->release();
1340	}
1341    }
1342
1343    return( result);
1344}
1345
1346void IORegistryEntry::breakLink( IORegistryEntry * to,
1347                                 unsigned int relation,
1348                                 const IORegistryPlane * plane ) const
1349{
1350    OSArray *		links;
1351    unsigned int	index;
1352
1353    if( (links = (OSArray *)
1354		registryTable()->getObject( plane->keys[ relation ]))) {
1355
1356	if( arrayMember( links, to, &index )) {
1357            links->removeObject( index );
1358	    if( 0 == links->getCount())
1359                registryTable()->removeObject( plane->keys[ relation ]);
1360	    }
1361    }
1362}
1363
1364
1365OSArray * IORegistryEntry::getParentSetReference(
1366				const IORegistryPlane * plane ) const
1367{
1368    if( plane)
1369        return( (OSArray *) registryTable()->getObject(
1370                            plane->keys[ kParentSetIndex ]));
1371    else
1372	return( 0 );
1373}
1374
1375OSIterator * IORegistryEntry::getParentIterator(
1376				const IORegistryPlane * plane ) const
1377{
1378    OSArray *		links;
1379    OSIterator *	iter;
1380
1381    if( !plane)
1382	return( 0 );
1383
1384    RLOCK;
1385    links = getParentSetReference( plane );
1386    if( 0 == links)
1387	links = OSArray::withCapacity( 1 );
1388    else
1389	links = OSArray::withArray( links, links->getCount() );
1390    UNLOCK;
1391
1392    iter = IOLinkIterator::withCollection( links );
1393
1394    if( links)
1395        links->release();
1396
1397    return( iter );
1398}
1399
1400IORegistryEntry * IORegistryEntry::copyParentEntry( const IORegistryPlane * plane ) const
1401{
1402    IORegistryEntry *	entry = 0;
1403    OSArray *		links;
1404
1405    RLOCK;
1406
1407    if( (links = getParentSetReference( plane ))) {
1408        entry = (IORegistryEntry *) links->getObject( 0 );
1409        entry->retain();
1410    }
1411
1412    UNLOCK;
1413
1414    return( entry);
1415}
1416
1417IORegistryEntry * IORegistryEntry::getParentEntry( const IORegistryPlane * plane ) const
1418{
1419    IORegistryEntry * entry;
1420
1421    entry = copyParentEntry( plane );
1422    if( entry)
1423        entry->release();
1424
1425    return( entry );
1426}
1427
1428OSArray * IORegistryEntry::getChildSetReference( const IORegistryPlane * plane ) const
1429{
1430    if( plane)
1431        return( (OSArray *) registryTable()->getObject(
1432                            plane->keys[ kChildSetIndex ]));
1433    else
1434	return( 0 );
1435}
1436
1437OSIterator * IORegistryEntry::getChildIterator( const IORegistryPlane * plane ) const
1438{
1439    OSArray *		links;
1440    OSIterator *	iter;
1441
1442    if( !plane)
1443	return( 0 );
1444
1445    RLOCK;
1446    links = getChildSetReference( plane );
1447    if( 0 == links)
1448        links = OSArray::withCapacity( 1 );
1449    else
1450        links = OSArray::withArray( links, links->getCount() );
1451    UNLOCK;
1452
1453    iter = IOLinkIterator::withCollection( links );
1454
1455    if( links)
1456        links->release();
1457
1458    return( iter );
1459}
1460
1461
1462IORegistryEntry * IORegistryEntry::copyChildEntry(
1463				const IORegistryPlane * plane ) const
1464{
1465    IORegistryEntry *	entry = 0;
1466    OSArray *		links;
1467
1468    RLOCK;
1469
1470    if( (links = getChildSetReference( plane ))) {
1471	entry = (IORegistryEntry *) links->getObject( 0 );
1472        entry->retain();
1473    }
1474
1475    UNLOCK;
1476
1477    return( entry);
1478}
1479
1480IORegistryEntry * IORegistryEntry::getChildEntry(
1481				const IORegistryPlane * plane ) const
1482{
1483    IORegistryEntry * entry;
1484
1485    entry = copyChildEntry( plane );
1486    if( entry)
1487        entry->release();
1488
1489    return( entry );
1490}
1491
1492void IORegistryEntry::applyToChildren( IORegistryEntryApplierFunction applier,
1493                                       void * context,
1494                                       const IORegistryPlane * plane ) const
1495{
1496    OSArray *	 	array;
1497    unsigned int 	index;
1498    IORegistryEntry *	next;
1499
1500    if( !plane)
1501        return;
1502
1503    RLOCK;
1504    array = OSArray::withArray( getChildSetReference( plane ));
1505    UNLOCK;
1506    if( array) {
1507        for( index = 0;
1508             (next = (IORegistryEntry *) array->getObject( index ));
1509             index++)
1510            (*applier)(next, context);
1511        array->release();
1512    }
1513}
1514
1515void IORegistryEntry::applyToParents( IORegistryEntryApplierFunction applier,
1516                                      void * context,
1517                                      const IORegistryPlane * plane ) const
1518{
1519    OSArray *	 	array;
1520    unsigned int 	index;
1521    IORegistryEntry *	next;
1522
1523    if( !plane)
1524        return;
1525
1526    RLOCK;
1527    array = OSArray::withArray( getParentSetReference( plane ));
1528    UNLOCK;
1529    if( array) {
1530        for( index = 0;
1531             (next = (IORegistryEntry *) array->getObject( index ));
1532             index++)
1533            (*applier)(next, context);
1534        array->release();
1535    }
1536}
1537
1538bool IORegistryEntry::isChild( IORegistryEntry * child,
1539                                const IORegistryPlane * plane,
1540				bool onlyChild ) const
1541{
1542    OSArray *	links;
1543    bool	ret = false;
1544
1545    RLOCK;
1546
1547    if( (links = getChildSetReference( plane ))) {
1548	if( (!onlyChild) || (1 == links->getCount()))
1549            ret = arrayMember( links, child );
1550    }
1551    if( ret && (links = child->getParentSetReference( plane )))
1552	ret = arrayMember( links, this );
1553
1554    UNLOCK;
1555
1556    return( ret);
1557}
1558
1559bool IORegistryEntry::isParent( IORegistryEntry * parent,
1560                                const IORegistryPlane * plane,
1561				bool onlyParent ) const
1562
1563{
1564    OSArray *	links;
1565    bool	ret = false;
1566
1567    RLOCK;
1568
1569    if( (links = getParentSetReference( plane ))) {
1570	if( (!onlyParent) || (1 == links->getCount()))
1571            ret = arrayMember( links, parent );
1572    }
1573    if( ret && (links = parent->getChildSetReference( plane )))
1574	ret = arrayMember( links, this );
1575
1576    UNLOCK;
1577
1578    return( ret);
1579}
1580
1581bool IORegistryEntry::inPlane( const IORegistryPlane * plane ) const
1582{
1583    bool ret;
1584
1585    RLOCK;
1586
1587    if( plane)
1588	ret = (0 != getParentSetReference( plane ));
1589    else {
1590
1591	// Check to see if this is in any plane.  If it is in a plane
1592	// then the registryTable will contain a key with the ParentLinks
1593	// suffix.  When we iterate over the keys looking for that suffix
1594	ret = false;
1595
1596	OSCollectionIterator *iter =
1597	    OSCollectionIterator::withCollection( registryTable());
1598	if( iter) {
1599	    const OSSymbol *key;
1600
1601            while( (key = (OSSymbol *) iter->getNextObject()) ) {
1602		size_t keysuffix;
1603
1604		// Get a pointer to this keys suffix
1605		keysuffix = key->getLength();
1606		if (keysuffix <= kIORegPlaneParentSuffixLen)
1607		    continue;
1608		keysuffix -= kIORegPlaneParentSuffixLen;
1609		if( !strncmp(key->getCStringNoCopy() + keysuffix,
1610				kIORegPlaneParentSuffix,
1611				kIORegPlaneParentSuffixLen + 1) ) {
1612		    ret = true;
1613		    break;
1614		}
1615            }
1616            iter->release();
1617        }
1618    }
1619
1620    UNLOCK;
1621
1622    return( ret );
1623}
1624
1625bool IORegistryEntry::attachToParent( IORegistryEntry * parent,
1626                                const IORegistryPlane * plane )
1627{
1628    OSArray *	links;
1629    bool	ret;
1630    bool	needParent;
1631
1632    if( this == parent)
1633	return( false );
1634
1635    WLOCK;
1636
1637    if (!reserved->fRegistryEntryID)
1638	reserved->fRegistryEntryID = ++gIORegistryLastID;
1639
1640    ret = makeLink( parent, kParentSetIndex, plane );
1641
1642    if( (links = parent->getChildSetReference( plane )))
1643	needParent = (false == arrayMember( links, this ));
1644    else
1645	needParent = true;
1646
1647    UNLOCK;
1648
1649    PLOCK;
1650
1651    // Mark any collections in the property list as immutable
1652    OSDictionary *ptable = getPropertyTable();
1653    OSCollectionIterator *iter =
1654	OSCollectionIterator::withCollection( ptable );
1655    if( iter) {
1656	const OSSymbol *key;
1657
1658	while( (key = (OSSymbol *) iter->getNextObject( ))) {
1659	    // Is object for key a collection?
1660	    OSCollection *coll =
1661		OSDynamicCast( OSCollection, ptable->getObject( key ));
1662
1663	    if( coll) {
1664		// Yup so mark it as immutable
1665		coll->setOptions( OSCollection::kMASK,
1666				  OSCollection::kImmutable );
1667	    }
1668	}
1669	iter->release();
1670    }
1671
1672    PUNLOCK;
1673
1674    if( needParent)
1675        ret &= parent->attachToChild( this, plane );
1676
1677    return( ret );
1678}
1679
1680uint64_t IORegistryEntry::getRegistryEntryID( void )
1681{
1682    if (reserved)
1683	return (reserved->fRegistryEntryID);
1684    else
1685	return (0);
1686}
1687
1688bool IORegistryEntry::attachToChild( IORegistryEntry * child,
1689                                        const IORegistryPlane * plane )
1690{
1691    OSArray *	links;
1692    bool	ret;
1693    bool	needChild;
1694
1695    if( this == child)
1696	return( false );
1697
1698    WLOCK;
1699
1700    ret = makeLink( child, kChildSetIndex, plane );
1701
1702    if( (links = child->getParentSetReference( plane )))
1703	needChild = (false == arrayMember( links, this ));
1704    else
1705	needChild = true;
1706
1707    UNLOCK;
1708
1709    if( needChild)
1710	ret &= child->attachToParent( this, plane );
1711
1712    return( ret );
1713}
1714
1715void IORegistryEntry::detachFromParent( IORegistryEntry * parent,
1716                                const IORegistryPlane * plane )
1717{
1718    OSArray *	links;
1719    bool	needParent;
1720
1721    WLOCK;
1722
1723    parent->retain();
1724
1725    breakLink( parent, kParentSetIndex, plane );
1726
1727    if( (links = parent->getChildSetReference( plane )))
1728	needParent = arrayMember( links, this );
1729    else
1730	needParent = false;
1731
1732//    parent->breakLink( this, kChildSetIndex, plane );
1733
1734    UNLOCK;
1735
1736    if( needParent)
1737	parent->detachFromChild( this, plane );
1738
1739    parent->release();
1740}
1741
1742void IORegistryEntry::detachFromChild( IORegistryEntry * child,
1743                                const IORegistryPlane * plane )
1744{
1745    OSArray *		links;
1746    bool	needChild;
1747
1748    WLOCK;
1749
1750    child->retain();
1751
1752    breakLink( child, kChildSetIndex, plane );
1753
1754    if( (links = child->getParentSetReference( plane )))
1755	needChild = arrayMember( links, this );
1756    else
1757	needChild = false;
1758
1759    UNLOCK;
1760
1761    if( needChild)
1762	child->detachFromParent( this, plane );
1763
1764    child->release();
1765}
1766
1767void IORegistryEntry::detachAbove( const IORegistryPlane * plane )
1768{
1769    IORegistryEntry *	parent;
1770
1771    retain();
1772    while( (parent = getParentEntry( plane )))
1773	detachFromParent( parent, plane );
1774    release();
1775}
1776
1777void IORegistryEntry::detachAll( const IORegistryPlane * plane )
1778{
1779    OSOrderedSet *		all;
1780    IORegistryEntry *		next;
1781    IORegistryIterator *	regIter;
1782
1783    regIter = IORegistryIterator::iterateOver( this, plane, true );
1784    if( 0 == regIter)
1785	return;
1786    all = regIter->iterateAll();
1787    regIter->release();
1788
1789    detachAbove( plane );
1790    if( all) {
1791	while( (next = (IORegistryEntry *) all->getLastObject())) {
1792
1793            next->retain();
1794            all->removeObject(next);
1795
1796            next->detachAbove( plane );
1797            next->release();
1798        }
1799        all->release();
1800    }
1801}
1802
1803unsigned int IORegistryEntry::getDepth( const IORegistryPlane * plane ) const
1804{
1805    unsigned int		depth = 1;
1806    OSArray *			parents;
1807    unsigned int 		oneDepth, maxParentDepth, count;
1808    IORegistryEntry *		one;
1809    const IORegistryEntry *	next;
1810    unsigned int		index;
1811
1812    RLOCK;
1813
1814    next = this;
1815    while( (parents = next->getParentSetReference( plane ))) {
1816
1817	count = parents->getCount();
1818	if( 0 == count)
1819	    break;
1820	if( 1 == count) {
1821            depth++;
1822            next = (IORegistryEntry *) parents->getObject( 0 );
1823	} else {
1824	    // painful
1825	    maxParentDepth = 0;
1826	    for( index = 0;
1827		 (one = (IORegistryEntry *) parents->getObject( index ));
1828		 index++ ) {
1829                oneDepth = one->getDepth( plane );
1830                if( oneDepth > maxParentDepth)
1831                    maxParentDepth = oneDepth;
1832            }
1833            depth += maxParentDepth;
1834	    break;
1835	}
1836    }
1837
1838    UNLOCK;
1839
1840    return( depth);
1841}
1842
1843/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1844
1845#undef super
1846#define super OSIterator
1847
1848OSDefineMetaClassAndStructors(IORegistryIterator, OSIterator)
1849
1850enum { kIORegistryIteratorInvalidFlag = 0x80000000 };
1851
1852/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1853
1854IORegistryIterator *
1855IORegistryIterator::iterateOver( IORegistryEntry * root,
1856                                 const IORegistryPlane * plane,
1857                                 IOOptionBits options )
1858{
1859    IORegistryIterator *	create;
1860
1861    if( 0 == root)
1862	return( 0);
1863    if( 0 == plane)
1864	return( 0);
1865
1866    create = new IORegistryIterator;
1867    if( create) {
1868        if( create->init()) {
1869
1870            root->retain();
1871            create->root = root;
1872            create->where = &create->start;
1873            create->start.current = root;
1874            create->plane = plane;
1875            create->options = options & ~kIORegistryIteratorInvalidFlag;
1876
1877	} else {
1878	    create->release();
1879	    create = 0;
1880	}
1881    }
1882    return( create);
1883}
1884
1885IORegistryIterator *
1886IORegistryIterator::iterateOver( const IORegistryPlane * plane,
1887				 IOOptionBits options )
1888{
1889    return( iterateOver( gRegistryRoot, plane, options ));
1890}
1891
1892bool IORegistryIterator::isValid( void )
1893{
1894    bool		ok;
1895    IORegCursor *	next;
1896
1897    next = where;
1898
1899    RLOCK;
1900
1901    ok = (0 == (kIORegistryIteratorInvalidFlag & options));
1902
1903    while( ok && next) {
1904	if( where->iter)
1905            ok = where->iter->isValid();
1906	next = next->next;
1907    }
1908    UNLOCK;
1909
1910    return( ok);
1911}
1912
1913void IORegistryIterator::enterEntry( const IORegistryPlane * enterPlane )
1914{
1915    IORegCursor *	prev;
1916
1917    prev = where;
1918    where = (IORegCursor *) IOMalloc( sizeof(IORegCursor));
1919    assert( where);
1920
1921    if( where) {
1922        where->iter = 0;
1923        where->next = prev;
1924        where->current = prev->current;
1925        plane = enterPlane;
1926    }
1927}
1928
1929void IORegistryIterator::enterEntry( void )
1930{
1931    enterEntry( plane );
1932}
1933
1934bool IORegistryIterator::exitEntry( void )
1935{
1936    IORegCursor *	gone;
1937
1938    if( where->iter) {
1939	where->iter->release();
1940	where->iter = 0;
1941        if( where->current)// && (where != &start))
1942            where->current->release();
1943    }
1944
1945    if( where != &start) {
1946	gone = where;
1947        where = gone->next;
1948        IOFree( gone, sizeof(IORegCursor));
1949	return( true);
1950
1951    } else
1952        return( false);
1953}
1954
1955void IORegistryIterator::reset( void )
1956{
1957    while( exitEntry())
1958	{}
1959
1960    if( done) {
1961	done->release();
1962	done = 0;
1963    }
1964
1965    where->current = root;
1966    options &= ~kIORegistryIteratorInvalidFlag;
1967}
1968
1969void IORegistryIterator::free( void )
1970{
1971    reset();
1972
1973    if( root)
1974        root->release();
1975
1976    super::free();
1977}
1978
1979
1980IORegistryEntry * IORegistryIterator::getNextObjectFlat( void )
1981{
1982    IORegistryEntry * 	next = 0;
1983    OSArray *		links = 0;
1984
1985    RLOCK;
1986
1987    if( (0 == where->iter)) {
1988	// just entered - create new iter
1989	if( isValid()
1990        &&  where->current
1991        &&  (links = ( (options & kIORegistryIterateParents) ?
1992                        where->current->getParentSetReference( plane ) :
1993                        where->current->getChildSetReference( plane ) )) )
1994
1995            where->iter = OSCollectionIterator::withCollection( links );
1996
1997    } else
1998	// next sibling - release current
1999        if( where->current)
2000            where->current->release();
2001
2002    if( where->iter) {
2003
2004        next = (IORegistryEntry *) where->iter->getNextObject();
2005
2006        if( next)
2007            next->retain();
2008        else if( !where->iter->isValid())
2009            options |= kIORegistryIteratorInvalidFlag;
2010    }
2011
2012    where->current = next;
2013
2014    UNLOCK;
2015
2016    return( next);
2017}
2018
2019IORegistryEntry * IORegistryIterator::getNextObjectRecursive( void )
2020{
2021    IORegistryEntry *	next;
2022
2023    do
2024        next = getNextObjectFlat();
2025    while( (0 == next) && exitEntry());
2026
2027    if( next) {
2028	if( 0 == done)
2029            done = OSOrderedSet::withCapacity( 10 );
2030	if( done->setObject((OSObject *) next)) {
2031       	    // done set didn't contain this one, so recurse
2032            enterEntry();
2033	}
2034    }
2035    return( next);
2036}
2037
2038IORegistryEntry * IORegistryIterator::getNextObject( void )
2039{
2040    if( options & kIORegistryIterateRecursively)
2041	return( getNextObjectRecursive());
2042    else
2043	return( getNextObjectFlat());
2044}
2045
2046IORegistryEntry * IORegistryIterator::getCurrentEntry( void )
2047{
2048    if( isValid())
2049	return( where->current);
2050    else
2051	return( 0);
2052}
2053
2054OSOrderedSet * IORegistryIterator::iterateAll( void )
2055{
2056    reset();
2057    while( getNextObjectRecursive())
2058        {}
2059    if( done)
2060        done->retain();
2061    return( done);
2062}
2063
2064#if __LP64__
2065OSMetaClassDefineReservedUnused(IORegistryEntry, 0);
2066OSMetaClassDefineReservedUnused(IORegistryEntry, 1);
2067OSMetaClassDefineReservedUnused(IORegistryEntry, 2);
2068OSMetaClassDefineReservedUnused(IORegistryEntry, 3);
2069OSMetaClassDefineReservedUnused(IORegistryEntry, 4);
2070OSMetaClassDefineReservedUnused(IORegistryEntry, 5);
2071#else
2072OSMetaClassDefineReservedUsed(IORegistryEntry, 0);
2073OSMetaClassDefineReservedUsed(IORegistryEntry, 1);
2074OSMetaClassDefineReservedUsed(IORegistryEntry, 2);
2075OSMetaClassDefineReservedUsed(IORegistryEntry, 3);
2076OSMetaClassDefineReservedUsed(IORegistryEntry, 4);
2077OSMetaClassDefineReservedUsed(IORegistryEntry, 5);
2078#endif
2079OSMetaClassDefineReservedUnused(IORegistryEntry, 6);
2080OSMetaClassDefineReservedUnused(IORegistryEntry, 7);
2081OSMetaClassDefineReservedUnused(IORegistryEntry, 8);
2082OSMetaClassDefineReservedUnused(IORegistryEntry, 9);
2083OSMetaClassDefineReservedUnused(IORegistryEntry, 10);
2084OSMetaClassDefineReservedUnused(IORegistryEntry, 11);
2085OSMetaClassDefineReservedUnused(IORegistryEntry, 12);
2086OSMetaClassDefineReservedUnused(IORegistryEntry, 13);
2087OSMetaClassDefineReservedUnused(IORegistryEntry, 14);
2088OSMetaClassDefineReservedUnused(IORegistryEntry, 15);
2089OSMetaClassDefineReservedUnused(IORegistryEntry, 16);
2090OSMetaClassDefineReservedUnused(IORegistryEntry, 17);
2091OSMetaClassDefineReservedUnused(IORegistryEntry, 18);
2092OSMetaClassDefineReservedUnused(IORegistryEntry, 19);
2093OSMetaClassDefineReservedUnused(IORegistryEntry, 20);
2094OSMetaClassDefineReservedUnused(IORegistryEntry, 21);
2095OSMetaClassDefineReservedUnused(IORegistryEntry, 22);
2096OSMetaClassDefineReservedUnused(IORegistryEntry, 23);
2097OSMetaClassDefineReservedUnused(IORegistryEntry, 24);
2098OSMetaClassDefineReservedUnused(IORegistryEntry, 25);
2099OSMetaClassDefineReservedUnused(IORegistryEntry, 26);
2100OSMetaClassDefineReservedUnused(IORegistryEntry, 27);
2101OSMetaClassDefineReservedUnused(IORegistryEntry, 28);
2102OSMetaClassDefineReservedUnused(IORegistryEntry, 29);
2103OSMetaClassDefineReservedUnused(IORegistryEntry, 30);
2104OSMetaClassDefineReservedUnused(IORegistryEntry, 31);
2105
2106/* inline function implementation */
2107OSDictionary * IORegistryEntry::getPropertyTable( void ) const
2108{ return(fPropertyTable); }
2109