The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/iokit/Kernel/IODeviceTreeSupport.cpp

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.