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#include <IOKit/firewire/IOFWAddressSpace.h> 24#include <IOKit/firewire/IOFireWireController.h> 25 26#include "FWDebugging.h" 27 28OSData *IOFWPseudoAddressSpace::allocatedAddresses = NULL; // unused 29 30OSDefineMetaClassAndStructors(IOFWPseudoAddressSpaceAux, IOFWAddressSpaceAux); 31 32OSMetaClassDefineReservedUsed(IOFWPseudoAddressSpaceAux, 0); 33OSMetaClassDefineReservedUsed(IOFWPseudoAddressSpaceAux, 1); 34OSMetaClassDefineReservedUnused(IOFWPseudoAddressSpaceAux, 2); 35OSMetaClassDefineReservedUnused(IOFWPseudoAddressSpaceAux, 3); 36OSMetaClassDefineReservedUnused(IOFWPseudoAddressSpaceAux, 4); 37OSMetaClassDefineReservedUnused(IOFWPseudoAddressSpaceAux, 5); 38OSMetaClassDefineReservedUnused(IOFWPseudoAddressSpaceAux, 6); 39OSMetaClassDefineReservedUnused(IOFWPseudoAddressSpaceAux, 7); 40OSMetaClassDefineReservedUnused(IOFWPseudoAddressSpaceAux, 8); 41OSMetaClassDefineReservedUnused(IOFWPseudoAddressSpaceAux, 9); 42 43#pragma mark - 44 45// init 46// 47// 48 49bool IOFWPseudoAddressSpaceAux::init( IOFWAddressSpace * primary ) 50{ 51 bool success = true; // assume success 52 53 // init super 54 55 success = IOFWAddressSpaceAux::init( primary ); 56 57 // create member variables 58 59 if( success ) 60 { 61 success = createMemberVariables(); 62 } 63 64 return success; 65} 66 67// free 68// 69// 70 71void IOFWPseudoAddressSpaceAux::free() 72{ 73 destroyMemberVariables(); 74 75 IOFWAddressSpaceAux::free(); 76} 77 78// createMemberVariables 79// 80// 81 82bool IOFWPseudoAddressSpaceAux::createMemberVariables( void ) 83{ 84 bool success = true; 85 86 if( fMembers == NULL ) 87 { 88 // create member variables 89 90 if( success ) 91 { 92 fMembers = (MemberVariables*)IOMalloc( sizeof(MemberVariables) ); 93 if( fMembers == NULL ) 94 success = false; 95 } 96 97 // zero member variables 98 99 if( success ) 100 { 101 bzero( fMembers, sizeof(MemberVariables) ); 102 } 103 104 // clean up on failure 105 106 if( !success ) 107 { 108 destroyMemberVariables(); 109 } 110 } 111 112 return success; 113} 114 115// destroyMemberVariables 116// 117// 118 119void IOFWPseudoAddressSpaceAux::destroyMemberVariables( void ) 120{ 121 if( fMembers != NULL ) 122 { 123 IOFree( fMembers, sizeof(MemberVariables) ); 124 fMembers = NULL; 125 } 126} 127 128// handleARxReqIntComplete 129// 130// 131 132void IOFWPseudoAddressSpaceAux::handleARxReqIntComplete( void ) 133{ 134 if( fMembers->fARxReqIntCompleteHandler != NULL ) 135 { 136 (*fMembers->fARxReqIntCompleteHandler)( fMembers->fARxReqIntCompleteHandlerRefcon ); 137 } 138} 139 140// setARxReqIntCompleteHandler 141// 142// 143 144void IOFWPseudoAddressSpaceAux::setARxReqIntCompleteHandler( void * refcon, IOFWARxReqIntCompleteHandler handler ) 145{ 146 fMembers->fARxReqIntCompleteHandler = handler; 147 fMembers->fARxReqIntCompleteHandlerRefcon = refcon; 148} 149 150// intersects 151// 152// 153 154bool IOFWPseudoAddressSpaceAux::intersects( IOFWAddressSpace * space ) 155{ 156 bool intersects = false; 157 158 IOFWPseudoAddressSpace * pseudo_space = OSDynamicCast( IOFWPseudoAddressSpace, space ); 159 160 if( pseudo_space ) 161 { 162 // do we contain the start of the other space? 163 FWAddress address = pseudo_space->fBase; 164 intersects = (fPrimary->contains( address ) > 0); 165 166 // do we contain the end of the other space? 167 // because of how we allocate address spaces we can ignore the roll over into addressHi 168 if( pseudo_space->fLen > 0 ) 169 { 170 address.addressLo += pseudo_space->fLen - 1; 171 } 172 intersects |= (fPrimary->contains( address ) > 0); 173 } 174 175 return intersects; 176} 177 178#pragma mark - 179 180/* 181 * Pseudo firewire addresses usually represent emulated registers of some kind. 182 * Accesses to these addresses will result in the owner being notified. 183 * 184 * Virtual addresses should not have zero as the top 16 bits of the 48 bit local address, 185 * since that may look like a physical address to hardware (eg. OHCI). 186 * if reader is NULL then reads will not be allowed. 187 * if writer is NULL then writes will not be allowed. 188 * if either is NULL then lock requests will not be allowed. 189 * refcon is passed back as the first argument of read and write callbacks. 190 */ 191 192OSDefineMetaClassAndStructors(IOFWPseudoAddressSpace, IOFWAddressSpace) 193OSMetaClassDefineReservedUnused(IOFWPseudoAddressSpace, 0); 194OSMetaClassDefineReservedUnused(IOFWPseudoAddressSpace, 1); 195 196#pragma mark - 197 198// allocateAddress 199// 200// 201 202IOReturn IOFWPseudoAddressSpace::allocateAddress(FWAddress *addr, UInt32 lenDummy) 203{ 204 return fControl->allocatePseudoAddress( addr, lenDummy ); 205} 206 207// freeAddress 208// 209// 210 211void IOFWPseudoAddressSpace::freeAddress(FWAddress addr, UInt32 lenDummy) 212{ 213 fControl->freePseudoAddress( addr, lenDummy ); 214} 215 216// simpleReader 217// 218// 219 220UInt32 IOFWPseudoAddressSpace::simpleReader(void *refcon, UInt16 nodeID, IOFWSpeed &speed, 221 FWAddress addr, UInt32 len, IOMemoryDescriptor **buf, 222 IOByteCount * offset, IOFWRequestRefCon reqrefcon) 223{ 224 IOFWPseudoAddressSpace * space = (IOFWPseudoAddressSpace *)refcon; 225 226 *buf = space->fDesc; 227 *offset = addr.addressLo - space->fBase.addressLo; 228 229 return kFWResponseComplete; 230} 231 232// simpleWriter 233// 234// 235 236UInt32 IOFWPseudoAddressSpace::simpleWriter(void *refcon, UInt16 nodeID, IOFWSpeed &speed, 237 FWAddress addr, UInt32 len, const void *buf, IOFWRequestRefCon reqrefcon) 238{ 239 IOFWPseudoAddressSpace * space = (IOFWPseudoAddressSpace *)refcon; 240 241 space->fDesc->writeBytes(addr.addressLo - space->fBase.addressLo, buf, len); 242 243 return kFWResponseComplete; 244} 245 246// simpleRead 247// 248// 249 250IOFWPseudoAddressSpace * 251IOFWPseudoAddressSpace::simpleRead(IOFireWireBus *control, 252 FWAddress *addr, UInt32 len, const void *data) 253{ 254 IOFWPseudoAddressSpace * me = OSTypeAlloc( IOFWPseudoAddressSpace ); 255 do 256 { 257 if(!me) 258 break; 259 260 if(!me->initAll(control, addr, len, simpleReader, NULL, (void *)me)) 261 { 262 me->release(); 263 me = NULL; 264 break; 265 } 266 267 me->fDesc = IOMemoryDescriptor::withAddress((void *)data, len, kIODirectionOut); 268 if(!me->fDesc) 269 { 270 me->release(); 271 me = NULL; 272 } 273 274 } while(false); 275 276 return me; 277} 278 279// simpleReadFixed 280// 281// 282 283IOFWPseudoAddressSpace * 284IOFWPseudoAddressSpace::simpleReadFixed(IOFireWireBus *control, 285 FWAddress addr, UInt32 len, const void *data) 286{ 287 IOFWPseudoAddressSpace * me = OSTypeAlloc( IOFWPseudoAddressSpace ); 288 do 289 { 290 if(!me) 291 break; 292 293 if(!me->initFixed(control, addr, len, simpleReader, NULL, (void *)me)) 294 { 295 me->release(); 296 me = NULL; 297 break; 298 } 299 300 me->fDesc = IOMemoryDescriptor::withAddress((void *)data, len, kIODirectionOut); 301 if(!me->fDesc) 302 { 303 me->release(); 304 me = NULL; 305 } 306 307 } while(false); 308 309 return me; 310} 311 312// simpleReadFixed 313// 314// 315 316IOFWPseudoAddressSpace * 317IOFWPseudoAddressSpace::simpleRWFixed(IOFireWireBus *control, 318 FWAddress addr, UInt32 len, const void *data) 319{ 320 IOFWPseudoAddressSpace * me = OSTypeAlloc( IOFWPseudoAddressSpace ); 321 do 322 { 323 if(!me) 324 break; 325 326 if(!me->initFixed(control, addr, len, simpleReader, simpleWriter, (void *)me)) 327 { 328 me->release(); 329 me = NULL; 330 break; 331 } 332 333 me->fDesc = IOMemoryDescriptor::withAddress((void *)data, len, kIODirectionOutIn); 334 if(!me->fDesc) 335 { 336 me->release(); 337 me = NULL; 338 } 339 340 } while(false); 341 342 return me; 343} 344 345 346// simpleRW 347// 348// 349 350IOFWPseudoAddressSpace *IOFWPseudoAddressSpace::simpleRW(IOFireWireBus *control, 351 FWAddress *addr, UInt32 len, void *data) 352{ 353 IOFWPseudoAddressSpace * me = OSTypeAlloc( IOFWPseudoAddressSpace ); 354 do 355 { 356 if(!me) 357 break; 358 359 if(!me->initAll(control, addr, len, simpleReader, simpleWriter, (void *)me)) 360 { 361 me->release(); 362 me = NULL; 363 break; 364 } 365 366 me->fDesc = IOMemoryDescriptor::withAddress(data, len, kIODirectionOutIn); 367 if(!me->fDesc) 368 { 369 me->release(); 370 me = NULL; 371 } 372 373 } while(false); 374 375 return me; 376} 377 378// simpleRW 379// 380// 381 382IOFWPseudoAddressSpace *IOFWPseudoAddressSpace::simpleRW(IOFireWireBus *control, 383 FWAddress *addr, IOMemoryDescriptor * data) 384{ 385 IOFWPseudoAddressSpace * me = OSTypeAlloc( IOFWPseudoAddressSpace ); 386 do 387 { 388 if(!me) 389 break; 390 391 if(!me->initAll(control, addr, data->getLength(), simpleReader, simpleWriter, (void *)me)) 392 { 393 me->release(); 394 me = NULL; 395 break; 396 } 397 398 data->retain(); 399 me->fDesc = data; 400 401 } while(false); 402 403 return me; 404} 405 406// initAll 407// 408// 409 410bool IOFWPseudoAddressSpace::initAll(IOFireWireBus *control, FWAddress *addr, UInt32 len, 411 FWReadCallback reader, FWWriteCallback writer, void *refCon) 412{ 413 if(!IOFWAddressSpace::init(control)) 414 return false; 415 416 if(allocateAddress(addr, len) != kIOReturnSuccess) 417 return false; 418 419 fBase = *addr; 420 fBase.addressHi &= 0xFFFF; // Mask off nodeID part. 421 fLen = len; 422 fDesc = NULL; // Only used by simpleRead case. 423 fRefCon = refCon; 424 fReader = reader; 425 fWriter = writer; 426 427 return true; 428} 429 430// initFixed 431// 432// 433 434bool IOFWPseudoAddressSpace::initFixed(IOFireWireBus *control, FWAddress addr, UInt32 len, 435 FWReadCallback reader, FWWriteCallback writer, void *refCon) 436{ 437 if( !IOFWAddressSpace::init(control) ) 438 return false; 439 440 // Only allow fixed addresses at top of address space 441 if( addr.addressHi != kCSRRegisterSpaceBaseAddressHi ) 442 return false; 443 444 fBase = addr; 445 fLen = len; 446 fDesc = NULL; // Only used by simpleRead case. 447 fRefCon = refCon; 448 fReader = reader; 449 fWriter = writer; 450 451 return true; 452} 453 454// createAuxiliary 455// 456// virtual method for creating auxiliary object. subclasses needing to subclass 457// the auxiliary object can override this. 458 459IOFWAddressSpaceAux * IOFWPseudoAddressSpace::createAuxiliary( void ) 460{ 461 IOFWPseudoAddressSpaceAux * auxiliary; 462 463 auxiliary = OSTypeAlloc( IOFWPseudoAddressSpaceAux ); 464 465 if( auxiliary != NULL && !auxiliary->init(this) ) 466 { 467 auxiliary->release(); 468 auxiliary = NULL; 469 } 470 471 return auxiliary; 472} 473 474// free 475// 476// 477 478void IOFWPseudoAddressSpace::free() 479{ 480 if(fDesc) 481 fDesc->release(); 482 483 if(fBase.addressHi != kCSRRegisterSpaceBaseAddressHi) 484 freeAddress(fBase, fLen); 485 486 IOFWAddressSpace::free(); 487} 488 489// doRead 490// 491// 492 493UInt32 IOFWPseudoAddressSpace::doRead( UInt16 nodeID, IOFWSpeed &speed, FWAddress addr, UInt32 len, 494 IOMemoryDescriptor **buf, IOByteCount * offset, IOFWRequestRefCon refcon) 495{ 496 if( !isTrustedNode( nodeID ) ) 497 return kFWResponseAddressError; 498 499 if(addr.addressHi != fBase.addressHi) 500 return kFWResponseAddressError; 501 502 if(addr.addressLo < fBase.addressLo) 503 return kFWResponseAddressError; 504 505 if(addr.addressLo + len > fBase.addressLo+fLen) 506 return kFWResponseAddressError; 507 508 if(!fReader) 509 return kFWResponseTypeError; 510 511 return fReader(fRefCon, nodeID, speed, addr, len, buf, offset, refcon); 512} 513 514// doWrite 515// 516// 517 518UInt32 IOFWPseudoAddressSpace::doWrite(UInt16 nodeID, IOFWSpeed &speed, FWAddress addr, UInt32 len, 519 const void *buf, IOFWRequestRefCon refcon) 520{ 521 if( !isTrustedNode( nodeID ) ) 522 return kFWResponseAddressError; 523 524 if(addr.addressHi != fBase.addressHi) 525 return kFWResponseAddressError; 526 527 if(addr.addressLo < fBase.addressLo) 528 return kFWResponseAddressError; 529 530 if(addr.addressLo + len > fBase.addressLo+fLen) 531 return kFWResponseAddressError; 532 533 if(!fWriter) 534 return kFWResponseTypeError; 535 536 return fWriter(fRefCon, nodeID, speed, addr, len, buf, refcon); 537} 538 539// contains 540// 541// 542 543UInt32 IOFWPseudoAddressSpace::contains(FWAddress addr) 544{ 545 UInt32 offset; 546 547 if(addr.addressHi != fBase.addressHi) 548 return 0; 549 550 if(addr.addressLo < fBase.addressLo) 551 return 0; 552 553 offset = addr.addressLo - fBase.addressLo; 554 if(offset > fLen) 555 return 0; 556 557 return fLen - offset; 558}