1/* 2 * Copyright (c) 2001 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 <IOKit/firewire/IOFireWireController.h> 25#include <IOKit/firewire/IOFireWireLocalNode.h> 26#include <IOKit/avc/IOFireWireAVCConsts.h> 27#include <IOKit/avc/IOFireWirePCRSpace.h> 28 29OSDefineMetaClassAndStructors(IOFireWirePCRSpace, IOFWPseudoAddressSpace) 30OSMetaClassDefineReservedUnused(IOFireWirePCRSpace, 0); 31OSMetaClassDefineReservedUnused(IOFireWirePCRSpace, 1); 32OSMetaClassDefineReservedUnused(IOFireWirePCRSpace, 2); 33OSMetaClassDefineReservedUnused(IOFireWirePCRSpace, 3); 34 35static IOReturn MyServiceInterestHandler( void * target, 36 void * refCon, 37 UInt32 messageType, 38 IOService * provider, 39 void * messageArgument, 40 vm_size_t argSize ) 41{ 42 IOReturn res = kIOReturnUnsupported; 43 IOFireWirePCRSpace *pPCRSpace = (IOFireWirePCRSpace*) target; 44 45 //IOLog( "IOFireWirePCRSpace received MyServiceInterestHandler (message = 0x%08X)\n",(int) messageType); 46 47 switch (messageType) 48 { 49 case kIOMessageServiceIsTerminated: 50 case kIOMessageServiceIsRequestingClose: 51 case kIOMessageServiceIsResumed: 52 res = kIOReturnSuccess; 53 break; 54 55 // This message is received when a bus-reset start happens! 56 case kIOMessageServiceIsSuspended: 57 res = kIOReturnSuccess; 58 if (pPCRSpace) 59 pPCRSpace->clearAllP2PConnections(); 60 break; 61 62 default: 63 break; 64 } 65 66 return res; 67} 68 69bool IOFireWirePCRSpace::init(IOFireWireBus *bus) 70{ 71 //IOLog( "IOFireWirePCRSpace::init (0x%08X)\n",(int) this); 72 73 if(!IOFWPseudoAddressSpace::initFixed(bus, 74 FWAddress(kCSRRegisterSpaceBaseAddressHi, kPCRBaseAddress), 75 sizeof(fBuf), simpleReader, NULL, this)) 76 return false; 77 78 fDesc = IOMemoryDescriptor::withAddress(fBuf, sizeof(fBuf), kIODirectionOutIn); 79 if (fDesc == NULL) { 80 return false; 81 } 82 83 IOReturn status = fDesc->prepare(); 84 if( status != kIOReturnSuccess ) 85 { 86 fDesc->release(); 87 fDesc = NULL; 88 return false; 89 } 90 91 // Output Master Control - 400 Mbit, broadcast channel base 63, 31 output plugs 92 fBuf[0] = OSSwapHostToBigInt32((2 << kIOFWPCRDataRatePhase) | 93 (63 << kIOFWPCRBroadcastBasePhase) | 94 (0xff << kIOFWPCRExtensionPhase) | 95 (31 << kIOFWPCRNumPlugsPhase)); 96 97 // Input Master Control - 400 Mbit, 31 output plugs 98 fBuf[32] = OSSwapHostToBigInt32((2 << kIOFWPCRDataRatePhase) | 99 (0xff << kIOFWPCRExtensionPhase) | 100 (31 << kIOFWPCRNumPlugsPhase)); 101 102 fAVCTargetSpace = NULL; 103 104 // Register for messages from IOFireWireLocalNode to detect bus-resets! 105 IOFireWireController *pFireWireController = OSDynamicCast(IOFireWireController, bus); 106 if (pFireWireController) 107 { 108 IOFireWireLocalNode *pFireWireLocalNode = (pFireWireController)->getLocalNode(pFireWireController); 109 if (pFireWireLocalNode) 110 { 111 // Register with the IOFireWireBus for messages 112 fNotifier = pFireWireLocalNode->registerInterest(gIOGeneralInterest,MyServiceInterestHandler,this,this); 113 } 114 } 115 116 // Get the pointert to the IOFireWireAVCTargetSpace 117 // Note: This will create it, if it doesn't already exist. 118 fAVCTargetSpace = IOFireWireAVCTargetSpace::getAVCTargetSpace((IOFireWireController*)bus); 119 if(fAVCTargetSpace) 120 fAVCTargetSpace->activateWithUserClient((IOFireWireAVCProtocolUserClient*)0xFFFFFFFF); 121 122 return true; 123} 124 125IOFireWirePCRSpace * IOFireWirePCRSpace::getPCRAddressSpace(IOFireWireBus *bus) 126{ 127 IOFWAddressSpace *existing; 128 IOFireWirePCRSpace *space; 129 130 //IOLog( "IOFireWirePCRSpace::getPCRAddressSpace\n"); 131 132 existing = bus->getAddressSpace(FWAddress(kCSRRegisterSpaceBaseAddressHi, kPCRBaseAddress)); 133 if(existing && OSDynamicCast(IOFireWirePCRSpace, existing)) { 134 existing->retain(); 135 return OSDynamicCast(IOFireWirePCRSpace, existing); 136 } 137 space = new IOFireWirePCRSpace; 138 if(space) { 139 if(!space->init(bus)) { 140 space->release(); 141 space = NULL; 142 } 143 } 144 return space; 145} 146 147 148UInt32 IOFireWirePCRSpace::doWrite(UInt16 nodeID, IOFWSpeed &speed, FWAddress addr, UInt32 len, 149 const void *buf, IOFWRequestRefCon refcon) 150{ 151 //IOLog( "IOFireWirePCRSpace::doWrite (0x%08X)\n",(int) this); 152 153 if(addr.addressHi != kCSRRegisterSpaceBaseAddressHi) 154 return kFWResponseAddressError; 155 if((addr.addressLo < kPCRBaseAddress) || (addr.addressLo + len > kPCRBaseAddress + 64*4)) 156 return kFWResponseAddressError; 157 158 //IOLog("PCRSpace write, addr %x len %d\n", addr.addressLo, len); 159 // Writes to Plug Control registers not allowed. 160 if(!fControl->isLockRequest(refcon)) 161 return kFWResponseTypeError; 162 163 // Only allow update of one register. 164 if(len != 4 || (addr.addressLo & 3)) 165 return kFWResponseTypeError; 166 167 UInt32 newVal = *(const UInt32 *)buf; 168 UInt32 offset = (addr.addressLo - kPCRBaseAddress)/4; 169 UInt32 oldVal = OSSwapBigToHostInt32(fBuf[offset]); 170 171 fBuf[offset] = newVal; 172 if(fClients[offset].func) 173 (fClients[offset].func)(fClients[offset].refcon, nodeID, (offset-1) & 31, oldVal, OSSwapBigToHostInt32(newVal)); 174 175 // Notify target space object of plug value modification 176 if ((fAVCTargetSpace) && (offset > 0) && (offset < 32)) 177 fAVCTargetSpace->pcrModified(IOFWAVCPlugIsochOutputType,(offset-1),OSSwapBigToHostInt32(newVal)); 178 else if ((fAVCTargetSpace) && (offset > 32) && (offset < 64)) 179 fAVCTargetSpace->pcrModified(IOFWAVCPlugIsochInputType,(offset-33),OSSwapBigToHostInt32(newVal)); 180 181 return kFWResponseComplete; 182} 183 184IOReturn IOFireWirePCRSpace::activate() 185{ 186 IOReturn res = kIOReturnSuccess; 187 188 //IOLog( "IOFireWirePCRSpace::activate (0x%08X)\n",(int) this); 189 190 if(!fActivations++) 191 res = IOFWAddressSpace::activate(); 192 193 return res; 194} 195 196void IOFireWirePCRSpace::deactivate() 197{ 198 //IOLog( "IOFireWirePCRSpace::deactivate (0x%08X)\n",(int) this); 199 200 if(!--fActivations) 201 { 202 IOFWAddressSpace::deactivate(); 203 204 // If we successfully registered for notifications, remove it now! 205 if (fNotifier) 206 fNotifier->remove(); 207 fNotifier = NULL; 208 } 209} 210 211IOReturn IOFireWirePCRSpace::allocatePlug(void *refcon, IOFireWirePCRCallback func, UInt32 &plug, Client* head) 212{ 213 UInt32 i; 214 IOReturn res = kIOReturnNoResources; 215 216 //IOLog( "IOFireWirePCRSpace::allocatePlug (0x%08X)\n",(int) this); 217 218 fControl->closeGate(); 219 for(i=0; i<32; i++) { 220 if(!head[i].func) { 221 head[i].func = func; 222 head[i].refcon = refcon; 223 plug = i; 224 res = kIOReturnSuccess; 225 break; 226 } 227 } 228 fControl->openGate(); 229 return res; 230} 231 232void IOFireWirePCRSpace::freePlug(UInt32 plug, Client* client) 233{ 234 //IOLog( "IOFireWirePCRSpace::freePlug (0x%08X)\n",(int) this); 235 236 fControl->closeGate(); 237 client->func = NULL; 238 fBuf[plug] = 0; 239 fControl->openGate(); 240} 241 242UInt32 IOFireWirePCRSpace::readPlug(UInt32 plug) 243{ 244 //IOLog( "IOFireWirePCRSpace::readPlug (0x%08X)\n",(int) this); 245 246 UInt32 val; 247 fControl->closeGate(); 248 val = OSSwapBigToHostInt32(fBuf[plug]); 249 fControl->openGate(); 250 return val; 251} 252 253 254IOReturn IOFireWirePCRSpace::updatePlug(UInt32 plug, UInt32 oldVal, UInt32 newVal) 255{ 256 //IOLog( "IOFireWirePCRSpace::updatePlug (0x%08X)\n",(int) this); 257 258 IOReturn res; 259 fControl->closeGate(); 260 if(oldVal == OSSwapBigToHostInt32(fBuf[plug])) { 261 fBuf[plug] = OSSwapHostToBigInt32(newVal); 262 res = kIOReturnSuccess; 263 264 // Notify target space object of plug value modification 265 if ((fAVCTargetSpace) && (plug > 0) && (plug < 32)) 266 fAVCTargetSpace->pcrModified(IOFWAVCPlugIsochOutputType,(plug-1),newVal); 267 else if ((fAVCTargetSpace) && (plug > 32) && (plug < 64)) 268 fAVCTargetSpace->pcrModified(IOFWAVCPlugIsochInputType,(plug-33),newVal); 269 } 270 else 271 res = kIOReturnCannotLock; 272 fControl->openGate(); 273 return res; 274} 275 276IOReturn IOFireWirePCRSpace::allocateInputPlug(void *refcon, IOFireWirePCRCallback func, UInt32 &plug) 277{ 278 //IOLog( "IOFireWirePCRSpace::allocateInputPlug (0x%08X)\n",(int) this); 279 280 return allocatePlug(refcon, func, plug, fClients+33); 281} 282 283void IOFireWirePCRSpace::freeInputPlug(UInt32 plug) 284{ 285 //IOLog( "IOFireWirePCRSpace::freeInputPlug (0x%08X)\n",(int) this); 286 287 freePlug(plug+33, fClients+plug+33); 288} 289 290 291UInt32 IOFireWirePCRSpace::readInputPlug(UInt32 plug) 292{ 293 //IOLog( "IOFireWirePCRSpace::readInputPlug (0x%08X)\n",(int) this); 294 295 return readPlug(plug+33); 296} 297 298 299IOReturn IOFireWirePCRSpace::updateInputPlug(UInt32 plug, UInt32 oldVal, UInt32 newVal) 300{ 301 //IOLog( "IOFireWirePCRSpace::updateInputPlug (0x%08X)\n",(int) this); 302 303 return updatePlug(plug+33, oldVal, newVal); 304} 305 306IOReturn IOFireWirePCRSpace::allocateOutputPlug(void *refcon, IOFireWirePCRCallback func, UInt32 &plug) 307{ 308 IOReturn result; 309 310 //IOLog( "IOFireWirePCRSpace::allocateOutputPlug (0x%08X)\n",(int) this); 311 312 result = allocatePlug(refcon, func, plug, fClients+1); 313 return result; 314} 315 316void IOFireWirePCRSpace::freeOutputPlug(UInt32 plug) 317{ 318 //IOLog( "IOFireWirePCRSpace::freeOutputPlug (0x%08X)\n",(int) this); 319 320 freePlug(plug+1, fClients+plug+1); 321} 322 323 324UInt32 IOFireWirePCRSpace::readOutputPlug(UInt32 plug) 325{ 326 //IOLog( "IOFireWirePCRSpace::readOutputPlug (0x%08X)\n",(int) this); 327 328 return readPlug(plug+1); 329} 330 331 332IOReturn IOFireWirePCRSpace::updateOutputPlug(UInt32 plug, UInt32 oldVal, UInt32 newVal) 333{ 334 //IOLog( "IOFireWirePCRSpace::updateOutputPlug (0x%08X)\n",(int) this); 335 336 return updatePlug(plug+1, oldVal, newVal); 337} 338 339UInt32 IOFireWirePCRSpace::readOutputMasterPlug() 340{ 341 //IOLog( "IOFireWirePCRSpace::readOutputMasterPlug (0x%08X)\n",(int) this); 342 343 return readPlug(0); 344} 345 346 347IOReturn IOFireWirePCRSpace::updateOutputMasterPlug(UInt32 oldVal, UInt32 newVal) 348{ 349 //IOLog( "IOFireWirePCRSpace::updateOutputMasterPlug (0x%08X)\n",(int) this); 350 351 return updatePlug(0, oldVal, newVal); 352} 353 354UInt32 IOFireWirePCRSpace::readInputMasterPlug() 355{ 356 //IOLog( "IOFireWirePCRSpace::readInputMasterPlug (0x%08X)\n",(int) this); 357 358 return readPlug(32); 359} 360 361 362IOReturn IOFireWirePCRSpace::updateInputMasterPlug(UInt32 oldVal, UInt32 newVal) 363{ 364 //IOLog( "IOFireWirePCRSpace::updateInputMasterPlug (0x%08X)\n",(int) this); 365 366 return updatePlug(32, oldVal, newVal); 367} 368 369void IOFireWirePCRSpace::setAVCTargetSpacePointer(IOFireWireAVCTargetSpace *pAVCTargetSpace) 370{ 371 //IOLog( "IOFireWirePCRSpace::setAVCTargetSpacePointer (0x%08X)\n",(int) this); 372 373 // NOTE: This function no longer does anything, since the relationship 374 // between the IOFireWirePCRSpace, and the IOFireWireAVCTargetSpace 375 // is now established in IOFireWirePCRSpace::init(...). 376 377 // fAVCTargetSpace = pAVCTargetSpace; 378 return; 379} 380 381void IOFireWirePCRSpace::clearAllP2PConnections(void) 382{ 383 int i; 384 UInt32 oldVal; 385 386 //IOLog( "IOFireWirePCRSpace::clearAllP2PConnections (0x%08X)\n",(int) this); 387 388 // Handle oPCRs 389 for(i=0; i<32; i++) 390 { 391 fControl->closeGate(); 392 oldVal = OSSwapBigToHostInt32(fBuf[i+1]); 393 if ((oldVal & 0x3F000000) != 0) 394 { 395 fBuf[i+1] &= OSSwapHostToBigInt32(0xC0FFFFFF); // Clear P2P field 396 397 // If this plug has a client, notify it 398 if(fClients[i+1].func) 399 (fClients[i+1].func)(fClients[i+1].refcon, 0xFFFF, i, oldVal, OSSwapBigToHostInt32(fBuf[i+1])); 400 401 // Notify the AVC Target Space Object of the change 402 if (fAVCTargetSpace) 403 fAVCTargetSpace->pcrModified(IOFWAVCPlugIsochOutputType,i,OSSwapBigToHostInt32(fBuf[i+1])); 404 } 405 fControl->openGate(); 406 } 407 408 // Handle iPCRs 409 for(i=0; i<32; i++) 410 { 411 fControl->closeGate(); 412 oldVal = OSSwapBigToHostInt32(fBuf[i+33]); 413 if ((oldVal & 0x3F000000) != 0) 414 { 415 fBuf[i+33] &= OSSwapHostToBigInt32(0xC0FFFFFF); // Clear P2P field 416 417 // If this plug has a client, notify it 418 if(fClients[i+33].func) 419 (fClients[i+33].func)(fClients[i+33].refcon, 0xFFFF, i, oldVal, OSSwapBigToHostInt32(fBuf[i+33])); 420 421 // Notify the AVC Target Space Object of the change 422 if (fAVCTargetSpace) 423 fAVCTargetSpace->pcrModified(IOFWAVCPlugIsochInputType,i,OSSwapBigToHostInt32(fBuf[i+33])); 424 } 425 fControl->openGate(); 426 } 427 428 return; 429} 430