1/* 2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * The contents of this file constitute Original Code as defined in and 7 * are subject to the Apple Public Source License Version 1.1 (the 8 * "License"). You may not use this file except in compliance with the 9 * License. Please obtain a copy of the License at 10 * http://www.apple.com/publicsource and read it before using this file. 11 * 12 * This Original Code and all software distributed under the License are 13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 17 * License for the specific language governing rights and limitations 18 * under the License. 19 * 20 * @APPLE_LICENSE_HEADER_END@ 21 */ 22 23#include <IOKit/IOLib.h> 24#include <libkern/c++/OSContainers.h> 25#include <IOKit/IODeviceTreeSupport.h> 26#include <IOKit/IOPlatformExpert.h> 27#include <IOKit/pci/IOPCIDevice.h> 28#include <IOKit/IOHibernatePrivate.h> 29 30#include "IONDRV.h" 31 32#include <IOKit/ndrvsupport/IONDRVFramebuffer.h> 33#include <IOKit/ndrvsupport/IONDRVSupport.h> 34#include <IOKit/ndrvsupport/IONDRVLibraries.h> 35#include <IOKit/graphics/IOGraphicsPrivate.h> 36 37#include <IOKit/assert.h> 38 39#include <pexpert/pexpert.h> 40#include <string.h> 41 42extern "C" 43{ 44#include <kern/debug.h> 45 46extern void *kern_os_malloc(size_t size); 47extern void kern_os_free(void * addr); 48 49#define LOG if(1) IOLog 50#define LOGNAMEREG 0 51 52#define CHECK_INTERRUPT(s) \ 53if( ml_at_interrupt_context()) { \ 54 /* IOLog("interrupt:%s(%s)\n", __FUNCTION__, s); */ \ 55 return( nrLockedErr ); \ 56} 57 58extern "C" IOReturn _IONDRVLibrariesMappingInitialize( IOService * provider ); 59 60/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 61 62//#define EXP(s) _e ## s 63#define EXP(s) s 64 65 66/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 67 68OSStatus EXP(RegistryEntryIDCopy)( const RegEntryID * entryID, RegEntryID * to ) 69{ 70 bcopy( entryID, to, sizeof( RegEntryID) ); 71 return (noErr); 72} 73 74OSStatus EXP(RegistryEntryIDInit)( RegEntryID * entryID ) 75{ 76 MAKE_REG_ENTRY( entryID, 0); 77 return (noErr); 78} 79 80OSStatus EXP(RegistryEntryIDDispose) 81 (RegEntryID * entryID) 82{ 83 return (noErr); 84} 85 86/* 87 * Compare EntryID's for equality or if invalid 88 * 89 * If a NULL value is given for either id1 or id2, the other id 90 * is compared with an invalid ID. If both are NULL, the id's 91 * are consided equal (result = true). 92 * note: invalid != uninitialized 93 */ 94Boolean EXP(RegistryEntryIDCompare)( const RegEntryID * entryID1, const RegEntryID * entryID2 ) 95{ 96 IORegistryEntry * regEntry1; 97 IORegistryEntry * regEntry2; 98 99 if (entryID1) 100 { 101 REG_ENTRY_TO_OBJ_RET( entryID1, regEntry1, false) 102 } 103 else 104 regEntry1 = 0; 105 106 if (entryID2) 107 { 108 REG_ENTRY_TO_OBJ_RET( entryID2, regEntry2, false) 109 } 110 else 111 regEntry2 = 0; 112 113 return (regEntry1 == regEntry2); 114} 115 116OSStatus EXP(RegistryPropertyGetSize)( const RegEntryID * entryID, 117 const RegPropertyName * propertyName, 118 RegPropertyValueSize * propertySize ) 119{ 120 OSStatus err = noErr; 121 OSData * prop; 122 123 CHECK_INTERRUPT(propertyName) 124 REG_ENTRY_TO_PT( entryID, regEntry) 125 126 if (!strcmp(kPropertyAAPLAddress, propertyName)) 127 _IONDRVLibrariesMappingInitialize((IOService *) regEntry); 128 129 prop = OSDynamicCast( OSData, regEntry->getProperty( propertyName)); 130 if (prop) 131 *propertySize = prop->getLength(); 132 else 133 err = nrNotFoundErr; 134 135#if LOGNAMEREG 136 LOG("RegistryPropertyGetSize: %s : %d\n", propertyName, err); 137#endif 138 return (err); 139} 140 141OSStatus EXP(RegistryPropertyGet)(const RegEntryID * entryID, 142 const RegPropertyName * propertyName, void *propertyValue, 143 RegPropertyValueSize * propertySize) 144{ 145 OSStatus err = noErr; 146 OSData * prop; 147 UInt32 len; 148 149 CHECK_INTERRUPT(propertyName) 150 REG_ENTRY_TO_PT( entryID, regEntry) 151 152 if (!strcmp(kPropertyAAPLAddress, propertyName)) 153 _IONDRVLibrariesMappingInitialize((IOService *) regEntry); 154 155 prop = OSDynamicCast( OSData, regEntry->getProperty( propertyName)); 156 if (prop) 157 { 158 len = *propertySize; 159 *propertySize = prop->getLength(); 160 len = (len > prop->getLength()) ? prop->getLength() : len; 161 bcopy( prop->getBytesNoCopy(), propertyValue, len); 162#if LOGNAMEREG 163 LOG("value: %08x ", *propertyValue); 164#endif 165 166 } 167 else 168 err = nrNotFoundErr; 169 170#if LOGNAMEREG 171 LOG("RegistryPropertyGet: %s : %d\n", propertyName, err); 172#endif 173 return (err); 174} 175 176OSStatus EXP(RegistryPropertyCreate)( const RegEntryID * entryID, const RegPropertyName * propertyName, 177 const void * propertyValue, RegPropertyValueSize propertySize ) 178{ 179 OSStatus err = noErr; 180 OSData * prop; 181 182 CHECK_INTERRUPT(propertyName) 183 REG_ENTRY_TO_PT( entryID, regEntry) 184 185 prop = OSData::withBytes( propertyValue, propertySize ); 186 187 if (prop) 188 { 189 regEntry->setProperty( propertyName, prop); 190 prop->release(); 191 } 192 else 193 err = nrNotCreatedErr; 194 195#if LOGNAMEREG 196 LOG("RegistryPropertyCreate: %s : %d\n", propertyName, err); 197#endif 198 return (err); 199} 200 201OSStatus EXP(RegistryPropertyDelete)( const RegEntryID * entryID, const RegPropertyName * propertyName ) 202{ 203 OSStatus err = noErr; 204 OSObject * old; 205 206 CHECK_INTERRUPT(propertyName) 207 REG_ENTRY_TO_PT( entryID, regEntry) 208 209 old = regEntry->getProperty(propertyName); 210 if (old) 211 regEntry->removeProperty(propertyName); 212 else 213 err = nrNotFoundErr; 214 215#if LOGNAMEREG 216 LOG("RegistryPropertyDelete: %s : %d\n", propertyName, err); 217#endif 218 return (err); 219} 220 221void IONDRVSetNVRAMPropertyName( IORegistryEntry * regEntry, 222 const OSSymbol * sym ) 223{ 224 regEntry->setProperty( "IONVRAMProperty", /*(OSObject *)*/ sym ); 225} 226 227static IOReturn IONDRVSetNVRAMPropertyValue( IORegistryEntry * regEntry, 228 const OSSymbol * name, OSData * value ) 229{ 230 IOReturn err; 231 IODTPlatformExpert * platform; 232 233 if ((platform = OSDynamicCast(IODTPlatformExpert, 234 IOService::getPlatform()))) 235 err = platform->writeNVRAMProperty( regEntry, name, value ); 236 else 237 err = kIOReturnUnsupported; 238 239 return (err); 240} 241 242OSStatus EXP(RegistryPropertySet)( const RegEntryID * entryID, 243 const RegPropertyName * propertyName, 244 const void * propertyValue, RegPropertyValueSize propertySize ) 245{ 246 OSStatus err = noErr; 247 OSData * prop; 248 const OSSymbol * sym; 249 250 CHECK_INTERRUPT(propertyName) 251 REG_ENTRY_TO_PT( entryID, regEntry) 252 253 sym = OSSymbol::withCString( propertyName ); 254 if (!sym) 255 return (kIOReturnNoMemory); 256 257 prop = OSDynamicCast( OSData, regEntry->getProperty( sym )); 258 if (0 == prop) 259 err = nrNotFoundErr; 260 261 else if ((prop = OSData::withBytes(propertyValue, propertySize))) 262 { 263 regEntry->setProperty( sym, prop); 264 265 if (sym == (const OSSymbol *) 266 regEntry->getProperty("IONVRAMProperty")) 267 err = IONDRVSetNVRAMPropertyValue( regEntry, sym, prop ); 268 prop->release(); 269 } 270 else 271 err = nrNotCreatedErr; 272 273 sym->release(); 274 275#if LOGNAMEREG 276 LOG("RegistryPropertySet: %s : %d\n", propertyName, err); 277#endif 278 return (err); 279} 280 281OSStatus EXP(RegistryPropertyGetMod)(const RegEntryID * entryID, 282 const RegPropertyName * propertyName, 283 RegPropertyModifiers * mod) 284{ 285 const OSSymbol * sym; 286 287 CHECK_INTERRUPT(propertyName) 288 REG_ENTRY_TO_PT( entryID, regEntry) 289 290 if ((sym = OSDynamicCast(OSSymbol, 291 regEntry->getProperty("IONVRAMProperty"))) 292 && (0 == strcmp(propertyName, sym->getCStringNoCopy()))) 293 294 *mod = kNVRAMProperty; 295 else 296 *mod = 0; 297 298 return (noErr); 299} 300 301OSStatus EXP(RegistryPropertySetMod)(const RegEntryID * entryID, 302 const RegPropertyName * propertyName, 303 RegPropertyModifiers mod ) 304{ 305 OSStatus err = noErr; 306 OSData * data; 307 const OSSymbol * sym; 308 309 CHECK_INTERRUPT(propertyName) 310 REG_ENTRY_TO_PT( entryID, regEntry) 311 312 if ((mod & kNVRAMProperty) 313 && (sym = OSSymbol::withCString(propertyName))) 314 { 315 if ((data = OSDynamicCast(OSData, regEntry->getProperty(sym)))) 316 { 317 err = IONDRVSetNVRAMPropertyValue( regEntry, sym, data ); 318 if (kIOReturnSuccess == err) 319 IONDRVSetNVRAMPropertyName( regEntry, sym ); 320 } 321 sym->release(); 322 } 323 324 return (err); 325} 326 327OSStatus EXP(RegistryPropertyIterateCreate)( const RegEntryID * entryID, 328 OSIterator ** cookie) 329{ 330 CHECK_INTERRUPT("") 331 REG_ENTRY_TO_PT( entryID, regEntry) 332 333 // NB. unsynchronized. But should only happen on an owned nub! 334 // Should non OSData be filtered out? 335 336 OSDictionary * dict = regEntry->dictionaryWithProperties(); 337 *cookie = OSCollectionIterator::withCollection(dict); 338 if (dict) 339 dict->release(); 340 341 if (*cookie) 342 return (noErr); 343 else 344 return (nrNotEnoughMemoryErr); 345} 346 347OSStatus EXP(RegistryPropertyIterateDispose)( OSIterator ** cookie) 348{ 349 if (*cookie) 350 { 351 (*cookie)->release(); 352 *cookie = NULL; 353 return (noErr); 354 } 355 else 356 return (nrIterationDone); 357} 358 359OSStatus EXP(RegistryPropertyIterate)( OSIterator ** cookie, 360 char * name, Boolean * done ) 361{ 362 const OSSymbol * key; 363 364 key = (const OSSymbol *) (*cookie)->getNextObject(); 365 if (key) 366 strncpy( name, key->getCStringNoCopy(), kRegMaximumPropertyNameLength); 367 368 // Seems to be differences in handling "done". 369 // ATI assumes done = true when getting the last property. 370 // The Book says done is true after last property. 371 // ATI does check err, so this will work. 372 // Control ignores err and checks done. 373 374 *done = (key == 0); 375 376 if (0 != key) 377 return (noErr); 378 else 379 return (nrIterationDone); 380} 381 382OSStatus 383EXP(RegistryEntryIterateCreate)( IORegistryIterator ** cookie) 384{ 385 *cookie = IORegistryIterator::iterateOver( gIODTPlane ); 386 if (*cookie) 387 return (noErr); 388 else 389 return (nrNotEnoughMemoryErr); 390} 391 392OSStatus 393EXP(RegistryEntryIterateDispose)( IORegistryIterator ** cookie) 394{ 395 if (*cookie) 396 { 397 (*cookie)->release(); 398 *cookie = NULL; 399 return (noErr); 400 } 401 else 402 return (nrIterationDone); 403} 404 405OSStatus 406EXP(RegistryEntryIterate)( IORegistryIterator ** cookie, 407 UInt32 /* relationship */, 408 RegEntryID * foundEntry, 409 Boolean * done) 410{ 411 IORegistryEntry * regEntry; 412 413 // TODO: check requested type of iteration 414 regEntry = (*cookie)->getNextObjectRecursive(); 415 416 MAKE_REG_ENTRY( foundEntry, regEntry); 417 *done = (0 == regEntry); 418 419#if LOGNAMEREG 420 if (regEntry) 421 LOG("RegistryEntryIterate: %s\n", regEntry->getName( gIODTPlane )); 422#endif 423 424 if (regEntry) 425 return (noErr); 426 else 427 return (nrNotFoundErr); 428} 429 430OSStatus 431EXP(RegistryCStrEntryToName)( const RegEntryID * entryID, 432 RegEntryID * parentEntry, 433 char * nameComponent, 434 Boolean * done ) 435{ 436 IORegistryEntry * regEntry; 437 438 REG_ENTRY_TO_OBJ( entryID, regEntry) 439 440 strncpy( nameComponent, regEntry->getName( gIODTPlane ), kRegMaximumPropertyNameLength ); 441 nameComponent[ kRegMaximumPropertyNameLength ] = 0; 442 443 regEntry = regEntry->getParentEntry( gIODTPlane ); 444 if (regEntry) 445 { 446 MAKE_REG_ENTRY( parentEntry, regEntry); 447 *done = false; 448 } 449 else 450 *done = true; 451 452 return (noErr); 453} 454 455OSStatus 456EXP(RegistryCStrEntryLookup)( const RegEntryID * parentEntry, 457 const RegCStrPathName * path, 458 RegEntryID * newEntry) 459{ 460 IOReturn err; 461 IORegistryEntry * regEntry = 0; 462 char * buf; 463 char * cvtPath; 464 char c; 465#define kDTRoot "Devices:device-tree:" 466#define kMacIORoot "Devices:device-tree:pci:mac-io:" 467 468 if (parentEntry) 469 { 470 REG_ENTRY_TO_OBJ( parentEntry, regEntry) 471 } 472 else 473 regEntry = 0; 474 475 buf = IONew( char, 512 ); 476 if (!buf) 477 return (nrNotEnoughMemoryErr); 478 479 cvtPath = buf; 480 if (':' == path[0]) 481 path++; 482 else if (0 == strncmp(path, kMacIORoot, strlen(kMacIORoot))) 483 { 484 path += strlen( kMacIORoot ) - 7; 485 regEntry = 0; 486 } 487 else if (0 == strncmp(path, kDTRoot, strlen(kDTRoot))) 488 { 489 path += strlen( kDTRoot ) - 1; 490 regEntry = 0; 491 } 492 493 do 494 { 495 c = *(path++); 496 if (':' == c) 497 c = '/'; 498 *(cvtPath++) = c; 499 } 500 while (c != 0); 501 502 if (regEntry) 503 regEntry = regEntry->childFromPath( buf, gIODTPlane ); 504 else 505 regEntry = IORegistryEntry::fromPath( buf, gIODTPlane ); 506 507 if (regEntry) 508 { 509 MAKE_REG_ENTRY( newEntry, regEntry); 510 regEntry->release(); 511 err = noErr; 512 } 513 else 514 err = nrNotFoundErr; 515 516 IODelete( buf, char, 512 ); 517 518 return (err); 519} 520 521 522/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 523 524OSStatus EXP(VSLGestalt)( VSLGestaltType selector, UInt32 * response ) 525{ 526 IOReturn ret; 527 528 if (!response) 529 return (paramErr); 530 531 *response = 0; 532 533 switch (selector) 534 { 535 case kVSLClamshellStateGestaltType: 536 ret = IOGetHardwareClamshellState(response); 537 break; 538 default: 539 ret = gestaltUndefSelectorErr; 540 break; 541 } 542 543 return (ret); 544} 545 546OSErr 547EXP(VSLNewInterruptService)( 548 RegEntryID * serviceDevice, 549 InterruptServiceType serviceType, 550 InterruptServiceIDPtr serviceID) 551{ 552 return(IONDRVFramebuffer::VSLNewInterruptService(serviceDevice, serviceType, serviceID)); 553} 554 555OSErr 556EXP(VSLDisposeInterruptService)(InterruptServiceIDType serviceID) 557{ 558 return(IONDRVFramebuffer::VSLDisposeInterruptService(serviceID)); 559} 560 561OSErr 562EXP(VSLDoInterruptService)(InterruptServiceIDType serviceID) 563{ 564 return(IONDRVFramebuffer::VSLDoInterruptService(serviceID)); 565} 566 567Boolean 568EXP(VSLPrepareCursorForHardwareCursor)( 569 void * cursorRef, 570 IOHardwareCursorDescriptor * hardwareDescriptor, 571 IOHardwareCursorInfo * hwCursorInfo) 572{ 573 return(IONDRVFramebuffer::VSLPrepareCursorForHardwareCursor(cursorRef, 574 hardwareDescriptor, hwCursorInfo)); 575} 576 577/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 578 579} 580 581/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 582 583extern "C" IOReturn _IONDRVLibrariesFinalize( IOService * provider ) 584{ 585 provider->removeProperty(kPropertyAAPLAddress); 586 provider->removeProperty("AAPL,maps"); 587 588 return (kIOReturnSuccess); 589} 590 591extern "C" IOReturn _IONDRVLibrariesMappingInitialize( IOService * provider ) 592{ 593 // map memory 594 OSData * data; 595 unsigned int i; 596 IOItemCount numMaps; 597 OSArray * maps = 0; 598 data = 0; 599 600 if (provider->getProperty(kPropertyAAPLAddress)) 601 return (kIOReturnSuccess); 602 603 numMaps = provider->getDeviceMemoryCount(); 604 for (i = 0; i < numMaps; i++) 605 { 606 IODeviceMemory * mem; 607 IOMemoryMap * map; 608 IOVirtualAddress virtAddress; 609 610 mem = provider->getDeviceMemoryWithIndex(i); 611 if (!mem) 612 continue; 613 if (!maps) 614 maps = OSArray::withCapacity(numMaps); 615 if (!maps) 616 continue; 617 618 map = mem->map(); 619 if (!map) 620 { 621// IOLog("%s: map[%ld] failed\n", provider->getName(), i); 622 maps->setObject(kOSBooleanFalse); // placeholder 623 continue; 624 } 625 626 maps->setObject(map); 627 map->release(); 628 629 virtAddress = map->getVirtualAddress(); 630 mem->setMapping(kernel_task, virtAddress, kIOMapInhibitCache); 631 if (!data) 632 data = OSData::withCapacity( numMaps * sizeof( IOVirtualAddress)); 633 if (!data) 634 continue; 635 data->appendBytes( &virtAddress, sizeof( IOVirtualAddress)); 636 } 637 638 // NDRV aperture vectors 639 if (maps) 640 { 641 provider->setProperty( "AAPL,maps", maps ); 642 maps->release(); 643 } 644 if (data) 645 { 646 provider->setProperty(kPropertyAAPLAddress, data ); 647 data->release(); 648 } 649 return (kIOReturnSuccess); 650} 651 652extern "C" IOReturn _IONDRVLibrariesInitialize( IOService * provider ) 653{ 654 IODTPlatformExpert * platform; 655 const OSSymbol * sym; 656 OSData * data; 657 658#if NDRVLIBTEST 659 IONDRVLibrariesTest( provider ); 660#endif 661 662 // copy nvram property 663 664 if ((platform = OSDynamicCast(IODTPlatformExpert, 665 IOService::getPlatform()))) 666 { 667 // IOService::waitForService( IOService::resourceMatching( "IONVRAM" )); 668 669 if (kIOReturnSuccess == platform->readNVRAMProperty(provider, 670 &sym, &data)) 671 { 672 IONDRVSetNVRAMPropertyName( provider, sym ); 673 provider->setProperty( sym, data); 674 data->release(); 675 sym->release(); 676 } 677 } 678 679#if VERSION_MAJOR < 9 680 _IONDRVLibrariesMappingInitialize(provider); 681#endif 682 683 return (kIOReturnSuccess); 684} 685 686/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 687