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