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