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 * IOFireWireLibPseudoAddressSpace.cpp 24 * IOFireWireLib 25 * 26 * Created by NWG on Wed Dec 06 2000. 27 * Copyright (c) 2000 Apple, Inc. All rights reserved. 28 * 29 */ 30 31#import "IOFireWireLibPseudoAddressSpace.h" 32#import "IOFireWireLibDevice.h" 33 34#import <IOKit/iokitmig.h> 35#import <System/libkern/OSCrossEndian.h> 36 37namespace IOFireWireLib { 38 39 PseudoAddressSpace::Interface PseudoAddressSpace::sInterface = 40 { 41 INTERFACEIMP_INTERFACE, 42 1, 1, // version/revision 43 & PseudoAddressSpace::SSetWriteHandler, 44 & PseudoAddressSpace::SSetReadHandler, 45 & PseudoAddressSpace::SSetSkippedPacketHandler, 46 & PseudoAddressSpace::SNotificationIsOn, 47 & PseudoAddressSpace::STurnOnNotification, 48 & PseudoAddressSpace::STurnOffNotification, 49 & PseudoAddressSpace::SClientCommandIsComplete, 50 & PseudoAddressSpace::SGetFWAddress, 51 & PseudoAddressSpace::SGetBuffer, 52 & PseudoAddressSpace::SGetBufferSize, 53 & PseudoAddressSpace::SGetRefCon 54 } ; 55 56 IUnknownVTbl** 57 PseudoAddressSpace::Alloc( Device& userclient, UserObjectHandle inKernAddrSpaceRef, void* inBuffer, UInt32 inBufferSize, 58 void* inBackingStore, void* inRefCon ) 59 { 60 PseudoAddressSpace* me = nil ; 61 62 try { 63 me = new PseudoAddressSpace(userclient, inKernAddrSpaceRef, inBuffer, inBufferSize, inBackingStore, inRefCon) ; 64 } catch (...) { 65 } 66 67 return (nil == me) ? nil : reinterpret_cast<IUnknownVTbl**>(& me->GetInterface()) ; 68 } 69 70 HRESULT STDMETHODCALLTYPE 71 PseudoAddressSpace::QueryInterface(REFIID iid, LPVOID* ppv) 72 { 73 HRESULT result = S_OK ; 74 *ppv = nil ; 75 76 CFUUIDRef interfaceID = CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, iid) ; 77 78 if ( CFEqual(interfaceID, IUnknownUUID) || CFEqual(interfaceID, kIOFireWirePseudoAddressSpaceInterfaceID) ) 79 { 80 *ppv = & GetInterface() ; 81 AddRef() ; 82 } 83 else 84 { 85 *ppv = nil ; 86 result = E_NOINTERFACE ; 87 } 88 89 CFRelease(interfaceID) ; 90 return result ; 91 } 92 93 // ============================================================ 94 // 95 // interface table methods 96 // 97 // ============================================================ 98 99 const PseudoAddressSpace::WriteHandler 100 PseudoAddressSpace::SSetWriteHandler( AddressSpaceRef self, WriteHandler inWriter ) 101 { 102 return IOFireWireIUnknown::InterfaceMap<PseudoAddressSpace>::GetThis(self)->SetWriteHandler(inWriter); 103 } 104 105 const PseudoAddressSpace::ReadHandler 106 PseudoAddressSpace::SSetReadHandler(AddressSpaceRef self, ReadHandler inReader) 107 { 108 return IOFireWireIUnknown::InterfaceMap<PseudoAddressSpace>::GetThis(self)->SetReadHandler(inReader); 109 } 110 111 const PseudoAddressSpace::SkippedPacketHandler 112 PseudoAddressSpace::SSetSkippedPacketHandler(AddressSpaceRef self, SkippedPacketHandler inHandler) 113 { 114 return IOFireWireIUnknown::InterfaceMap<PseudoAddressSpace>::GetThis(self)->SetSkippedPacketHandler(inHandler); 115 } 116 117 Boolean 118 PseudoAddressSpace::SNotificationIsOn(AddressSpaceRef self) 119 { 120 return IOFireWireIUnknown::InterfaceMap<PseudoAddressSpace>::GetThis(self)->mNotifyIsOn; 121 } 122 123 Boolean 124 PseudoAddressSpace::STurnOnNotification(AddressSpaceRef self) 125 { 126 return IOFireWireIUnknown::InterfaceMap<PseudoAddressSpace>::GetThis(self)->TurnOnNotification(self); 127 } 128 129 void 130 PseudoAddressSpace::STurnOffNotification(AddressSpaceRef self) 131 { 132 IOFireWireIUnknown::InterfaceMap<PseudoAddressSpace>::GetThis(self)->TurnOffNotification(); 133 } 134 135 void 136 PseudoAddressSpace::SClientCommandIsComplete(AddressSpaceRef self, FWClientCommandID commandID, IOReturn status) 137 { 138 IOFireWireIUnknown::InterfaceMap<PseudoAddressSpace>::GetThis(self)->ClientCommandIsComplete(commandID, status); 139 } 140 141 void 142 PseudoAddressSpace::SGetFWAddress(AddressSpaceRef self, FWAddress* outAddr) 143 { 144 bcopy (&IOFireWireIUnknown::InterfaceMap<PseudoAddressSpace>::GetThis(self)->mFWAddress, outAddr, sizeof(FWAddress)); 145 } 146 147 void* 148 PseudoAddressSpace::SGetBuffer(AddressSpaceRef self) 149 { 150 return IOFireWireIUnknown::InterfaceMap<PseudoAddressSpace>::GetThis(self)->GetBuffer() ; 151 } 152 153 const UInt32 154 PseudoAddressSpace::SGetBufferSize(AddressSpaceRef self) 155 { 156 return IOFireWireIUnknown::InterfaceMap<PseudoAddressSpace>::GetThis(self)->mBufferSize; 157 } 158 159 void* 160 PseudoAddressSpace::SGetRefCon(AddressSpaceRef self) 161 { 162 return IOFireWireIUnknown::InterfaceMap<PseudoAddressSpace>::GetThis(self)->mRefCon; 163 } 164 165 #pragma mark - 166 // ============================================================ 167 // 168 // class methods 169 // 170 // ============================================================ 171 172 PseudoAddressSpace::PseudoAddressSpace( Device& userclient, UserObjectHandle inKernAddrSpaceRef, 173 void* inBuffer, UInt32 inBufferSize, void* inBackingStore, void* inRefCon) 174 : IOFireWireIUnknown( reinterpret_cast<const IUnknownVTbl &>( sInterface ) ), 175 mNotifyIsOn(false), 176 mWriter( nil ), 177 mReader( nil ), 178 mSkippedPacketHandler( nil ), 179 mUserClient(userclient), 180 mKernAddrSpaceRef(inKernAddrSpaceRef), 181 mBuffer((char*)inBuffer), 182 mBufferSize(inBufferSize), 183 mBackingStore(inBackingStore), 184 mRefCon(inRefCon) 185 { 186 userclient.AddRef() ; 187 188 mPendingLocks = ::CFDictionaryCreateMutable( kCFAllocatorDefault, 0, NULL, NULL ) ; 189 if (!mPendingLocks) 190 throw kIOReturnNoMemory ; 191 192 AddressSpaceInfo info ; 193 194 IOReturn error ; 195 196 uint32_t outputCnt = 0; 197 size_t outputStructSize = sizeof( info ) ; 198 const uint64_t inputs[1]={(const uint64_t)mKernAddrSpaceRef}; 199 200 error = IOConnectCallMethod(mUserClient.GetUserClientConnection(), 201 kPseudoAddrSpace_GetFWAddrInfo, 202 inputs,1, 203 NULL,0, 204 NULL,&outputCnt, 205 &info,&outputStructSize); 206 if (error) 207 { 208 throw error ; 209 } 210 211#ifndef __LP64__ 212 ROSETTA_ONLY( 213 { 214 info.address.nodeID = OSSwapInt16( info.address.nodeID ); 215 info.address.addressHi = OSSwapInt16( info.address.addressHi ); 216 info.address.addressLo = OSSwapInt32( info.address.addressLo ); 217 } 218 ); 219#endif 220 221 mFWAddress = info.address ; 222 } 223 224 PseudoAddressSpace::~PseudoAddressSpace() 225 { 226 227 uint32_t outputCnt = 0; 228 const uint64_t inputs[1]={(const uint64_t)mKernAddrSpaceRef}; 229 230#if IOFIREWIREUSERCLIENTDEBUG > 0 231 IOReturn error = 232#endif 233 234 IOConnectCallScalarMethod(mUserClient.GetUserClientConnection(), 235 kReleaseUserObject, 236 inputs,1,NULL,&outputCnt); 237 238 DebugLogCond( error, "PseudoAddressSpace::~PseudoAddressSpace: error %x releasing address space!\n", error ) ; 239 240 if( mPendingLocks ) 241 { 242 ::CFDictionaryRemoveAllValues( mPendingLocks ); 243 ::CFRelease( mPendingLocks ); 244 mPendingLocks = 0; 245 } 246 247 if( mBuffer and mBufferSize > 0 ) 248 { 249 delete[] mBuffer; 250 mBuffer = 0; 251 mBufferSize = 0; 252 } 253 254 mUserClient.Release() ; 255 } 256 257 // callback management 258 259 #pragma mark - 260 #pragma mark --callback management 261 262 const PseudoAddressSpace::WriteHandler 263 PseudoAddressSpace::SetWriteHandler( WriteHandler inWriter ) 264 { 265 WriteHandler oldWriter = mWriter ; 266 mWriter = inWriter ; 267 268 return oldWriter ; 269 } 270 271 272 const PseudoAddressSpace::ReadHandler 273 PseudoAddressSpace::SetReadHandler( 274 ReadHandler inReader) 275 { 276 ReadHandler oldReader = mReader ; 277 mReader = inReader ; 278 279 return oldReader ; 280 } 281 282 const PseudoAddressSpace::SkippedPacketHandler 283 PseudoAddressSpace::SetSkippedPacketHandler( 284 SkippedPacketHandler inHandler) 285 { 286 SkippedPacketHandler result = mSkippedPacketHandler ; 287 mSkippedPacketHandler = inHandler ; 288 289 return result ; 290 } 291 292 Boolean 293 PseudoAddressSpace::TurnOnNotification( void* callBackRefCon ) 294 { 295 IOReturn err = kIOReturnSuccess ; 296 io_connect_t connection = mUserClient.GetUserClientConnection() ; 297 298 // if notification is already on, skip out. 299 if (mNotifyIsOn) 300 return true ; 301 302 if (!connection) 303 err = kIOReturnNoDevice ; 304 305 if ( kIOReturnSuccess == err ) 306 { 307 uint64_t refrncData[kOSAsyncRef64Count]; 308 refrncData[kIOAsyncCalloutFuncIndex] = (uint64_t) 0; 309 refrncData[kIOAsyncCalloutRefconIndex] = (unsigned long)0; 310 const uint64_t inputs[3] = {(const uint64_t)mKernAddrSpaceRef, (const uint64_t)&PseudoAddressSpace::Writer, (const uint64_t)callBackRefCon}; 311 uint32_t outputCnt = 0; 312 err = IOConnectCallAsyncScalarMethod(connection, 313 kSetAsyncRef_Packet, 314 mUserClient.GetAsyncPort(), 315 refrncData,kOSAsyncRef64Count, 316 inputs,3, 317 NULL,&outputCnt); 318 } 319 320 if ( kIOReturnSuccess == err) 321 { 322 uint64_t refrncData[kOSAsyncRef64Count]; 323 refrncData[kIOAsyncCalloutFuncIndex] = (uint64_t) 0; 324 refrncData[kIOAsyncCalloutRefconIndex] = (unsigned long)0; 325 const uint64_t inputs[3] = {(const uint64_t)mKernAddrSpaceRef, (const uint64_t)& SkippedPacket, (const uint64_t)callBackRefCon}; 326 uint32_t outputCnt = 0; 327 err = IOConnectCallAsyncScalarMethod(connection, 328 kSetAsyncRef_SkippedPacket, 329 mUserClient.GetAsyncPort(), 330 refrncData,kOSAsyncRef64Count, 331 inputs,3, 332 NULL,&outputCnt); 333 } 334 335 if ( kIOReturnSuccess == err) 336 { 337 uint64_t refrncData[kOSAsyncRef64Count]; 338 refrncData[kIOAsyncCalloutFuncIndex] = (uint64_t) 0; 339 refrncData[kIOAsyncCalloutRefconIndex] = (unsigned long)0; 340 const uint64_t inputs[3] = {(const uint64_t)mKernAddrSpaceRef, (const uint64_t)& Reader, (const uint64_t)callBackRefCon}; 341 uint32_t outputCnt = 0; 342 err = IOConnectCallAsyncScalarMethod(connection, 343 kSetAsyncRef_Read, 344 mUserClient.GetAsyncPort(), 345 refrncData,kOSAsyncRef64Count, 346 inputs,3, 347 NULL,&outputCnt); 348 } 349 350 if ( kIOReturnSuccess == err ) 351 mNotifyIsOn = true ; 352 353 return ( kIOReturnSuccess == err ) ; 354 } 355 356 void 357 PseudoAddressSpace::TurnOffNotification() 358 { 359 IOReturn err = kIOReturnSuccess ; 360 io_connect_t connection = mUserClient.GetUserClientConnection() ; 361 362 // if notification isn't on, skip out. 363 if (!mNotifyIsOn) 364 return ; 365 366 if (!connection) 367 err = kIOReturnNoDevice ; 368 369 if ( kIOReturnSuccess == err ) 370 { 371 372 uint64_t refrncData[kOSAsyncRef64Count]; 373 refrncData[kIOAsyncCalloutFuncIndex] = (uint64_t) 0; 374 refrncData[kIOAsyncCalloutRefconIndex] = (unsigned long)0; 375 const uint64_t inputs[3] = {(const uint64_t)mKernAddrSpaceRef, (const uint64_t)0, (const uint64_t)this}; 376 uint32_t outputCnt = 0; 377 err = IOConnectCallAsyncScalarMethod(connection, 378 kSetAsyncRef_Packet, 379 mUserClient.GetAsyncPort(), 380 refrncData,kOSAsyncRef64Count, 381 inputs,3, 382 NULL,&outputCnt); 383 384 outputCnt = 0; 385 err = IOConnectCallAsyncScalarMethod(connection, 386 kSetAsyncRef_SkippedPacket, 387 mUserClient.GetAsyncPort(), 388 refrncData,kOSAsyncRef64Count, 389 inputs,3, 390 NULL,&outputCnt); 391 392 outputCnt = 0; 393 err = IOConnectCallAsyncScalarMethod(connection, 394 kSetAsyncRef_Read, 395 mUserClient.GetAsyncPort(), 396 refrncData,kOSAsyncRef64Count, 397 inputs,3, 398 NULL,&outputCnt); 399 } 400 401 mNotifyIsOn = false ; 402 } 403 404 void 405 PseudoAddressSpace::ClientCommandIsComplete( 406 FWClientCommandID commandID, 407 IOReturn status) 408 { 409 void** args ; 410 411 if (::CFDictionaryGetValueIfPresent( mPendingLocks, commandID, (const void**) &args ) && (status == kIOReturnSuccess) ) 412 { 413 ::CFDictionaryRemoveValue( mPendingLocks, commandID ) ; 414 AddressSpaceRef addressSpaceRef = (AddressSpaceRef) args[0] ; 415 416 ++args ; // we tacked on an extra arg at the beginning, so we undo that. 417 418 bool equal ; 419 UInt32 offset = (unsigned long)args[6] ; 420 421 if ( (unsigned long) args[1] == 8 ) 422 // 32-bit compare 423 equal = *(UInt32*)((char*)mBackingStore + offset) == *(UInt32*)(mBuffer + (unsigned long)args[2]) ; 424 else 425 // 64-bit compare 426 equal = *(UInt64*)((char*)mBackingStore + offset) == *(UInt64*)(mBuffer + (unsigned long)args[2]) ; 427 428 if ( equal ) 429 { 430 mWriter( 431 addressSpaceRef, 432 (FWClientCommandID)(args[0]), // commandID, 433 (unsigned long)(args[1]) >> 1, // packetSize 434 mBuffer + (unsigned long)args[2] + ( (unsigned long) args[1] == 8 ? 4 : 8),// packet 435 (UInt16)(unsigned long)args[3], // nodeID 436 (unsigned long)(args[5]), // addr.nodeID, addr.addressHi, 437 (unsigned long)(args[6]), 438 (void*) mRefCon) ; // refcon 439 } 440 else 441 status = kFWResponseAddressError ; 442 443 delete[] (args-1) ; 444 } 445 446 uint32_t outputCnt = 0; 447 const uint64_t inputs[3] = {(const uint64_t)mKernAddrSpaceRef, (const uint64_t)commandID, status}; 448 449 #if IOFIREWIREUSERCLIENTDEBUG > 0 450 OSStatus err = 451 #endif 452 453 IOConnectCallScalarMethod(mUserClient.GetUserClientConnection(), 454 kPseudoAddrSpace_ClientCommandIsComplete, 455 inputs,3, 456 NULL,&outputCnt); 457 458#ifdef __LP64__ 459 DebugLogCond( err, "PseudoAddressSpace::ClientCommandIsComplete: err=0x%08X\n", (UInt32)err ) ; 460#else 461 DebugLogCond( err, "PseudoAddressSpace::ClientCommandIsComplete: err=0x%08lX\n", (UInt32)err ) ; 462#endif 463 } 464 465 void 466 PseudoAddressSpace::Writer( AddressSpaceRef refcon, IOReturn result, void** args, int numArgs) 467 { 468 PseudoAddressSpace* me = IOFireWireIUnknown::InterfaceMap<PseudoAddressSpace>::GetThis(refcon) ; 469 470 if ( !me->mWriter || ( (bool)args[7] && !me->mReader) ) 471 { 472 me->ClientCommandIsComplete( args[0], kFWResponseTypeError) ; 473 return ; 474 } 475 else if ( (bool)args[7] ) 476 { 477// void** lockValues = new (void*)[numArgs+1] ; 478 void** lockValues = (void**) new UInt32 *[numArgs+1] ; 479 480 bcopy( args, & lockValues[1], sizeof(void*) * numArgs ) ; 481 lockValues[0] = refcon ; 482 483 ::CFDictionaryAddValue( me->mPendingLocks, args[0], lockValues ) ; 484 485 UInt32 offset = (unsigned long)args[6] ; // !!! hack - all address spaces have 0 for addressLo 486 487 (me->mReader)( (AddressSpaceRef) refcon, 488 (FWClientCommandID)(args[0]), // commandID, 489 (unsigned long)(args[1]), // packetSize 490 offset, // packetOffset 491 (UInt16)(unsigned long)(args[3]), // nodeID; double cast avoids compiler warning 492 (unsigned long)(args[5]), // addr.addressHi, 493 (unsigned long)(args[6]), // addr.addressLo 494 (void*) me->mRefCon) ; // refcon 495 496 } 497 else 498 { 499 (me->mWriter)( 500 (AddressSpaceRef) refcon, 501 (FWClientCommandID) args[0], // commandID, 502 (unsigned long)(args[1]), // packetSize 503 me->mBuffer + (unsigned long)(args[2]), // packet 504 (UInt16)(unsigned long)(args[3]), // nodeID 505 (unsigned long)(args[5]), // addr.addressHi, addr.addressLo 506 (unsigned long)(args[6]), 507 (void*) me->mRefCon) ; // refcon 508 509 } 510 } 511 512 void 513 PseudoAddressSpace::SkippedPacket( AddressSpaceRef refcon, IOReturn result, FWClientCommandID commandID, UInt32 packetCount) 514 { 515 PseudoAddressSpace* me = IOFireWireIUnknown::InterfaceMap<PseudoAddressSpace>::GetThis(refcon) ; 516 517 if (me->mSkippedPacketHandler) 518 (me->mSkippedPacketHandler)( refcon, commandID, packetCount) ; 519 } 520 521 void 522 PseudoAddressSpace::Reader( AddressSpaceRef refcon, IOReturn result, void** args, int numArgs ) 523 { 524 PseudoAddressSpace* me = IOFireWireIUnknown::InterfaceMap<PseudoAddressSpace>::GetThis(refcon) ; 525 526 527 if (me->mReader) 528 { 529 (me->mReader)( (AddressSpaceRef) refcon, 530 (FWClientCommandID) args[0], // commandID, 531 (unsigned long)(args[1]), // packetSize 532 (unsigned long)(args[2]), // packetOffset 533 (UInt16)(unsigned long)(args[3]), // nodeID 534 (unsigned long)(args[5]), // addr.nodeID, addr.addressHi, 535 (unsigned long)(args[6]), 536 (void*) me->mRefCon) ; // refcon 537 } 538 else 539 me->ClientCommandIsComplete( args[0], //commandID 540 kFWResponseTypeError) ; 541 } 542 543 544 #pragma mark - 545 #pragma mark --accessors 546 547 const FWAddress& 548 PseudoAddressSpace::GetFWAddress() 549 { 550 return mFWAddress ; 551 } 552 553 void* 554 PseudoAddressSpace::GetBuffer() 555 { 556 return mBackingStore ; // I assume this is what the user wants instead of 557 // the queue buffer stored in mBuffer. 558 } 559 560 const UInt32 561 PseudoAddressSpace::GetBufferSize() 562 { 563 return mBufferSize ; 564 } 565 566 void* 567 PseudoAddressSpace::GetRefCon() 568 { 569 return mRefCon ; 570 } 571} 572