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/IOFireWireLib.h> 25 26// private 27#include "IOFireWireLibVectorCommand.h" 28#include "IOFireWireLibCommand.h" 29#import "IOFireWireLibDevice.h" 30#import "IOFireWireLibPriv.h" 31 32namespace IOFireWireLib 33{ 34 35 IOFireWireLibVectorCommandInterface VectorCommand::sInterface = 36 { 37 INTERFACEIMP_INTERFACE, 38 1, 1, // version/revision 39 40 &VectorCommand::SSubmit, 41 &VectorCommand::SSubmitWithRefconAndCallback, 42 &VectorCommand::SIsExecuting, 43 &VectorCommand::SSetCallback, 44 &VectorCommand::SSetRefCon, 45 &VectorCommand::SGetRefCon, 46 &VectorCommand::SSetFlags, 47 &VectorCommand::SGetFlags, 48 &VectorCommand::SEnsureCapacity, 49 &VectorCommand::SAddCommand, 50 &VectorCommand::SRemoveCommand, 51 &VectorCommand::SInsertCommandAtIndex, 52 &VectorCommand::SGetCommandAtIndex, 53 &VectorCommand::SGetIndexOfCommand, 54 &VectorCommand::SRemoveCommandAtIndex, 55 &VectorCommand::SRemoveAllCommands, 56 &VectorCommand::SGetCommandCount 57 }; 58 59 CFArrayCallBacks VectorCommand::sArrayCallbacks = 60 { 61 0, // version 62 &VectorCommand::SRetainCallback, // retain 63 &VectorCommand::SReleaseCallback, // release 64 NULL, // copyDescription 65 NULL, // equal - NULL means pointer equality will be used 66 }; 67 68 // Alloc 69 // 70 // 71 72 IUnknownVTbl** VectorCommand::Alloc( Device& userclient, 73 IOFireWireLibCommandCallback callback, 74 void* inRefCon ) 75 { 76 VectorCommand * me = new VectorCommand( userclient, callback, inRefCon ); 77 if( !me ) 78 return nil; 79 80 return reinterpret_cast<IUnknownVTbl**>(&me->GetInterface()); 81 } 82 83 // VectorCommand 84 // 85 // 86 87 VectorCommand::VectorCommand( Device & userClient, 88 IOFireWireLibCommandCallback inCallback, void* inRefCon ) 89 : IOFireWireIUnknown( reinterpret_cast<const IUnknownVTbl &>( sInterface ) ), 90 mUserClient( userClient ), 91 mKernCommandRef( 0 ), 92 mRefCon( inRefCon ), 93 mCallback( inCallback ), 94 mFlags( 0 ), 95 mInflightCount( 0 ), 96 mSubmitBuffer( NULL ), 97 mSubmitBufferSize( 0 ), 98 mResultBuffer( NULL ), 99 mResultBufferSize( 0 ) 100 { 101 mUserClient.AddRef(); 102 103 mCommandArray = CFArrayCreateMutable( kCFAllocatorDefault, 104 0, // unlimited capacity 105 &sArrayCallbacks ); 106 if( mCommandArray == NULL ) 107 { 108 throw kIOReturnNoMemory; 109 } 110 111 // output data 112 UserObjectHandle kernel_ref = 0; 113 size_t outputStructCnt = sizeof(kernel_ref); 114 115 // send it down 116 IOReturn status = IOConnectCallStructMethod( mUserClient.GetUserClientConnection(), 117 kVectorCommandCreate, 118 NULL, 0, 119 &kernel_ref, &outputStructCnt ); 120 if( status != kIOReturnSuccess ) 121 { 122 throw status; 123 } 124 125 mKernCommandRef = kernel_ref; 126 } 127 128 // ~VectorCommand 129 // 130 // 131 132 VectorCommand::~VectorCommand() 133 { 134 if( mKernCommandRef ) 135 { 136 IOReturn result = kIOReturnSuccess; 137 138 uint32_t outputCnt = 0; 139 const uint64_t inputs[1]={ (const uint64_t)mKernCommandRef }; 140 result = IOConnectCallScalarMethod( mUserClient.GetUserClientConnection(), 141 kReleaseUserObject, 142 inputs, 1, 143 NULL, &outputCnt); 144 145 DebugLogCond( result, "VectorCommand::~VectorCommand: command release returned 0x%08x\n", result ); 146 } 147 148 // free any current storage 149 if( mSubmitBuffer != NULL ) 150 { 151 vm_deallocate( mach_task_self(), (vm_address_t)mSubmitBuffer, mSubmitBufferSize ); 152 mSubmitBuffer = NULL; 153 mSubmitBufferSize = 0; 154 } 155 156 if( mResultBuffer != NULL ) 157 { 158 vm_deallocate( mach_task_self(), (vm_address_t)mResultBuffer, mResultBufferSize ); 159 mResultBuffer = NULL; 160 mResultBufferSize = 0; 161 } 162 163 if( mCommandArray ) 164 { 165 CFRelease( mCommandArray ); 166 mCommandArray = NULL; 167 } 168 169 mUserClient.Release(); 170 } 171 172 // QueryInterface 173 // 174 // 175 176 HRESULT 177 VectorCommand::QueryInterface( REFIID iid, LPVOID* ppv ) 178 { 179 HRESULT result = S_OK; 180 *ppv = nil; 181 182 CFUUIDRef interfaceID = CFUUIDCreateFromUUIDBytes( kCFAllocatorDefault, iid ); 183 184 if( CFEqual(interfaceID, IUnknownUUID) || CFEqual(interfaceID, kIOFireWireVectorCommandInterfaceID) ) 185 { 186 *ppv = &GetInterface(); 187 AddRef(); 188 } 189 else 190 { 191 *ppv = nil; 192 result = E_NOINTERFACE; 193 } 194 195 CFRelease( interfaceID ); 196 return result; 197 } 198 199 // EnsureCapacity 200 // 201 // 202 203 IOReturn VectorCommand::SEnsureCapacity( IOFireWireLibVectorCommandRef self, UInt32 capacity ) 204 { 205 return IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self)->EnsureCapacity( capacity ); 206 } 207 208 IOReturn VectorCommand::EnsureCapacity( UInt32 capacity ) 209 { 210 IOReturn status = kIOReturnSuccess; 211 212 mach_vm_size_t required_submit_size = capacity * sizeof(CommandSubmitParams); 213 mach_vm_size_t required_result_size = capacity * sizeof(CommandSubmitResult); 214 215 // do we have enough space? 216 if( (mSubmitBufferSize < required_submit_size) || 217 (mResultBufferSize < required_result_size) ) 218 { 219 // 220 // allocate new buffers 221 // 222 223 // allocate the submit buffer 224 vm_address_t submit_buffer = NULL; 225 status = vm_allocate( mach_task_self(), &submit_buffer, required_submit_size, true /*anywhere*/ ) ; 226 if ( !submit_buffer && (status == kIOReturnSuccess) ) 227 { 228 status = kIOReturnNoMemory; 229 } 230 231 // allocate the result buffer 232 vm_address_t result_buffer = NULL; 233 status = vm_allocate( mach_task_self(), &result_buffer, required_result_size, true /*anywhere*/ ) ; 234 if ( !result_buffer && (status == kIOReturnSuccess) ) 235 { 236 status = kIOReturnNoMemory; 237 } 238 239 // 240 // send the buffers to the kernel 241 // 242 243 if( status == kIOReturnSuccess ) 244 { 245 // send the buffer to the kernel 246 247 // inputs 248 const uint64_t inputs[4] = { (const uint64_t)submit_buffer, 249 (const uint64_t)required_submit_size, 250 (const uint64_t)result_buffer, 251 (const uint64_t)required_result_size }; 252 253 // outputs 254 uint32_t output_count = 0; 255 256 status = IOConnectCallScalarMethod( mUserClient.GetUserClientConnection(), 257 mUserClient.MakeSelectorWithObject( kVectorCommandSetBuffers, mKernCommandRef ), 258 inputs, 4, 259 NULL, &output_count); 260 } 261 262 // 263 // free any prior storage 264 // 265 266 if( status == kIOReturnSuccess ) 267 { 268 // this must be done after calling the kernel so the kernel can release it's wiring, else we'd hang 269 // we also only do this if the above kernel call was successful as we may hang if the memory is still wired 270 271 if( mSubmitBuffer != NULL ) 272 { 273 vm_deallocate( mach_task_self(), (vm_address_t)mSubmitBuffer, mSubmitBufferSize ); 274 mSubmitBuffer = NULL; 275 mSubmitBufferSize = 0; 276 } 277 278 if( mResultBuffer != NULL ) 279 { 280 vm_deallocate( mach_task_self(), (vm_address_t)mResultBuffer, mResultBufferSize ); 281 mResultBuffer = NULL; 282 mResultBufferSize = 0; 283 } 284 } 285 286 // 287 // remember our storage 288 // 289 290 if( status == kIOReturnSuccess ) 291 { 292 mSubmitBuffer = (CommandSubmitParams*)submit_buffer; 293 mSubmitBufferSize = required_submit_size; 294 295 mResultBuffer = (CommandSubmitResult*)result_buffer; 296 mResultBufferSize = required_result_size; 297 } 298 } 299 300 return status; 301 } 302 303 // Submit 304 // 305 // 306 307 IOReturn 308 VectorCommand::SSubmit( IOFireWireLibVectorCommandRef self ) 309 { 310 return IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self)->Submit(); 311 } 312 313 IOReturn 314 VectorCommand::Submit() 315 { 316 IOReturn status = kIOReturnSuccess; 317 318 if( mInflightCount != 0 ) 319 { 320 status = kIOReturnNotReady; 321 } 322 323 CFIndex count = 0; 324 if( status == kIOReturnSuccess ) 325 { 326 count = CFArrayGetCount( mCommandArray ); 327 status = EnsureCapacity( count ); 328 } 329 330 if( status == kIOReturnSuccess ) 331 { 332 // reset vector status 333 mStatus = kIOReturnSuccess; 334 335 for( CFIndex index = 0; (status == kIOReturnSuccess) && (index < count); index++ ) 336 { 337 IOFireWireLibCommandRef command = (IOFireWireLibCommandRef)CFArrayGetValueAtIndex( mCommandArray, index ); 338 339 Cmd * cmd = IOFireWireIUnknown::InterfaceMap<Cmd>::GetThis(command); 340 341 status = cmd->PrepareForVectorSubmit( &mSubmitBuffer[index] ); 342 } 343 } 344 345 if( status == kIOReturnSuccess ) 346 { 347 // send the requests to the kernel 348 349 // async ref 350 uint64_t async_ref[kOSAsyncRef64Count]; 351 async_ref[kIOAsyncCalloutFuncIndex] = (uint64_t) 0; 352 async_ref[kIOAsyncCalloutRefconIndex] = (unsigned long) 0; 353 354 // inputs 355 const uint64_t inputs[2] = { (const uint64_t)&SVectorCompletionHandler, 356 (const uint64_t)this }; 357 // outputs 358 uint32_t output_count = 0; 359 360 status = IOConnectCallAsyncScalarMethod( mUserClient.GetUserClientConnection(), 361 mUserClient.MakeSelectorWithObject( kVectorCommandSubmit, mKernCommandRef ), 362 mUserClient.GetAsyncPort(), 363 async_ref, kOSAsyncRef64Count, 364 inputs, 2, 365 NULL, &output_count); 366 367 mInflightCount = count; 368 369// printf( "VectorCommand::Submit - IOConnectCallAsyncStructMethod status = 0x%08lx\n", status ); 370 } 371 372 if( status == kIOReturnSuccess ) 373 { 374 for( CFIndex index = 0; (status == kIOReturnSuccess) && (index < count); index++ ) 375 { 376 IOFireWireLibCommandRef command = (IOFireWireLibCommandRef)CFArrayGetValueAtIndex( mCommandArray, index ); 377 378 Cmd * cmd = IOFireWireIUnknown::InterfaceMap<Cmd>::GetThis(command); 379 380 cmd->VectorIsExecuting(); 381 } 382 } 383 384#if 0 385 if( status == kIOReturnSuccess ) 386 { 387 // reset vector status 388 mStatus = kIOReturnSuccess; 389 390 for( CFIndex index = 0; index < count; index++ ) 391 { 392 IOFireWireLibCommandRef command = (IOFireWireLibCommandRef)CFArrayGetValueAtIndex( mCommandArray, index ); 393 mInflightCount++; 394 (*command)->Submit( command ); 395 // our commands seem to call the completion handler on error 396 // so pretend all was success 397 } 398 } 399#endif 400 401// printf( "VectorCommand::Submit - status = 0x%08lx\n", status ); 402 403 return status; 404 } 405 406 // SubmitWithRefconAndCallback 407 // 408 // 409 410 IOReturn VectorCommand::SSubmitWithRefconAndCallback( IOFireWireLibVectorCommandRef self, void* refCon, IOFireWireLibCommandCallback inCallback ) 411 { 412 (*self)->SetRefCon( self, refCon ); 413 (*self)->SetCallback( self, inCallback ); 414 return (*self)->Submit( self ); 415 } 416 417 // IsExecuting 418 // 419 // 420 421 Boolean VectorCommand::SIsExecuting( IOFireWireLibVectorCommandRef self ) 422 { 423 VectorCommand * me = IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self); 424 return (me->mInflightCount != 0); 425 } 426 427 // VectorCompletionHandler 428 // 429 // 430 431 void 432 VectorCommand::SVectorCompletionHandler( 433 void* refcon, 434 IOReturn result, 435 void* quads[], 436 UInt32 numQuads ) 437 { 438 VectorCommand * me = (VectorCommand*)refcon; 439 me->VectorCompletionHandler( result, quads, numQuads ); 440 } 441 442 void 443 VectorCommand::VectorCompletionHandler( 444 IOReturn result, 445 void* quads[], 446 UInt32 numQuads ) 447 { 448 //printf( "VectorCommand::VectorCompletionHandler - status = 0x%08lx\n", result ); 449 450 CFIndex count = CFArrayGetCount( mCommandArray ); 451 452 for( CFIndex index = 0; (index < count); index++ ) 453 { 454 Cmd * cmd = (Cmd*)mResultBuffer[index].refCon; 455 456 IOReturn status = mResultBuffer[index].result; 457 458 // pack 'em up like the kernel would 459 void * args[3]; 460 args[0] = (void*)mResultBuffer[index].bytesTransferred; 461 args[1] = (void*)mResultBuffer[index].ackCode; 462 args[2] = (void*)mResultBuffer[index].responseCode; 463 464 // call the completion routine 465 cmd->CommandCompletionHandler( cmd, status, args, 3 ); 466 467 if( mInflightCount > 0 ) 468 { 469 mInflightCount--; 470 } 471 } 472 473 (*mCallback)( mRefCon, mStatus ); 474 } 475 476 // SetCallback 477 // 478 // 479 480 void VectorCommand::SSetCallback( IOFireWireLibVectorCommandRef self, IOFireWireLibCommandCallback inCallback ) 481 { 482 VectorCommand * me = IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self); 483 me->mCallback = inCallback; 484 } 485 486 // SetRefCon 487 // 488 // 489 490 void VectorCommand::SSetRefCon( IOFireWireLibVectorCommandRef self, void* refCon ) 491 { 492 VectorCommand * me = IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self); 493 me->mRefCon = refCon; 494 } 495 496 // GetRefCon 497 // 498 // 499 500 void * VectorCommand::SGetRefCon( IOFireWireLibVectorCommandRef self ) 501 { 502 VectorCommand * me = IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self); 503 return me->mRefCon; 504 } 505 506 // SetFlags 507 // 508 // 509 510 void VectorCommand::SSetFlags( IOFireWireLibVectorCommandRef self, UInt32 inFlags ) 511 { 512 VectorCommand * me = IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self); 513 me->mFlags = inFlags; 514 } 515 516 // GetFlags 517 // 518 // 519 520 UInt32 VectorCommand::SGetFlags( IOFireWireLibVectorCommandRef self ) 521 { 522 VectorCommand * me = IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self); 523 return me->mFlags; 524 } 525 526 // AddCommand 527 // 528 // 529 530 void VectorCommand::SAddCommand( IOFireWireLibVectorCommandRef self, IOFireWireLibCommandRef command ) 531 { 532 VectorCommand * me = IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self); 533 534 CFArrayAppendValue( me->mCommandArray, command ); 535 } 536 537 // RemoveCommand 538 // 539 // 540 541 void VectorCommand::SRemoveCommand( IOFireWireLibVectorCommandRef self, IOFireWireLibCommandRef command ) 542 { 543 VectorCommand * me = IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self); 544 545 CFMutableArrayRef array = me->mCommandArray; 546 547 CFRange search_range = CFRangeMake( 0, CFArrayGetCount( array ) ); 548 CFIndex index = kCFNotFound; 549 550 // search for all instances of a given command 551 while( (index = CFArrayGetFirstIndexOfValue( array, search_range, command)) != kCFNotFound ) 552 { 553 // remove the index 554 CFArrayRemoveValueAtIndex( array, index ); 555 556 // recalc the search range 557 search_range = CFRangeMake( 0, CFArrayGetCount( array ) ); 558 } 559 } 560 561 // InsertCommandAtIndex 562 // 563 // 564 565 void VectorCommand::SInsertCommandAtIndex( IOFireWireLibVectorCommandRef self, IOFireWireLibCommandRef command, UInt32 index ) 566 { 567 VectorCommand * me = IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self); 568 569 CFArrayInsertValueAtIndex( me->mCommandArray, index, command ); 570 } 571 572 // CommandAtIndex 573 // 574 // 575 576 IOFireWireLibCommandRef VectorCommand::SGetCommandAtIndex( IOFireWireLibVectorCommandRef self, UInt32 index ) 577 { 578 VectorCommand * me = IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self); 579 580 return (IOFireWireLibCommandRef)CFArrayGetValueAtIndex( me->mCommandArray, index ); 581 } 582 583 // GetIndexOfCommand 584 // 585 // 586 587 UInt32 VectorCommand::SGetIndexOfCommand( IOFireWireLibVectorCommandRef self, IOFireWireLibCommandRef command ) 588 { 589 VectorCommand * me = IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self); 590 591 CFRange search_range = CFRangeMake( 0, CFArrayGetCount( me->mCommandArray ) ); 592 593 return CFArrayGetFirstIndexOfValue( me->mCommandArray, search_range, command ); 594 } 595 596 // RemoveCommandAtIndex 597 // 598 // 599 600 void VectorCommand::SRemoveCommandAtIndex( IOFireWireLibVectorCommandRef self, UInt32 index ) 601 { 602 VectorCommand * me = IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self); 603 604 CFArrayRemoveValueAtIndex( me->mCommandArray, index ); 605 } 606 607 // RemoveAllCommands 608 // 609 // 610 611 void VectorCommand::SRemoveAllCommands( IOFireWireLibVectorCommandRef self ) 612 { 613 VectorCommand * me = IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self); 614 615 CFArrayRemoveAllValues( me->mCommandArray ); 616 } 617 618 // GetCommandCount 619 // 620 // 621 622 UInt32 VectorCommand::SGetCommandCount( IOFireWireLibVectorCommandRef self ) 623 { 624 VectorCommand * me = IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self); 625 626 return CFArrayGetCount( me->mCommandArray ); 627 } 628 629 // RetainCallback 630 // 631 // 632 633 const void * VectorCommand::SRetainCallback( CFAllocatorRef allocator, const void * value ) 634 { 635 IUnknownVTbl** iUnknown = (IUnknownVTbl**)value; 636 (*iUnknown)->AddRef( iUnknown ); 637 638 return value; 639 } 640 641 // ReleaseCallback 642 // 643 // 644 645 void VectorCommand::SReleaseCallback( CFAllocatorRef allocator, const void * value ) 646 { 647 IUnknownVTbl** iUnknown = (IUnknownVTbl**)value; 648 (*iUnknown)->Release( iUnknown ); 649 } 650 651}