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 <libkern/c++/OSSharedPtr.h> 32 #include <IOKit/IODeviceMemory.h> 33 #include <IOKit/IOService.h> 34 #include <IOKit/IOCatalogue.h> 35 36 #include <IOKit/IOLib.h> 37 #include <IOKit/IOKitKeys.h> 38 39 #include <pexpert/device_tree.h> 40 41 #if __arm64__ 42 typedef UInt64 dtptr_t; 43 #else 44 typedef UInt32 dtptr_t; 45 #endif 46 47 #include <machine/machine_routines.h> 48 49 extern "C" { 50 int IODTGetLoaderInfo( const char *key, void **infoAddr, int *infosize ); 51 void IODTFreeLoaderInfo( const char *key, void *infoAddr, int infoSize ); 52 int IODTGetDefault(const char *key, void *infoAddr, unsigned int infoSize ); 53 } 54 55 #include <IOKit/assert.h> 56 57 #define IODTSUPPORTDEBUG 0 58 59 const IORegistryPlane * gIODTPlane; 60 61 static OSArray * gIODTPHandles; 62 static OSArray * gIODTPHandleMap; 63 static OSData * gIODTResolvers; 64 65 const OSSymbol * gIODTNameKey; 66 const OSSymbol * gIODTUnitKey; 67 const OSSymbol * gIODTCompatibleKey; 68 const OSSymbol * gIODTTypeKey; 69 const OSSymbol * gIODTModelKey; 70 const OSSymbol * gIODTBridgeModelKey; 71 const OSSymbol * gIODTTargetTypeKey; 72 73 const OSSymbol * gIODTSizeCellKey; 74 const OSSymbol * gIODTAddressCellKey; 75 const OSSymbol * gIODTRangeKey; 76 77 const OSSymbol * gIODTPersistKey; 78 79 const OSSymbol * gIODTDefaultInterruptController; 80 const OSSymbol * gIODTAAPLInterruptsKey; 81 const OSSymbol * gIODTPHandleKey; 82 const OSSymbol * gIODTInterruptCellKey; 83 const OSSymbol * gIODTInterruptParentKey; 84 const OSSymbol * gIODTNWInterruptMappingKey; 85 86 OSDictionary * gIODTSharedInterrupts; 87 88 static IOLock * gIODTResolversLock; 89 90 static IORegistryEntry * MakeReferenceTable( DTEntry dtEntry, bool copy ); 91 static void AddPHandle( IORegistryEntry * regEntry ); 92 static void FreePhysicalMemory( vm_offset_t * range ); 93 static bool IODTMapInterruptsSharing( IORegistryEntry * regEntry, OSDictionary * allInts ); 94 95 // FIXME: Implementation of this function is hidden from the static analyzer. 96 // The analyzer doesn't know that the registry holds retains, and gets confused 97 // about releases after calls to 'attachToParent'. 98 // Feel free to remove the #ifndef and address the warning! 99 #ifndef __clang_analyzer__ 100 IORegistryEntry * 101 IODeviceTreeAlloc( void * dtTop ) 102 { 103 IORegistryEntry * parent; 104 IORegistryEntry * child; 105 IORegistryIterator * regIter; 106 OpaqueDTEntryIterator iter; 107 DTEntry dtChild; 108 DTEntry mapEntry; 109 OSArray * stack; 110 OSData * prop; 111 OSDictionary * allInts; 112 vm_offset_t * dtMap; 113 unsigned int propSize; 114 bool intMap; 115 bool foundDTNode; 116 bool freeDT; 117 118 gIODTPlane = IORegistryEntry::makePlane( kIODeviceTreePlane ); 119 120 gIODTNameKey = OSSymbol::withCStringNoCopy( "name" ); 121 gIODTUnitKey = OSSymbol::withCStringNoCopy( "AAPL,unit-string" ); 122 gIODTCompatibleKey = OSSymbol::withCStringNoCopy( "compatible" ); 123 gIODTTypeKey = OSSymbol::withCStringNoCopy( "device_type" ); 124 gIODTModelKey = OSSymbol::withCStringNoCopy( "model" ); 125 gIODTBridgeModelKey = OSSymbol::withCStringNoCopy( "bridge-model" ); 126 gIODTTargetTypeKey = OSSymbol::withCStringNoCopy( "target-type" ); 127 gIODTSizeCellKey = OSSymbol::withCStringNoCopy( "#size-cells" ); 128 gIODTAddressCellKey = OSSymbol::withCStringNoCopy( "#address-cells" ); 129 gIODTRangeKey = OSSymbol::withCStringNoCopy( "ranges" ); 130 gIODTPersistKey = OSSymbol::withCStringNoCopy( "IODTPersist" ); 131 132 assert( gIODTPlane && gIODTCompatibleKey 133 && gIODTTypeKey && gIODTModelKey 134 && gIODTSizeCellKey && gIODTAddressCellKey && gIODTRangeKey 135 && gIODTPersistKey ); 136 137 gIODTDefaultInterruptController 138 = OSSymbol::withCStringNoCopy("IOPrimaryInterruptController"); 139 gIODTNWInterruptMappingKey 140 = OSSymbol::withCStringNoCopy("IONWInterrupts"); 141 142 gIODTAAPLInterruptsKey 143 = OSSymbol::withCStringNoCopy("AAPL,interrupts"); 144 gIODTPHandleKey 145 = OSSymbol::withCStringNoCopy("AAPL,phandle"); 146 147 gIODTInterruptParentKey 148 = OSSymbol::withCStringNoCopy("interrupt-parent"); 149 150 gIODTPHandles = OSArray::withCapacity( 1 ); 151 gIODTPHandleMap = OSArray::withCapacity( 1 ); 152 gIODTResolvers = OSData::withCapacity(16); 153 154 gIODTResolversLock = IOLockAlloc(); 155 156 gIODTInterruptCellKey 157 = OSSymbol::withCStringNoCopy("#interrupt-cells"); 158 159 assert( gIODTDefaultInterruptController && gIODTNWInterruptMappingKey 160 && gIODTAAPLInterruptsKey 161 && gIODTPHandleKey && gIODTInterruptParentKey 162 && gIODTPHandles && gIODTPHandleMap && gIODTResolvers && gIODTResolversLock 163 && gIODTInterruptCellKey 164 ); 165 166 foundDTNode = (kSuccess == SecureDTLookupEntry( NULL, "/chosen/memory-map", &mapEntry )) 167 && (kSuccess == SecureDTGetProperty( mapEntry, 168 "DeviceTree", (void const **) &dtMap, &propSize )) 169 && ((2 * sizeof(uint32_t)) == propSize); 170 171 freeDT = foundDTNode && !SecureDTIsLockedDown(); 172 173 parent = MakeReferenceTable((DTEntry)dtTop, freeDT ); 174 175 stack = OSArray::withObjects((const OSObject **) &parent, 1, 10 ); 176 SecureDTInitEntryIterator((DTEntry)dtTop, &iter ); 177 178 do { 179 parent = (IORegistryEntry *)stack->getObject( stack->getCount() - 1); 180 //parent->release(); 181 stack->removeObject( stack->getCount() - 1); 182 183 while (kSuccess == SecureDTIterateEntries( &iter, &dtChild)) { 184 child = MakeReferenceTable( dtChild, freeDT ); 185 child->attachToParent( parent, gIODTPlane); 186 187 AddPHandle( child ); 188 189 if (kSuccess == SecureDTEnterEntry( &iter, dtChild)) { 190 stack->setObject( parent); 191 parent = child; 192 } 193 // only registry holds retain 194 child->release(); 195 } 196 } while (stack->getCount() 197 && (kSuccess == SecureDTExitEntry( &iter, &dtChild))); 198 199 stack->release(); 200 assert(kSuccess != SecureDTExitEntry(&iter, &dtChild)); 201 202 // parent is now root of the created tree 203 204 // make root name first compatible entry (purely cosmetic) 205 if ((prop = (OSData *) parent->getProperty( gIODTCompatibleKey))) { 206 parent->setName( parent->getName(), gIODTPlane ); 207 parent->setName((const char *) prop->getBytesNoCopy()); 208 } 209 210 // attach tree to meta root 211 parent->attachToParent( IORegistryEntry::getRegistryRoot(), gIODTPlane); 212 parent->release(); 213 214 if (freeDT) { 215 // free original device tree 216 SecureDTInit(NULL, 0); 217 IODTFreeLoaderInfo( "DeviceTree", 218 (void *)dtMap[0], (int) round_page(dtMap[1])); 219 } 220 221 // adjust tree 222 223 gIODTSharedInterrupts = OSDictionary::withCapacity(4); 224 allInts = OSDictionary::withCapacity(4); 225 intMap = false; 226 regIter = IORegistryIterator::iterateOver( gIODTPlane, 227 kIORegistryIterateRecursively ); 228 assert( regIter && allInts && gIODTSharedInterrupts ); 229 if (regIter && allInts && gIODTSharedInterrupts) { 230 while ((child = regIter->getNextObject())) { 231 IODTMapInterruptsSharing( child, allInts ); 232 if (!intMap && child->getProperty( gIODTInterruptParentKey)) { 233 intMap = true; 234 } 235 if (!strcmp("sep", child->getName()) 236 || !strcmp("aop", child->getName()) 237 || !strcmp("disp0", child->getName())) { 238 uint32_t aotFlags = 1; 239 child->setProperty("aot-power", &aotFlags, sizeof(aotFlags)); 240 } 241 } 242 regIter->release(); 243 } 244 245 #if IODTSUPPORTDEBUG 246 parent->setProperty("allInts", allInts); 247 parent->setProperty("sharedInts", gIODTSharedInterrupts); 248 249 regIter = IORegistryIterator::iterateOver( gIODTPlane, 250 kIORegistryIterateRecursively ); 251 if (regIter) { 252 while ((child = regIter->getNextObject())) { 253 OSArray * 254 array = OSDynamicCast(OSArray, child->getProperty( gIOInterruptSpecifiersKey )); 255 for (UInt32 i = 0; array && (i < array->getCount()); i++) { 256 IOOptionBits options; 257 IOReturn ret = IODTGetInterruptOptions( child, i, &options ); 258 if ((ret != kIOReturnSuccess) || options) { 259 IOLog("%s[%ld] %ld (%x)\n", child->getName(), i, options, ret); 260 } 261 } 262 } 263 regIter->release(); 264 } 265 #endif 266 267 allInts->release(); 268 269 if (intMap) { 270 // set a key in the root to indicate we found NW interrupt mapping 271 parent->setProperty( gIODTNWInterruptMappingKey, 272 (OSObject *) gIODTNWInterruptMappingKey ); 273 } 274 275 return parent; 276 } 277 #endif 278 279 int 280 IODTGetLoaderInfo( const char *key, void **infoAddr, int *infoSize ) 281 { 282 IORegistryEntry *chosen; 283 OSData *propObj; 284 dtptr_t *propPtr; 285 unsigned int propSize; 286 int ret = -1; 287 288 chosen = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane ); 289 if (chosen == NULL) { 290 return -1; 291 } 292 293 propObj = OSDynamicCast( OSData, chosen->getProperty(key)); 294 if (propObj == NULL) { 295 goto cleanup; 296 } 297 298 propSize = propObj->getLength(); 299 if (propSize != (2 * sizeof(dtptr_t))) { 300 goto cleanup; 301 } 302 303 propPtr = (dtptr_t *)propObj->getBytesNoCopy(); 304 if (propPtr == NULL) { 305 goto cleanup; 306 } 307 308 *infoAddr = (void *)(uintptr_t) (propPtr[0]); 309 *infoSize = (int) (propPtr[1]); 310 311 ret = 0; 312 313 cleanup: 314 chosen->release(); 315 316 return ret; 317 } 318 319 void 320 IODTFreeLoaderInfo( const char *key, void *infoAddr, int infoSize ) 321 { 322 vm_offset_t range[2]; 323 IORegistryEntry *chosen; 324 325 range[0] = (vm_offset_t)infoAddr; 326 range[1] = (vm_offset_t)infoSize; 327 FreePhysicalMemory( range ); 328 329 if (key != NULL) { 330 chosen = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane ); 331 if (chosen != NULL) { 332 chosen->removeProperty(key); 333 chosen->release(); 334 } 335 } 336 } 337 338 int 339 IODTGetDefault(const char *key, void *infoAddr, unsigned int infoSize ) 340 { 341 IORegistryEntry *defaults; 342 OSData *defaultObj; 343 unsigned int defaultSize; 344 345 defaults = IORegistryEntry::fromPath( "/defaults", gIODTPlane ); 346 if (defaults == NULL) { 347 return -1; 348 } 349 350 defaultObj = OSDynamicCast( OSData, defaults->getProperty(key)); 351 if (defaultObj == NULL) { 352 return -1; 353 } 354 355 defaultSize = defaultObj->getLength(); 356 if (defaultSize > infoSize) { 357 return -1; 358 } 359 360 memcpy( infoAddr, defaultObj->getBytesNoCopy(), defaultSize ); 361 362 return 0; 363 } 364 365 static void 366 FreePhysicalMemory( vm_offset_t * range ) 367 { 368 vm_offset_t virt; 369 370 virt = ml_static_ptovirt( range[0] ); 371 if (virt) { 372 ml_static_mfree( virt, range[1] ); 373 } 374 } 375 376 static IORegistryEntry * 377 MakeReferenceTable( DTEntry dtEntry, bool copy ) 378 { 379 IORegistryEntry *regEntry; 380 OSDictionary *propTable; 381 const OSSymbol *nameKey; 382 OSData *data; 383 const OSSymbol *sym; 384 OpaqueDTPropertyIterator dtIter; 385 void const *prop; 386 unsigned int propSize; 387 char const *name; 388 char location[32]; 389 bool noLocation = true; 390 bool kernelOnly; 391 392 regEntry = new IOService; 393 394 if (regEntry && (false == regEntry->init())) { 395 regEntry->release(); 396 regEntry = NULL; 397 } 398 399 if (regEntry && 400 (kSuccess == SecureDTInitPropertyIterator( dtEntry, &dtIter))) { 401 kernelOnly = (kSuccess == SecureDTGetProperty(dtEntry, "kernel-only", &prop, &propSize)); 402 propTable = regEntry->getPropertyTable(); 403 404 while (kSuccess == SecureDTIterateProperties( &dtIter, &name)) { 405 if (kSuccess != SecureDTGetProperty( dtEntry, name, &prop, &propSize )) { 406 continue; 407 } 408 409 if (copy) { 410 nameKey = OSSymbol::withCString(name); 411 data = OSData::withBytes(prop, propSize); 412 } else { 413 nameKey = OSSymbol::withCStringNoCopy(name); 414 /* There is no OSDataConst or other way to indicate 415 * that the OSData is actually immutable. But CTRR 416 * will catch any write attempts. */ 417 data = OSData::withBytesNoCopy((void**)(uintptr_t)prop, propSize); 418 } 419 assert( nameKey && data ); 420 421 if (kernelOnly) { 422 data->setSerializable(false); 423 } 424 425 propTable->setObject( nameKey, data); 426 data->release(); 427 nameKey->release(); 428 429 if (nameKey == gIODTNameKey) { 430 if (copy) { 431 sym = OSSymbol::withCString((const char *) prop); 432 } else { 433 sym = OSSymbol::withCStringNoCopy((const char *) prop); 434 } 435 regEntry->setName( sym ); 436 sym->release(); 437 } else if (nameKey == gIODTUnitKey) { 438 // all OF strings are null terminated... except this one 439 if (propSize >= (int) sizeof(location)) { 440 propSize = sizeof(location) - 1; 441 } 442 strncpy( location, (const char *) prop, propSize ); 443 location[propSize] = 0; 444 regEntry->setLocation( location ); 445 propTable->removeObject( gIODTUnitKey ); 446 noLocation = false; 447 } else if (noLocation && (!strncmp(name, "reg", sizeof("reg")))) { 448 // default location - override later 449 snprintf(location, sizeof(location), "%X", *((uint32_t *) prop)); 450 regEntry->setLocation( location ); 451 } 452 } 453 } 454 455 return regEntry; 456 } 457 458 static void 459 AddPHandle( IORegistryEntry * regEntry ) 460 { 461 OSData * data; 462 463 if (regEntry->getProperty( gIODTInterruptCellKey) 464 && (data = OSDynamicCast( OSData, regEntry->getProperty( gIODTPHandleKey )))) { 465 // a possible interrupt-parent 466 gIODTPHandles->setObject( data ); 467 gIODTPHandleMap->setObject( regEntry ); 468 } 469 } 470 471 static IORegistryEntry * 472 FindPHandle( UInt32 phandle ) 473 { 474 OSData *data; 475 IORegistryEntry *regEntry = NULL; 476 int i; 477 478 for (i = 0; (data = (OSData *)gIODTPHandles->getObject( i )); i++) { 479 if (phandle == *((UInt32 *)data->getBytesNoCopy())) { 480 regEntry = (IORegistryEntry *) 481 gIODTPHandleMap->getObject( i ); 482 break; 483 } 484 } 485 486 return regEntry; 487 } 488 489 static bool 490 GetUInt32( IORegistryEntry * regEntry, const OSSymbol * name, 491 UInt32 * value ) 492 { 493 OSObject * obj; 494 OSData * data; 495 bool result; 496 497 if (!(obj = regEntry->copyProperty(name))) { 498 return false; 499 } 500 501 result = ((data = OSDynamicCast(OSData, obj)) && (sizeof(UInt32) == data->getLength())); 502 if (result) { 503 *value = *((UInt32 *) data->getBytesNoCopy()); 504 } 505 506 obj->release(); 507 return result; 508 } 509 510 static IORegistryEntry * 511 IODTFindInterruptParent( IORegistryEntry * regEntry, IOItemCount index ) 512 { 513 IORegistryEntry * parent; 514 UInt32 phandle; 515 OSData * data; 516 unsigned int len; 517 518 if ((data = OSDynamicCast( OSData, regEntry->getProperty( gIODTInterruptParentKey ))) 519 && (sizeof(UInt32) <= (len = data->getLength()))) { 520 if (((index + 1) * sizeof(UInt32)) > len) { 521 index = 0; 522 } 523 phandle = ((UInt32 *) data->getBytesNoCopy())[index]; 524 parent = FindPHandle( phandle ); 525 } else if (NULL == regEntry->getProperty( "interrupt-controller")) { 526 parent = regEntry->getParentEntry( gIODTPlane); 527 } else { 528 parent = NULL; 529 } 530 531 return parent; 532 } 533 534 const OSSymbol * 535 IODTInterruptControllerName( IORegistryEntry * regEntry ) 536 { 537 const OSSymbol *sym; 538 UInt32 phandle; 539 bool ok; 540 char buf[48]; 541 542 ok = GetUInt32( regEntry, gIODTPHandleKey, &phandle); 543 assert( ok ); 544 545 if (ok) { 546 snprintf(buf, sizeof(buf), "IOInterruptController%08X", (uint32_t)phandle); 547 sym = OSSymbol::withCString( buf ); 548 } else { 549 sym = NULL; 550 } 551 552 return sym; 553 } 554 555 #define unexpected(a) { kprintf("unexpected %s:%d\n", __FILE__, __LINE__); a; } 556 557 static void 558 IODTGetICellCounts( IORegistryEntry * regEntry, 559 UInt32 * iCellCount, UInt32 * aCellCount) 560 { 561 if (!GetUInt32( regEntry, gIODTInterruptCellKey, iCellCount)) { 562 unexpected( *iCellCount = 1 ); 563 } 564 if (!GetUInt32( regEntry, gIODTAddressCellKey, aCellCount)) { 565 *aCellCount = 0; 566 } 567 } 568 569 static UInt32 570 IODTMapOneInterrupt( IORegistryEntry * regEntry, UInt32 * intSpec, UInt32 index, 571 LIBKERN_RETURNS_RETAINED OSData ** spec, 572 LIBKERN_RETURNS_RETAINED const OSSymbol ** controller ) 573 { 574 IORegistryEntry *parent = NULL; 575 OSData *data; 576 UInt32 *addrCmp; 577 UInt32 *maskCmp; 578 UInt32 *map; 579 UInt32 *endMap; 580 UInt32 acells, icells, pacells, picells, cell; 581 UInt32 i, original_icells; 582 bool cmp, ok = false; 583 584 parent = IODTFindInterruptParent( regEntry, index ); 585 IODTGetICellCounts( parent, &icells, &acells ); 586 addrCmp = NULL; 587 if (acells) { 588 data = OSDynamicCast( OSData, regEntry->getProperty( "reg" )); 589 if (data && (data->getLength() >= (acells * sizeof(UInt32)))) { 590 addrCmp = (UInt32 *) data->getBytesNoCopy(); 591 } 592 } 593 original_icells = icells; 594 regEntry = parent; 595 596 do { 597 #if IODTSUPPORTDEBUG 598 kprintf("IODTMapOneInterrupt: current regEntry name %s\n", regEntry->getName()); 599 kprintf("acells - icells: "); 600 for (i = 0; i < acells; i++) { 601 kprintf("0x%08X ", addrCmp[i]); 602 } 603 kprintf("- "); 604 for (i = 0; i < icells; i++) { 605 kprintf("0x%08X ", intSpec[i]); 606 } 607 kprintf("\n"); 608 #endif 609 610 if (parent && (data = OSDynamicCast( OSData, 611 regEntry->getProperty( "interrupt-controller")))) { 612 // found a controller - don't want to follow cascaded controllers 613 parent = NULL; 614 *spec = OSData::withBytesNoCopy((void *) intSpec, 615 icells * sizeof(UInt32)); 616 *controller = IODTInterruptControllerName( regEntry ); 617 ok = (*spec && *controller); 618 } else if (parent && (data = OSDynamicCast( OSData, 619 regEntry->getProperty( "interrupt-map")))) { 620 // interrupt-map 621 map = (UInt32 *) data->getBytesNoCopy(); 622 endMap = map + (data->getLength() / sizeof(UInt32)); 623 data = OSDynamicCast( OSData, regEntry->getProperty( "interrupt-map-mask" )); 624 if (data && (data->getLength() >= ((acells + icells) * sizeof(UInt32)))) { 625 maskCmp = (UInt32 *) data->getBytesNoCopy(); 626 } else { 627 maskCmp = NULL; 628 } 629 630 #if IODTSUPPORTDEBUG 631 if (maskCmp) { 632 kprintf(" maskCmp: "); 633 for (i = 0; i < acells + icells; i++) { 634 if (i == acells) { 635 kprintf("- "); 636 } 637 kprintf("0x%08X ", maskCmp[i]); 638 } 639 kprintf("\n"); 640 kprintf(" masked: "); 641 for (i = 0; i < acells + icells; i++) { 642 if (i == acells) { 643 kprintf("- "); 644 } 645 kprintf("0x%08X ", ((i < acells) ? addrCmp[i] : intSpec[i - acells]) & maskCmp[i]); 646 } 647 kprintf("\n"); 648 } else { 649 kprintf("no maskCmp\n"); 650 } 651 #endif 652 do { 653 #if IODTSUPPORTDEBUG 654 kprintf(" map: "); 655 for (i = 0; i < acells + icells; i++) { 656 if (i == acells) { 657 kprintf("- "); 658 } 659 kprintf("0x%08X ", map[i]); 660 } 661 kprintf("\n"); 662 #endif 663 for (i = 0, cmp = true; cmp && (i < (acells + icells)); i++) { 664 cell = (i < acells) ? addrCmp[i] : intSpec[i - acells]; 665 if (maskCmp) { 666 cell &= maskCmp[i]; 667 } 668 cmp = (cell == map[i]); 669 } 670 671 map += acells + icells; 672 if (NULL == (parent = FindPHandle( *(map++)))) { 673 unexpected(break); 674 } 675 676 IODTGetICellCounts( parent, &picells, &pacells ); 677 if (cmp) { 678 addrCmp = map; 679 intSpec = map + pacells; 680 regEntry = parent; 681 } else { 682 map += pacells + picells; 683 } 684 } while (!cmp && (map < endMap)); 685 if (!cmp) { 686 parent = NULL; 687 } 688 } 689 690 if (parent) { 691 IODTGetICellCounts( parent, &icells, &acells ); 692 regEntry = parent; 693 } 694 } while (parent); 695 696 return ok ? original_icells : 0; 697 } 698 699 IOReturn 700 IODTGetInterruptOptions( IORegistryEntry * regEntry, int source, IOOptionBits * options ) 701 { 702 OSArray * controllers; 703 OSArray * specifiers; 704 OSArray * shared; 705 OSObject * spec; 706 OSObject * oneSpec; 707 708 *options = 0; 709 710 controllers = OSDynamicCast(OSArray, regEntry->getProperty(gIOInterruptControllersKey)); 711 specifiers = OSDynamicCast(OSArray, regEntry->getProperty(gIOInterruptSpecifiersKey)); 712 713 if (!controllers || !specifiers) { 714 return kIOReturnNoInterrupt; 715 } 716 717 shared = (OSArray *) gIODTSharedInterrupts->getObject( 718 (const OSSymbol *) controllers->getObject(source)); 719 if (!shared) { 720 return kIOReturnSuccess; 721 } 722 723 spec = specifiers->getObject(source); 724 if (!spec) { 725 return kIOReturnNoInterrupt; 726 } 727 728 for (unsigned int i = 0; 729 (oneSpec = shared->getObject(i)) 730 && (!oneSpec->isEqualTo(spec)); 731 i++) { 732 } 733 734 if (oneSpec) { 735 *options = kIODTInterruptShared; 736 } 737 738 return kIOReturnSuccess; 739 } 740 741 static bool 742 IODTMapInterruptsSharing( IORegistryEntry * regEntry, OSDictionary * allInts ) 743 { 744 IORegistryEntry * parent; 745 OSData * local; 746 OSData * local2; 747 UInt32 * localBits; 748 UInt32 * localEnd; 749 IOItemCount index; 750 OSData * map; 751 OSObject * oneMap; 752 OSArray * mapped; 753 OSArray * controllerInts; 754 const OSSymbol * controller = NULL; 755 OSArray * controllers; 756 UInt32 skip = 1; 757 bool ok, nw; 758 759 nw = (NULL == (local = OSDynamicCast( OSData, 760 regEntry->getProperty( gIODTAAPLInterruptsKey)))); 761 if (nw && (NULL == (local = OSDynamicCast( OSData, 762 regEntry->getProperty( "interrupts"))))) { 763 return true; // nothing to see here 764 } 765 if (nw && (parent = regEntry->getParentEntry( gIODTPlane))) { 766 // check for bridges on old world 767 if ((local2 = OSDynamicCast( OSData, 768 parent->getProperty( gIODTAAPLInterruptsKey)))) { 769 local = local2; 770 nw = false; 771 } 772 } 773 774 localBits = (UInt32 *) local->getBytesNoCopy(); 775 localEnd = localBits + (local->getLength() / sizeof(UInt32)); 776 index = 0; 777 mapped = OSArray::withCapacity( 1 ); 778 controllers = OSArray::withCapacity( 1 ); 779 780 ok = (mapped && controllers); 781 782 if (ok) { 783 do { 784 if (nw) { 785 skip = IODTMapOneInterrupt( regEntry, localBits, index, &map, &controller ); 786 if (0 == skip) { 787 IOLog("%s: error mapping interrupt[%d]\n", 788 regEntry->getName(), mapped->getCount()); 789 break; 790 } 791 } else { 792 map = OSData::withData( local, mapped->getCount() * sizeof(UInt32), 793 sizeof(UInt32)); 794 controller = gIODTDefaultInterruptController; 795 controller->retain(); 796 } 797 798 index++; 799 localBits += skip; 800 mapped->setObject( map ); 801 controllers->setObject( controller ); 802 803 if (allInts) { 804 controllerInts = (OSArray *) allInts->getObject( controller ); 805 if (controllerInts) { 806 for (unsigned int i = 0; (oneMap = controllerInts->getObject(i)); i++) { 807 if (map->isEqualTo(oneMap)) { 808 controllerInts = (OSArray *) gIODTSharedInterrupts->getObject( controller ); 809 if (controllerInts) { 810 controllerInts->setObject(map); 811 } else { 812 controllerInts = OSArray::withObjects((const OSObject **) &map, 1, 4 ); 813 if (controllerInts) { 814 gIODTSharedInterrupts->setObject( controller, controllerInts ); 815 controllerInts->release(); 816 } 817 } 818 break; 819 } 820 } 821 if (!oneMap) { 822 controllerInts->setObject(map); 823 } 824 } else { 825 controllerInts = OSArray::withObjects((const OSObject **) &map, 1, 16 ); 826 if (controllerInts) { 827 allInts->setObject( controller, controllerInts ); 828 controllerInts->release(); 829 } 830 } 831 } 832 833 map->release(); 834 controller->release(); 835 } while (localBits < localEnd); 836 } 837 838 ok &= (localBits == localEnd); 839 840 if (ok) { 841 // store results 842 ok = regEntry->setProperty( gIOInterruptControllersKey, controllers); 843 ok &= regEntry->setProperty( gIOInterruptSpecifiersKey, mapped); 844 } 845 846 if (controllers) { 847 controllers->release(); 848 } 849 if (mapped) { 850 mapped->release(); 851 } 852 853 return ok; 854 } 855 856 bool 857 IODTMapInterrupts( IORegistryEntry * regEntry ) 858 { 859 return IODTMapInterruptsSharing( regEntry, NULL ); 860 } 861 862 /* 863 */ 864 865 static bool 866 CompareKey( OSString * key, 867 const IORegistryEntry * table, const OSSymbol * propName, 868 LIBKERN_RETURNS_RETAINED OSString ** matchingName ) 869 { 870 OSObject *prop; 871 OSData *data; 872 OSString *string; 873 const char *ckey; 874 UInt32 keyLen; 875 UInt32 nlen; 876 const char *names; 877 const char *lastName; 878 bool wild; 879 bool matched; 880 const char *result = NULL; 881 882 if (NULL == (prop = table->copyProperty( propName ))) { 883 return 0; 884 } 885 886 if ((data = OSDynamicCast( OSData, prop ))) { 887 names = (const char *) data->getBytesNoCopy(); 888 lastName = names + data->getLength(); 889 } else if ((string = OSDynamicCast( OSString, prop ))) { 890 names = string->getCStringNoCopy(); 891 lastName = names + string->getLength() + 1; 892 } else { 893 names = NULL; 894 } 895 896 if (names) { 897 ckey = key->getCStringNoCopy(); 898 keyLen = key->getLength(); 899 wild = ('*' == key->getChar( keyLen - 1 )); 900 901 do { 902 // for each name in the property 903 nlen = (unsigned int) strnlen(names, lastName - names); 904 if (wild) { 905 matched = ((nlen >= (keyLen - 1)) && (0 == strncmp(ckey, names, keyLen - 1))); 906 } else { 907 matched = (keyLen == nlen) && (0 == strncmp(ckey, names, keyLen)); 908 } 909 910 if (matched) { 911 result = names; 912 } 913 914 names = names + nlen + 1; 915 } while ((names < lastName) && (false == matched)); 916 } 917 918 if (result && matchingName) { 919 *matchingName = OSString::withCString( result ); 920 } 921 922 if (prop) { 923 prop->release(); 924 } 925 926 return result != NULL; 927 } 928 929 930 bool 931 IODTCompareNubName( const IORegistryEntry * regEntry, 932 OSString * name, OSString ** matchingName ) 933 { 934 bool matched; 935 936 matched = CompareKey( name, regEntry, gIODTNameKey, matchingName) 937 || CompareKey( name, regEntry, gIODTCompatibleKey, matchingName) 938 || CompareKey( name, regEntry, gIODTTypeKey, matchingName) 939 || CompareKey( name, regEntry, gIODTModelKey, matchingName); 940 941 return matched; 942 } 943 944 bool 945 IODTCompareNubName( const IORegistryEntry * regEntry, 946 OSString * name, OSSharedPtr<OSString>& matchingName ) 947 { 948 OSString* matchingNameRaw = NULL; 949 bool result = IODTCompareNubName(regEntry, name, &matchingNameRaw); 950 matchingName.reset(matchingNameRaw, OSNoRetain); 951 return result; 952 } 953 954 bool 955 IODTMatchNubWithKeys( IORegistryEntry * regEntry, 956 const char * keys ) 957 { 958 OSObject *obj; 959 bool result = false; 960 961 obj = OSUnserialize( keys, NULL ); 962 963 if (obj) { 964 result = regEntry->compareNames( obj ); 965 obj->release(); 966 } 967 #if DEBUG 968 else { 969 IOLog("Couldn't unserialize %s\n", keys ); 970 } 971 #endif 972 973 return result; 974 } 975 976 OSCollectionIterator * 977 IODTFindMatchingEntries( IORegistryEntry * from, 978 IOOptionBits options, const char * keys ) 979 { 980 OSSet *result = NULL; 981 IORegistryEntry *next; 982 IORegistryIterator *iter; 983 OSCollectionIterator *cIter; 984 bool cmp; 985 bool minus = options & kIODTExclusive; 986 987 988 iter = IORegistryIterator::iterateOver( from, gIODTPlane, 989 (options & kIODTRecursive) ? kIORegistryIterateRecursively : 0 ); 990 if (iter) { 991 do { 992 if (result) { 993 result->release(); 994 } 995 result = OSSet::withCapacity( 3 ); 996 if (!result) { 997 break; 998 } 999 1000 iter->reset(); 1001 while ((next = iter->getNextObject())) { 1002 // Look for existence of a debug property to skip 1003 if (next->getProperty("AAPL,ignore")) { 1004 continue; 1005 } 1006 1007 if (keys) { 1008 cmp = IODTMatchNubWithKeys( next, keys ); 1009 if ((minus && (false == cmp)) 1010 || ((false == minus) && (false != cmp))) { 1011 result->setObject( next); 1012 } 1013 } else { 1014 result->setObject( next); 1015 } 1016 } 1017 } while (!iter->isValid()); 1018 1019 iter->release(); 1020 } 1021 1022 cIter = OSCollectionIterator::withCollection( result); 1023 if (result) { 1024 result->release(); 1025 } 1026 1027 return cIter; 1028 } 1029 1030 1031 struct IODTPersistent { 1032 IODTCompareAddressCellFunc compareFunc; 1033 }; 1034 1035 void 1036 IODTSetResolving( IORegistryEntry * regEntry, 1037 IODTCompareAddressCellFunc compareFunc, 1038 IODTNVLocationFunc locationFunc __unused ) 1039 { 1040 IODTPersistent persist; 1041 IODTPersistent * entry; 1042 OSNumber * num; 1043 unsigned int index, count; 1044 1045 IOLockLock(gIODTResolversLock); 1046 1047 count = (gIODTResolvers->getLength() / sizeof(IODTPersistent)); 1048 entry = (typeof(entry))gIODTResolvers->getBytesNoCopy(); 1049 for (index = 0; index < count; index++) { 1050 if (compareFunc == entry->compareFunc) { 1051 break; 1052 } 1053 entry++; 1054 } 1055 if (index == count) { 1056 persist.compareFunc = compareFunc; 1057 if (!gIODTResolvers->appendBytes(&persist, sizeof(IODTPersistent))) { 1058 panic("IODTSetResolving"); 1059 } 1060 } 1061 1062 IOLockUnlock(gIODTResolversLock); 1063 1064 num = OSNumber::withNumber(index, 32); 1065 regEntry->setProperty(gIODTPersistKey, num); 1066 OSSafeReleaseNULL(num); 1067 1068 return; 1069 } 1070 1071 #if defined(__arm64__) 1072 static SInt64 1073 DefaultCompare( UInt32 cellCount, UInt32 left[], UInt32 right[] ) 1074 { 1075 SInt64 diff = 0; 1076 1077 if (cellCount == 2) { 1078 diff = IOPhysical32(left[1], left[0]) - IOPhysical32(right[1], right[0]); 1079 } else if (cellCount == 1) { 1080 diff = (left[0] - right[0]); 1081 } else { 1082 panic("DefaultCompare only knows how to handle 1 or 2 cells."); 1083 } 1084 1085 return diff; 1086 } 1087 #elif defined(__arm__) || defined(__i386__) || defined(__x86_64__) 1088 static SInt32 1089 DefaultCompare( UInt32 cellCount, UInt32 left[], UInt32 right[] ) 1090 { 1091 cellCount--; 1092 return left[cellCount] - right[cellCount]; 1093 } 1094 #else 1095 #error Unknown architecture. 1096 #endif 1097 1098 static void 1099 AddLengthToCells( UInt32 numCells, UInt32 *cells, UInt64 offset) 1100 { 1101 if (numCells == 1) { 1102 cells[0] += (UInt32)offset; 1103 } else { 1104 #if defined(__arm64__) || defined(__arm__) 1105 UInt64 sum = cells[numCells - 2] + offset; 1106 cells[numCells - 2] = (UInt32)sum; 1107 if (sum > UINT32_MAX) { 1108 cells[numCells - 1] += (UInt32)(sum >> 32); 1109 } 1110 #else 1111 UInt64 sum = cells[numCells - 1] + offset; 1112 cells[numCells - 1] = (UInt32)sum; 1113 if (sum > UINT32_MAX) { 1114 cells[numCells - 2] += (UInt32)(sum >> 32); 1115 } 1116 #endif 1117 } 1118 } 1119 1120 static IOPhysicalAddress 1121 CellsValue( UInt32 numCells, UInt32 *cells) 1122 { 1123 if (numCells == 1) { 1124 return IOPhysical32( 0, cells[0] ); 1125 } else { 1126 #if defined(__arm64__) || defined(arm) 1127 return IOPhysical32( cells[numCells - 1], cells[numCells - 2] ); 1128 #else 1129 return IOPhysical32( cells[numCells - 2], cells[numCells - 1] ); 1130 #endif 1131 } 1132 } 1133 1134 void 1135 IODTGetCellCounts( IORegistryEntry * regEntry, 1136 UInt32 * sizeCount, UInt32 * addressCount) 1137 { 1138 if (!GetUInt32( regEntry, gIODTSizeCellKey, sizeCount)) { 1139 *sizeCount = 1; 1140 } 1141 if (!GetUInt32( regEntry, gIODTAddressCellKey, addressCount)) { 1142 *addressCount = 2; 1143 } 1144 return; 1145 } 1146 1147 // Given addr & len cells from our child, find it in our ranges property, then 1148 // look in our parent to resolve the base of the range for us. 1149 1150 // Range[]: child-addr our-addr child-len 1151 // #cells: child ours child 1152 1153 bool 1154 IODTResolveAddressCell( IORegistryEntry * startEntry, 1155 UInt32 cellsIn[], 1156 IOPhysicalAddress * phys, IOPhysicalLength * lenOut ) 1157 { 1158 IORegistryEntry * parent; 1159 IORegistryEntry * regEntry; 1160 OSData * prop; 1161 OSNumber * num; 1162 unsigned int index, count; 1163 // cells in addresses at regEntry 1164 UInt32 sizeCells, addressCells; 1165 // cells in addresses below regEntry 1166 UInt32 childSizeCells, childAddressCells; 1167 UInt32 childCells; 1168 UInt32 cell[8], propLen; 1169 UInt64 offset = 0; 1170 UInt32 endCell[8]; 1171 UInt32 *range; 1172 UInt32 *lookRange; 1173 UInt32 *startRange; 1174 UInt32 *endRanges; 1175 bool ok = true; 1176 SInt64 diff, diff2, endDiff; 1177 UInt64 len, rangeLen; 1178 1179 IODTPersistent *persist; 1180 IODTCompareAddressCellFunc compare; 1181 1182 regEntry = startEntry; 1183 IODTGetCellCounts( regEntry, &childSizeCells, &childAddressCells ); 1184 childCells = childAddressCells + childSizeCells; 1185 1186 if (childCells > sizeof(cell) / sizeof(cell[0])) { 1187 panic("IODTResolveAddressCell: Invalid device tree (%u,%u)", (uint32_t)childAddressCells, (uint32_t)childSizeCells); 1188 } 1189 1190 bcopy( cellsIn, cell, sizeof(UInt32) * childCells ); 1191 *lenOut = CellsValue( childSizeCells, cellsIn + childAddressCells ); 1192 1193 do{ 1194 prop = OSDynamicCast( OSData, regEntry->getProperty( gIODTRangeKey )); 1195 if (NULL == prop) { 1196 /* end of the road */ 1197 *phys = CellsValue( childAddressCells, cell ); 1198 *phys += offset; 1199 if (regEntry != startEntry) { 1200 regEntry->release(); 1201 } 1202 break; 1203 } 1204 1205 parent = regEntry->copyParentEntry( gIODTPlane ); 1206 IODTGetCellCounts( parent, &sizeCells, &addressCells ); 1207 1208 if ((propLen = prop->getLength())) { 1209 // search 1210 startRange = (UInt32 *) prop->getBytesNoCopy(); 1211 range = startRange; 1212 endRanges = range + (propLen / sizeof(UInt32)); 1213 1214 compare = NULL; 1215 num = OSDynamicCast(OSNumber, regEntry->getProperty(gIODTPersistKey)); 1216 if (num) { 1217 IOLockLock(gIODTResolversLock); 1218 index = num->unsigned32BitValue(); 1219 count = gIODTResolvers->getLength() / sizeof(IODTPersistent); 1220 if (index < count) { 1221 persist = ((IODTPersistent *) gIODTResolvers->getBytesNoCopy()) + index; 1222 compare = persist->compareFunc; 1223 } 1224 IOLockUnlock(gIODTResolversLock); 1225 } 1226 1227 if (!compare && (addressCells == childAddressCells)) { 1228 compare = DefaultCompare; 1229 } 1230 if (!compare) { 1231 panic("There is no mixed comparison function yet..."); 1232 } 1233 1234 for (ok = false; 1235 range < endRanges; 1236 range += (childCells + addressCells)) { 1237 // is cell start within range? 1238 diff = (*compare)( childAddressCells, cell, range ); 1239 1240 if (childAddressCells > sizeof(endCell) / sizeof(endCell[0])) { 1241 panic("IODTResolveAddressCell: Invalid device tree (%u)", (uint32_t)childAddressCells); 1242 } 1243 1244 bcopy(range, endCell, childAddressCells * sizeof(UInt32)); 1245 1246 rangeLen = CellsValue(childSizeCells, range + childAddressCells + addressCells); 1247 AddLengthToCells(childAddressCells, endCell, rangeLen); 1248 1249 diff2 = (*compare)( childAddressCells, cell, endCell ); 1250 1251 // if start of cell < start of range, or end of range >= start of cell, skip 1252 if ((diff < 0) || (diff2 >= 0)) { 1253 continue; 1254 } 1255 1256 len = CellsValue(childSizeCells, cell + childAddressCells); 1257 ok = (0 == len); 1258 1259 if (!ok) { 1260 // search for cell end 1261 bcopy(cell, endCell, childAddressCells * sizeof(UInt32)); 1262 1263 AddLengthToCells(childAddressCells, endCell, len - 1); 1264 1265 for (lookRange = startRange; 1266 lookRange < endRanges; 1267 lookRange += (childCells + addressCells)) { 1268 // make sure end of cell >= range start 1269 endDiff = (*compare)( childAddressCells, endCell, lookRange ); 1270 if (endDiff < 0) { 1271 continue; 1272 } 1273 1274 UInt64 rangeStart = CellsValue(addressCells, range + childAddressCells); 1275 UInt64 lookRangeStart = CellsValue(addressCells, lookRange + childAddressCells); 1276 if ((endDiff - len + 1 + lookRangeStart) == (diff + rangeStart)) { 1277 ok = true; 1278 break; 1279 } 1280 } 1281 if (!ok) { 1282 continue; 1283 } 1284 } 1285 offset += diff; 1286 break; 1287 } 1288 1289 if (addressCells + sizeCells > sizeof(cell) / sizeof(cell[0])) { 1290 panic("IODTResolveAddressCell: Invalid device tree (%u, %u)", (uint32_t)addressCells, (uint32_t)sizeCells); 1291 } 1292 1293 // Get the physical start of the range from our parent 1294 bcopy( range + childAddressCells, cell, sizeof(UInt32) * addressCells ); 1295 bzero( cell + addressCells, sizeof(UInt32) * sizeCells ); 1296 } /* else zero length range => pass thru to parent */ 1297 1298 if (regEntry != startEntry) { 1299 regEntry->release(); 1300 } 1301 regEntry = parent; 1302 childSizeCells = sizeCells; 1303 childAddressCells = addressCells; 1304 childCells = childAddressCells + childSizeCells; 1305 }while (ok && regEntry); 1306 1307 return ok; 1308 } 1309 1310 1311 OSArray * 1312 IODTResolveAddressing( IORegistryEntry * regEntry, 1313 const char * addressPropertyName, 1314 IODeviceMemory * parent ) 1315 { 1316 IORegistryEntry *parentEntry; 1317 OSData *addressProperty; 1318 UInt32 sizeCells, addressCells, cells; 1319 int i, num; 1320 UInt32 *reg; 1321 IOPhysicalAddress phys; 1322 IOPhysicalLength len; 1323 OSArray *array; 1324 IODeviceMemory *range; 1325 1326 array = NULL; 1327 do{ 1328 parentEntry = regEntry->copyParentEntry( gIODTPlane ); 1329 addressProperty = (OSData *) regEntry->getProperty( addressPropertyName ); 1330 if ((NULL == addressProperty) || (NULL == parentEntry)) { 1331 break; 1332 } 1333 1334 IODTGetCellCounts( parentEntry, &sizeCells, &addressCells ); 1335 if (0 == sizeCells) { 1336 break; 1337 } 1338 1339 cells = sizeCells + addressCells; 1340 reg = (UInt32 *) addressProperty->getBytesNoCopy(); 1341 num = addressProperty->getLength() / (4 * cells); 1342 1343 array = OSArray::withCapacity( 1 ); 1344 if (NULL == array) { 1345 break; 1346 } 1347 1348 for (i = 0; i < num; i++) { 1349 if (IODTResolveAddressCell( parentEntry, reg, &phys, &len )) { 1350 range = NULL; 1351 if (parent) { 1352 range = IODeviceMemory::withSubRange( parent, 1353 phys - parent->getPhysicalSegment(0, NULL, kIOMemoryMapperNone), len ); 1354 } 1355 if (NULL == range) { 1356 range = IODeviceMemory::withRange( phys, len ); 1357 } 1358 if (range) { 1359 array->setObject( range ); 1360 } 1361 } 1362 reg += cells; 1363 } 1364 1365 regEntry->setProperty( gIODeviceMemoryKey, array); 1366 array->release(); /* ??? */ 1367 }while (false); 1368 1369 OSSafeReleaseNULL(parentEntry); 1370 1371 return array; 1372 } 1373 1374 OSData * 1375 IODTFindSlotName( IORegistryEntry * regEntry, UInt32 deviceNumber ) 1376 { 1377 IORegistryEntry *parent; 1378 OSData *data; 1379 OSData *ret = NULL; 1380 UInt32 *bits; 1381 UInt32 i; 1382 UInt32 nlen; 1383 char *names; 1384 char *lastName; 1385 UInt32 mask; 1386 1387 data = (OSData *) regEntry->getProperty("AAPL,slot-name"); 1388 if (data) { 1389 return data; 1390 } 1391 1392 do{ 1393 parent = regEntry->copyParentEntry( gIODTPlane ); 1394 if (!parent) { 1395 break; 1396 } 1397 1398 data = OSDynamicCast( OSData, parent->getProperty("slot-names")); 1399 if (!data) { 1400 break; 1401 } 1402 if (data->getLength() <= 4) { 1403 break; 1404 } 1405 1406 bits = (UInt32 *) data->getBytesNoCopy(); 1407 mask = *bits; 1408 if ((0 == (mask & (1 << deviceNumber)))) { 1409 break; 1410 } 1411 1412 names = (char *)(bits + 1); 1413 lastName = names + (data->getLength() - 4); 1414 1415 for (i = 0; (i <= deviceNumber) && (names < lastName); i++) { 1416 if (mask & (1 << i)) { 1417 nlen = 1 + ((unsigned int) strnlen(names, lastName - names)); 1418 if (i == deviceNumber) { 1419 data = OSData::withBytesNoCopy(names, nlen); 1420 if (data) { 1421 regEntry->setProperty("AAPL,slot-name", data); 1422 ret = data; 1423 data->release(); 1424 } 1425 } else { 1426 names += nlen; 1427 } 1428 } 1429 } 1430 }while (false); 1431 1432 OSSafeReleaseNULL(parent); 1433 1434 return ret; 1435 } 1436 1437 extern "C" IOReturn 1438 IONDRVLibrariesInitialize( IOService * provider ) 1439 { 1440 return kIOReturnUnsupported; 1441 } 1442