1 /*
2 * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #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 unsigned 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 || (strncmp("display", (char *)prop->getBytesNoCopy(), sizeof("display"))) ) {
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 #if defined (__i386__)
312 virt = ml_boot_ptovirt( range[0] );
313 #else
314 virt = ml_static_ptovirt( range[0] );
315 #endif
316 if( virt) {
317 ml_static_mfree( virt, range[1] );
318 }
319 }
320
321 static IORegistryEntry *
322 MakeReferenceTable( DTEntry dtEntry, bool copy )
323 {
324 IORegistryEntry *regEntry;
325 OSDictionary *propTable;
326 const OSSymbol *nameKey;
327 OSData *data;
328 const OSSymbol *sym;
329 DTPropertyIterator dtIter;
330 void *prop;
331 unsigned int propSize;
332 char *name;
333 char location[ 32 ];
334 bool noLocation = true;
335
336 regEntry = new IOService;
337
338 if( regEntry && (false == regEntry->init())) {
339 regEntry->release();
340 regEntry = 0;
341 }
342
343 if( regEntry &&
344 (kSuccess == DTCreatePropertyIterator( dtEntry, &dtIter))) {
345
346 propTable = regEntry->getPropertyTable();
347
348 while( kSuccess == DTIterateProperties( dtIter, &name)) {
349
350 if( kSuccess != DTGetProperty( dtEntry, name, &prop, &propSize ))
351 continue;
352
353 if( copy) {
354 nameKey = OSSymbol::withCString(name);
355 data = OSData::withBytes(prop, propSize);
356 } else {
357 nameKey = OSSymbol::withCStringNoCopy(name);
358 data = OSData::withBytesNoCopy(prop, propSize);
359 }
360 assert( nameKey && data );
361
362 propTable->setObject( nameKey, data);
363 data->release();
364 nameKey->release();
365
366 if( nameKey == gIODTNameKey ) {
367 if( copy)
368 sym = OSSymbol::withCString( (const char *) prop);
369 else
370 sym = OSSymbol::withCStringNoCopy( (const char *) prop);
371 regEntry->setName( sym );
372 sym->release();
373
374 } else if( nameKey == gIODTUnitKey ) {
375 // all OF strings are null terminated... except this one
376 if( propSize >= (int) sizeof(location))
377 propSize = sizeof(location) - 1;
378 strncpy( location, (const char *) prop, propSize );
379 location[ propSize ] = 0;
380 regEntry->setLocation( location );
381 propTable->removeObject( gIODTUnitKey );
382 noLocation = false;
383
384 } else if(noLocation && (!strncmp(name, "reg", sizeof("reg")))) {
385 // default location - override later
386 snprintf(location, sizeof(location), "%lX", *((UInt32 *) prop));
387 regEntry->setLocation( location );
388 }
389 }
390 DTDisposePropertyIterator( dtIter);
391 }
392
393 return( regEntry);
394 }
395
396 static void AddPHandle( IORegistryEntry * regEntry )
397 {
398 OSData * data;
399
400 if( regEntry->getProperty( gIODTInterruptCellKey)
401 && (data = OSDynamicCast( OSData, regEntry->getProperty( gIODTPHandleKey )))) {
402 // a possible interrupt-parent
403 gIODTPHandles->setObject( data );
404 gIODTPHandleMap->setObject( regEntry );
405 }
406 }
407
408 static IORegistryEntry * FindPHandle( UInt32 phandle )
409 {
410 OSData *data;
411 IORegistryEntry *regEntry = 0;
412 int i;
413
414 for( i = 0; (data = (OSData *)gIODTPHandles->getObject( i )); i++ ) {
415 if( phandle == *((UInt32 *)data->getBytesNoCopy())) {
416 regEntry = (IORegistryEntry *)
417 gIODTPHandleMap->getObject( i );
418 break;
419 }
420 }
421
422 return( regEntry );
423 }
424
425 static bool GetUInt32( IORegistryEntry * regEntry, const OSSymbol * name,
426 UInt32 * value )
427 {
428 OSData *data;
429
430 if( (data = OSDynamicCast( OSData, regEntry->getProperty( name )))
431 && (4 == data->getLength())) {
432 *value = *((UInt32 *) data->getBytesNoCopy());
433 return( true );
434 } else
435 return( false );
436 }
437
438 IORegistryEntry * IODTFindInterruptParent( IORegistryEntry * regEntry )
439 {
440 IORegistryEntry * parent;
441 UInt32 phandle;
442
443 if( GetUInt32( regEntry, gIODTInterruptParentKey, &phandle))
444 parent = FindPHandle( phandle );
445
446 else if( 0 == regEntry->getProperty( "interrupt-controller"))
447 parent = regEntry->getParentEntry( gIODTPlane);
448 else
449 parent = 0;
450
451 return( parent );
452 }
453
454 const OSSymbol * IODTInterruptControllerName( IORegistryEntry * regEntry )
455 {
456 const OSSymbol *sym;
457 UInt32 phandle;
458 bool ok;
459 char buf[48];
460
461 ok = GetUInt32( regEntry, gIODTPHandleKey, &phandle);
462 assert( ok );
463
464 if( ok) {
465 snprintf(buf, sizeof(buf), "IOInterruptController%08lX", phandle);
466 sym = OSSymbol::withCString( buf );
467 } else
468 sym = 0;
469
470 return( sym );
471 }
472
473 #define unexpected(a) { kprintf("unexpected %s:%d\n", __FILE__, __LINE__); a; }
474
475 static void IODTGetICellCounts( IORegistryEntry * regEntry,
476 UInt32 * iCellCount, UInt32 * aCellCount)
477 {
478 if( !GetUInt32( regEntry, gIODTInterruptCellKey, iCellCount))
479 unexpected( *iCellCount = 1 );
480 if( !GetUInt32( regEntry, gIODTAddressCellKey, aCellCount))
481 *aCellCount = 0;
482 }
483
484 UInt32 IODTMapOneInterrupt( IORegistryEntry * regEntry, UInt32 * intSpec,
485 OSData ** spec, const OSSymbol ** controller )
486 {
487 IORegistryEntry *parent = 0;
488 OSData *data;
489 UInt32 *addrCmp;
490 UInt32 *maskCmp;
491 UInt32 *map;
492 UInt32 *endMap;
493 UInt32 acells, icells, pacells, picells, cell;
494 UInt32 i, original_icells;
495 bool cmp, ok = false;
496
497 parent = IODTFindInterruptParent( regEntry );
498 IODTGetICellCounts( parent, &icells, &acells );
499 addrCmp = 0;
500 if( acells) {
501 data = OSDynamicCast( OSData, regEntry->getProperty( "reg" ));
502 if( data && (data->getLength() >= (acells * sizeof(UInt32))))
503 addrCmp = (UInt32 *) data->getBytesNoCopy();
504 }
505 original_icells = icells;
506 regEntry = parent;
507
508 do {
509 #if IODTSUPPORTDEBUG
510 kprintf ("IODTMapOneInterrupt: current regEntry name %s\n", regEntry->getName());
511 kprintf ("acells - icells: ");
512 for (i = 0; i < acells; i++) kprintf ("0x%08X ", addrCmp[i]);
513 kprintf ("- ");
514 for (i = 0; i < icells; i++) kprintf ("0x%08X ", intSpec[i]);
515 kprintf ("\n");
516 #endif
517
518 if( parent && (data = OSDynamicCast( OSData,
519 regEntry->getProperty( "interrupt-controller")))) {
520 // found a controller - don't want to follow cascaded controllers
521 parent = 0;
522 *spec = OSData::withBytesNoCopy( (void *) intSpec,
523 icells * sizeof(UInt32));
524 *controller = IODTInterruptControllerName( regEntry );
525 ok = (*spec && *controller);
526 } else if( parent && (data = OSDynamicCast( OSData,
527 regEntry->getProperty( "interrupt-map")))) {
528 // interrupt-map
529 map = (UInt32 *) data->getBytesNoCopy();
530 endMap = map + (data->getLength() / sizeof(UInt32));
531 data = OSDynamicCast( OSData, regEntry->getProperty( "interrupt-map-mask" ));
532 if( data && (data->getLength() >= ((acells + icells) * sizeof(UInt32))))
533 maskCmp = (UInt32 *) data->getBytesNoCopy();
534 else
535 maskCmp = 0;
536
537 #if IODTSUPPORTDEBUG
538 if (maskCmp) {
539 kprintf (" maskCmp: ");
540 for (i = 0; i < acells + icells; i++) {
541 if (i == acells)
542 kprintf ("- ");
543 kprintf ("0x%08X ", maskCmp[i]);
544 }
545 kprintf ("\n");
546 kprintf (" masked: ");
547 for (i = 0; i < acells + icells; i++) {
548 if (i == acells)
549 kprintf ("- ");
550 kprintf ("0x%08X ", ((i < acells) ? addrCmp[i] : intSpec[i-acells]) & maskCmp[i]);
551 }
552 kprintf ("\n");
553 } else
554 kprintf ("no maskCmp\n");
555 #endif
556 do {
557 #if IODTSUPPORTDEBUG
558 kprintf (" map: ");
559 for (i = 0; i < acells + icells; i++) {
560 if (i == acells)
561 kprintf ("- ");
562 kprintf ("0x%08X ", map[i]);
563 }
564 kprintf ("\n");
565 #endif
566 for( i = 0, cmp = true; cmp && (i < (acells + icells)); i++) {
567 cell = (i < acells) ? addrCmp[i] : intSpec[ i - acells ];
568 if( maskCmp)
569 cell &= maskCmp[i];
570 cmp = (cell == map[i]);
571 }
572
573 map += acells + icells;
574 if( 0 == (parent = FindPHandle( *(map++) )))
575 unexpected(break);
576
577 IODTGetICellCounts( parent, &picells, &pacells );
578 if( cmp) {
579 addrCmp = map;
580 intSpec = map + pacells;
581 regEntry = parent;
582 } else {
583 map += pacells + picells;
584 }
585 } while( !cmp && (map < endMap) );
586 if (!cmp)
587 parent = 0;
588 }
589
590 if( parent) {
591 IODTGetICellCounts( parent, &icells, &acells );
592 regEntry = parent;
593 }
594
595 } while( parent);
596
597 return( ok ? original_icells : 0 );
598 }
599
600 IOReturn IODTGetInterruptOptions( IORegistryEntry * regEntry, int source, IOOptionBits * options )
601 {
602 OSArray * controllers;
603 OSArray * specifiers;
604 OSArray * shared;
605 OSObject * spec;
606 OSObject * oneSpec;
607
608 *options = 0;
609
610 controllers = OSDynamicCast(OSArray, regEntry->getProperty(gIOInterruptControllersKey));
611 specifiers = OSDynamicCast(OSArray, regEntry->getProperty(gIOInterruptSpecifiersKey));
612
613 if( !controllers || !specifiers)
614 return (kIOReturnNoInterrupt);
615
616 shared = (OSArray *) gIODTSharedInterrupts->getObject(
617 (const OSSymbol *) controllers->getObject(source) );
618 if (!shared)
619 return (kIOReturnSuccess);
620
621 spec = specifiers->getObject(source);
622 if (!spec)
623 return (kIOReturnNoInterrupt);
624
625 for (unsigned int i = 0;
626 (oneSpec = shared->getObject(i))
627 && (!oneSpec->isEqualTo(spec));
628 i++ ) {}
629
630 if (oneSpec)
631 *options = kIODTInterruptShared;
632
633 return (kIOReturnSuccess);
634 }
635
636 static bool IODTMapInterruptsSharing( IORegistryEntry * regEntry, OSDictionary * allInts )
637 {
638 IORegistryEntry * parent;
639 OSData * local;
640 OSData * local2;
641 UInt32 * localBits;
642 UInt32 * localEnd;
643 OSData * map;
644 OSObject * oneMap;
645 OSArray * mapped;
646 OSArray * controllerInts;
647 const OSSymbol * controller;
648 OSArray * controllers;
649 UInt32 skip = 1;
650 bool ok, nw;
651
652 nw = (0 == (local = OSDynamicCast( OSData,
653 regEntry->getProperty( gIODTAAPLInterruptsKey))));
654 if( nw && (0 == (local = OSDynamicCast( OSData,
655 regEntry->getProperty( "interrupts")))))
656 return( true ); // nothing to see here
657
658 if( nw && (parent = regEntry->getParentEntry( gIODTPlane))) {
659 // check for bridges on old world
660 if( (local2 = OSDynamicCast( OSData,
661 parent->getProperty( gIODTAAPLInterruptsKey)))) {
662 local = local2;
663 nw = false;
664 }
665 }
666
667 localBits = (UInt32 *) local->getBytesNoCopy();
668 localEnd = localBits + (local->getLength() / sizeof(UInt32));
669 mapped = OSArray::withCapacity( 1 );
670 controllers = OSArray::withCapacity( 1 );
671
672 ok = (mapped && controllers);
673
674 if( ok) do {
675 if( nw) {
676 skip = IODTMapOneInterrupt( regEntry, localBits, &map, &controller );
677 if( 0 == skip) {
678 IOLog("%s: error mapping interrupt[%d]\n",
679 regEntry->getName(), mapped->getCount());
680 break;
681 }
682 } else {
683 map = OSData::withData( local, mapped->getCount() * sizeof(UInt32),
684 sizeof(UInt32));
685 controller = gIODTDefaultInterruptController;
686 controller->retain();
687 }
688
689 localBits += skip;
690 mapped->setObject( map );
691 controllers->setObject( controller );
692
693 if (allInts)
694 {
695 controllerInts = (OSArray *) allInts->getObject( controller );
696 if (controllerInts)
697 {
698 for (unsigned int i = 0; (oneMap = controllerInts->getObject(i)); i++)
699 {
700 if (map->isEqualTo(oneMap))
701 {
702 controllerInts = (OSArray *) gIODTSharedInterrupts->getObject( controller );
703 if (controllerInts)
704 controllerInts->setObject(map);
705 else
706 {
707 controllerInts = OSArray::withObjects( (const OSObject **) &map, 1, 4 );
708 if (controllerInts)
709 {
710 gIODTSharedInterrupts->setObject( controller, controllerInts );
711 controllerInts->release();
712 }
713 }
714 break;
715 }
716 }
717 if (!oneMap)
718 controllerInts->setObject(map);
719 }
720 else
721 {
722 controllerInts = OSArray::withObjects( (const OSObject **) &map, 1, 16 );
723 if (controllerInts)
724 {
725 allInts->setObject( controller, controllerInts );
726 controllerInts->release();
727 }
728 }
729 }
730
731 map->release();
732 controller->release();
733
734 } while( localBits < localEnd);
735
736 ok &= (localBits == localEnd);
737
738 if( ok ) {
739 // store results
740 ok = regEntry->setProperty( gIOInterruptControllersKey, controllers);
741 ok &= regEntry->setProperty( gIOInterruptSpecifiersKey, mapped);
742 }
743
744 if( controllers)
745 controllers->release();
746 if( mapped)
747 mapped->release();
748
749 return( ok );
750 }
751
752 bool IODTMapInterrupts( IORegistryEntry * regEntry )
753 {
754 return( IODTMapInterruptsSharing( regEntry, 0 ));
755 }
756
757 /*
758 */
759
760 static const char *
761 CompareKey( OSString * key,
762 const IORegistryEntry * table, const OSSymbol * propName )
763 {
764 OSObject *prop;
765 OSData *data;
766 OSString *string;
767 const char *ckey;
768 UInt32 keyLen;
769 const char *names;
770 const char *lastName;
771 bool wild;
772 bool matched;
773 const char *result = 0;
774
775 if( 0 == (prop = table->getProperty( propName )))
776 return( 0 );
777
778 if( (data = OSDynamicCast( OSData, prop ))) {
779 names = (const char *) data->getBytesNoCopy();
780 lastName = names + data->getLength();
781 } else if( (string = OSDynamicCast( OSString, prop ))) {
782 names = string->getCStringNoCopy();
783 lastName = names + string->getLength() + 1;
784 } else
785 return( 0 );
786
787 ckey = key->getCStringNoCopy();
788 keyLen = key->getLength();
789 wild = ('*' == key->getChar( keyLen - 1 ));
790
791 do {
792 // for each name in the property
793 if( wild)
794 matched = (0 == strncmp( ckey, names, keyLen - 1 ));
795 else
796 matched = (keyLen == strlen( names ))
797 && (0 == strncmp( ckey, names, keyLen ));
798
799 if( matched)
800 result = names;
801
802 names = names + strlen( names) + 1;
803
804 } while( (names < lastName) && (false == matched));
805
806 return( result);
807 }
808
809
810 bool IODTCompareNubName( const IORegistryEntry * regEntry,
811 OSString * name, OSString ** matchingName )
812 {
813 const char *result;
814 bool matched;
815
816 matched = (0 != (result = CompareKey( name, regEntry, gIODTNameKey)))
817 || (0 != (result = CompareKey( name, regEntry, gIODTCompatibleKey)))
818 || (0 != (result = CompareKey( name, regEntry, gIODTTypeKey)))
819 || (0 != (result = CompareKey( name, regEntry, gIODTModelKey)));
820
821 if( result && matchingName)
822 *matchingName = OSString::withCString( result );
823
824 return( result != 0 );
825 }
826
827 bool IODTMatchNubWithKeys( IORegistryEntry * regEntry,
828 const char * keys )
829 {
830 OSObject *obj;
831 bool result = false;
832
833 obj = OSUnserialize( keys, 0 );
834
835 if( obj) {
836 result = regEntry->compareNames( obj );
837 obj->release();
838 }
839 #ifdef DEBUG
840 else IOLog("Couldn't unserialize %s\n", keys );
841 #endif
842
843 return( result );
844 }
845
846 OSCollectionIterator * IODTFindMatchingEntries( IORegistryEntry * from,
847 IOOptionBits options, const char * keys )
848 {
849 OSSet *result = 0;
850 IORegistryEntry *next;
851 IORegistryIterator *iter;
852 OSCollectionIterator *cIter;
853 bool cmp;
854 bool minus = options & kIODTExclusive;
855
856
857 iter = IORegistryIterator::iterateOver( from, gIODTPlane,
858 (options & kIODTRecursive) ? kIORegistryIterateRecursively : 0 );
859 if( iter) {
860
861 do {
862
863 if( result)
864 result->release();
865 result = OSSet::withCapacity( 3 );
866 if( !result)
867 break;
868
869 iter->reset();
870 while( (next = iter->getNextObject())) {
871
872 // Look for existence of a debug property to skip
873 if( next->getProperty("AAPL,ignore"))
874 continue;
875
876 if( keys) {
877 cmp = IODTMatchNubWithKeys( next, keys );
878 if( (minus && (false == cmp))
879 || ((false == minus) && (false != cmp)) )
880 result->setObject( next);
881 } else
882 result->setObject( next);
883 }
884 } while( !iter->isValid());
885
886 iter->release();
887 }
888
889 cIter = OSCollectionIterator::withCollection( result);
890 result->release();
891
892 return( cIter);
893 }
894
895
896 struct IODTPersistent {
897 IODTCompareAddressCellFunc compareFunc;
898 IODTNVLocationFunc locationFunc;
899 };
900
901 void IODTSetResolving( IORegistryEntry * regEntry,
902 IODTCompareAddressCellFunc compareFunc,
903 IODTNVLocationFunc locationFunc )
904 {
905 IODTPersistent persist;
906 OSData *prop;
907
908 persist.compareFunc = compareFunc;
909 persist.locationFunc = locationFunc;
910 prop = OSData::withBytes( &persist, sizeof(persist));
911 if( !prop)
912 return;
913
914 regEntry->setProperty( gIODTPersistKey, prop);
915 prop->release();
916 return;
917 }
918
919 static SInt32 DefaultCompare( UInt32 cellCount, UInt32 left[], UInt32 right[] )
920 {
921 cellCount--;
922 return( left[ cellCount ] - right[ cellCount ] );
923 }
924
925 void IODTGetCellCounts( IORegistryEntry * regEntry,
926 UInt32 * sizeCount, UInt32 * addressCount)
927 {
928 if( !GetUInt32( regEntry, gIODTSizeCellKey, sizeCount))
929 *sizeCount = 1;
930 if( !GetUInt32( regEntry, gIODTAddressCellKey, addressCount))
931 *addressCount = 2;
932 return;
933 }
934
935 // Given addr & len cells from our child, find it in our ranges property, then
936 // look in our parent to resolve the base of the range for us.
937
938 // Range[]: child-addr our-addr child-len
939 // #cells: child ours child
940
941 bool IODTResolveAddressCell( IORegistryEntry * regEntry,
942 UInt32 cellsIn[],
943 IOPhysicalAddress * phys, IOPhysicalLength * len )
944 {
945 IORegistryEntry *parent;
946 OSData *prop;
947 // cells in addresses at regEntry
948 UInt32 sizeCells, addressCells;
949 // cells in addresses below regEntry
950 UInt32 childSizeCells, childAddressCells;
951 UInt32 childCells;
952 UInt32 cell[ 5 ], offset = 0, length;
953 UInt32 endCell[ 5 ];
954 UInt32 *range;
955 UInt32 *lookRange;
956 UInt32 *startRange;
957 UInt32 *endRanges;
958 bool ok = true;
959 SInt32 diff, diff2, endDiff;
960
961 IODTPersistent *persist;
962 IODTCompareAddressCellFunc compare;
963
964 IODTGetCellCounts( regEntry, &childSizeCells, &childAddressCells );
965 childCells = childAddressCells + childSizeCells;
966
967 bcopy( cellsIn, cell, sizeof(UInt32) * childCells );
968 if( childSizeCells > 1)
969 *len = IOPhysical32( cellsIn[ childAddressCells ],
970 cellsIn[ childAddressCells + 1 ] );
971 else
972 *len = IOPhysical32( 0, cellsIn[ childAddressCells ] );
973
974 do
975 {
976 prop = OSDynamicCast( OSData, regEntry->getProperty( gIODTRangeKey ));
977 if( 0 == prop) {
978 /* end of the road */
979 *phys = IOPhysical32( 0, cell[ childAddressCells - 1 ] + offset);
980 break;
981 }
982
983 parent = regEntry->getParentEntry( gIODTPlane );
984 IODTGetCellCounts( parent, &sizeCells, &addressCells );
985
986 if( (length = prop->getLength())) {
987 // search
988 startRange = (UInt32 *) prop->getBytesNoCopy();
989 range = startRange;
990 endRanges = range + (length / sizeof(UInt32));
991
992 prop = (OSData *) regEntry->getProperty( gIODTPersistKey );
993 if( prop) {
994 persist = (IODTPersistent *) prop->getBytesNoCopy();
995 compare = persist->compareFunc;
996 } else
997 compare = DefaultCompare;
998
999 for( ok = false;
1000 range < endRanges;
1001 range += (childCells + addressCells) ) {
1002
1003 // is cell start within range?
1004 diff = (*compare)( childAddressCells, cell, range );
1005
1006 bcopy(range, endCell, childAddressCells * sizeof(UInt32));
1007 endCell[childAddressCells - 1] += range[childCells + addressCells - 1];
1008 diff2 = (*compare)( childAddressCells, cell, endCell );
1009
1010 if ((diff < 0) || (diff2 >= 0))
1011 continue;
1012
1013 ok = (0 == cell[childCells - 1]);
1014 if (!ok)
1015 {
1016 // search for cell end
1017 bcopy(cell, endCell, childAddressCells * sizeof(UInt32));
1018 endCell[childAddressCells - 1] += cell[childCells - 1] - 1;
1019 lookRange = startRange;
1020 for( ;
1021 lookRange < endRanges;
1022 lookRange += (childCells + addressCells) )
1023 {
1024 // is cell >= range start?
1025 endDiff = (*compare)( childAddressCells, endCell, lookRange );
1026 if( endDiff < 0)
1027 continue;
1028 if ((endDiff - cell[childCells - 1] + 1 + lookRange[childAddressCells + addressCells - 1])
1029 == (diff + range[childAddressCells + addressCells - 1]))
1030 {
1031 ok = true;
1032 break;
1033 }
1034 }
1035 if (!ok)
1036 continue;
1037 }
1038 offset += diff;
1039 break;
1040 }
1041
1042 // Get the physical start of the range from our parent
1043 bcopy( range + childAddressCells, cell, sizeof(UInt32) * addressCells );
1044 bzero( cell + addressCells, sizeof(UInt32) * sizeCells );
1045
1046 } /* else zero length range => pass thru to parent */
1047
1048 regEntry = parent;
1049 childSizeCells = sizeCells;
1050 childAddressCells = addressCells;
1051 childCells = childAddressCells + childSizeCells;
1052 }
1053 while( ok && regEntry);
1054
1055 return( ok);
1056 }
1057
1058
1059 OSArray * IODTResolveAddressing( IORegistryEntry * regEntry,
1060 const char * addressPropertyName,
1061 IODeviceMemory * parent )
1062 {
1063 IORegistryEntry *parentEntry;
1064 OSData *addressProperty;
1065 UInt32 sizeCells, addressCells, cells;
1066 int i, num;
1067 UInt32 *reg;
1068 IOPhysicalAddress phys;
1069 IOPhysicalLength len;
1070 OSArray *array;
1071 IODeviceMemory *range;
1072
1073 parentEntry = regEntry->getParentEntry( gIODTPlane );
1074 addressProperty = (OSData *) regEntry->getProperty( addressPropertyName );
1075 if( (0 == addressProperty) || (0 == parentEntry))
1076 return( 0);
1077
1078 IODTGetCellCounts( parentEntry, &sizeCells, &addressCells );
1079 if( 0 == sizeCells)
1080 return( 0);
1081
1082 cells = sizeCells + addressCells;
1083 reg = (UInt32 *) addressProperty->getBytesNoCopy();
1084 num = addressProperty->getLength() / (4 * cells);
1085
1086 array = OSArray::withCapacity( 1 );
1087 if( 0 == array)
1088 return( 0);
1089
1090 for( i = 0; i < num; i++) {
1091 if( IODTResolveAddressCell( parentEntry, reg, &phys, &len )) {
1092 range = 0;
1093 if( parent)
1094 range = IODeviceMemory::withSubRange( parent,
1095 phys - parent->getPhysicalAddress(), len );
1096 if( 0 == range)
1097 range = IODeviceMemory::withRange( phys, len );
1098 if( range)
1099 array->setObject( range );
1100 }
1101 reg += cells;
1102 }
1103
1104 regEntry->setProperty( gIODeviceMemoryKey, array);
1105 array->release(); /* ??? */
1106
1107 return( array);
1108 }
1109
1110 static void IODTGetNVLocation(
1111 IORegistryEntry * parent,
1112 IORegistryEntry * regEntry,
1113 UInt8 * busNum, UInt8 * deviceNum, UInt8 * functionNum )
1114 {
1115
1116 OSData *prop;
1117 IODTPersistent *persist;
1118 UInt32 *cell;
1119
1120 prop = (OSData *) parent->getProperty( gIODTPersistKey );
1121 if( prop) {
1122 persist = (IODTPersistent *) prop->getBytesNoCopy();
1123 (*persist->locationFunc)( regEntry, busNum, deviceNum, functionNum );
1124 } else {
1125 prop = (OSData *) regEntry->getProperty( "reg" );
1126 *functionNum = 0;
1127 if( prop) {
1128 cell = (UInt32 *) prop->getBytesNoCopy();
1129 *busNum = 3;
1130 *deviceNum = 0x1f & (cell[ 0 ] >> 24);
1131 } else {
1132 *busNum = 0;
1133 *deviceNum = 0;
1134 }
1135 }
1136 return;
1137 }
1138
1139 /*
1140 * Try to make the same messed up descriptor as Mac OS
1141 */
1142
1143 IOReturn IODTMakeNVDescriptor( IORegistryEntry * regEntry,
1144 IONVRAMDescriptor * hdr )
1145 {
1146 IORegistryEntry *parent;
1147 UInt32 level;
1148 UInt32 bridgeDevices;
1149 UInt8 busNum;
1150 UInt8 deviceNum;
1151 UInt8 functionNum;
1152
1153 hdr->format = 1;
1154 hdr->marker = 0;
1155
1156 for(level = 0, bridgeDevices = 0;
1157 (parent = regEntry->getParentEntry( gIODTPlane )) && (level < 7); level++ ) {
1158
1159 IODTGetNVLocation( parent, regEntry,
1160 &busNum, &deviceNum, &functionNum );
1161 if( level)
1162 bridgeDevices |= ((deviceNum & 0x1f) << ((level - 1) * 5));
1163 else {
1164 hdr->busNum = busNum;
1165 hdr->deviceNum = deviceNum;
1166 hdr->functionNum = functionNum;
1167 }
1168 regEntry = parent;
1169 }
1170 hdr->bridgeCount = level - 2;
1171 hdr->bridgeDevices = bridgeDevices;
1172
1173 return( kIOReturnSuccess );
1174 }
1175
1176 OSData * IODTFindSlotName( IORegistryEntry * regEntry, UInt32 deviceNumber )
1177 {
1178 IORegistryEntry *parent;
1179 OSData *data;
1180 OSData *ret = 0;
1181 UInt32 *bits;
1182 UInt32 i;
1183 char *names;
1184 char *lastName;
1185 UInt32 mask;
1186
1187 data = (OSData *) regEntry->getProperty("AAPL,slot-name");
1188 if( data)
1189 return( data);
1190 parent = regEntry->getParentEntry( gIODTPlane );
1191 if( !parent)
1192 return( 0 );
1193 data = OSDynamicCast( OSData, parent->getProperty("slot-names"));
1194 if( !data)
1195 return( 0 );
1196 if( data->getLength() <= 4)
1197 return( 0 );
1198
1199 bits = (UInt32 *) data->getBytesNoCopy();
1200 mask = *bits;
1201 if( (0 == (mask & (1 << deviceNumber))))
1202 return( 0 );
1203
1204 names = (char *)(bits + 1);
1205 lastName = names + (data->getLength() - 4);
1206
1207 for( i = 0; (i <= deviceNumber) && (names < lastName); i++ ) {
1208
1209 if( mask & (1 << i)) {
1210 if( i == deviceNumber) {
1211 data = OSData::withBytesNoCopy( names, 1 + strlen( names));
1212 if( data) {
1213 regEntry->setProperty("AAPL,slot-name", data);
1214 ret = data;
1215 data->release();
1216 }
1217 } else
1218 names += 1 + strlen( names);
1219 }
1220 }
1221
1222 return( ret );
1223 }
1224
1225 extern "C" IOReturn IONDRVLibrariesInitialize( IOService * provider )
1226 {
1227 return( kIOReturnUnsupported );
1228 }
Cache object: e67d1f04b8f4614f0f46a125f4e28b81
|