2 * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <IOKit/IODeviceTreeSupport.h>
30 #include <libkern/c++/OSContainers.h>
31 #include <IOKit/IODeviceMemory.h>
32 #include <IOKit/IOService.h>
33 #include <IOKit/IOCatalogue.h>
35 #include <IOKit/IOLib.h>
36 #include <IOKit/IOKitKeys.h>
38 #include <pexpert/device_tree.h>
40 #include <machine/machine_routines.h>
44 int IODTGetLoaderInfo( const char *key
, void **infoAddr
, int *infosize
);
45 void IODTFreeLoaderInfo( const char *key
, void *infoAddr
, int infoSize
);
46 int IODTGetDefault(const char *key
, void *infoAddr
, unsigned int infoSize
);
50 #include <IOKit/assert.h>
52 #define IODTSUPPORTDEBUG 0
54 const IORegistryPlane
* gIODTPlane
;
56 static OSArray
* gIODTPHandles
;
57 static OSArray
* gIODTPHandleMap
;
59 const OSSymbol
* gIODTNameKey
;
60 const OSSymbol
* gIODTUnitKey
;
61 const OSSymbol
* gIODTCompatibleKey
;
62 const OSSymbol
* gIODTTypeKey
;
63 const OSSymbol
* gIODTModelKey
;
65 const OSSymbol
* gIODTSizeCellKey
;
66 const OSSymbol
* gIODTAddressCellKey
;
67 const OSSymbol
* gIODTRangeKey
;
69 const OSSymbol
* gIODTPersistKey
;
71 const OSSymbol
* gIODTDefaultInterruptController
;
72 const OSSymbol
* gIODTAAPLInterruptsKey
;
73 const OSSymbol
* gIODTPHandleKey
;
74 const OSSymbol
* gIODTInterruptCellKey
;
75 const OSSymbol
* gIODTInterruptParentKey
;
76 const OSSymbol
* gIODTNWInterruptMappingKey
;
78 OSDictionary
* gIODTSharedInterrupts
;
80 static IORegistryEntry
* MakeReferenceTable( DTEntry dtEntry
, bool copy
);
81 static void AddPHandle( IORegistryEntry
* regEntry
);
82 static void FreePhysicalMemory( vm_offset_t
* range
);
83 static bool IODTMapInterruptsSharing( IORegistryEntry
* regEntry
, OSDictionary
* allInts
);
86 IODeviceTreeAlloc( void * dtTop
)
88 IORegistryEntry
* parent
;
89 IORegistryEntry
* child
;
90 IORegistryIterator
* regIter
;
96 OSDictionary
* allInts
;
98 unsigned int propSize
;
102 gIODTPlane
= IORegistryEntry::makePlane( kIODeviceTreePlane
);
104 gIODTNameKey
= OSSymbol::withCStringNoCopy( "name" );
105 gIODTUnitKey
= OSSymbol::withCStringNoCopy( "AAPL,unit-string" );
106 gIODTCompatibleKey
= OSSymbol::withCStringNoCopy( "compatible" );
107 gIODTTypeKey
= OSSymbol::withCStringNoCopy( "device_type" );
108 gIODTModelKey
= OSSymbol::withCStringNoCopy( "model" );
109 gIODTSizeCellKey
= OSSymbol::withCStringNoCopy( "#size-cells" );
110 gIODTAddressCellKey
= OSSymbol::withCStringNoCopy( "#address-cells" );
111 gIODTRangeKey
= OSSymbol::withCStringNoCopy( "ranges" );
112 gIODTPersistKey
= OSSymbol::withCStringNoCopy( "IODTPersist" );
114 assert( gIODTPlane
&& gIODTCompatibleKey
115 && gIODTTypeKey
&& gIODTModelKey
116 && gIODTSizeCellKey
&& gIODTAddressCellKey
&& gIODTRangeKey
117 && gIODTPersistKey
);
119 gIODTDefaultInterruptController
120 = OSSymbol::withCStringNoCopy("IOPrimaryInterruptController");
121 gIODTNWInterruptMappingKey
122 = OSSymbol::withCStringNoCopy("IONWInterrupts");
124 gIODTAAPLInterruptsKey
125 = OSSymbol::withCStringNoCopy("AAPL,interrupts");
127 = OSSymbol::withCStringNoCopy("AAPL,phandle");
129 gIODTInterruptParentKey
130 = OSSymbol::withCStringNoCopy("interrupt-parent");
132 gIODTPHandles
= OSArray::withCapacity( 1 );
133 gIODTPHandleMap
= OSArray::withCapacity( 1 );
135 gIODTInterruptCellKey
136 = OSSymbol::withCStringNoCopy("#interrupt-cells");
138 assert( gIODTDefaultInterruptController
&& gIODTNWInterruptMappingKey
139 && gIODTAAPLInterruptsKey
140 && gIODTPHandleKey
&& gIODTInterruptParentKey
141 && gIODTPHandles
&& gIODTPHandleMap
142 && gIODTInterruptCellKey
145 freeDT
= (kSuccess
== DTLookupEntry( 0, "/chosen/memory-map", &mapEntry
))
146 && (kSuccess
== DTGetProperty( mapEntry
,
147 "DeviceTree", (void **) &dtMap
, &propSize
))
148 && ((2 * sizeof(uint32_t)) == propSize
);
150 parent
= MakeReferenceTable( (DTEntry
)dtTop
, freeDT
);
152 stack
= OSArray::withObjects( (const OSObject
**) &parent
, 1, 10 );
153 DTCreateEntryIterator( (DTEntry
)dtTop
, &iter
);
156 parent
= (IORegistryEntry
*)stack
->getObject( stack
->getCount() - 1);
158 stack
->removeObject( stack
->getCount() - 1);
160 while( kSuccess
== DTIterateEntries( iter
, &dtChild
) ) {
162 child
= MakeReferenceTable( dtChild
, freeDT
);
163 child
->attachToParent( parent
, gIODTPlane
);
167 if( kSuccess
== DTEnterEntry( iter
, dtChild
)) {
168 stack
->setObject( parent
);
171 // only registry holds retain
175 } while( stack
->getCount()
176 && (kSuccess
== DTExitEntry( iter
, &dtChild
)));
179 DTDisposeEntryIterator( iter
);
181 // parent is now root of the created tree
183 // make root name first compatible entry (purely cosmetic)
184 if( (prop
= (OSData
*) parent
->getProperty( gIODTCompatibleKey
))) {
185 parent
->setName( parent
->getName(), gIODTPlane
);
186 parent
->setName( (const char *) prop
->getBytesNoCopy() );
189 // attach tree to meta root
190 parent
->attachToParent( IORegistryEntry::getRegistryRoot(), gIODTPlane
);
194 // free original device tree
196 IODTFreeLoaderInfo( "DeviceTree",
197 (void *)dtMap
[0], (int) round_page(dtMap
[1]) );
202 gIODTSharedInterrupts
= OSDictionary::withCapacity(4);
203 allInts
= OSDictionary::withCapacity(4);
205 regIter
= IORegistryIterator::iterateOver( gIODTPlane
,
206 kIORegistryIterateRecursively
);
207 assert( regIter
&& allInts
&& gIODTSharedInterrupts
);
208 if( regIter
&& allInts
&& gIODTSharedInterrupts
) {
209 while( (child
= regIter
->getNextObject())) {
210 IODTMapInterruptsSharing( child
, allInts
);
211 if( !intMap
&& child
->getProperty( gIODTInterruptParentKey
))
219 parent
->setProperty("allInts", allInts
);
220 parent
->setProperty("sharedInts", gIODTSharedInterrupts
);
222 regIter
= IORegistryIterator::iterateOver( gIODTPlane
,
223 kIORegistryIterateRecursively
);
225 while( (child
= regIter
->getNextObject())) {
227 array
= OSDynamicCast(OSArray
, child
->getProperty( gIOInterruptSpecifiersKey
));
228 for( UInt32 i
= 0; array
&& (i
< array
->getCount()); i
++)
230 IOOptionBits options
;
231 IOReturn ret
= IODTGetInterruptOptions( child
, i
, &options
);
232 if( (ret
!= kIOReturnSuccess
) || options
)
233 IOLog("%s[%ld] %ld (%x)\n", child
->getName(), i
, options
, ret
);
243 // set a key in the root to indicate we found NW interrupt mapping
244 parent
->setProperty( gIODTNWInterruptMappingKey
,
245 (OSObject
*) gIODTNWInterruptMappingKey
);
250 int IODTGetLoaderInfo( const char *key
, void **infoAddr
, int *infoSize
)
252 IORegistryEntry
*chosen
;
254 unsigned int *propPtr
;
255 unsigned int propSize
;
257 chosen
= IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane
);
258 if ( chosen
== 0 ) return -1;
260 propObj
= OSDynamicCast( OSData
, chosen
->getProperty(key
) );
261 if ( propObj
== 0 ) return -1;
263 propSize
= propObj
->getLength();
264 if ( propSize
!= (2 * sizeof(UInt32
)) ) return -1;
266 propPtr
= (unsigned int *)propObj
->getBytesNoCopy();
267 if ( propPtr
== 0 ) return -1;
269 *infoAddr
= (void *)(uintptr_t) (propPtr
[0]);
270 *infoSize
= (int) (propPtr
[1]);
275 void IODTFreeLoaderInfo( const char *key
, void *infoAddr
, int infoSize
)
277 vm_offset_t range
[2];
278 IORegistryEntry
*chosen
;
280 range
[0] = (vm_offset_t
)infoAddr
;
281 range
[1] = (vm_offset_t
)infoSize
;
282 FreePhysicalMemory( range
);
285 chosen
= IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane
);
287 chosen
->removeProperty(key
);
292 int IODTGetDefault(const char *key
, void *infoAddr
, unsigned int infoSize
)
294 IORegistryEntry
*defaults
;
296 unsigned int defaultSize
;
298 defaults
= IORegistryEntry::fromPath( "/defaults", gIODTPlane
);
299 if ( defaults
== 0 ) return -1;
301 defaultObj
= OSDynamicCast( OSData
, defaults
->getProperty(key
) );
302 if ( defaultObj
== 0 ) return -1;
304 defaultSize
= defaultObj
->getLength();
305 if ( defaultSize
> infoSize
) return -1;
307 memcpy( infoAddr
, defaultObj
->getBytesNoCopy(), defaultSize
);
312 static void FreePhysicalMemory( vm_offset_t
* range
)
316 virt
= ml_static_ptovirt( range
[0] );
318 ml_static_mfree( virt
, range
[1] );
322 static IORegistryEntry
*
323 MakeReferenceTable( DTEntry dtEntry
, bool copy
)
325 IORegistryEntry
*regEntry
;
326 OSDictionary
*propTable
;
327 const OSSymbol
*nameKey
;
330 DTPropertyIterator dtIter
;
332 unsigned int propSize
;
335 bool noLocation
= true;
337 regEntry
= new IOService
;
339 if( regEntry
&& (false == regEntry
->init())) {
345 (kSuccess
== DTCreatePropertyIterator( dtEntry
, &dtIter
))) {
347 propTable
= regEntry
->getPropertyTable();
349 while( kSuccess
== DTIterateProperties( dtIter
, &name
)) {
351 if( kSuccess
!= DTGetProperty( dtEntry
, name
, &prop
, &propSize
))
355 nameKey
= OSSymbol::withCString(name
);
356 data
= OSData::withBytes(prop
, propSize
);
358 nameKey
= OSSymbol::withCStringNoCopy(name
);
359 data
= OSData::withBytesNoCopy(prop
, propSize
);
361 assert( nameKey
&& data
);
363 propTable
->setObject( nameKey
, data
);
367 if( nameKey
== gIODTNameKey
) {
369 sym
= OSSymbol::withCString( (const char *) prop
);
371 sym
= OSSymbol::withCStringNoCopy( (const char *) prop
);
372 regEntry
->setName( sym
);
375 } else if( nameKey
== gIODTUnitKey
) {
376 // all OF strings are null terminated... except this one
377 if( propSize
>= (int) sizeof(location
))
378 propSize
= sizeof(location
) - 1;
379 strncpy( location
, (const char *) prop
, propSize
);
380 location
[ propSize
] = 0;
381 regEntry
->setLocation( location
);
382 propTable
->removeObject( gIODTUnitKey
);
385 } else if(noLocation
&& (!strncmp(name
, "reg", sizeof("reg")))) {
386 // default location - override later
387 snprintf(location
, sizeof(location
), "%X", *((uint32_t *) prop
));
388 regEntry
->setLocation( location
);
391 DTDisposePropertyIterator( dtIter
);
397 static void AddPHandle( IORegistryEntry
* regEntry
)
401 if( regEntry
->getProperty( gIODTInterruptCellKey
)
402 && (data
= OSDynamicCast( OSData
, regEntry
->getProperty( gIODTPHandleKey
)))) {
403 // a possible interrupt-parent
404 gIODTPHandles
->setObject( data
);
405 gIODTPHandleMap
->setObject( regEntry
);
409 static IORegistryEntry
* FindPHandle( UInt32 phandle
)
412 IORegistryEntry
*regEntry
= 0;
415 for( i
= 0; (data
= (OSData
*)gIODTPHandles
->getObject( i
)); i
++ ) {
416 if( phandle
== *((UInt32
*)data
->getBytesNoCopy())) {
417 regEntry
= (IORegistryEntry
*)
418 gIODTPHandleMap
->getObject( i
);
426 static bool GetUInt32( IORegistryEntry
* regEntry
, const OSSymbol
* name
,
431 if( (data
= OSDynamicCast( OSData
, regEntry
->getProperty( name
)))
432 && (4 == data
->getLength())) {
433 *value
= *((UInt32
*) data
->getBytesNoCopy());
439 static IORegistryEntry
* IODTFindInterruptParent( IORegistryEntry
* regEntry
, IOItemCount index
)
441 IORegistryEntry
* parent
;
446 if( (data
= OSDynamicCast( OSData
, regEntry
->getProperty( gIODTInterruptParentKey
)))
447 && (sizeof(UInt32
) <= (len
= data
->getLength()))) {
448 if (((index
+ 1) * sizeof(UInt32
)) > len
)
450 phandle
= ((UInt32
*) data
->getBytesNoCopy())[index
];
451 parent
= FindPHandle( phandle
);
453 } else if( 0 == regEntry
->getProperty( "interrupt-controller"))
454 parent
= regEntry
->getParentEntry( gIODTPlane
);
461 const OSSymbol
* IODTInterruptControllerName( IORegistryEntry
* regEntry
)
468 ok
= GetUInt32( regEntry
, gIODTPHandleKey
, &phandle
);
472 snprintf(buf
, sizeof(buf
), "IOInterruptController%08X", (uint32_t)phandle
);
473 sym
= OSSymbol::withCString( buf
);
480 #define unexpected(a) { kprintf("unexpected %s:%d\n", __FILE__, __LINE__); a; }
482 static void IODTGetICellCounts( IORegistryEntry
* regEntry
,
483 UInt32
* iCellCount
, UInt32
* aCellCount
)
485 if( !GetUInt32( regEntry
, gIODTInterruptCellKey
, iCellCount
))
486 unexpected( *iCellCount
= 1 );
487 if( !GetUInt32( regEntry
, gIODTAddressCellKey
, aCellCount
))
491 static UInt32
IODTMapOneInterrupt( IORegistryEntry
* regEntry
, UInt32
* intSpec
, UInt32 index
,
492 OSData
** spec
, const OSSymbol
** controller
)
494 IORegistryEntry
*parent
= 0;
500 UInt32 acells
, icells
, pacells
, picells
, cell
;
501 UInt32 i
, original_icells
;
502 bool cmp
, ok
= false;
504 parent
= IODTFindInterruptParent( regEntry
, index
);
505 IODTGetICellCounts( parent
, &icells
, &acells
);
508 data
= OSDynamicCast( OSData
, regEntry
->getProperty( "reg" ));
509 if( data
&& (data
->getLength() >= (acells
* sizeof(UInt32
))))
510 addrCmp
= (UInt32
*) data
->getBytesNoCopy();
512 original_icells
= icells
;
517 kprintf ("IODTMapOneInterrupt: current regEntry name %s\n", regEntry
->getName());
518 kprintf ("acells - icells: ");
519 for (i
= 0; i
< acells
; i
++) kprintf ("0x%08X ", addrCmp
[i
]);
521 for (i
= 0; i
< icells
; i
++) kprintf ("0x%08X ", intSpec
[i
]);
525 if( parent
&& (data
= OSDynamicCast( OSData
,
526 regEntry
->getProperty( "interrupt-controller")))) {
527 // found a controller - don't want to follow cascaded controllers
529 *spec
= OSData::withBytesNoCopy( (void *) intSpec
,
530 icells
* sizeof(UInt32
));
531 *controller
= IODTInterruptControllerName( regEntry
);
532 ok
= (*spec
&& *controller
);
533 } else if( parent
&& (data
= OSDynamicCast( OSData
,
534 regEntry
->getProperty( "interrupt-map")))) {
536 map
= (UInt32
*) data
->getBytesNoCopy();
537 endMap
= map
+ (data
->getLength() / sizeof(UInt32
));
538 data
= OSDynamicCast( OSData
, regEntry
->getProperty( "interrupt-map-mask" ));
539 if( data
&& (data
->getLength() >= ((acells
+ icells
) * sizeof(UInt32
))))
540 maskCmp
= (UInt32
*) data
->getBytesNoCopy();
546 kprintf (" maskCmp: ");
547 for (i
= 0; i
< acells
+ icells
; i
++) {
550 kprintf ("0x%08X ", maskCmp
[i
]);
553 kprintf (" masked: ");
554 for (i
= 0; i
< acells
+ icells
; i
++) {
557 kprintf ("0x%08X ", ((i
< acells
) ? addrCmp
[i
] : intSpec
[i
-acells
]) & maskCmp
[i
]);
561 kprintf ("no maskCmp\n");
566 for (i
= 0; i
< acells
+ icells
; i
++) {
569 kprintf ("0x%08X ", map
[i
]);
573 for( i
= 0, cmp
= true; cmp
&& (i
< (acells
+ icells
)); i
++) {
574 cell
= (i
< acells
) ? addrCmp
[i
] : intSpec
[ i
- acells
];
577 cmp
= (cell
== map
[i
]);
580 map
+= acells
+ icells
;
581 if( 0 == (parent
= FindPHandle( *(map
++) )))
584 IODTGetICellCounts( parent
, &picells
, &pacells
);
587 intSpec
= map
+ pacells
;
590 map
+= pacells
+ picells
;
592 } while( !cmp
&& (map
< endMap
) );
598 IODTGetICellCounts( parent
, &icells
, &acells
);
604 return( ok
? original_icells
: 0 );
607 IOReturn
IODTGetInterruptOptions( IORegistryEntry
* regEntry
, int source
, IOOptionBits
* options
)
609 OSArray
* controllers
;
610 OSArray
* specifiers
;
617 controllers
= OSDynamicCast(OSArray
, regEntry
->getProperty(gIOInterruptControllersKey
));
618 specifiers
= OSDynamicCast(OSArray
, regEntry
->getProperty(gIOInterruptSpecifiersKey
));
620 if( !controllers
|| !specifiers
)
621 return (kIOReturnNoInterrupt
);
623 shared
= (OSArray
*) gIODTSharedInterrupts
->getObject(
624 (const OSSymbol
*) controllers
->getObject(source
) );
626 return (kIOReturnSuccess
);
628 spec
= specifiers
->getObject(source
);
630 return (kIOReturnNoInterrupt
);
632 for (unsigned int i
= 0;
633 (oneSpec
= shared
->getObject(i
))
634 && (!oneSpec
->isEqualTo(spec
));
638 *options
= kIODTInterruptShared
;
640 return (kIOReturnSuccess
);
643 static bool IODTMapInterruptsSharing( IORegistryEntry
* regEntry
, OSDictionary
* allInts
)
645 IORegistryEntry
* parent
;
654 OSArray
* controllerInts
;
655 const OSSymbol
* controller
= 0;
656 OSArray
* controllers
;
660 nw
= (0 == (local
= OSDynamicCast( OSData
,
661 regEntry
->getProperty( gIODTAAPLInterruptsKey
))));
662 if( nw
&& (0 == (local
= OSDynamicCast( OSData
,
663 regEntry
->getProperty( "interrupts")))))
664 return( true ); // nothing to see here
666 if( nw
&& (parent
= regEntry
->getParentEntry( gIODTPlane
))) {
667 // check for bridges on old world
668 if( (local2
= OSDynamicCast( OSData
,
669 parent
->getProperty( gIODTAAPLInterruptsKey
)))) {
675 localBits
= (UInt32
*) local
->getBytesNoCopy();
676 localEnd
= localBits
+ (local
->getLength() / sizeof(UInt32
));
678 mapped
= OSArray::withCapacity( 1 );
679 controllers
= OSArray::withCapacity( 1 );
681 ok
= (mapped
&& controllers
);
685 skip
= IODTMapOneInterrupt( regEntry
, localBits
, index
, &map
, &controller
);
687 IOLog("%s: error mapping interrupt[%d]\n",
688 regEntry
->getName(), mapped
->getCount());
692 map
= OSData::withData( local
, mapped
->getCount() * sizeof(UInt32
),
694 controller
= gIODTDefaultInterruptController
;
695 controller
->retain();
700 mapped
->setObject( map
);
701 controllers
->setObject( controller
);
705 controllerInts
= (OSArray
*) allInts
->getObject( controller
);
708 for (unsigned int i
= 0; (oneMap
= controllerInts
->getObject(i
)); i
++)
710 if (map
->isEqualTo(oneMap
))
712 controllerInts
= (OSArray
*) gIODTSharedInterrupts
->getObject( controller
);
714 controllerInts
->setObject(map
);
717 controllerInts
= OSArray::withObjects( (const OSObject
**) &map
, 1, 4 );
720 gIODTSharedInterrupts
->setObject( controller
, controllerInts
);
721 controllerInts
->release();
728 controllerInts
->setObject(map
);
732 controllerInts
= OSArray::withObjects( (const OSObject
**) &map
, 1, 16 );
735 allInts
->setObject( controller
, controllerInts
);
736 controllerInts
->release();
742 controller
->release();
744 } while( localBits
< localEnd
);
746 ok
&= (localBits
== localEnd
);
750 ok
= regEntry
->setProperty( gIOInterruptControllersKey
, controllers
);
751 ok
&= regEntry
->setProperty( gIOInterruptSpecifiersKey
, mapped
);
755 controllers
->release();
762 bool IODTMapInterrupts( IORegistryEntry
* regEntry
)
764 return( IODTMapInterruptsSharing( regEntry
, 0 ));
771 CompareKey( OSString
* key
,
772 const IORegistryEntry
* table
, const OSSymbol
* propName
)
780 const char *lastName
;
783 const char *result
= 0;
785 if( 0 == (prop
= table
->getProperty( propName
)))
788 if( (data
= OSDynamicCast( OSData
, prop
))) {
789 names
= (const char *) data
->getBytesNoCopy();
790 lastName
= names
+ data
->getLength();
791 } else if( (string
= OSDynamicCast( OSString
, prop
))) {
792 names
= string
->getCStringNoCopy();
793 lastName
= names
+ string
->getLength() + 1;
797 ckey
= key
->getCStringNoCopy();
798 keyLen
= key
->getLength();
799 wild
= ('*' == key
->getChar( keyLen
- 1 ));
802 // for each name in the property
804 matched
= (0 == strncmp( ckey
, names
, keyLen
- 1 ));
806 matched
= (keyLen
== strlen( names
))
807 && (0 == strncmp( ckey
, names
, keyLen
));
812 names
= names
+ strlen( names
) + 1;
814 } while( (names
< lastName
) && (false == matched
));
820 bool IODTCompareNubName( const IORegistryEntry
* regEntry
,
821 OSString
* name
, OSString
** matchingName
)
826 matched
= (0 != (result
= CompareKey( name
, regEntry
, gIODTNameKey
)))
827 || (0 != (result
= CompareKey( name
, regEntry
, gIODTCompatibleKey
)))
828 || (0 != (result
= CompareKey( name
, regEntry
, gIODTTypeKey
)))
829 || (0 != (result
= CompareKey( name
, regEntry
, gIODTModelKey
)));
831 if( result
&& matchingName
)
832 *matchingName
= OSString::withCString( result
);
834 return( result
!= 0 );
837 bool IODTMatchNubWithKeys( IORegistryEntry
* regEntry
,
843 obj
= OSUnserialize( keys
, 0 );
846 result
= regEntry
->compareNames( obj
);
850 else IOLog("Couldn't unserialize %s\n", keys
);
856 OSCollectionIterator
* IODTFindMatchingEntries( IORegistryEntry
* from
,
857 IOOptionBits options
, const char * keys
)
860 IORegistryEntry
*next
;
861 IORegistryIterator
*iter
;
862 OSCollectionIterator
*cIter
;
864 bool minus
= options
& kIODTExclusive
;
867 iter
= IORegistryIterator::iterateOver( from
, gIODTPlane
,
868 (options
& kIODTRecursive
) ? kIORegistryIterateRecursively
: 0 );
875 result
= OSSet::withCapacity( 3 );
880 while( (next
= iter
->getNextObject())) {
882 // Look for existence of a debug property to skip
883 if( next
->getProperty("AAPL,ignore"))
887 cmp
= IODTMatchNubWithKeys( next
, keys
);
888 if( (minus
&& (false == cmp
))
889 || ((false == minus
) && (false != cmp
)) )
890 result
->setObject( next
);
892 result
->setObject( next
);
894 } while( !iter
->isValid());
899 cIter
= OSCollectionIterator::withCollection( result
);
906 struct IODTPersistent
{
907 IODTCompareAddressCellFunc compareFunc
;
908 IODTNVLocationFunc locationFunc
;
911 void IODTSetResolving( IORegistryEntry
* regEntry
,
912 IODTCompareAddressCellFunc compareFunc
,
913 IODTNVLocationFunc locationFunc
)
915 IODTPersistent persist
;
918 persist
.compareFunc
= compareFunc
;
919 persist
.locationFunc
= locationFunc
;
920 prop
= OSData::withBytes( &persist
, sizeof(persist
));
924 prop
->setSerializable(false);
925 regEntry
->setProperty( gIODTPersistKey
, prop
);
930 #if defined(__arm__) || defined(__i386__) || defined(__x86_64__)
931 static SInt32
DefaultCompare( UInt32 cellCount
, UInt32 left
[], UInt32 right
[] )
934 return( left
[ cellCount
] - right
[ cellCount
] );
937 #error Unknown architecture.
940 static void AddLengthToCells( UInt32 numCells
, UInt32
*cells
, UInt64 offset
)
944 cells
[0] += (UInt32
)offset
;
947 UInt64 sum
= cells
[numCells
- 1] + offset
;
948 cells
[numCells
- 1] = (UInt32
)sum
;
949 if (sum
> UINT32_MAX
) {
950 cells
[numCells
- 2] += (UInt32
)(sum
>> 32);
955 static IOPhysicalAddress
CellsValue( UInt32 numCells
, UInt32
*cells
)
958 return IOPhysical32( 0, cells
[0] );
960 return IOPhysical32( cells
[numCells
- 2], cells
[numCells
- 1] );
964 void IODTGetCellCounts( IORegistryEntry
* regEntry
,
965 UInt32
* sizeCount
, UInt32
* addressCount
)
967 if( !GetUInt32( regEntry
, gIODTSizeCellKey
, sizeCount
))
969 if( !GetUInt32( regEntry
, gIODTAddressCellKey
, addressCount
))
974 // Given addr & len cells from our child, find it in our ranges property, then
975 // look in our parent to resolve the base of the range for us.
977 // Range[]: child-addr our-addr child-len
978 // #cells: child ours child
980 bool IODTResolveAddressCell( IORegistryEntry
* regEntry
,
982 IOPhysicalAddress
* phys
, IOPhysicalLength
* lenOut
)
984 IORegistryEntry
*parent
;
986 // cells in addresses at regEntry
987 UInt32 sizeCells
, addressCells
;
988 // cells in addresses below regEntry
989 UInt32 childSizeCells
, childAddressCells
;
991 UInt32 cell
[ 8 ], propLen
;
999 SInt64 diff
, diff2
, endDiff
;
1000 UInt64 len
, rangeLen
;
1002 IODTPersistent
*persist
;
1003 IODTCompareAddressCellFunc compare
;
1005 IODTGetCellCounts( regEntry
, &childSizeCells
, &childAddressCells
);
1006 childCells
= childAddressCells
+ childSizeCells
;
1008 if (childCells
> sizeof(cell
)/sizeof(cell
[0]))
1009 panic("IODTResolveAddressCell: Invalid device tree (%u,%u)", (uint32_t)childAddressCells
, (uint32_t)childSizeCells
);
1011 bcopy( cellsIn
, cell
, sizeof(UInt32
) * childCells
);
1012 *lenOut
= CellsValue( childSizeCells
, cellsIn
+ childAddressCells
);
1016 prop
= OSDynamicCast( OSData
, regEntry
->getProperty( gIODTRangeKey
));
1018 /* end of the road */
1019 *phys
= CellsValue( childAddressCells
, cell
);
1024 parent
= regEntry
->getParentEntry( gIODTPlane
);
1025 IODTGetCellCounts( parent
, &sizeCells
, &addressCells
);
1027 if( (propLen
= prop
->getLength())) {
1029 startRange
= (UInt32
*) prop
->getBytesNoCopy();
1031 endRanges
= range
+ (propLen
/ sizeof(UInt32
));
1033 prop
= (OSData
*) regEntry
->getProperty( gIODTPersistKey
);
1035 persist
= (IODTPersistent
*) prop
->getBytesNoCopy();
1036 compare
= persist
->compareFunc
;
1037 } else if (addressCells
== childAddressCells
) {
1038 compare
= DefaultCompare
;
1040 panic("There is no mixed comparison function yet...");
1045 range
+= (childCells
+ addressCells
) ) {
1047 // is cell start within range?
1048 diff
= (*compare
)( childAddressCells
, cell
, range
);
1050 if (childAddressCells
> sizeof(endCell
)/sizeof(endCell
[0]))
1051 panic("IODTResolveAddressCell: Invalid device tree (%u)", (uint32_t)childAddressCells
);
1053 bcopy(range
, endCell
, childAddressCells
* sizeof(UInt32
));
1055 rangeLen
= CellsValue(childSizeCells
, range
+ childAddressCells
+ addressCells
);
1056 AddLengthToCells(childAddressCells
, endCell
, rangeLen
);
1058 diff2
= (*compare
)( childAddressCells
, cell
, endCell
);
1060 // if start of cell < start of range, or end of range >= start of cell, skip
1061 if ((diff
< 0) || (diff2
>= 0))
1064 len
= CellsValue(childSizeCells
, cell
+ childAddressCells
);
1069 // search for cell end
1070 bcopy(cell
, endCell
, childAddressCells
* sizeof(UInt32
));
1072 AddLengthToCells(childAddressCells
, endCell
, len
- 1);
1074 for( lookRange
= startRange
;
1075 lookRange
< endRanges
;
1076 lookRange
+= (childCells
+ addressCells
) )
1078 // make sure end of cell >= range start
1079 endDiff
= (*compare
)( childAddressCells
, endCell
, lookRange
);
1083 UInt64 rangeStart
= CellsValue(addressCells
, range
+ childAddressCells
);
1084 UInt64 lookRangeStart
= CellsValue(addressCells
, lookRange
+ childAddressCells
);
1085 if ((endDiff
- len
+ 1 + lookRangeStart
) == (diff
+ rangeStart
))
1098 if (addressCells
+ sizeCells
> sizeof(cell
)/sizeof(cell
[0]))
1099 panic("IODTResolveAddressCell: Invalid device tree (%u, %u)", (uint32_t)addressCells
, (uint32_t)sizeCells
);
1101 // Get the physical start of the range from our parent
1102 bcopy( range
+ childAddressCells
, cell
, sizeof(UInt32
) * addressCells
);
1103 bzero( cell
+ addressCells
, sizeof(UInt32
) * sizeCells
);
1105 } /* else zero length range => pass thru to parent */
1108 childSizeCells
= sizeCells
;
1109 childAddressCells
= addressCells
;
1110 childCells
= childAddressCells
+ childSizeCells
;
1112 while( ok
&& regEntry
);
1118 OSArray
* IODTResolveAddressing( IORegistryEntry
* regEntry
,
1119 const char * addressPropertyName
,
1120 IODeviceMemory
* parent
)
1122 IORegistryEntry
*parentEntry
;
1123 OSData
*addressProperty
;
1124 UInt32 sizeCells
, addressCells
, cells
;
1127 IOPhysicalAddress phys
;
1128 IOPhysicalLength len
;
1130 IODeviceMemory
*range
;
1132 parentEntry
= regEntry
->getParentEntry( gIODTPlane
);
1133 addressProperty
= (OSData
*) regEntry
->getProperty( addressPropertyName
);
1134 if( (0 == addressProperty
) || (0 == parentEntry
))
1137 IODTGetCellCounts( parentEntry
, &sizeCells
, &addressCells
);
1141 cells
= sizeCells
+ addressCells
;
1142 reg
= (UInt32
*) addressProperty
->getBytesNoCopy();
1143 num
= addressProperty
->getLength() / (4 * cells
);
1145 array
= OSArray::withCapacity( 1 );
1149 for( i
= 0; i
< num
; i
++) {
1150 if( IODTResolveAddressCell( parentEntry
, reg
, &phys
, &len
)) {
1153 range
= IODeviceMemory::withSubRange( parent
,
1154 phys
- parent
->getPhysicalSegment(0, 0, kIOMemoryMapperNone
), len
);
1156 range
= IODeviceMemory::withRange( phys
, len
);
1158 array
->setObject( range
);
1163 regEntry
->setProperty( gIODeviceMemoryKey
, array
);
1164 array
->release(); /* ??? */
1169 static void IODTGetNVLocation(
1170 IORegistryEntry
* parent
,
1171 IORegistryEntry
* regEntry
,
1172 UInt8
* busNum
, UInt8
* deviceNum
, UInt8
* functionNum
)
1176 IODTPersistent
*persist
;
1179 prop
= (OSData
*) parent
->getProperty( gIODTPersistKey
);
1181 persist
= (IODTPersistent
*) prop
->getBytesNoCopy();
1182 (*persist
->locationFunc
)( regEntry
, busNum
, deviceNum
, functionNum
);
1184 prop
= (OSData
*) regEntry
->getProperty( "reg" );
1187 cell
= (UInt32
*) prop
->getBytesNoCopy();
1189 *deviceNum
= 0x1f & (cell
[ 0 ] >> 24);
1199 * Try to make the same messed up descriptor as Mac OS
1202 IOReturn
IODTMakeNVDescriptor( IORegistryEntry
* regEntry
,
1203 IONVRAMDescriptor
* hdr
)
1205 IORegistryEntry
*parent
;
1207 UInt32 bridgeDevices
;
1215 for(level
= 0, bridgeDevices
= 0;
1216 (parent
= regEntry
->getParentEntry( gIODTPlane
)) && (level
< 7); level
++ ) {
1218 IODTGetNVLocation( parent
, regEntry
,
1219 &busNum
, &deviceNum
, &functionNum
);
1221 bridgeDevices
|= ((deviceNum
& 0x1f) << ((level
- 1) * 5));
1223 hdr
->busNum
= busNum
;
1224 hdr
->deviceNum
= deviceNum
;
1225 hdr
->functionNum
= functionNum
;
1229 hdr
->bridgeCount
= level
- 2;
1230 hdr
->bridgeDevices
= bridgeDevices
;
1232 return( kIOReturnSuccess
);
1235 OSData
* IODTFindSlotName( IORegistryEntry
* regEntry
, UInt32 deviceNumber
)
1237 IORegistryEntry
*parent
;
1246 data
= (OSData
*) regEntry
->getProperty("AAPL,slot-name");
1249 parent
= regEntry
->getParentEntry( gIODTPlane
);
1252 data
= OSDynamicCast( OSData
, parent
->getProperty("slot-names"));
1255 if( data
->getLength() <= 4)
1258 bits
= (UInt32
*) data
->getBytesNoCopy();
1260 if( (0 == (mask
& (1 << deviceNumber
))))
1263 names
= (char *)(bits
+ 1);
1264 lastName
= names
+ (data
->getLength() - 4);
1266 for( i
= 0; (i
<= deviceNumber
) && (names
< lastName
); i
++ ) {
1268 if( mask
& (1 << i
)) {
1269 if( i
== deviceNumber
) {
1270 data
= OSData::withBytesNoCopy( names
, 1 + strlen( names
));
1272 regEntry
->setProperty("AAPL,slot-name", data
);
1277 names
+= 1 + strlen( names
);
1284 extern "C" IOReturn
IONDRVLibrariesInitialize( IOService
* provider
)
1286 return( kIOReturnUnsupported
);