]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IODeviceTreeSupport.cpp
xnu-201.42.3.tar.gz
[apple/xnu.git] / iokit / Kernel / IODeviceTreeSupport.cpp
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * Copyright (c) 1998 Apple Computer, Inc. All rights reserved.
24 *
25 * HISTORY
26 * 23 Nov 98 sdouglas, created from IODeviceTreeBus.m, & MacOS exp mgr.
27 * 05 Apr 99 sdouglas, add interrupt mapping.
28 *
29 */
30
31#include <IOKit/IODeviceTreeSupport.h>
32#include <libkern/c++/OSContainers.h>
33#include <IOKit/IODeviceMemory.h>
34#include <IOKit/IOService.h>
35#include <IOKit/IOCatalogue.h>
36
37#include <IOKit/IOLib.h>
38#include <IOKit/IOKitKeys.h>
39
40#include <DeviceTree.h>
41extern "C" {
0b4e3aa0
A
42 #include <machine/machine_routines.h>
43 void DTInit( void * data );
1c79356b 44
0b4e3aa0
A
45 int IODTGetLoaderInfo( char *key, void **infoAddr, int *infosize );
46 void IODTFreeLoaderInfo( char *key, void *infoAddr, int infoSize );
1c79356b
A
47}
48
49#include <IOKit/assert.h>
50
0b4e3aa0 51#define IODTSUPPORTDEBUG 0
1c79356b
A
52
53const IORegistryPlane * gIODTPlane;
54
55static OSArray * gIODTPHandles;
56static OSArray * gIODTPHandleMap;
57
58const OSSymbol * gIODTNameKey;
59const OSSymbol * gIODTUnitKey;
60const OSSymbol * gIODTCompatibleKey;
61const OSSymbol * gIODTTypeKey;
62const OSSymbol * gIODTModelKey;
63
64const OSSymbol * gIODTSizeCellKey;
65const OSSymbol * gIODTAddressCellKey;
66const OSSymbol * gIODTRangeKey;
67
68const OSSymbol * gIODTPersistKey;
69
70const OSSymbol * gIODTDefaultInterruptController;
71const OSSymbol * gIODTAAPLInterruptsKey;
72const OSSymbol * gIODTPHandleKey;
73const OSSymbol * gIODTInterruptCellKey;
74const OSSymbol * gIODTInterruptParentKey;
75const OSSymbol * gIODTNWInterruptMappingKey;
76
77
78static IORegistryEntry * MakeReferenceTable( DTEntry dtEntry, bool copy );
79static void AddPHandle( IORegistryEntry * regEntry );
80static void FreePhysicalMemory( vm_offset_t * range );
81
82IORegistryEntry *
83IODeviceTreeAlloc( void * dtTop )
84{
0b4e3aa0
A
85 IORegistryEntry *parent;
86 IORegistryEntry *child;
87 IORegistryIterator *regIter;
88 DTEntryIterator iter;
89 DTEntry dtChild;
90 DTEntry mapEntry;
91 OSArray *stack;
92 OSData *prop;
93 OSObject *obj;
94 vm_offset_t *dtMap;
95 int propSize;
96 bool intMap;
97 bool freeDT;
1c79356b
A
98
99 IOLog("IODeviceTreeSupport ");
100
101 gIODTPlane = IORegistryEntry::makePlane( kIODeviceTreePlane );
102
0b4e3aa0
A
103 gIODTNameKey = OSSymbol::withCStringNoCopy( "name" );
104 gIODTUnitKey = OSSymbol::withCStringNoCopy( "AAPL,unit-string" );
1c79356b 105 gIODTCompatibleKey = OSSymbol::withCStringNoCopy( "compatible" );
0b4e3aa0
A
106 gIODTTypeKey = OSSymbol::withCStringNoCopy( "device_type" );
107 gIODTModelKey = OSSymbol::withCStringNoCopy( "model" );
1c79356b
A
108 gIODTSizeCellKey = OSSymbol::withCStringNoCopy( "#size-cells" );
109 gIODTAddressCellKey = OSSymbol::withCStringNoCopy( "#address-cells" );
0b4e3aa0
A
110 gIODTRangeKey = OSSymbol::withCStringNoCopy( "ranges" );
111 gIODTPersistKey = OSSymbol::withCStringNoCopy( "IODTPersist" );
1c79356b
A
112
113 assert( gIODTPlane && gIODTCompatibleKey
114 && gIODTTypeKey && gIODTModelKey
115 && gIODTSizeCellKey && gIODTAddressCellKey && gIODTRangeKey
116 && gIODTPersistKey );
117
118 gIODTDefaultInterruptController
0b4e3aa0 119 = OSSymbol::withCStringNoCopy("IOPrimaryInterruptController");
1c79356b 120 gIODTNWInterruptMappingKey
0b4e3aa0 121 = OSSymbol::withCStringNoCopy("IONWInterrupts");
1c79356b
A
122
123 gIODTAAPLInterruptsKey
0b4e3aa0 124 = OSSymbol::withCStringNoCopy("AAPL,interrupts");
1c79356b 125 gIODTPHandleKey
0b4e3aa0 126 = OSSymbol::withCStringNoCopy("AAPL,phandle");
1c79356b
A
127
128 gIODTInterruptParentKey
0b4e3aa0 129 = OSSymbol::withCStringNoCopy("interrupt-parent");
1c79356b
A
130
131 gIODTPHandles = OSArray::withCapacity( 1 );
132 gIODTPHandleMap = OSArray::withCapacity( 1 );
133
134 gIODTInterruptCellKey
0b4e3aa0 135 = OSSymbol::withCStringNoCopy("#interrupt-cells");
1c79356b
A
136
137 assert( gIODTDefaultInterruptController && gIODTNWInterruptMappingKey
138 && gIODTAAPLInterruptsKey
139 && gIODTPHandleKey && gIODTInterruptParentKey
140 && gIODTPHandles && gIODTPHandleMap
141 && gIODTInterruptCellKey
142 );
143
144 freeDT = (kSuccess == DTLookupEntry( 0, "/chosen/memory-map", &mapEntry ))
145 && (kSuccess == DTGetProperty( mapEntry,
146 "DeviceTree", (void **) &dtMap, &propSize ))
147 && ((2 * sizeof( vm_offset_t)) == propSize);
148
149 parent = MakeReferenceTable( (DTEntry)dtTop, freeDT );
150
151 stack = OSArray::withObjects( & (const OSObject *) parent, 1, 10 );
152 DTCreateEntryIterator( (DTEntry)dtTop, &iter );
153
154 do {
155 parent = (IORegistryEntry *)stack->getObject( stack->getCount() - 1);
0b4e3aa0 156 //parent->release();
1c79356b
A
157 stack->removeObject( stack->getCount() - 1);
158
159 while( kSuccess == DTIterateEntries( iter, &dtChild) ) {
160
161 child = MakeReferenceTable( dtChild, freeDT );
162 child->attachToParent( parent, gIODTPlane);
163
0b4e3aa0 164 AddPHandle( child );
1c79356b
A
165
166 if( kSuccess == DTEnterEntry( iter, dtChild)) {
167 stack->setObject( parent);
168 parent = child;
169 }
0b4e3aa0
A
170 // only registry holds retain
171 child->release();
1c79356b
A
172 }
173
174 } while( stack->getCount()
0b4e3aa0 175 && (kSuccess == DTExitEntry( iter, &dtChild)));
1c79356b
A
176
177 stack->release();
178 DTDisposeEntryIterator( iter);
179
180 // parent is now root of the created tree
181
182 // make root name first compatible entry (purely cosmetic)
183 if( (prop = (OSData *) parent->getProperty( gIODTCompatibleKey))) {
0b4e3aa0
A
184 parent->setName( parent->getName(), gIODTPlane );
185 parent->setName( (const char *) prop->getBytesNoCopy() );
1c79356b
A
186 }
187
188 // attach tree to meta root
189 parent->attachToParent( IORegistryEntry::getRegistryRoot(), gIODTPlane);
190 parent->release();
191
192 if( freeDT ) {
0b4e3aa0 193 // free original device tree
1c79356b
A
194 DTInit(0);
195 IODTFreeLoaderInfo( "DeviceTree",
0b4e3aa0 196 (void *)dtMap[0], round_page(dtMap[1]) );
1c79356b
A
197 }
198
199 // adjust tree
200 intMap = false;
201 regIter = IORegistryIterator::iterateOver( gIODTPlane,
202 kIORegistryIterateRecursively );
203 assert( regIter );
204 if( regIter) {
0b4e3aa0
A
205 while( (child = regIter->getNextObject())) {
206 IODTMapInterrupts( child );
207 if( !intMap && child->getProperty( gIODTInterruptParentKey))
208 intMap = true;
209
210 // Look for a "driver,AAPL,MacOSX,PowerPC" property.
211 if( (obj = child->getProperty( "driver,AAPL,MacOSX,PowerPC"))) {
212 gIOCatalogue->addExtensionsFromArchive((OSData *)obj);
213
214 child->removeProperty( "driver,AAPL,MacOSX,PowerPC");
215 }
216
217 // some gross pruning
218 child->removeProperty( "lanLib,AAPL,MacOS,PowerPC");
219
220 if( (obj = child->getProperty( "driver,AAPL,MacOS,PowerPC"))) {
221
222 if( (0 == (prop = (OSData *)child->getProperty( gIODTTypeKey )))
223 || (strcmp( "display", (char *) prop->getBytesNoCopy())) ) {
224 child->removeProperty( "driver,AAPL,MacOS,PowerPC");
225 }
226 }
1c79356b 227 }
0b4e3aa0 228 regIter->release();
1c79356b
A
229 }
230
231 if( intMap)
0b4e3aa0
A
232 // set a key in the root to indicate we found NW interrupt mapping
233 parent->setProperty( gIODTNWInterruptMappingKey,
234 (OSObject *) gIODTNWInterruptMappingKey );
1c79356b
A
235
236 IOLog("done\n");
237
238 return( parent);
239}
240
241int IODTGetLoaderInfo( char *key, void **infoAddr, int *infoSize )
242{
243 IORegistryEntry *chosen;
0b4e3aa0 244 OSData *propObj;
1c79356b
A
245 unsigned int *propPtr;
246 unsigned int propSize;
247
248 chosen = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane );
249 if ( chosen == 0 ) return -1;
250
251 propObj = OSDynamicCast( OSData, chosen->getProperty(key) );
252 if ( propObj == 0 ) return -1;
253
254 propSize = propObj->getLength();
255 if ( propSize != (2 * sizeof(UInt32)) ) return -1;
256
257 propPtr = (unsigned int *)propObj->getBytesNoCopy();
258 if ( propPtr == 0 ) return -1;
259
260 *infoAddr = (void *)propPtr[0] ;
261 *infoSize = (int) propPtr[1];
262
263 return 0;
264}
265
266void IODTFreeLoaderInfo( char *key, void *infoAddr, int infoSize )
267{
268 vm_offset_t range[2];
269 IORegistryEntry *chosen;
270
271 range[0] = (vm_offset_t)infoAddr;
272 range[1] = (vm_offset_t)infoSize;
273 FreePhysicalMemory( range );
274
275 if ( key != 0 ) {
276 chosen = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane );
277 if ( chosen != 0 ) {
278 chosen->removeProperty(key);
279 }
280 }
281}
282
283static void FreePhysicalMemory( vm_offset_t * range )
284{
285 vm_offset_t virt;
286
287 virt = ml_static_ptovirt( range[0] );
288 if( virt) {
289 ml_static_mfree( virt, range[1] );
290 }
291}
292
293static IORegistryEntry *
294MakeReferenceTable( DTEntry dtEntry, bool copy )
295{
0b4e3aa0
A
296 IORegistryEntry *regEntry;
297 OSDictionary *propTable;
298 const OSSymbol *nameKey;
299 OSData *data;
300 const OSSymbol *sym;
1c79356b 301 DTPropertyIterator dtIter;
0b4e3aa0
A
302 void *prop;
303 int propSize;
304 char *name;
305 char location[ 32 ];
306 bool noLocation = true;
1c79356b
A
307
308 regEntry = new IOService;
309
310 if( regEntry && (false == regEntry->init())) {
0b4e3aa0
A
311 regEntry->release();
312 regEntry = 0;
1c79356b
A
313 }
314
315 if( regEntry &&
0b4e3aa0 316 (kSuccess == DTCreatePropertyIterator( dtEntry, &dtIter))) {
1c79356b
A
317
318 propTable = regEntry->getPropertyTable();
319
0b4e3aa0
A
320 while( kSuccess == DTIterateProperties( dtIter, &name)) {
321
322 if( kSuccess != DTGetProperty( dtEntry, name, &prop, &propSize ))
323 continue;
324
325 if( copy) {
326 nameKey = OSSymbol::withCString(name);
327 data = OSData::withBytes(prop, propSize);
328 } else {
329 nameKey = OSSymbol::withCStringNoCopy(name);
330 data = OSData::withBytesNoCopy(prop, propSize);
331 }
332 assert( nameKey && data );
333
334 propTable->setObject( nameKey, data);
335 data->release();
336 nameKey->release();
337
338 if( nameKey == gIODTNameKey ) {
339 if( copy)
340 sym = OSSymbol::withCString( (const char *) prop);
341 else
342 sym = OSSymbol::withCStringNoCopy( (const char *) prop);
343 regEntry->setName( sym );
344 sym->release();
345 } else if( nameKey == gIODTUnitKey ) {
346 // all OF strings are null terminated... except this one
347 if( propSize >= (int) sizeof( location))
348 propSize = sizeof( location) - 1;
349 strncpy( location, (const char *) prop, propSize );
350 location[ propSize ] = 0;
351 regEntry->setLocation( location );
352 propTable->removeObject( gIODTUnitKey );
353 noLocation = false;
354
355 } else if( noLocation && (0 == strcmp( name, "reg"))) {
356 // default location - override later
357 sprintf( location, "%lX", *((UInt32 *) prop) );
358 regEntry->setLocation( location );
359 }
360 }
361 DTDisposePropertyIterator( dtIter);
1c79356b
A
362 }
363
364 return( regEntry);
365}
366
367static void AddPHandle( IORegistryEntry * regEntry )
368{
369 OSData * data;
370
371 if( regEntry->getProperty( gIODTInterruptCellKey)
0b4e3aa0
A
372 && (data = OSDynamicCast( OSData, regEntry->getProperty( gIODTPHandleKey )))) {
373 // a possible interrupt-parent
374 gIODTPHandles->setObject( data );
375 gIODTPHandleMap->setObject( regEntry );
1c79356b
A
376 }
377}
378
379static IORegistryEntry * FindPHandle( UInt32 phandle )
380{
0b4e3aa0
A
381 OSData *data;
382 IORegistryEntry *regEntry = 0;
383 int i;
384
385 for( i = 0; (data = (OSData *)gIODTPHandles->getObject( i )); i++ ) {
386 if( phandle == *((UInt32 *)data->getBytesNoCopy())) {
387 regEntry = (IORegistryEntry *)
388 gIODTPHandleMap->getObject( i );
389 break;
1c79356b
A
390 }
391 }
392
393 return( regEntry );
394}
395
396static bool GetUInt32( IORegistryEntry * regEntry, const OSSymbol * name,
397 UInt32 * value )
398{
0b4e3aa0 399 OSData *data;
1c79356b
A
400
401 if( (data = OSDynamicCast( OSData, regEntry->getProperty( name )))
0b4e3aa0 402 && (4 == data->getLength())) {
1c79356b 403 *value = *((UInt32 *) data->getBytesNoCopy());
0b4e3aa0 404 return( true );
1c79356b 405 } else
0b4e3aa0 406 return( false );
1c79356b
A
407}
408
409IORegistryEntry * IODTFindInterruptParent( IORegistryEntry * regEntry )
410{
411 IORegistryEntry * parent;
412 UInt32 phandle;
413
414 if( GetUInt32( regEntry, gIODTInterruptParentKey, &phandle))
0b4e3aa0 415 parent = FindPHandle( phandle );
1c79356b
A
416
417 else if( 0 == regEntry->getProperty( "interrupt-controller"))
0b4e3aa0 418 parent = regEntry->getParentEntry( gIODTPlane);
1c79356b 419 else
0b4e3aa0 420 parent = 0;
1c79356b
A
421
422 return( parent );
423}
424
425const OSSymbol * IODTInterruptControllerName( IORegistryEntry * regEntry )
426{
0b4e3aa0
A
427 const OSSymbol *sym;
428 UInt32 phandle;
429 bool ok;
430 char buf[48];
1c79356b
A
431
432 ok = GetUInt32( regEntry, gIODTPHandleKey, &phandle);
433 assert( ok );
434
435 if( ok) {
436 sprintf( buf, "IOInterruptController%08lX", phandle);
437 sym = OSSymbol::withCString( buf );
438 } else
0b4e3aa0 439 sym = 0;
1c79356b
A
440
441 return( sym );
442}
443
444#define unexpected(a) { kprintf("unexpected %s:%d\n", __FILE__, __LINE__); a; }
445
446static void IODTGetICellCounts( IORegistryEntry * regEntry,
447 UInt32 * iCellCount, UInt32 * aCellCount)
448{
449 if( !GetUInt32( regEntry, gIODTInterruptCellKey, iCellCount))
450 unexpected( *iCellCount = 1 );
451 if( !GetUInt32( regEntry, gIODTAddressCellKey, aCellCount))
452 *aCellCount = 0;
453}
454
455UInt32 IODTMapOneInterrupt( IORegistryEntry * regEntry, UInt32 * intSpec,
456 OSData ** spec, const OSSymbol ** controller )
457{
0b4e3aa0
A
458 IORegistryEntry *parent = 0;
459 OSData *data;
460 UInt32 *addrCmp;
461 UInt32 *maskCmp;
462 UInt32 *map;
463 UInt32 *endMap;
464 UInt32 acells, icells, pacells, picells, cell;
465 UInt32 i, original_icells;
466 bool cmp, ok = false;
467
468
469 parent = IODTFindInterruptParent( regEntry );
470 IODTGetICellCounts( parent, &icells, &acells );
471 addrCmp = 0;
472 if( acells) {
473 data = OSDynamicCast( OSData, regEntry->getProperty( "reg" ));
474 if( data && (data->getLength() >= (acells * sizeof( UInt32))))
475 addrCmp = (UInt32 *) data->getBytesNoCopy();
476 }
477 original_icells = icells;
478 regEntry = parent;
479
480 do {
481#if IODTSUPPORTDEBUG
482 kprintf ("IODTMapOneInterrupt: current regEntry name %s\n", regEntry->getName());
483 kprintf ("acells - icells: ");
484 for (i = 0; i < acells; i++) kprintf ("0x%08X ", addrCmp[i]);
485 kprintf ("- ");
486 for (i = 0; i < icells; i++) kprintf ("0x%08X ", intSpec[i]);
487 kprintf ("\n");
488#endif
1c79356b 489
0b4e3aa0
A
490 if( parent && (data = OSDynamicCast( OSData,
491 regEntry->getProperty( "interrupt-controller")))) {
492 // found a controller - don't want to follow cascaded controllers
1c79356b
A
493 parent = 0;
494 *spec = OSData::withBytesNoCopy( (void *) intSpec,
495 icells * sizeof( UInt32));
496 *controller = IODTInterruptControllerName( regEntry );
0b4e3aa0
A
497 ok = (*spec && *controller);
498 } else if( parent && (data = OSDynamicCast( OSData,
499 regEntry->getProperty( "interrupt-map")))) {
1c79356b
A
500 // interrupt-map
501 map = (UInt32 *) data->getBytesNoCopy();
502 endMap = map + (data->getLength() / sizeof(UInt32));
503 data = OSDynamicCast( OSData, regEntry->getProperty( "interrupt-map-mask" ));
504 if( data && (data->getLength() >= ((acells + icells) * sizeof( UInt32))))
505 maskCmp = (UInt32 *) data->getBytesNoCopy();
0b4e3aa0
A
506 else
507 maskCmp = 0;
508
509#if IODTSUPPORTDEBUG
510 if (maskCmp) {
511 kprintf (" maskCmp: ");
512 for (i = 0; i < acells + icells; i++) {
513 if (i == acells)
514 kprintf ("- ");
515 kprintf ("0x%08X ", maskCmp[i]);
516 }
517 kprintf ("\n");
518 kprintf (" masked: ");
519 for (i = 0; i < acells + icells; i++) {
520 if (i == acells)
521 kprintf ("- ");
522 kprintf ("0x%08X ", ((i < acells) ? addrCmp[i] : intSpec[i-acells]) & maskCmp[i]);
523 }
524 kprintf ("\n");
525 } else
526 kprintf ("no maskCmp\n");
527#endif
528 do {
529#if IODTSUPPORTDEBUG
530 kprintf (" map: ");
531 for (i = 0; i < acells + icells; i++) {
532 if (i == acells)
533 kprintf ("- ");
534 kprintf ("0x%08X ", map[i]);
535 }
536 kprintf ("\n");
537#endif
538 for( i = 0, cmp = true; cmp && (i < (acells + icells)); i++) {
1c79356b
A
539 cell = (i < acells) ? addrCmp[i] : intSpec[ i - acells ];
540 if( maskCmp)
541 cell &= maskCmp[i];
542 cmp = (cell == map[i]);
543 }
544
545 map += acells + icells;
546 if( 0 == (parent = FindPHandle( *(map++) )))
547 unexpected(break);
548
0b4e3aa0
A
549 IODTGetICellCounts( parent, &picells, &pacells );
550 if( cmp) {
551 addrCmp = map;
552 intSpec = map + pacells;
553 regEntry = parent;
554 } else {
1c79356b 555 map += pacells + picells;
0b4e3aa0 556 }
1c79356b 557 } while( !cmp && (map < endMap) );
0b4e3aa0
A
558 if (!cmp)
559 parent = 0;
560 }
1c79356b 561
0b4e3aa0 562 if( parent) {
1c79356b 563 IODTGetICellCounts( parent, &icells, &acells );
0b4e3aa0
A
564 regEntry = parent;
565 }
566 } while( parent);
567
568 return( ok ? original_icells : 0 );
1c79356b
A
569}
570
571bool IODTMapInterrupts( IORegistryEntry * regEntry )
572{
0b4e3aa0
A
573 IORegistryEntry *parent;
574 OSData *local;
575 OSData *local2;
576 UInt32 *localBits;
577 UInt32 *localEnd;
578 OSData *map;
579 OSArray *mapped;
580 const OSSymbol *controller;
581 OSArray *controllers;
582 UInt32 skip = 1;
583 bool ok, nw;
1c79356b
A
584
585 nw = (0 == (local = OSDynamicCast( OSData,
0b4e3aa0
A
586 regEntry->getProperty( gIODTAAPLInterruptsKey))));
587 if( nw && (0 == (local = OSDynamicCast( OSData,
588 regEntry->getProperty( "interrupts")))))
589 return( true ); // nothing to see here
1c79356b
A
590
591 if( nw && (parent = regEntry->getParentEntry( gIODTPlane))) {
0b4e3aa0
A
592 // check for bridges on old world
593 if( (local2 = OSDynamicCast( OSData,
594 parent->getProperty( gIODTAAPLInterruptsKey)))) {
595 local = local2;
596 nw = false;
597 }
1c79356b
A
598 }
599
600 localBits = (UInt32 *) local->getBytesNoCopy();
601 localEnd = localBits + (local->getLength() / sizeof( UInt32));
602 mapped = OSArray::withCapacity( 1 );
603 controllers = OSArray::withCapacity( 1 );
604
605 ok = (mapped && controllers);
606
607 if( ok) do {
608 if( nw) {
609 skip = IODTMapOneInterrupt( regEntry, localBits, &map, &controller );
610 if( 0 == skip) {
611 IOLog("%s: error mapping interrupt[%d]\n",
0b4e3aa0 612 regEntry->getName(), mapped->getCount());
1c79356b
A
613 break;
614 }
615 } else {
616 map = OSData::withData( local, mapped->getCount() * sizeof( UInt32),
0b4e3aa0 617 sizeof( UInt32));
1c79356b 618 controller = gIODTDefaultInterruptController;
fa4905b1 619 controller->retain();
1c79356b
A
620 }
621
622 localBits += skip;
623 mapped->setObject( map );
624 map->release();
625 controllers->setObject( (OSObject *) controller );
626 controller->release();
627
628 } while( localBits < localEnd);
629
630 ok &= (localBits == localEnd);
631
632 if( ok ) {
0b4e3aa0 633 // store results
1c79356b
A
634 ok = regEntry->setProperty( gIOInterruptControllersKey, controllers);
635 ok &= regEntry->setProperty( gIOInterruptSpecifiersKey, mapped);
636 }
637
638 if( controllers)
639 controllers->release();
640 if( mapped)
641 mapped->release();
642
643 return( ok );
644}
645
646/*
647 */
648
649static const char *
650CompareKey( OSString * key,
651 const IORegistryEntry * table, const OSSymbol * propName )
652{
0b4e3aa0
A
653 OSObject *prop;
654 OSData *data;
655 OSString *string;
656 const char *ckey;
657 UInt32 keyLen;
658 const char *names;
659 const char *lastName;
660 bool wild;
661 bool matched;
662 const char *result = 0;
1c79356b
A
663
664 if( 0 == (prop = table->getProperty( propName )))
665 return( 0 );
666
667 if( (data = OSDynamicCast( OSData, prop ))) {
668 names = (const char *) data->getBytesNoCopy();
669 lastName = names + data->getLength();
1c79356b
A
670 } else if( (string = OSDynamicCast( OSString, prop ))) {
671 names = string->getCStringNoCopy();
672 lastName = names + string->getLength() + 1;
1c79356b 673 } else
0b4e3aa0 674 return( 0 );
1c79356b
A
675
676 ckey = key->getCStringNoCopy();
677 keyLen = key->getLength();
678 wild = ('*' == key->getChar( keyLen - 1 ));
679
680 do {
681 // for each name in the property
682 if( wild)
683 matched = (0 == strncmp( ckey, names, keyLen - 1 ));
684 else
685 matched = (keyLen == strlen( names ))
686 && (0 == strncmp( ckey, names, keyLen ));
687
688 if( matched)
689 result = names;
690
691 names = names + strlen( names) + 1;
692
693 } while( (names < lastName) && (false == matched));
694
695 return( result);
696}
697
698
699bool IODTCompareNubName( const IORegistryEntry * regEntry,
700 OSString * name, OSString ** matchingName )
701{
0b4e3aa0
A
702 const char *result;
703 bool matched;
1c79356b
A
704
705 matched = (0 != (result = CompareKey( name, regEntry, gIODTNameKey)))
706 || (0 != (result = CompareKey( name, regEntry, gIODTCompatibleKey)))
707 || (0 != (result = CompareKey( name, regEntry, gIODTTypeKey)))
708 || (0 != (result = CompareKey( name, regEntry, gIODTModelKey)));
709
710 if( result && matchingName)
711 *matchingName = OSString::withCString( result );
712
713 return( result != 0 );
714}
715
716bool IODTMatchNubWithKeys( IORegistryEntry * regEntry,
717 const char * keys )
718{
0b4e3aa0 719 OSObject *obj;
1c79356b
A
720 bool result = false;
721
722 obj = OSUnserialize( keys, 0 );
723
724 if( obj) {
725 result = regEntry->compareNames( obj );
0b4e3aa0 726 obj->release();
1c79356b
A
727 }
728#ifdef DEBUG
0b4e3aa0 729 else IOLog("Couldn't unserialize %s\n", keys );
1c79356b
A
730#endif
731
732 return( result );
733}
734
735OSCollectionIterator * IODTFindMatchingEntries( IORegistryEntry * from,
736 IOOptionBits options, const char * keys )
737{
fa4905b1 738 OSSet *result = 0;
0b4e3aa0
A
739 IORegistryEntry *next;
740 IORegistryIterator *iter;
741 OSCollectionIterator *cIter;
742 bool cmp;
743 bool minus = options & kIODTExclusive;
1c79356b 744
1c79356b
A
745
746 iter = IORegistryIterator::iterateOver( from, gIODTPlane,
0b4e3aa0 747 (options & kIODTRecursive) ? kIORegistryIterateRecursively : 0 );
1c79356b 748 if( iter) {
fa4905b1 749 do {
1c79356b 750
fa4905b1
A
751 if( result)
752 result->release();
753 result = OSSet::withCapacity( 3 );
754 if( !result)
755 break;
1c79356b 756
fa4905b1
A
757 iter->reset();
758 while( (next = iter->getNextObject())) {
759
760 // Look for existence of a debug property to skip
761 if( next->getProperty("AAPL,ignore"))
762 continue;
763
764 if( keys) {
765 cmp = IODTMatchNubWithKeys( next, keys );
766 if( (minus && (false == cmp))
767 || ((false == minus) && (false != cmp)) )
768 result->setObject( next);
769 } else
1c79356b 770 result->setObject( next);
fa4905b1
A
771 }
772 } while( !iter->isValid());
1c79356b
A
773 iter->release();
774 }
775
776 cIter = OSCollectionIterator::withCollection( result);
777 result->release();
778
779 return( cIter);
780}
781
782
783struct IODTPersistent {
784 IODTCompareAddressCellFunc compareFunc;
785 IODTNVLocationFunc locationFunc;
786};
787
788void IODTSetResolving( IORegistryEntry * regEntry,
789 IODTCompareAddressCellFunc compareFunc,
790 IODTNVLocationFunc locationFunc )
791{
792 IODTPersistent persist;
0b4e3aa0 793 OSData *prop;
1c79356b
A
794
795 persist.compareFunc = compareFunc;
796 persist.locationFunc = locationFunc;
797 prop = OSData::withBytes( &persist, sizeof( persist));
798 if( !prop)
0b4e3aa0 799 return;
1c79356b
A
800
801 regEntry->setProperty( gIODTPersistKey, prop);
802 prop->release();
0b4e3aa0 803 return;
1c79356b
A
804}
805
806static SInt32 DefaultCompare( UInt32 cellCount, UInt32 left[], UInt32 right[] )
807{
808 cellCount--;
809 return( left[ cellCount ] - right[ cellCount ] );
810}
811
812
813void IODTGetCellCounts( IORegistryEntry * regEntry,
814 UInt32 * sizeCount, UInt32 * addressCount)
815{
816 if( !GetUInt32( regEntry, gIODTSizeCellKey, sizeCount))
817 *sizeCount = 1;
818 if( !GetUInt32( regEntry, gIODTAddressCellKey, addressCount))
819 *addressCount = 2;
0b4e3aa0 820 return;
1c79356b
A
821}
822
823// Given addr & len cells from our child, find it in our ranges property, then
824// look in our parent to resolve the base of the range for us.
825
826// Range[]: child-addr our-addr child-len
827// #cells: child ours child
828
829bool IODTResolveAddressCell( IORegistryEntry * regEntry,
830 UInt32 cellsIn[],
831 IOPhysicalAddress * phys, IOPhysicalLength * len )
832{
0b4e3aa0
A
833 IORegistryEntry *parent;
834 OSData *prop;
1c79356b 835 // cells in addresses at regEntry
0b4e3aa0 836 UInt32 sizeCells, addressCells;
1c79356b 837 // cells in addresses below regEntry
0b4e3aa0
A
838 UInt32 childSizeCells, childAddressCells;
839 UInt32 childCells;
840 UInt32 cell[ 5 ], offset = 0, length;
841 UInt32 *range;
842 UInt32 *endRanges;
843 bool ok = true;
844 SInt32 diff;
845
846 IODTPersistent *persist;
1c79356b
A
847 IODTCompareAddressCellFunc compare;
848
849 IODTGetCellCounts( regEntry, &childSizeCells, &childAddressCells );
850 childCells = childAddressCells + childSizeCells;
851
852 bcopy( cellsIn, cell, 4 * childCells );
853 if( childSizeCells > 1)
854 *len = IOPhysical32( cellsIn[ childAddressCells ],
0b4e3aa0 855 cellsIn[ childAddressCells + 1 ] );
1c79356b
A
856 else
857 *len = IOPhysical32( 0, cellsIn[ childAddressCells ] );
858
859 do {
860 prop = OSDynamicCast( OSData, regEntry->getProperty( gIODTRangeKey ));
861 if( 0 == prop) {
0b4e3aa0 862 /* end of the road */
1c79356b
A
863 *phys = IOPhysical32( 0, cell[ childAddressCells - 1 ] + offset);
864 break;
865 }
866
867 parent = regEntry->getParentEntry( gIODTPlane );
0b4e3aa0 868 IODTGetCellCounts( parent, &sizeCells, &addressCells );
1c79356b
A
869
870 if( (length = prop->getLength())) {
871 // search
872 range = (UInt32 *) prop->getBytesNoCopy();
873 endRanges = range + (length / 4);
874
875 prop = (OSData *) regEntry->getProperty( gIODTPersistKey );
876 if( prop) {
877 persist = (IODTPersistent *) prop->getBytesNoCopy();
878 compare = persist->compareFunc;
879 } else
880 compare = DefaultCompare;
881
882 for( ok = false;
883 range < endRanges;
884 range += (childCells + addressCells) ) {
885
886 // is cell >= range start?
887 diff = (*compare)( childAddressCells, cell, range );
888 if( diff < 0)
889 continue;
0b4e3aa0 890
1c79356b
A
891 // is cell + size <= range end?
892 if( (diff + cell[ childCells - 1 ])
893 > range[ childCells + addressCells - 1 ])
894 continue;
895
896 offset += diff;
897 ok = true;
898 break;
899 }
900
901 // Get the physical start of the range from our parent
902 bcopy( range + childAddressCells, cell, 4 * addressCells );
903 bzero( cell + addressCells, 4 * sizeCells );
904
905 } /* else zero length range => pass thru to parent */
906
0b4e3aa0 907 regEntry = parent;
1c79356b
A
908 childSizeCells = sizeCells;
909 childAddressCells = addressCells;
0b4e3aa0 910 childCells = childAddressCells + childSizeCells;
1c79356b
A
911
912 } while( ok && regEntry);
913
914 return( ok);
915}
916
917
918OSArray * IODTResolveAddressing( IORegistryEntry * regEntry,
919 const char * addressPropertyName,
920 IODeviceMemory * parent )
921{
0b4e3aa0
A
922 IORegistryEntry *parentEntry;
923 OSData *addressProperty;
924 UInt32 sizeCells, addressCells, cells;
925 int i, num;
926 UInt32 *reg;
1c79356b
A
927 IOPhysicalAddress phys;
928 IOPhysicalLength len;
0b4e3aa0
A
929 OSArray *array;
930 IODeviceMemory *range;
1c79356b
A
931
932 parentEntry = regEntry->getParentEntry( gIODTPlane );
933 addressProperty = (OSData *) regEntry->getProperty( addressPropertyName );
934 if( (0 == addressProperty) || (0 == parentEntry))
0b4e3aa0 935 return( 0);
1c79356b
A
936
937 IODTGetCellCounts( parentEntry, &sizeCells, &addressCells );
938 if( 0 == sizeCells)
0b4e3aa0 939 return( 0);
1c79356b
A
940
941 cells = sizeCells + addressCells;
942 reg = (UInt32 *) addressProperty->getBytesNoCopy();
943 num = addressProperty->getLength() / (4 * cells);
944
945 array = OSArray::withCapacity( 1 );
946 if( 0 == array)
0b4e3aa0 947 return( 0);
1c79356b
A
948
949 for( i = 0; i < num; i++) {
0b4e3aa0
A
950 if( IODTResolveAddressCell( parentEntry, reg, &phys, &len )) {
951 range = 0;
952 if( parent)
953 range = IODeviceMemory::withSubRange( parent,
954 phys - parent->getPhysicalAddress(), len );
955 if( 0 == range)
956 range = IODeviceMemory::withRange( phys, len );
957 if( range)
958 array->setObject( range );
959 }
960 reg += cells;
1c79356b
A
961 }
962
963 regEntry->setProperty( gIODeviceMemoryKey, array);
964 array->release(); /* ??? */
965
966 return( array);
967}
968
969static void IODTGetNVLocation(
970 IORegistryEntry * parent,
971 IORegistryEntry * regEntry,
972 UInt8 * busNum, UInt8 * deviceNum, UInt8 * functionNum )
973{
974
0b4e3aa0
A
975 OSData *prop;
976 IODTPersistent *persist;
977 UInt32 *cell;
1c79356b
A
978
979 prop = (OSData *) parent->getProperty( gIODTPersistKey );
980 if( prop) {
981 persist = (IODTPersistent *) prop->getBytesNoCopy();
0b4e3aa0 982 (*persist->locationFunc)( regEntry, busNum, deviceNum, functionNum );
1c79356b
A
983 } else {
984 prop = (OSData *) regEntry->getProperty( "reg" );
985 *functionNum = 0;
986 if( prop) {
987 cell = (UInt32 *) prop->getBytesNoCopy();
1c79356b
A
988 *busNum = 3;
989 *deviceNum = 0x1f & (cell[ 0 ] >> 24);
990 } else {
991 *busNum = 0;
992 *deviceNum = 0;
0b4e3aa0 993 }
1c79356b 994 }
0b4e3aa0 995 return;
1c79356b
A
996}
997
998/*
999 * Try to make the same messed up descriptor as Mac OS
1000 */
1001
1002IOReturn IODTMakeNVDescriptor( IORegistryEntry * regEntry,
1003 IONVRAMDescriptor * hdr )
1004{
0b4e3aa0
A
1005 IORegistryEntry *parent;
1006 UInt32 level;
1007 UInt32 bridgeDevices;
1008 UInt8 busNum;
1009 UInt8 deviceNum;
1010 UInt8 functionNum;
1c79356b
A
1011
1012 hdr->format = 1;
1013 hdr->marker = 0;
1014
0b4e3aa0
A
1015 for(level = 0, bridgeDevices = 0;
1016 (parent = regEntry->getParentEntry( gIODTPlane )) && (level < 7); level++ ) {
1c79356b
A
1017
1018 IODTGetNVLocation( parent, regEntry,
0b4e3aa0
A
1019 &busNum, &deviceNum, &functionNum );
1020 if( level)
1021 bridgeDevices |= ((deviceNum & 0x1f) << ((level - 1) * 5));
1022 else {
1c79356b
A
1023 hdr->busNum = busNum;
1024 hdr->deviceNum = deviceNum;
1025 hdr->functionNum = functionNum;
0b4e3aa0
A
1026 }
1027 regEntry = parent;
1c79356b
A
1028 }
1029 hdr->bridgeCount = level - 2;
1030 hdr->bridgeDevices = bridgeDevices;
1031
1032 return( kIOReturnSuccess );
1033}
1034
1035OSData * IODTFindSlotName( IORegistryEntry * regEntry, UInt32 deviceNumber )
1036{
0b4e3aa0
A
1037 IORegistryEntry *parent;
1038 OSData *data;
1039 OSData *ret = 0;
1040 UInt32 *bits;
1041 UInt32 i;
1042 char *names;
1043 char *lastName;
1044 UInt32 mask;
1c79356b
A
1045
1046 data = (OSData *) regEntry->getProperty("AAPL,slot-name");
1047 if( data)
0b4e3aa0 1048 return( data);
1c79356b
A
1049 parent = regEntry->getParentEntry( gIODTPlane );
1050 if( !parent)
0b4e3aa0 1051 return( 0 );
1c79356b
A
1052 data = OSDynamicCast( OSData, parent->getProperty("slot-names"));
1053 if( !data)
0b4e3aa0 1054 return( 0 );
1c79356b 1055 if( data->getLength() <= 4)
0b4e3aa0 1056 return( 0 );
1c79356b
A
1057
1058 bits = (UInt32 *) data->getBytesNoCopy();
1059 mask = *bits;
1060 if( (0 == (mask & (1 << deviceNumber))))
0b4e3aa0 1061 return( 0 );
1c79356b
A
1062
1063 names = (char *)(bits + 1);
1064 lastName = names + (data->getLength() - 4);
1065
0b4e3aa0 1066 for( i = 0; (i <= deviceNumber) && (names < lastName); i++ ) {
1c79356b 1067
0b4e3aa0 1068 if( mask & (1 << i)) {
1c79356b 1069 if( i == deviceNumber) {
0b4e3aa0
A
1070 data = OSData::withBytesNoCopy( names, 1 + strlen( names));
1071 if( data) {
1072 regEntry->setProperty("AAPL,slot-name", data);
1073 ret = data;
1074 data->release();
1075 }
1c79356b 1076 } else
0b4e3aa0 1077 names += 1 + strlen( names);
1c79356b
A
1078 }
1079 }
1080
1081 return( ret );
1082}