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 "FWDebugging.h" 25 26#import <IOKit/firewire/IOFireWireFamilyCommon.h> 27#import <IOKit/firewire/IOLocalConfigDirectory.h> 28#import <IOKit/firewire/IOFWUtils.h> 29#import <IOKit/firewire/IOFireWireNub.h> 30#import <IOKit/firewire/IOFireWireBus.h> 31 32// private 33#import "IOConfigEntry.h" 34#import "IOFireWireUserClient.h" 35#import "IOFWUserObjectExporter.h" 36 37 38// system 39#import <libkern/c++/OSIterator.h> 40#import <libkern/c++/OSData.h> 41#import <libkern/c++/OSArray.h> 42#import <libkern/c++/OSObject.h> 43#import <libkern/c++/OSString.h> 44#import <IOKit/IOLib.h> 45 46OSDefineMetaClassAndStructors(IOLocalConfigDirectory, IOConfigDirectory); 47OSMetaClassDefineReservedUsed(IOLocalConfigDirectory, 0); 48OSMetaClassDefineReservedUnused(IOLocalConfigDirectory, 1); 49OSMetaClassDefineReservedUnused(IOLocalConfigDirectory, 2); 50 51// init 52// 53// 54 55bool IOLocalConfigDirectory::init() 56{ 57 if(!IOConfigDirectory::initWithOffset(0, 0)) 58 return false; 59 fEntries = OSArray::withCapacity(2); 60 if(!fEntries) 61 return false; 62 return true; 63} 64 65// free 66// 67// 68 69void IOLocalConfigDirectory::free() 70{ 71 if(fEntries) 72 fEntries->release(); 73 if(fROM) 74 fROM->release(); 75IOConfigDirectory::free(); 76} 77 78// getBase 79// 80// 81 82const UInt32 *IOLocalConfigDirectory::getBase() 83{ 84 if(fROM) 85 return ((const UInt32 *)fROM->getBytesNoCopy()) ;//+fStart+1; 86 else 87 return &fHeader; 88} 89 90IOConfigDirectory *IOLocalConfigDirectory::getSubDir(int start, int type) 91{ 92 return NULL; 93} 94 95// lockData 96// 97// 98 99const UInt32 * IOLocalConfigDirectory::lockData( void ) 100{ 101 return getBase(); 102} 103 104// unlockData 105// 106// 107 108void IOLocalConfigDirectory::unlockData( void ) 109{ 110 // nothing to do 111} 112 113// create 114// 115// 116 117IOLocalConfigDirectory *IOLocalConfigDirectory::create() 118{ 119 IOLocalConfigDirectory *dir; 120 dir = OSTypeAlloc( IOLocalConfigDirectory ); 121 if(!dir) 122 return NULL; 123 124 if(!dir->init()) { 125 dir->release(); 126 return NULL; 127 } 128 return dir; 129} 130 131// update 132// 133// 134 135IOReturn IOLocalConfigDirectory::update(UInt32 offset, const UInt32 *&romBase) 136{ 137 IOReturn res = kIOReturnSuccess; 138 if(!fROM) { 139 if(offset == 0) 140 romBase = &fHeader; 141 else 142 res = kIOReturnNoMemory; 143 } 144 else { 145 if(offset*sizeof(UInt32) <= fROM->getLength()) 146 romBase = (const UInt32 *)fROM->getBytesNoCopy(); 147 else 148 res = kIOReturnNoMemory; 149 } 150 return res; 151} 152 153// updateROMCache 154// 155// 156 157IOReturn IOLocalConfigDirectory::updateROMCache( UInt32 offset, UInt32 length ) 158{ 159 return kIOReturnSuccess; 160} 161 162// checkROMState 163// 164// 165 166IOReturn IOLocalConfigDirectory::checkROMState( void ) 167{ 168 return kIOReturnSuccess; 169} 170 171// incrementGeneration 172// 173// 174 175IOReturn IOLocalConfigDirectory::incrementGeneration( void ) 176{ 177 IOReturn status = kIOReturnSuccess; 178 179 unsigned int numEntries = fEntries->getCount(); 180 181 unsigned int i; 182 for( i = 0; i < numEntries; i++ ) 183 { 184 IOConfigEntry * entry = OSDynamicCast( IOConfigEntry, fEntries->getObject(i) ); 185 if( entry == NULL ) 186 { 187 IOLog( __FILE__" %d internal error!\n", __LINE__ ); 188 status = kIOReturnInternalError; 189 break; 190 } 191 192 if( (entry->fType == kConfigImmediateKeyType) && (entry->fKey == kConfigGenerationKey) ) 193 { 194 entry->fValue++; 195 } 196 } 197 198 return status; 199} 200 201// compile 202// 203// 204 205IOReturn IOLocalConfigDirectory::compile(OSData *rom) 206{ 207 UInt32 header; 208 UInt32 big_header; 209 UInt16 crc = 0; 210 OSData *tmp; // Temporary data for directory entries. 211 unsigned int size; 212 unsigned int numEntries; 213 unsigned int i; 214 unsigned int offset = 0; 215 if(fROM) 216 fROM->release(); 217 fROM = rom; 218 rom->retain(); 219 size = fROM->getLength(); 220 fStart = size/sizeof(UInt32); 221 numEntries = fEntries->getCount(); 222 223 /* 224 * We can't just compile into the rom, because the CRC for the directory 225 * depends on the entry data, and we can't (legally) overwrite data in an 226 * OSData (it needs an overwriteBytes() method). 227 * So compile into tmp, then calculate crc, then append lenth|crc and tmp. 228 */ 229 230 rom->ensureCapacity(size + sizeof(UInt32)*(1+numEntries)); 231 tmp = OSData::withCapacity(sizeof(UInt32)*(numEntries)); 232 for( i = 0; i < numEntries; i++ ) 233 { 234 IOConfigEntry *entry = OSDynamicCast(IOConfigEntry, fEntries->getObject(i)); 235 UInt32 val; 236 UInt32 big_val; 237 if(!entry) 238 { 239 IOLog(__FILE__" %d internal error!\n", __LINE__ ) ; 240 return kIOReturnInternalError; // Oops! 241 } 242 243 switch(entry->fType) 244 { 245 case kConfigImmediateKeyType: 246 val = entry->fValue; 247 break; 248 case kConfigOffsetKeyType: 249 val = (entry->fAddr.addressLo-kCSRRegisterSpaceBaseAddressLo)/sizeof(UInt32); 250 break; 251 case kConfigLeafKeyType: 252 case kConfigDirectoryKeyType: 253 val = numEntries-i+offset; 254 offset += entry->totalSize(); 255 break; 256 default: 257 IOLog(__FILE__" %d internal error!\n", __LINE__ ) ; 258 return kIOReturnInternalError; // Oops! 259 } 260 261 val |= entry->fKey << kConfigEntryKeyValuePhase; 262 val |= entry->fType << kConfigEntryKeyTypePhase; 263 264 big_val = OSSwapHostToBigInt32( val ); 265 crc = FWUpdateCRC16(crc, big_val); 266 267 tmp->appendBytes(&big_val, sizeof(UInt32)); 268 } 269 270 header = numEntries << kConfigLeafDirLengthPhase; 271 header |= crc; 272 big_header = OSSwapHostToBigInt32( header ); 273 rom->appendBytes(&big_header, sizeof(UInt32)); 274 rom->appendBytes(tmp); 275 tmp->release(); 276 277 // Now (recursively) append each leaf and directory. 278 for(i=0; i<numEntries; i++) 279 { 280 IOConfigEntry *entry = OSDynamicCast(IOConfigEntry, fEntries->getObject(i)); 281 UInt32 val; 282 UInt32 big_val; 283 if(!entry) 284 { 285 return kIOReturnInternalError; // Oops! 286 } 287 switch(entry->fType) 288 { 289 case kConfigImmediateKeyType: 290 case kConfigOffsetKeyType: 291 break; 292 case kConfigLeafKeyType: 293 { 294 OSData *data = OSDynamicCast(OSData, entry->fData); 295 const void *buffer; 296 unsigned int len, pad; 297 if(data) 298 { 299 len = data->getLength(); 300 pad = (4 - (len & 3)) & 3; 301 if(pad) 302 { 303 len += pad; 304 // Make sure the buffer is big enough for the CRC calc. 305 data->ensureCapacity(len); 306 } 307 buffer = data->getBytesNoCopy(); 308 } 309 else 310 { 311 return kIOReturnInternalError; // Oops! 312 } 313 314 crc = FWComputeCRC16((const UInt32 *)buffer, len / 4); 315 val = (len/4) << kConfigLeafDirLengthPhase; 316 val |= crc; 317 big_val = OSSwapHostToBigInt32( val ); 318 rom->appendBytes(&big_val, sizeof(UInt32)); 319 rom->appendBytes(buffer, len); 320 break; 321 } 322 case kConfigDirectoryKeyType: 323 { 324 IOReturn res; 325 IOLocalConfigDirectory *dir = OSDynamicCast(IOLocalConfigDirectory, 326 entry->fData); 327 if(!dir) 328 return kIOReturnInternalError; // Oops! 329 res = dir->compile(rom); 330 if(kIOReturnSuccess != res) 331 return res; 332 break; 333 } 334 default: 335 return kIOReturnInternalError; // Oops! 336 } 337 } 338 return kIOReturnSuccess; 339} 340 341// addEntry 342// 343// 344 345IOReturn IOLocalConfigDirectory::addEntry(int key, UInt32 value, OSString* desc ) 346{ 347 IOReturn res; 348 349 IOConfigEntry *entry = IOConfigEntry::create(key, value); 350 351 if(!entry) 352 { 353 return kIOReturnNoMemory; 354 } 355 if(!fEntries->setObject(entry)) 356 { 357 res = kIOReturnNoMemory; 358 } 359 else 360 { 361 res = kIOReturnSuccess; 362 } 363 364 entry->release(); // In array now. 365 366 if(desc) 367 { 368 addEntry(desc); 369 } 370 371 // keep our count current... 372 fNumEntries = fEntries->getCount() ; 373 374 return res; 375} 376 377// addEntry 378// 379// 380 381IOReturn IOLocalConfigDirectory::addEntry( int key, IOLocalConfigDirectory *value, OSString* desc ) 382{ 383 IOReturn res; 384 385 IOConfigEntry *entry = IOConfigEntry::create(key, kConfigDirectoryKeyType, value); 386 if(!entry) 387 { 388 return kIOReturnNoMemory; 389 } 390 if(!fEntries->setObject(entry)) 391 { 392 res = kIOReturnNoMemory; 393 } 394 else 395 { 396 res = kIOReturnSuccess; 397 } 398 399 entry->release(); // In array now. 400 if(desc) 401 { 402 addEntry(desc); 403 } 404 405 // keep our count current... 406 fNumEntries = fEntries->getCount() ; 407 408 return res; 409} 410 411// addEntry 412// 413// 414 415IOReturn IOLocalConfigDirectory::addEntry(int key, OSData *value, OSString* desc ) 416{ 417 IOReturn res; 418 419 // copying the OSData makes us robust against clients 420 // which modify the OSData after they pass it in to us. 421 422 OSData * valueCopy = OSData::withData( value ); 423 if( valueCopy == NULL ) 424 return kIOReturnNoMemory; 425 426 IOConfigEntry *entry = IOConfigEntry::create(key, kConfigLeafKeyType, valueCopy ); 427 if( entry == NULL ) 428 { 429 return kIOReturnNoMemory; 430 } 431 432 valueCopy->release(); 433 valueCopy = NULL; 434 435 if(!fEntries->setObject(entry)) 436 { 437 res = kIOReturnNoMemory; 438 } 439 else 440 { 441 res = kIOReturnSuccess; 442 } 443 444 entry->release(); // In array now. 445 446 if(desc) 447 { 448 addEntry(desc); 449 } 450 451 // keep our count current... 452 fNumEntries = fEntries->getCount() ; 453 454 return res; 455} 456 457// addEntry 458// 459// 460 461IOReturn IOLocalConfigDirectory::addEntry( int key, FWAddress value, OSString* desc ) 462{ 463 IOReturn res; 464 465 IOConfigEntry *entry = IOConfigEntry::create(key, value); 466 if(!entry) 467 { 468 return kIOReturnNoMemory; 469 } 470 if(!fEntries->setObject(entry)) 471 { 472 res = kIOReturnNoMemory; 473 } 474 else 475 { 476 res = kIOReturnSuccess; 477 } 478 entry->release(); // In array now. 479 if(desc) 480 { 481 addEntry(desc); 482 } 483 484 // keep our count current... 485 fNumEntries = fEntries->getCount() ; 486 487 return res; 488} 489 490// addEntry 491// 492// 493 494IOReturn IOLocalConfigDirectory::addEntry(OSString *desc) 495{ 496 IOReturn res; 497 OSData * value; 498 499 UInt64 zeros = 0; 500 501 int stringLength = desc->getLength(); 502 int paddingLength = (4 - (stringLength & 3)) & 3; 503 int headerLength = 8; 504 505 // make an OSData containing the string 506 value = OSData::withCapacity( headerLength + stringLength + paddingLength ); 507 if( !value ) 508 { 509 return kIOReturnNoMemory; 510 } 511 512 // append zeros for header 513 value->appendBytes( &zeros, headerLength ); 514 515 // append the string 516 value->appendBytes( desc->getCStringNoCopy(), stringLength ); 517 518 // append zeros to pad to nearest quadlet 519 value->appendBytes( &zeros, paddingLength ); 520 521 res = addEntry( kConfigTextualDescriptorKey, value ); 522 523 value->release(); // In ROM now 524 desc->release(); // call eats a retain count 525 526 // keep our count current... 527 fNumEntries = fEntries->getCount() ; 528 529 return res; 530} 531 532// removeSubDir 533// 534// 535 536IOReturn IOLocalConfigDirectory::removeSubDir(IOLocalConfigDirectory *value) 537{ 538 unsigned int i, numEntries; 539 numEntries = fEntries->getCount(); 540 541 for(i=0; i<numEntries; ++i) 542 { 543 IOConfigEntry *entry = OSDynamicCast(IOConfigEntry, fEntries->getObject(i)); 544 if(!entry) 545 { 546 return kIOReturnInternalError; // Oops! 547 } 548 if(entry->fType == kConfigDirectoryKeyType) 549 { 550 if(entry->fData == value) 551 { 552 fEntries->removeObject(i); 553 554 // keep our count current... 555 fNumEntries = fEntries->getCount() ; 556 557 return kIOReturnSuccess; 558 } 559 } 560 } 561 return kIOConfigNoEntry; 562} 563 564// getEntries 565// 566// 567 568const OSArray * IOLocalConfigDirectory::getEntries() const 569{ 570 return fEntries; 571} 572 573// getIndexValue 574// 575// 576 577IOReturn 578IOLocalConfigDirectory::getIndexValue(int index, IOConfigDirectory *&value) 579{ 580 IOReturn error = checkROMState(); 581 if ( error ) 582 { 583 return error ; 584 } 585 586 if( index < 0 || index >= fNumEntries ) 587 { 588 return kIOReturnBadArgument; 589 } 590 591 { 592 lockData(); 593 594 value = OSDynamicCast( IOConfigDirectory, ((IOConfigEntry*)fEntries->getObject( index ) )->fData ) ; 595 596 unlockData(); 597 598 if ( value ) 599 { 600 value->retain() ; 601 } 602 else 603 { 604 error = kIOReturnBadArgument ; 605 } 606 607 } 608 609 return error ; 610} 611 612void 613IOLocalConfigDirectory::exporterCleanup( const OSObject * self, IOFWUserObjectExporter * exporter ) 614{ 615 IOLocalConfigDirectory * me = (IOLocalConfigDirectory*)self; 616 ((IOFireWireUserClient*)exporter->getOwner())->getOwner()->getBus()->RemoveUnitDirectory( me ) ; 617} 618