1/* 2 * Copyright (c) 1998-2002 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// public 24#import <IOKit/firewire/IOConfigDirectory.h> 25#import <IOKit/firewire/IORemoteConfigDirectory.h> 26#import <IOKit/firewire/IOFireWireDevice.h> 27 28// private 29#import "FWDebugging.h" 30#include "IOConfigDirectoryIterator.h" 31 32// system 33#import <libkern/c++/OSIterator.h> 34#import <libkern/c++/OSData.h> 35#import <libkern/OSByteOrder.h> 36 37static int findIndex(const UInt32* base, int size, int key, 38 UInt32 type = kInvalidConfigROMEntryType); 39 40int findIndex(const UInt32* base, int size, int key, UInt32 type) 41{ 42 int i; 43 UInt32 mask, test; 44 test = (UInt32)key << kConfigEntryKeyValuePhase; 45 mask = kConfigEntryKeyValue; 46 if(type != kInvalidConfigROMEntryType) { 47 test |= type << kConfigEntryKeyTypePhase; 48 mask |= kConfigEntryKeyType; 49 } 50 // OR test into mask, in case key was more than just the key value 51 mask |= test; 52 for(i=0; i<size; i++) { 53 if( (OSSwapBigToHostInt32(base[i]) & mask) == test ) 54 break; 55 } 56 if(i >= size) 57 i = -1; 58 return i; 59} 60 61 62/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 63 64OSDefineMetaClass( IOConfigDirectory, OSObject ) 65OSDefineAbstractStructors(IOConfigDirectory, OSObject) 66OSMetaClassDefineReservedUnused(IOConfigDirectory, 0); 67OSMetaClassDefineReservedUnused(IOConfigDirectory, 1); 68OSMetaClassDefineReservedUnused(IOConfigDirectory, 2); 69OSMetaClassDefineReservedUnused(IOConfigDirectory, 3); 70OSMetaClassDefineReservedUnused(IOConfigDirectory, 4); 71OSMetaClassDefineReservedUnused(IOConfigDirectory, 5); 72OSMetaClassDefineReservedUnused(IOConfigDirectory, 6); 73OSMetaClassDefineReservedUnused(IOConfigDirectory, 7); 74OSMetaClassDefineReservedUnused(IOConfigDirectory, 8); 75 76// initWithOffset 77// 78// 79 80bool IOConfigDirectory::initWithOffset(int start, int type) 81{ 82 IOReturn status = kIOReturnSuccess; 83 const UInt32 *data; 84 85 if( !OSObject::init() ) 86 { 87 status = kIOReturnError; 88 } 89 90 if( status == kIOReturnSuccess ) 91 { 92 fStart = start; 93 fType = type; 94 95 status = updateROMCache( start, 1 ); 96 } 97 98 if( status == kIOReturnSuccess ) 99 { 100 data = lockData(); 101 fNumEntries = (OSSwapBigToHostInt32(data[start]) & kConfigLeafDirLength) >> kConfigLeafDirLengthPhase; 102 unlockData(); 103 104 if( fNumEntries > 256 ) // 1k request 105 { 106 status = kIOReturnNoMemory; 107 } 108 } 109 110 if( status == kIOReturnSuccess ) 111 { 112 // FWKLOG(( "IOConfigDirectory::initWithOffset updateROMCache( %d, %d )\n", start, fNumEntries )); 113 status = updateROMCache(start + 1, fNumEntries); 114 } 115 116 if( status != kIOReturnSuccess ) 117 { 118 fNumEntries = 0; 119 } 120 121 return true; 122} 123 124// createIterator 125// 126// 127 128IOReturn IOConfigDirectory::createIterator(UInt32 testVal, UInt32 testMask, OSIterator *&iterator) 129{ 130 IOReturn status = kIOReturnSuccess; 131 132 IOConfigDirectoryIterator *iter = NULL; 133 134 status = checkROMState(); 135 136 if( status == kIOReturnSuccess ) 137 { 138 iter = OSTypeAlloc( IOConfigDirectoryIterator ); 139 if( iter == NULL ) 140 status = kIOReturnNoMemory; 141 } 142 143 if( status == kIOReturnSuccess ) 144 { 145 status = iter->init( this, testVal, testMask ); 146 if( status == kIOReturnSuccess ) 147 { 148 iterator = iter; 149 } 150 else 151 { 152 iter->release(); 153 iter = NULL; 154 } 155 } 156 157 return status; 158} 159 160// getKeyType 161// 162// 163 164IOReturn IOConfigDirectory::getKeyType(int key, IOConfigKeyType &type) 165{ 166 IOReturn status = kIOReturnSuccess; 167 int index = 0; 168 169 status = checkROMState(); 170 171 if( status == kIOReturnSuccess ) 172 { 173 const UInt32 * data = lockData() + fStart + 1; 174 index = findIndex(data, fNumEntries, key); 175 unlockData(); 176 177 if( index < 0 ) 178 status = kIOConfigNoEntry; 179 } 180 181 if( status == kIOReturnSuccess ) 182 { 183 status = getIndexType(index, type); 184 } 185 186 return status; 187} 188 189// getKeyValue 190// 191// 192 193IOReturn IOConfigDirectory::getKeyValue(int key, UInt32 &value, OSString** text) 194{ 195 IOReturn status = kIOReturnSuccess; 196 int index = 0; 197 198 status = checkROMState(); 199 200 if( status == kIOReturnSuccess ) 201 { 202 const UInt32 * data = lockData() + fStart + 1; 203 index = findIndex(data, fNumEntries, key); 204 unlockData(); 205 206 if( index < 0 ) 207 status = kIOConfigNoEntry; 208 } 209 210 if( status == kIOReturnSuccess ) 211 { 212 status = getIndexValue(index, value); 213 } 214 215 if( status == kIOReturnSuccess && text ) 216 { 217 // textual descriptor is optional 218 *text = NULL; 219 status = getIndexValue(index+1, *text); 220 if( status != kIOFireWireConfigROMInvalid ) 221 status = kIOReturnSuccess; 222 } 223 224 return status; 225} 226 227// getKeyValue 228// 229// 230 231IOReturn IOConfigDirectory::getKeyValue(int key, OSData *&value, OSString** text) 232{ 233 IOReturn status = kIOReturnSuccess; 234 int index = 0; 235 236 status = checkROMState(); 237 238 if( status == kIOReturnSuccess ) 239 { 240 const UInt32 * data = lockData() + fStart + 1; 241 index = findIndex(data, fNumEntries, key, kConfigLeafKeyType); 242 unlockData(); 243 244 if( index < 0 ) 245 { 246 status = kIOConfigNoEntry; 247 } 248 } 249 250 if( status == kIOReturnSuccess ) 251 { 252 status = getIndexValue(index, value); 253 } 254 255 if( status == kIOReturnSuccess && text ) 256 { 257 // textual descriptor is optional 258 *text = NULL; 259 status = getIndexValue(index+1, *text); 260 if( status != kIOFireWireConfigROMInvalid ) 261 status = kIOReturnSuccess; 262 } 263 264 return status; 265} 266 267// getKeyValue 268// 269// 270 271IOReturn IOConfigDirectory::getKeyValue(int key, IOConfigDirectory *&value, 272 OSString** text) 273{ 274 IOReturn status = kIOReturnSuccess; 275 int index = 0; 276 277 status = checkROMState(); 278 279 if( status == kIOReturnSuccess ) 280 { 281 const UInt32 * data = lockData() + fStart + 1; 282 index = findIndex(data, fNumEntries, key, kConfigDirectoryKeyType); 283 unlockData(); 284 285 if( index < 0 ) 286 { 287 status = kIOConfigNoEntry; 288 } 289 } 290 291 if( status == kIOReturnSuccess ) 292 { 293 status = getIndexValue(index, value); 294 } 295 296 if( status == kIOReturnSuccess && text ) 297 { 298 // textual descriptor is optional 299 *text = NULL; 300 status = getIndexValue(index+1, *text); 301 if( status != kIOFireWireConfigROMInvalid ) 302 status = kIOReturnSuccess; 303 } 304 305 return status; 306} 307 308// getKeyOffset 309// 310// 311 312IOReturn IOConfigDirectory::getKeyOffset(int key, FWAddress &value, OSString** text) 313{ 314 IOReturn status = kIOReturnSuccess; 315 int index = 0; 316 317 status = checkROMState(); 318 319 if( status == kIOReturnSuccess ) 320 { 321 const UInt32 * data = lockData() + fStart + 1; 322 index = findIndex(data, fNumEntries, key, kConfigOffsetKeyType); 323 unlockData(); 324 325 if( index < 0 ) 326 status = kIOConfigNoEntry; 327 } 328 329 if( status == kIOReturnSuccess ) 330 { 331 status = getIndexOffset(index, value); 332 } 333 334 if( status == kIOReturnSuccess && text) 335 { 336 // textual descriptor is optional 337 *text = NULL; 338 status = getIndexValue(index+1, *text); 339 if( status != kIOFireWireConfigROMInvalid ) 340 status = kIOReturnSuccess; 341 } 342 343 return status; 344} 345 346// getKeySubdirectories 347// 348// 349 350IOReturn IOConfigDirectory::getKeySubdirectories(int key, OSIterator *&iterator) 351{ 352 IOReturn status = createIterator((key << kConfigEntryKeyValuePhase) | 353 (kConfigDirectoryKeyType << kConfigEntryKeyTypePhase), 354 kConfigEntryKeyType | kConfigEntryKeyValue, iterator); 355 356 return status; 357} 358 359// getType 360// 361// 362 363int IOConfigDirectory::getType() const 364{ 365 return fType; 366} 367 368// getNumEntries 369// 370// 371 372int IOConfigDirectory::getNumEntries() const 373{ 374 return fNumEntries; 375} 376 377// getIndexType 378// 379// 380 381IOReturn IOConfigDirectory::getIndexType(int index, IOConfigKeyType &type) 382{ 383 IOReturn status = kIOReturnSuccess; 384 UInt32 entry; 385 386 status = checkROMState(); 387 388 if( status == kIOReturnSuccess ) 389 { 390 if( index < 0 || index >= fNumEntries ) 391 status = kIOReturnBadArgument; 392 } 393 394 if( status == kIOReturnSuccess ) 395 { 396 const UInt32 * data = lockData(); 397 entry = OSSwapBigToHostInt32(data[fStart + 1 + index]); 398 unlockData(); 399 400 type = (IOConfigKeyType)((entry & kConfigEntryKeyType) >> kConfigEntryKeyTypePhase); 401 } 402 403 return status; 404} 405 406// getIndexKey 407// 408// 409 410IOReturn IOConfigDirectory::getIndexKey(int index, int &key) 411{ 412 IOReturn status = kIOReturnSuccess; 413 UInt32 entry; 414 415 status = checkROMState(); 416 417 if( status == kIOReturnSuccess ) 418 { 419 if( index < 0 || index >= fNumEntries ) 420 status = kIOReturnBadArgument; 421 } 422 423 if( status == kIOReturnSuccess ) 424 { 425 const UInt32 * data = lockData(); 426 entry = OSSwapBigToHostInt32(data[fStart + 1 + index]); 427 unlockData(); 428 429 key = (IOConfigKeyType)((entry & kConfigEntryKeyValue) >> kConfigEntryKeyValuePhase); 430 } 431 432 return status; 433} 434 435// getIndexValue 436// 437// 438 439IOReturn IOConfigDirectory::getIndexValue(int index, UInt32 &value) 440{ 441 IOReturn status = kIOReturnSuccess; 442 UInt32 entry; 443 444 status = checkROMState(); 445 446 if( status == kIOReturnSuccess ) 447 { 448 if( index < 0 || index >= fNumEntries ) 449 status = kIOReturnBadArgument; 450 } 451 452 if( status == kIOReturnSuccess ) 453 { 454 const UInt32 * data = lockData(); 455 entry = OSSwapBigToHostInt32(data[fStart + 1 + index]); 456 unlockData(); 457 458 // Return the value as an integer, whatever it really is. 459 value = entry & kConfigEntryValue; 460 } 461 462 return status; 463} 464 465// getIndexValue 466// 467// 468 469IOReturn IOConfigDirectory::getIndexValue(int index, OSData *&value) 470{ 471 IOReturn status = kIOReturnSuccess; 472 UInt32 entry; 473 const UInt32 *data; 474 UInt32 offset; 475 int len = 0; 476 477 status = checkROMState(); 478 479 if( status == kIOReturnSuccess ) 480 { 481 if( index < 0 || index >= fNumEntries ) 482 status = kIOReturnBadArgument; 483 } 484 485 if( status == kIOReturnSuccess ) 486 { 487 data = lockData(); 488 entry = OSSwapBigToHostInt32(data[fStart + 1 + index]); 489 unlockData(); 490 491 if( ((entry & kConfigEntryKeyType) >> kConfigEntryKeyTypePhase) != kConfigLeafKeyType) 492 status = kIOReturnBadArgument; 493 } 494 495 if( status == kIOReturnSuccess ) 496 { 497 status = getIndexOffset( index, offset ); 498 } 499 500 if( status == kIOReturnSuccess ) 501 { 502 status = updateROMCache( offset, 1 ); 503 } 504 505 if( status == kIOReturnSuccess ) 506 { 507 data = lockData(); 508 len = ((OSSwapBigToHostInt32(data[offset]) & kConfigLeafDirLength) >> kConfigLeafDirLengthPhase); 509 unlockData(); 510 511 // FWKLOG(( "IOConfigDirectory::getIndexValue(OSData) updateROMCache( %ld, %d )\n", offset, len )); 512 513 status = updateROMCache( offset + 1, len ); 514 } 515 516 if( status == kIOReturnSuccess ) 517 { 518 data = lockData(); 519 value = OSData::withBytes(data+offset+1, len*sizeof(UInt32)); 520 unlockData(); 521 522 if( value == NULL) 523 status = kIOReturnNoMemory; 524 } 525 526 return status; 527} 528 529// getIndexValue 530// 531// 532 533IOReturn IOConfigDirectory::getIndexValue(int index, OSString *&value) 534{ 535 IOReturn status = kIOReturnSuccess; 536 UInt32 entry = 0; 537 const UInt32 *data; 538 UInt32 offset; 539 int len = 0; 540 541 status = checkROMState(); 542 543 if( status == kIOReturnSuccess ) 544 { 545 if( index < 0 || index >= fNumEntries ) 546 { 547 DebugLog("IOConfigDirectory<%p>::getIndexValue -- index out of bounds\n", this ) ; 548 status = kIOReturnBadArgument; 549 } 550 } 551 552 if( status == kIOReturnSuccess ) 553 { 554 data = lockData(); 555 entry = OSSwapBigToHostInt32(data[fStart + 1 + index]); 556 unlockData(); 557 558 if( ((entry & kConfigEntryKeyValue) >> kConfigEntryKeyValuePhase) != kConfigTextualDescriptorKey ) 559 { 560 DebugLog("IOConfigDirectory<%p>::getIndexValue -- key is not a textual descriptor key entry=0x%x\n", this, (uint32_t)entry ) ; 561 status = kIOReturnBadArgument; 562 } 563 } 564 565 if( status == kIOReturnSuccess ) 566 { 567 if( ((entry & kConfigEntryKeyType) >> kConfigEntryKeyTypePhase) != kConfigLeafKeyType ) 568 { 569 DebugLog("IOConfigDirectory<%p>::getIndexValue -- key type is not leaf\n", this ) ; 570 status = kIOReturnBadArgument; 571 } 572 } 573 574 if( status == kIOReturnSuccess ) 575 { 576 status = getIndexOffset(index, offset); 577 } 578 579 if( status == kIOReturnSuccess ) 580 { 581 status = updateROMCache(offset, 1); 582 } 583 584 if( status == kIOReturnSuccess ) 585 { 586 data = lockData(); 587 len = (OSSwapBigToHostInt32(data[offset]) & kConfigLeafDirLength) >> kConfigLeafDirLengthPhase; 588 unlockData(); 589 590 // Check for silly length, people are careless with string data! 591 if( (len * 4) > 256 ) 592 status = kIOReturnBadArgument; 593 } 594 595 if( status == kIOReturnSuccess ) 596 { 597 FWKLOG(( "IOConfigDirectory::getIndexValue(OSString) updateROMCache( %ld, %d )\n", offset, len )); 598 599 status = updateROMCache(offset + 1,len); 600 } 601 602 if( status == kIOReturnSuccess ) 603 { 604 data = lockData(); 605 606 len -= 2; // skip spec_type, specifier_ID, language_ID 607 len *= sizeof(UInt32); // Convert from Quads to chars 608 609 char tbuf[len]; 610 char * text; 611 612 UInt32 specifier = OSSwapBigToHostInt32(data[offset+1]); 613 //UInt32 specifier_ID = specifier & 0x00FFFFFF; 614 UInt8 specifier_type = (UInt8)(specifier >> 24); //descriptor_type 615 UInt32 language_ID = OSSwapBigToHostInt32(data[offset+2]) & 0x0000FFFF; 616 617 if ( specifier_type == 0x80 && language_ID == 0x409 ) 618 { 619 // Decode using vendor specific UTF-16 simple conversion 620 char * aUniStr = (char *)(&data[offset+3]); 621 const unsigned int halfsize = len/2; 622 unsigned int i; 623 for ( i=0; i < halfsize; i++ ) 624 tbuf[i] = aUniStr[i*2]; 625 626 text = (char *)tbuf; 627 len = halfsize; 628 } 629 else 630 { 631 // Skip over length, CRC, spec_type, specifier_ID, language_ID 632 text = (char *)(&data[offset+3]); 633 } 634 635 // Now skip over leading zeros in string 636 while(len && !*text) { 637 len--; 638 text++; 639 } 640 641 if(len) 642 { 643 // strings aren't required to have null terminators 644 // add one just in case 645 char * temp_string = (char *)IOMalloc( len+1 ); 646 if( temp_string ) 647 { 648 bcopy( text, temp_string, len ); 649 temp_string[len] = '\0'; 650 value = OSString::withCString(temp_string); 651 IOFree( temp_string, len+1 ); 652 } 653 } 654 else 655 value = OSString::withCString(""); 656 657 unlockData(); 658 659 if( value == NULL ) 660 status = kIOReturnNoMemory; 661 } 662 663 DebugLogCond( status != kIOReturnSuccess, "IOConfigDirectory<%p>::getIndexValue -- return status 0x%x\n", this, status ) ; 664 665 return status; 666} 667 668// getIndexValue 669// 670// 671 672IOReturn IOConfigDirectory::getIndexValue(int index, IOConfigDirectory *&value) 673{ 674 IOReturn status = kIOReturnSuccess; 675 UInt32 entry = 0; 676 UInt32 offset; 677 678 status = checkROMState(); 679 680 if( status == kIOReturnSuccess ) 681 { 682 if( index < 0 || index >= fNumEntries ) 683 status = kIOReturnBadArgument; 684 } 685 686 if( status == kIOReturnSuccess ) 687 { 688 const UInt32 * data = lockData(); 689 entry = OSSwapBigToHostInt32(data[fStart + 1 + index]); 690 unlockData(); 691 692 if( ((entry & kConfigEntryKeyType) >> kConfigEntryKeyTypePhase) != kConfigDirectoryKeyType) 693 status = kIOReturnBadArgument; 694 } 695 696 if( status == kIOReturnSuccess ) 697 { 698 status = getIndexOffset(index, offset); 699 } 700 701 if( status == kIOReturnSuccess ) 702 { 703 value = getSubDir( offset, (entry & kConfigEntryKeyValue) >> kConfigEntryKeyValuePhase ); 704 if( value == NULL ) 705 status = kIOReturnNoMemory; 706 } 707 708 return status; 709} 710 711// getIndexOffset 712// 713// 714 715IOReturn IOConfigDirectory::getIndexOffset(int index, FWAddress &value) 716{ 717 IOReturn status = kIOReturnSuccess; 718 UInt32 entry = 0; 719 UInt32 offset; 720 721 status = checkROMState(); 722 723 if( status == kIOReturnSuccess ) 724 { 725 if( index < 0 || index >= fNumEntries ) 726 status = kIOReturnBadArgument; 727 } 728 729 if( status == kIOReturnSuccess ) 730 { 731 const UInt32 * data = lockData(); 732 entry = OSSwapBigToHostInt32(data[fStart + 1 + index]); 733 unlockData(); 734 735 if(((entry & kConfigEntryKeyType) >> kConfigEntryKeyTypePhase) == kConfigImmediateKeyType) 736 status = kIOReturnBadArgument; 737 } 738 739 if( status == kIOReturnSuccess ) 740 { 741 value.addressHi = kCSRRegisterSpaceBaseAddressHi; 742 offset = entry & kConfigEntryValue; 743 if(((entry & kConfigEntryKeyType) >> kConfigEntryKeyTypePhase) == kConfigOffsetKeyType) 744 { 745 value.addressLo = kCSRRegisterSpaceBaseAddressLo + offset*sizeof(UInt32); 746 } 747 else 748 { 749 offset += fStart + 1 + index; 750 value.addressLo = kConfigROMBaseAddress + offset*sizeof(UInt32); 751 } 752 } 753 754 return status; 755} 756 757// getIndexOffset 758// 759// 760 761IOReturn IOConfigDirectory::getIndexOffset(int index, UInt32 &value) 762{ 763 IOReturn status = kIOReturnSuccess; 764 UInt32 entry = 0; 765 766 status = checkROMState(); 767 768 if( status == kIOReturnSuccess ) 769 { 770 if( index < 0 || index >= fNumEntries ) 771 status = kIOReturnBadArgument; 772 } 773 774 if( status == kIOReturnSuccess ) 775 { 776 const UInt32 * data = lockData(); 777 entry = OSSwapBigToHostInt32(data[fStart + 1 + index]); 778 unlockData(); 779 780 if(((entry & kConfigEntryKeyType) >> kConfigEntryKeyTypePhase) == kConfigImmediateKeyType) 781 { 782 status = kIOReturnBadArgument; 783 } 784 else if(((entry & kConfigEntryKeyType) >> kConfigEntryKeyTypePhase) == kConfigOffsetKeyType) 785 { 786 status = kIOReturnBadArgument; 787 } 788 } 789 790 if( status == kIOReturnSuccess ) 791 { 792 value = entry & kConfigEntryValue; 793 value += fStart + 1 + index; 794 } 795 796 return status; 797} 798 799// getIndexEntry 800// 801// 802 803IOReturn IOConfigDirectory::getIndexEntry(int index, UInt32 &value) 804{ 805 IOReturn status = kIOReturnSuccess; 806 807 status = checkROMState(); 808 809 if( status == kIOReturnSuccess ) 810 { 811 if( index < 0 || index >= fNumEntries ) 812 status = kIOReturnBadArgument; 813 } 814 815 if( status == kIOReturnSuccess ) 816 { 817 const UInt32 * data = lockData(); 818 value = OSSwapBigToHostInt32(data[fStart + 1 + index]); 819 unlockData(); 820 } 821 822 return status; 823} 824 825// getSubdirectories 826// 827// 828 829IOReturn IOConfigDirectory::getSubdirectories(OSIterator *&iterator) 830{ 831 return createIterator(kConfigDirectoryKeyType << kConfigEntryKeyTypePhase, 832 kConfigEntryKeyType, iterator); 833} 834 835