1/* 2 * Copyright (c) 1998-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 <stdlib.h> 24#include <stdio.h> 25 26#include <IOKit/avc/IOFireWireAVCLib.h> 27#include <IOKit/avc/IOFireWireAVCConsts.h> 28#include "IOFireWireAVCLibConsumer.h" 29#include "IOFireWireAVCUserClientCommon.h" 30#include "IOFireWireAVCLibUnit.h" 31 32#include <CoreFoundation/CFMachPort.h> 33#include <IOKit/IOMessage.h> 34 35#include <syslog.h> // Debug messages 36#include <pthread.h> // for mutexes 37#include <unistd.h> 38#import <sys/mman.h> 39#include <mach/mach_port.h> 40#include <mach/vm_map.h> 41 42#import <System/libkern/OSCrossEndian.h> 43 44#if 0 45#define FWLOG(x) printf x 46#else 47#define FWLOG(x) do {} while (0) 48#endif 49 50__BEGIN_DECLS 51#include <IOKit/iokitmig.h> 52 53void *IOFireWireAVCLibUnitFactory( CFAllocatorRef allocator, CFUUIDRef typeID ); 54__END_DECLS 55 56struct _AVCUnit; 57typedef struct _InterfaceMap 58{ 59 IUnknownVTbl *pseudoVTable; 60 struct _AVCUnit *obj; 61} InterfaceMap; 62 63// 64// UserLib AVCUnit Object 65// 66typedef struct _AVCUnit 67{ 68 ////////////////////////////////////// 69 // cf plugin interfaces 70 71 InterfaceMap fIOCFPlugInInterface; 72 InterfaceMap fIOFireWireAVCLibUnitInterface; 73 74 ////////////////////////////////////// 75 // cf plugin ref counting 76 77 CFUUIDRef fFactoryId; 78 UInt32 fRefCount; 79 80 ////////////////////////////////////// 81 // user client connection 82 83 io_service_t fService; 84 io_connect_t fConnection; 85 86 ////////////////////////////////////// 87 // async callbacks 88 89 CFRunLoopRef fCFRunLoop; 90 CFRunLoopSourceRef fCFRunLoopSource; 91 IONotificationPortRef fNotifyPort; 92 io_object_t fNotification; 93 IOFWAVCMessageCallback fMessageCallbackRoutine; 94 void * fMessageCallbackRefCon; 95 CFMachPortRef fCFAsyncPort; 96 mach_port_t fAsyncPort; 97 98 ////////////////////////////////////// 99 // async connection objects 100 101 CFMutableArrayRef fACObjectArray; 102 pthread_mutex_t fACObjectArrayLock; 103 104 ////////////////////////////////////// 105 // AVC async command objects 106 107 CFMutableArrayRef fAVCAsyncCommandArray; 108 pthread_mutex_t fAVCAsyncCommandArrayLock; 109 110 ////////////////////////////////////// 111 // notifications 112 113 Boolean fSuspended; 114 Boolean fHighPerfAVCCommands; 115 116} AVCUnit; 117 118// 119// Structure for wrapper of user-lib initiated async AVC commands 120// 121typedef struct _AVCLibAsynchronousCommandPriv 122{ 123 IOFireWireAVCLibAsynchronousCommand *pCmd; 124 IOFireWireAVCLibAsynchronousCommandCallback clientCallback; 125 UInt32 kernelAsyncAVCCommandHandle; 126 UInt8 *pResponseBuf; 127}AVCLibAsynchronousCommandPriv; 128 129// utility function to get "this" pointer from interface 130#define AVCUnit_getThis( self ) \ 131 (((InterfaceMap *) self)->obj) 132 133AVCLibAsynchronousCommandPriv *FindPrivAVCAsyncCommand(AVCUnit *me, IOFireWireAVCLibAsynchronousCommand *pCommandObject); 134static IOReturn stop( void * self ); 135static void removeIODispatcherFromRunLoop( void * self ); 136 137////////////////////////////////////////////////////// 138// AVCAsyncCommandCallback 139////////////////////////////////////////////////////// 140static void AVCAsyncCommandCallback( void *refcon, IOReturn result, io_user_reference_t *args, int numArgs) 141{ 142 AVCUnit *me = (AVCUnit*) refcon; 143 UInt32 commandIdentifierHandle = (args[0] & 0xFFFFFFFF); 144 UInt32 cmdState = (args[1] & 0xFFFFFFFF); 145 UInt32 respLen = (args[2] & 0xFFFFFFFF); 146 CFIndex count = 0; 147 CFIndex i = 0; 148 AVCLibAsynchronousCommandPriv *pPrivCmd = NULL; 149 bool found = false; 150 151 pthread_mutex_lock( &me->fAVCAsyncCommandArrayLock ); 152 count = CFArrayGetCount( me->fAVCAsyncCommandArray ); 153 for( i = 0; i < count; i++ ) 154 { 155 pPrivCmd = (AVCLibAsynchronousCommandPriv*) CFArrayGetValueAtIndex( me->fAVCAsyncCommandArray, i); 156 if (pPrivCmd->kernelAsyncAVCCommandHandle == commandIdentifierHandle) 157 { 158 found = true; 159 break; 160 } 161 } 162 pthread_mutex_unlock( &me->fAVCAsyncCommandArrayLock ); 163 164 // If we determined that the command object is valid, process it 165 if (found == true) 166 { 167 // Update the command state 168 pPrivCmd->pCmd->cmdState = (IOFWAVCAsyncCommandState) cmdState; 169 170 // For response states, set the response buffer 171 switch (cmdState) 172 { 173 case kAVCAsyncCommandStateReceivedInterimResponse: 174 pPrivCmd->pCmd->pInterimResponseBuf = &pPrivCmd->pResponseBuf[kAsyncCmdSharedBufInterimRespOffset]; 175 pPrivCmd->pCmd->interimResponseLen = respLen; 176 break; 177 178 case kAVCAsyncCommandStateReceivedFinalResponse: 179 pPrivCmd->pCmd->pFinalResponseBuf = &pPrivCmd->pResponseBuf[kAsyncCmdSharedBufFinalRespOffset]; 180 pPrivCmd->pCmd->finalResponseLen = respLen; 181 break; 182 183 case kAVCAsyncCommandStatePendingRequest: 184 case kAVCAsyncCommandStateRequestSent: 185 case kAVCAsyncCommandStateRequestFailed: 186 case kAVCAsyncCommandStateWaitingForResponse: 187 case kAVCAsyncCommandStateTimeOutBeforeResponse: 188 case kAVCAsyncCommandStateBusReset: 189 case kAVCAsyncCommandStateOutOfMemory: 190 case kAVCAsyncCommandStateCanceled: 191 default: 192 break; 193 }; 194 195 // Make the callback to the client 196 if (pPrivCmd->clientCallback) 197 pPrivCmd->clientCallback(pPrivCmd->pCmd->pRefCon,pPrivCmd->pCmd); 198 } 199} 200 201////////////////////////////////////////////////////// 202// addRef 203////////////////////////////////////////////////////// 204static UInt32 addRef( void * self ) 205{ 206 AVCUnit *me = AVCUnit_getThis(self); 207 me->fRefCount++; 208 return me->fRefCount; 209} 210 211////////////////////////////////////////////////////// 212// release 213////////////////////////////////////////////////////// 214static UInt32 release( void * self ) 215{ 216 AVCUnit *me = AVCUnit_getThis(self); 217 UInt32 retVal = me->fRefCount; 218 AVCLibAsynchronousCommandPriv *pPrivCmd; 219 uint32_t outputCnt = 0; 220 221 if( 1 == me->fRefCount-- ) 222 { 223 // First disconnect from kernel before deleting things accessed by kernel callbacks 224 removeIODispatcherFromRunLoop(self); 225 stop(self); 226 227 pthread_mutex_lock( &me->fACObjectArrayLock ); 228 if( me->fACObjectArray ) 229 { 230 CFRelease( me->fACObjectArray ); // release array and consumers 231 me->fACObjectArray = NULL; 232 } 233 pthread_mutex_unlock( &me->fACObjectArrayLock ); 234 pthread_mutex_destroy( &me->fACObjectArrayLock ); 235 236 pthread_mutex_lock( &me->fAVCAsyncCommandArrayLock ); 237 if( me->fAVCAsyncCommandArray ) 238 { 239 while(CFArrayGetCount( me->fAVCAsyncCommandArray )) 240 { 241 pPrivCmd = (AVCLibAsynchronousCommandPriv*) CFArrayGetValueAtIndex( me->fAVCAsyncCommandArray, 0); 242 if (pPrivCmd) 243 { 244 const uint64_t inArg = pPrivCmd->kernelAsyncAVCCommandHandle; 245 IOConnectCallScalarMethod(me->fConnection, 246 kIOFWAVCUserClientReleaseAsyncAVCCommand, 247 &inArg, 248 1,NULL,&outputCnt); 249 250 // unmap the 1K response buffer 251 if (pPrivCmd->pResponseBuf) 252 //munmap( (void*)pPrivCmd->pResponseBuf, 1024 ) ; 253 vm_deallocate(mach_task_self(), (vm_address_t) pPrivCmd->pResponseBuf,1024); 254 255 // delete the command byte buffer, and the user command 256 if (pPrivCmd->pCmd) 257 { 258 if (pPrivCmd->pCmd->pCommandBuf) 259 delete pPrivCmd->pCmd->pCommandBuf; 260 delete pPrivCmd->pCmd; 261 } 262 263 // Remove from array 264 CFArrayRemoveValueAtIndex(me->fAVCAsyncCommandArray, 0); 265 266 // Delete the private command 267 delete pPrivCmd; 268 } 269 } 270 271 CFRelease( me->fAVCAsyncCommandArray ); 272 me->fACObjectArray = NULL; 273 } 274 pthread_mutex_unlock( &me->fAVCAsyncCommandArrayLock ); 275 pthread_mutex_destroy( &me->fAVCAsyncCommandArrayLock ); 276 277 CFPlugInRemoveInstanceForFactory( me->fFactoryId ); 278 CFRelease( me->fFactoryId ); 279 free(me); 280 } 281 else if( me->fRefCount < 0 ) 282 { 283 me->fRefCount = 0; 284 } 285 286 return retVal; 287} 288 289////////////////////////////////////////////////////// 290// queryInterface 291////////////////////////////////////////////////////// 292static HRESULT queryInterface( void * self, REFIID iid, void **ppv ) 293{ 294 CFUUIDRef uuid = CFUUIDCreateFromUUIDBytes(NULL, iid); 295 HRESULT result = S_OK; 296 AVCUnit *me = AVCUnit_getThis(self); 297 298 if( CFEqual(uuid, IUnknownUUID) || CFEqual(uuid, kIOCFPlugInInterfaceID) ) 299 { 300 *ppv = &me->fIOCFPlugInInterface; 301 addRef(self); 302 } 303 else if( CFEqual(uuid, kIOFireWireAVCLibUnitInterfaceID) ) 304 { 305 // Set flag to throttle AVC Commands 306 me->fHighPerfAVCCommands = false; 307 308 *ppv = &me->fIOFireWireAVCLibUnitInterface; 309 addRef(self); 310 } 311 else if( CFEqual(uuid, kIOFireWireAVCLibUnitInterfaceID_v2) ) 312 { 313 // Set flag to not throttle AVC Commands 314 me->fHighPerfAVCCommands = true; 315 316 *ppv = &me->fIOFireWireAVCLibUnitInterface; 317 addRef(self); 318 } 319 else 320 *ppv = 0; 321 322 if( !*ppv ) 323 result = E_NOINTERFACE; 324 325 CFRelease( uuid ); 326 327 return result; 328} 329 330////////////////////////////////////////////////////////////////// 331// IOCFPlugInInterface methods 332// 333 334////////////////////////////////////////////////////////////////// 335// callback static methods 336// 337 338////////////////////////////////////////////////////// 339// messageCallback 340////////////////////////////////////////////////////// 341static void messageCallback(void * refcon, io_service_t service, 342 natural_t messageType, void *messageArgument) 343{ 344 AVCUnit *me = (AVCUnit *)refcon; 345 IOReturn status = kIOReturnSuccess; 346 347 CFIndex count = 0; 348 CFIndex i = 0; 349 350 //FWLOG(( "IOFireWireAVCLibUnit : messageCallback numArgs = %d\n", numArgs )); 351 352 switch( messageType ) 353 { 354 case kIOMessageServiceIsSuspended: 355 me->fSuspended = true; 356 break; 357 358 case kIOMessageServiceIsResumed: 359 me->fSuspended = false; 360 break; 361 362 default: 363 break; 364 } 365 366 if (me->fACObjectArray) 367 { 368 // 369 // put all consumers into a local array to avoid calling callback with lock held 370 // 371 372 CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 373 2, // max capacity 374 IOFireWireAVCLibConsumer::getCFArrayCallbacks() ); 375 if( array == NULL ) 376 status = kIOReturnNoMemory; 377 378 if( status == kIOReturnSuccess ) 379 { 380 pthread_mutex_lock( &me->fACObjectArrayLock ); 381 382 count = CFArrayGetCount( me->fACObjectArray ); 383 for( i = 0; i < count; i++ ) 384 { 385 CFArrayAppendValue( array, CFArrayGetValueAtIndex( me->fACObjectArray, i ) ); 386 } 387 388 pthread_mutex_unlock( &me->fACObjectArrayLock ); 389 390 for( i = 0; i < count; i++ ) 391 { 392 IOFireWireAVCLibConsumer * consumer = 393 ( IOFireWireAVCLibConsumer*)CFArrayGetValueAtIndex( array, i ); 394 395 consumer->deviceInterestCallback( messageType, messageArgument ); 396 } 397 398 CFRelease( array ); 399 } 400 } 401 402 if( me->fMessageCallbackRoutine != NULL ) 403 (me->fMessageCallbackRoutine)( me->fMessageCallbackRefCon, messageType, messageArgument ); 404} 405 406////////////////////////////////////////////////////// 407// isDeviceSuspended 408////////////////////////////////////////////////////// 409Boolean isDeviceSuspended( void * self ) 410{ 411 AVCUnit * me = AVCUnit_getThis(self); 412 413 return me->fSuspended; 414} 415 416////////////////////////////////////////////////////// 417// probe 418////////////////////////////////////////////////////// 419static IOReturn probe( void * self, CFDictionaryRef propertyTable, 420 io_service_t service, SInt32 *order ) 421{ 422 // only load against AVC Units and SubUnits 423 if( !service || !IOObjectConformsTo(service, "IOFireWireAVCNub") ) 424 return kIOReturnBadArgument; 425 426 return kIOReturnSuccess; 427} 428 429////////////////////////////////////////////////////// 430// start 431////////////////////////////////////////////////////// 432static IOReturn start( void * self, CFDictionaryRef propertyTable, 433 io_service_t service ) 434{ 435 IOReturn status = kIOReturnSuccess; 436 AVCUnit *me = AVCUnit_getThis(self); 437 uint64_t returnVal; 438 uint64_t refrncData[kOSAsyncRef64Count]; 439 uint32_t outputCnt = 1; 440 441 me->fService = service; 442 status = IOServiceOpen( me->fService, mach_task_self(), 443 kIOFireWireAVCLibConnection, &me->fConnection ); 444 if( !me->fConnection ) 445 status = kIOReturnNoDevice; 446 447 if( status == kIOReturnSuccess ) 448 { 449 status = IOCreateReceivePort( kOSAsyncCompleteMessageID, &me->fAsyncPort ); 450 } 451 452 // Setup the ref for the kernel user client to use for async AVC command callbacks 453 if( status == kIOReturnSuccess ) 454 { 455 refrncData[kIOAsyncCalloutFuncIndex] = (uint64_t)AVCAsyncCommandCallback; 456 refrncData[kIOAsyncCalloutRefconIndex] = (uint64_t)me; 457 458 status = IOConnectCallAsyncScalarMethod(me->fConnection, 459 kIOFWAVCUserClientInstallAsyncAVCCommandCallback, 460 me->fAsyncPort, 461 refrncData,kOSAsyncRef64Count, 462 NULL,0, 463 &returnVal,&outputCnt); 464 } 465 466 return status; 467} 468 469////////////////////////////////////////////////////// 470// stop 471////////////////////////////////////////////////////// 472static IOReturn stop( void * self ) 473{ 474 AVCUnit *me = AVCUnit_getThis(self); 475 if( me->fConnection ) 476 { 477 IOServiceClose( me->fConnection ); 478 me->fConnection = MACH_PORT_NULL; 479 } 480 481 if( me->fAsyncPort != MACH_PORT_NULL ) 482 { 483 mach_port_destroy( mach_task_self(), me->fAsyncPort); 484 me->fAsyncPort = MACH_PORT_NULL; 485 } 486 487 return kIOReturnSuccess; 488} 489 490////////////////////////////////////////////////////////////////// 491// IOFireWireAVCLibUnit methods 492// 493 494////////////////////////////////////////////////////// 495// open 496////////////////////////////////////////////////////// 497static IOReturn open( void * self ) 498{ 499 AVCUnit *me = AVCUnit_getThis(self); 500 IOReturn status = kIOReturnSuccess; 501 uint32_t outputCnt = 0; 502 503 if( !me->fConnection ) 504 return kIOReturnNoDevice; 505 506 status = IOConnectCallScalarMethod(me->fConnection,kIOFWAVCUserClientOpen,NULL,0,NULL,&outputCnt); 507 508 return status; 509} 510 511////////////////////////////////////////////////////// 512// openWithSessionRef 513////////////////////////////////////////////////////// 514static IOReturn openWithSessionRef( void * self, IOFireWireSessionRef sessionRef ) 515{ 516 AVCUnit *me = AVCUnit_getThis(self); 517 IOReturn status = kIOReturnSuccess; 518 uint32_t outputCnt = 0; 519 520 if( !me->fConnection ) 521 return kIOReturnNoDevice; 522 523 const uint64_t inputs[1]={(const uint64_t)sessionRef}; 524 status = IOConnectCallScalarMethod(me->fConnection,kIOFWAVCUserClientOpenWithSessionRef,inputs,1,NULL,&outputCnt); 525 526 return status; 527} 528 529////////////////////////////////////////////////////// 530// getSessionRef 531////////////////////////////////////////////////////// 532static IOFireWireSessionRef getSessionRef(void * self) 533{ 534 AVCUnit *me = AVCUnit_getThis(self); 535 IOReturn status = kIOReturnSuccess; 536 IOFireWireSessionRef sessionRef = 0; 537 uint32_t outputCnt = 1; 538 uint64_t outputVal; 539 540 if( !me->fConnection ) 541 return sessionRef; 542 543 status = IOConnectCallScalarMethod(me->fConnection,kIOFWAVCUserClientGetSessionRef,NULL,0,&outputVal,&outputCnt); 544 545 if( status != kIOReturnSuccess ) 546 sessionRef = 0; // just to make sure 547 else 548 sessionRef = (IOFireWireSessionRef) outputVal; 549 550 return sessionRef; 551} 552 553////////////////////////////////////////////////////// 554// close 555////////////////////////////////////////////////////// 556static void close( void * self ) 557{ 558 AVCUnit *me = AVCUnit_getThis(self); 559 uint32_t outputCnt = 0; 560 561 if( !me->fConnection ) 562 return; 563 564 IOConnectCallScalarMethod(me->fConnection,kIOFWAVCUserClientClose,NULL,0,NULL,&outputCnt); 565} 566 567////////////////////////////////////////////////////// 568// addIODispatcherToRunLoop 569////////////////////////////////////////////////////// 570static IOReturn addIODispatcherToRunLoop( void *self, CFRunLoopRef cfRunLoopRef ) 571{ 572 AVCUnit *me = AVCUnit_getThis(self); 573 IOReturn status = kIOReturnSuccess; 574 mach_port_t masterDevicePort; 575 IONotificationPortRef notifyPort; 576 CFRunLoopSourceRef cfSource; 577 //FWLOG(( "IOFireWireAVCLibUnit : addIODispatcherToRunLoop\n" )); 578 579 if( !me->fConnection ) 580 return kIOReturnNoDevice; 581 582 // get mach master port 583 status = IOMasterPort(bootstrap_port, &masterDevicePort) ; 584 585 notifyPort = IONotificationPortCreate(masterDevicePort); 586 cfSource = IONotificationPortGetRunLoopSource(notifyPort); 587 CFRunLoopAddSource(cfRunLoopRef, cfSource, kCFRunLoopDefaultMode); 588// Get messages from device 589 status = IOServiceAddInterestNotification(notifyPort, me->fService, 590 kIOGeneralInterest, messageCallback, me, 591 &me->fNotification); 592 593 me->fCFRunLoop = cfRunLoopRef; 594 me->fNotifyPort = notifyPort; 595 596 if( status == kIOReturnSuccess ) 597 { 598 CFMachPortContext context; 599 Boolean shouldFreeInfo; // zzz what's this for? I think it's set to true if the create failed. 600 601 context.version = 1; 602 context.info = me; 603 context.retain = NULL; 604 context.release = NULL; 605 context.copyDescription = NULL; 606 607 me->fCFAsyncPort = CFMachPortCreateWithPort( kCFAllocatorDefault, me->fAsyncPort, 608 (CFMachPortCallBack) IODispatchCalloutFromMessage, 609 &context, &shouldFreeInfo ); 610 if( !me->fCFAsyncPort ) 611 status = kIOReturnNoMemory; 612 } 613 614 if( status == kIOReturnSuccess ) 615 { 616 me->fCFRunLoopSource = CFMachPortCreateRunLoopSource( kCFAllocatorDefault, me->fCFAsyncPort, 0 ); 617 if( !me->fCFRunLoopSource ) 618 status = kIOReturnNoMemory; 619 } 620 621 if( status == kIOReturnSuccess ) 622 { 623 CFRunLoopAddSource(cfRunLoopRef, me->fCFRunLoopSource, kCFRunLoopDefaultMode ); 624 } 625 626 return status; 627} 628 629////////////////////////////////////////////////////// 630// removeIODispatcherFromRunLoop 631////////////////////////////////////////////////////// 632static void removeIODispatcherFromRunLoop( void * self ) 633{ 634 AVCUnit *me = AVCUnit_getThis(self); 635 if( me->fNotification ) 636 { 637 IOObjectRelease(me->fNotification); 638 me->fNotification = NULL; 639 } 640 if( me->fNotifyPort ) 641 { 642 CFRunLoopRemoveSource( me->fCFRunLoop, 643 IONotificationPortGetRunLoopSource(me->fNotifyPort), kCFRunLoopDefaultMode ); 644 IONotificationPortDestroy(me->fNotifyPort); 645 me->fNotifyPort = NULL; 646 } 647 648 if(me->fCFRunLoopSource) { 649 CFRunLoopRemoveSource( me->fCFRunLoop, 650 me->fCFRunLoopSource, kCFRunLoopDefaultMode ); 651 CFRelease(me->fCFRunLoopSource); 652 me->fCFRunLoopSource = NULL; 653 } 654 655 if( me->fCFAsyncPort != NULL ) { 656 CFMachPortInvalidate(me->fCFAsyncPort); 657 CFRelease( me->fCFAsyncPort ); 658 me->fCFAsyncPort = NULL; 659 } 660} 661 662////////////////////////////////////////////////////// 663// setMessageCallback 664////////////////////////////////////////////////////// 665static void setMessageCallback( void * self, void * refCon, 666 IOFWAVCMessageCallback callback ) 667{ 668 AVCUnit *me = AVCUnit_getThis(self); 669 me->fMessageCallbackRoutine = callback; 670 me->fMessageCallbackRefCon = refCon; 671} 672 673////////////////////////////////////////////////////// 674// AVCCommand 675////////////////////////////////////////////////////// 676static IOReturn AVCCommand(void *self, const UInt8 * command, UInt32 cmdLen, UInt8 * response, UInt32 *responseLen) 677{ 678 AVCUnit *me = AVCUnit_getThis(self); 679 IOReturn status; 680 size_t outputCnt = *responseLen; 681 if( !me->fConnection ) 682 return kIOReturnNotOpen; 683 684 status = IOConnectCallStructMethod(me->fConnection, kIOFWAVCUserClientAVCCommand, command, cmdLen, response,&outputCnt); 685 686 if(status == kIOReturnSuccess) 687 *responseLen = outputCnt; 688 689 if (me->fHighPerfAVCCommands == false) 690 { 691 // sleep for 8 milliseconds to throttle back iMovie 692 usleep( 8 * 1000 ); 693 } 694 695 return status; 696} 697 698////////////////////////////////////////////////////// 699// AVCCommandInGeneration 700////////////////////////////////////////////////////// 701static IOReturn AVCCommandInGeneration(void *self, UInt32 generation, 702 const UInt8 * command, UInt32 cmdLen, UInt8 * response, UInt32 *responseLen) 703{ 704 UInt8 annoying[sizeof(UInt32) + 512]; 705 AVCUnit *me = AVCUnit_getThis(self); 706 IOReturn status; 707 size_t outputCnt = *responseLen; 708 if( !me->fConnection ) 709 return kIOReturnNotOpen; 710 711 ROSETTA_ONLY( 712 { 713 generation = OSSwapInt32(generation); 714 } 715 ); 716 717 // Have to stick the generation in with the command bytes. 718 *(UInt32 *)annoying = generation; 719 bcopy(command, annoying+sizeof(UInt32), cmdLen); 720 721 status = IOConnectCallStructMethod(me->fConnection, kIOFWAVCUserClientAVCCommandInGen, annoying, cmdLen+sizeof(UInt32), response,&outputCnt); 722 723 if(status == kIOReturnSuccess) 724 *responseLen = outputCnt; 725 726 if (me->fHighPerfAVCCommands == false) 727 { 728 // sleep for 8 milliseconds to throttle back iMovie 729 usleep( 8 * 1000 ); 730 } 731 732 return status; 733} 734 735////////////////////////////////////////////////////// 736// GetAncestorInterface 737////////////////////////////////////////////////////// 738static void *GetAncestorInterface( void * self, char * object_class, REFIID pluginType, REFIID iid) 739{ 740 io_registry_entry_t parent = NULL; 741 io_registry_entry_t notTheDesiredParent = NULL; 742 IOCFPlugInInterface** theCFPlugInInterface = 0; 743 void * resultInterface = 0 ; 744 SInt32 theScore ; 745 IOReturn err; 746 HRESULT comErr; 747 AVCUnit * me = AVCUnit_getThis(self); 748 CFUUIDRef type_id = CFUUIDCreateFromUUIDBytes(NULL, pluginType); 749 750 do { 751 err = IORegistryEntryGetParentEntry(me->fService, kIOServicePlane, &parent); 752 753 while(!err && !IOObjectConformsTo(parent, object_class) ) 754 { 755 notTheDesiredParent = parent; 756 err = IORegistryEntryGetParentEntry(notTheDesiredParent, kIOServicePlane, &parent); 757 IOObjectRelease(notTheDesiredParent); 758 } 759 760 if(err) 761 { 762 parent = NULL; 763 break; 764 } 765 766 err = IOCreatePlugInInterfaceForService( 767 parent, 768 type_id, 769 kIOCFPlugInInterfaceID, //interfaceType, 770 & theCFPlugInInterface, 771 & theScore); 772 if(err) 773 break; 774 775 comErr = (*theCFPlugInInterface)->QueryInterface( 776 theCFPlugInInterface, 777 iid, 778 (void**) & resultInterface); 779 if (comErr != S_OK) { 780 err = comErr; 781 break; 782 } 783 } while (false); 784 785 if(theCFPlugInInterface) { 786 UInt32 ref; 787 ref = (*theCFPlugInInterface)->Release(theCFPlugInInterface); // Leave just one reference. 788 } 789 790 CFRelease( type_id ); 791 792 if ((!resultInterface) && (parent)) 793 IOObjectRelease(parent); 794 795 return resultInterface; 796} 797 798////////////////////////////////////////////////////// 799// GetProtocolInterface 800////////////////////////////////////////////////////// 801static void *GetProtocolInterface( void * self, REFIID pluginType, REFIID iid) 802{ 803 io_registry_entry_t parent = NULL; 804 io_registry_entry_t notTheDesiredParent = NULL; 805 io_registry_entry_t child = NULL; 806 io_iterator_t iterator = NULL; 807 IOCFPlugInInterface** theCFPlugInInterface = 0; 808 void * resultInterface = 0 ; 809 SInt32 theScore ; 810 IOReturn err; 811 HRESULT comErr; 812 AVCUnit * me = AVCUnit_getThis(self); 813 CFUUIDRef type_id = CFUUIDCreateFromUUIDBytes(NULL, pluginType); 814 815 do { 816 err = IORegistryEntryGetParentEntry(me->fService, kIOServicePlane, &parent); 817 818 while(!err && !IOObjectConformsTo(parent, "IOFireWireController") ) 819 { 820 notTheDesiredParent = parent; 821 err = IORegistryEntryGetParentEntry(notTheDesiredParent, kIOServicePlane, &parent); 822 IOObjectRelease(notTheDesiredParent); 823 } 824 825 if(err) 826 { 827 parent = NULL; 828 break; 829 } 830 831 // Now search for an IOFireWireLocalNode. 832 err = IORegistryEntryGetChildIterator(parent, kIOServicePlane, &iterator ); 833 if(err) 834 break; 835 836 while(child = IOIteratorNext(iterator)) { 837 if(IOObjectConformsTo(child, "IOFireWireLocalNode")) 838 break; 839 IOObjectRelease(child); 840 child = NULL; 841 } 842 843 if(!child) 844 break; 845 846 err = IOCreatePlugInInterfaceForService( 847 child, 848 type_id, 849 kIOCFPlugInInterfaceID, //interfaceType, 850 & theCFPlugInInterface, 851 & theScore); 852 if(err) 853 break; 854 855 comErr = (*theCFPlugInInterface)->QueryInterface( 856 theCFPlugInInterface, 857 iid, 858 (void**) & resultInterface); 859 if (comErr != S_OK) { 860 err = comErr; 861 break; 862 } 863 } while (false); 864 865 if(theCFPlugInInterface) { 866 UInt32 ref; 867 ref = (*theCFPlugInInterface)->Release(theCFPlugInInterface); // Leave just one reference. 868 } 869 870 if(iterator) 871 IOObjectRelease(iterator); 872 873 CFRelease( type_id ); 874 875 if (parent) 876 IOObjectRelease(parent); 877 878 if ((!resultInterface) && (child)) 879 IOObjectRelease(child); 880 881 return resultInterface; 882} 883 884////////////////////////////////////////////////////// 885// getAsyncConnectionPlugCounts 886////////////////////////////////////////////////////// 887static IOReturn getAsyncConnectionPlugCounts( void *self, UInt8 * inputPlugCount, UInt8 * outputPlugCount ) 888{ 889 IOReturn status; 890 UInt8 command[8]; 891 UInt8 response[8]; 892 UInt32 responseLength = 0; 893 894 command[0] = 0x01; 895 command[1] = kAVCUnitAddress; 896 command[2] = 0x02; 897 command[3] = 0x01; 898 command[4] = 0xFF; 899 command[5] = 0xFF; 900 command[6] = 0XFF; 901 command[7] = 0XFF; 902 903 status = AVCCommand( self, command, 8, response, &responseLength ); 904 905 if( status == kIOReturnSuccess && responseLength == 8 ) 906 { 907 *inputPlugCount = response[4]; 908 *outputPlugCount = response[5]; 909 910 return kIOReturnSuccess; 911 } 912 else 913 return kIOReturnError; 914} 915 916////////////////////////////////////////////////////// 917// createConsumerPlug 918////////////////////////////////////////////////////// 919static IUnknownVTbl ** createConsumerPlug( void *self, UInt8 plugNumber, REFIID iid ) 920{ 921 IOReturn status = kIOReturnSuccess; 922 IUnknownVTbl ** iunknown = NULL; 923 IUnknownVTbl ** consumer = NULL; 924 AVCUnit * me = AVCUnit_getThis(self); 925 926 pthread_mutex_lock( &me->fACObjectArrayLock ); 927 928 if( status == kIOReturnSuccess ) 929 { 930 iunknown = IOFireWireAVCLibConsumer::alloc( (IOFireWireAVCLibUnitInterface **)self, me->fCFRunLoop, plugNumber); 931 if( iunknown == NULL ) 932 status = kIOReturnNoMemory; 933 } 934 935 if( status == kIOReturnSuccess ) 936 { 937 HRESULT res; 938 res = (*iunknown)->QueryInterface( iunknown, iid, 939 (void **) &consumer ); 940 941 if( res != S_OK ) 942 status = kIOReturnError; 943 } 944 945 FWLOG(( "IOFireWireAVCLibUnit : about to CFArrayAppendValue\n" )); 946 947 if( status == kIOReturnSuccess ) 948 { 949 IOFireWireAVCLibConsumer * consumerObject; 950 951 consumerObject = IOFireWireAVCLibConsumer::getThis( consumer ); 952 953 CFArrayAppendValue( me->fACObjectArray, (void*)consumerObject ); 954 } 955 956 if( iunknown != NULL ) 957 { 958 (*iunknown)->Release(iunknown); 959 } 960 961 FWLOG(( "IOFireWireAVCLibUnit : just CFArrayAppendValue\n" )); 962 963 pthread_mutex_unlock( &me->fACObjectArrayLock ); 964 965 if( status == kIOReturnSuccess ) 966 return consumer; 967 else 968 return NULL; 969} 970 971////////////////////////////////////////////////////// 972// consumerPlugDestroyed 973////////////////////////////////////////////////////// 974void consumerPlugDestroyed( void * self, IOFireWireAVCLibConsumer * consumer ) 975{ 976 CFIndex count = 0; 977 CFIndex index = 0; 978 AVCUnit * me = AVCUnit_getThis(self); 979 980 FWLOG(( "IOFireWireAVCLibUnit : consumerPlugDestroyed\n" )); 981 982 pthread_mutex_lock( &me->fACObjectArrayLock ); 983 984 count = CFArrayGetCount( me->fACObjectArray ); 985 index = CFArrayGetFirstIndexOfValue( me->fACObjectArray, 986 CFRangeMake(0, count), 987 (void *)consumer ); 988 if( index != -1 ) 989 { 990 CFArrayRemoveValueAtIndex( me->fACObjectArray, index ); 991 } 992 993 pthread_mutex_unlock( &me->fACObjectArrayLock ); 994} 995 996////////////////////////////////////////////////////// 997// updateAVCCommandTimeout 998////////////////////////////////////////////////////// 999static IOReturn updateAVCCommandTimeout( void * self ) 1000{ 1001 AVCUnit *me = AVCUnit_getThis(self); 1002 uint32_t outputCnt = 0; 1003 1004 if( !me->fConnection ) 1005 return kIOReturnNotOpen; 1006 1007 return IOConnectCallScalarMethod(me->fConnection,kIOFWAVCUserClientUpdateAVCCommandTimeout,NULL,0,NULL,&outputCnt); 1008} 1009 1010////////////////////////////////////////////////////// 1011// makeP2PInputConnection 1012////////////////////////////////////////////////////// 1013static IOReturn makeP2PInputConnection(void * self, UInt32 inputPlug, UInt32 chan) 1014{ 1015 AVCUnit *me = AVCUnit_getThis(self); 1016 uint32_t outputCnt = 0; 1017 const uint64_t inputs[2] = {inputPlug,chan}; 1018 1019 return IOConnectCallScalarMethod(me->fConnection,kIOFWAVCUserClientMakeP2PInputConnection,inputs,2,NULL,&outputCnt); 1020 1021} 1022 1023////////////////////////////////////////////////////// 1024// breakP2PInputConnection 1025////////////////////////////////////////////////////// 1026static IOReturn breakP2PInputConnection(void * self, UInt32 inputPlug) 1027{ 1028 AVCUnit *me = AVCUnit_getThis(self); 1029 uint32_t outputCnt = 0; 1030 const uint64_t inputs[1]={(const uint64_t)inputPlug}; 1031 return IOConnectCallScalarMethod(me->fConnection,kIOFWAVCUserClientBreakP2PInputConnection,inputs,1,NULL,&outputCnt); 1032} 1033 1034////////////////////////////////////////////////////// 1035// makeP2POutputConnection 1036////////////////////////////////////////////////////// 1037static IOReturn makeP2POutputConnection(void * self, UInt32 outputPlug, UInt32 chan, IOFWSpeed speed) 1038{ 1039 AVCUnit *me = AVCUnit_getThis(self); 1040 uint32_t outputCnt = 0; 1041 const uint64_t inputs[3] = {outputPlug,chan,speed}; 1042 1043 return IOConnectCallScalarMethod(me->fConnection,kIOFWAVCUserClientMakeP2POutputConnection,inputs,3,NULL,&outputCnt); 1044} 1045 1046////////////////////////////////////////////////////// 1047// breakP2POutputConnection 1048////////////////////////////////////////////////////// 1049static IOReturn breakP2POutputConnection(void * self, UInt32 outputPlug) 1050{ 1051 AVCUnit *me = AVCUnit_getThis(self); 1052 uint32_t outputCnt = 0; 1053 const uint64_t inputs[1]={(const uint64_t)outputPlug}; 1054 1055 return IOConnectCallScalarMethod(me->fConnection,kIOFWAVCUserClientBreakP2POutputConnection,inputs,1,NULL,&outputCnt); 1056} 1057 1058////////////////////////////////////////////////////// 1059// createAVCAsynchronousCommand 1060////////////////////////////////////////////////////// 1061static IOReturn createAVCAsynchronousCommand(void * self, 1062 const UInt8 * command, 1063 UInt32 cmdLen, 1064 IOFireWireAVCLibAsynchronousCommandCallback completionCallback, 1065 void *pRefCon, 1066 IOFireWireAVCLibAsynchronousCommand **ppCommandObject) 1067{ 1068 AVCUnit *me = AVCUnit_getThis(self); 1069 AVCLibAsynchronousCommandPriv *pPrivCmd; 1070 IOReturn status = kIOReturnNoMemory; 1071 size_t outputCnt = sizeof(UInt32); 1072 //UInt8 **ppSharedBufAddress; 1073 mach_vm_address_t *pSharedBufAddress; 1074 mach_vm_address_t sharedBuf; 1075 1076 // Do some parameter validation 1077 if(cmdLen == 0 || cmdLen > 512) 1078 return kIOReturnBadArgument; 1079 1080 do 1081 { 1082 // Create a private async command object 1083 pPrivCmd = new AVCLibAsynchronousCommandPriv; 1084 if (!pPrivCmd) 1085 break; 1086 1087 // Create the client async command object 1088 pPrivCmd->pCmd = new IOFireWireAVCLibAsynchronousCommand; 1089 if (!pPrivCmd->pCmd) 1090 break; 1091 1092 // Create the client command buf, and copy the passed in command bytes 1093 // Note, add room at the end of this buffer for passing the address of the 1094 // shared kernel/user response buffer down to the kernel 1095 //pPrivCmd->pCmd->pCommandBuf = (UInt8*) malloc(cmdLen+sizeof(UInt8*)); 1096 pPrivCmd->pCmd->pCommandBuf = (UInt8*) malloc(cmdLen+sizeof(mach_vm_address_t)); 1097 if (!pPrivCmd->pCmd->pCommandBuf) 1098 break; 1099 1100 // Copy the passed in command bytes into the command buffer 1101 bcopy(command, pPrivCmd->pCmd->pCommandBuf, cmdLen); 1102 1103 // Create a 1 KByte memory buffer for the kernel/user shared memory 1104 // The first 512 bytes is the interim response buffer. 1105 // The second 512 bytes is the final response buffer 1106 //pPrivCmd->pResponseBuf = (UInt8*) mmap( NULL, 1024, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0 ); 1107 //if ((pPrivCmd->pResponseBuf == (UInt8*) -1 ) || (!pPrivCmd->pResponseBuf)) 1108 vm_allocate(mach_task_self(), (vm_address_t *)&pPrivCmd->pResponseBuf,1024, VM_FLAGS_ANYWHERE); 1109 if (!pPrivCmd->pResponseBuf) 1110 break; 1111 1112 // Put the address of the response buffer into the array of bytes we will send to the kernel 1113 pSharedBufAddress = (mach_vm_address_t *) &(pPrivCmd->pCmd->pCommandBuf[cmdLen]); 1114 sharedBuf = (mach_vm_address_t) pPrivCmd->pResponseBuf; 1115 *pSharedBufAddress = sharedBuf; 1116 1117 ROSETTA_ONLY( 1118 { 1119 *pSharedBufAddress = (mach_vm_address_t) OSSwapInt64(sharedBuf); 1120 } 1121 ); 1122 1123 // Initialize the command object 1124 pPrivCmd->pCmd->cmdLen = cmdLen; 1125 pPrivCmd->pCmd->cmdState = kAVCAsyncCommandStatePendingRequest; 1126 pPrivCmd->pCmd->pRefCon = pRefCon; 1127 pPrivCmd->pCmd->pInterimResponseBuf = nil; 1128 pPrivCmd->pCmd->interimResponseLen = 0; 1129 pPrivCmd->pCmd->pFinalResponseBuf = nil; 1130 pPrivCmd->pCmd->finalResponseLen = 0; 1131 pPrivCmd->clientCallback = completionCallback; 1132 1133 // Have the user-client create a in-kernel AVC async command object 1134 status = IOConnectCallStructMethod(me->fConnection, 1135 kIOFWAVCUserClientCreateAsyncAVCCommand, 1136 pPrivCmd->pCmd->pCommandBuf, 1137 cmdLen+sizeof(mach_vm_address_t), 1138 &(pPrivCmd->kernelAsyncAVCCommandHandle), 1139 &outputCnt); 1140 1141 ROSETTA_ONLY( 1142 { 1143 pPrivCmd->kernelAsyncAVCCommandHandle = OSSwapInt32(pPrivCmd->kernelAsyncAVCCommandHandle); 1144 } 1145 ); 1146 1147 if (status != kIOReturnSuccess) 1148 *ppCommandObject = nil; 1149 else 1150 *ppCommandObject = pPrivCmd->pCmd; 1151 }while(0); 1152 1153 // If success, add this command to our array, or, if something went wrong, clean up the allocated memory 1154 if (status == kIOReturnSuccess) 1155 { 1156 pthread_mutex_lock( &me->fAVCAsyncCommandArrayLock ); 1157 CFArrayAppendValue(me->fAVCAsyncCommandArray, pPrivCmd); 1158 pthread_mutex_unlock( &me->fAVCAsyncCommandArrayLock ); 1159 } 1160 else 1161 { 1162 if (pPrivCmd) 1163 { 1164 if (pPrivCmd->pResponseBuf) 1165 //munmap( (void*)pPrivCmd->pResponseBuf, 1024 ) ; 1166 vm_deallocate(mach_task_self(), (vm_address_t) pPrivCmd->pResponseBuf,1024); 1167 1168 if (pPrivCmd->pCmd) 1169 { 1170 if (pPrivCmd->pCmd->pCommandBuf) 1171 delete pPrivCmd->pCmd->pCommandBuf; 1172 delete pPrivCmd->pCmd; 1173 } 1174 1175 delete pPrivCmd; 1176 } 1177 } 1178 1179 return status; 1180} 1181 1182////////////////////////////////////////////////////// 1183// AVCAsynchronousCommandSubmit 1184////////////////////////////////////////////////////// 1185static IOReturn AVCAsynchronousCommandSubmit(void * self, IOFireWireAVCLibAsynchronousCommand *pCommandObject) 1186{ 1187 AVCUnit *me = AVCUnit_getThis(self); 1188 AVCLibAsynchronousCommandPriv *pPrivCmd; 1189 IOReturn res = kIOReturnBadArgument; 1190 uint32_t outputCnt = 0; 1191 1192 // Look up this command to see if it is valid 1193 pPrivCmd = FindPrivAVCAsyncCommand(me,pCommandObject); 1194 1195 // If we determined that the command object is valid, release it 1196 if (pPrivCmd) 1197 { 1198 if (pPrivCmd->pCmd->cmdState != kAVCAsyncCommandStatePendingRequest) 1199 { 1200 res = kIOReturnNotPermitted; 1201 } 1202 else 1203 { 1204 const uint64_t inArg = pPrivCmd->kernelAsyncAVCCommandHandle; 1205 res = IOConnectCallScalarMethod(me->fConnection, 1206 kIOFWAVCUserClientSubmitAsyncAVCCommand, 1207 &inArg, 1208 1,NULL,&outputCnt); 1209 if (res == kIOReturnSuccess) 1210 { 1211 // We need to check the command state here, because the callback may have already happened 1212 if (pPrivCmd->pCmd->cmdState == kAVCAsyncCommandStatePendingRequest) 1213 pPrivCmd->pCmd->cmdState = kAVCAsyncCommandStateRequestSent; 1214 } 1215 else 1216 { 1217 pPrivCmd->pCmd->cmdState = kAVCAsyncCommandStateRequestFailed; 1218 } 1219 } 1220 } 1221 1222 return res; 1223} 1224 1225////////////////////////////////////////////////////// 1226// AVCAsynchronousCommandReinit 1227////////////////////////////////////////////////////// 1228static IOReturn AVCAsynchronousCommandReinit(void * self, IOFireWireAVCLibAsynchronousCommand *pCommandObject) 1229{ 1230 AVCUnit *me = AVCUnit_getThis(self); 1231 AVCLibAsynchronousCommandPriv *pPrivCmd; 1232 IOReturn res = kIOReturnBadArgument; 1233 uint32_t outputCnt = 0; 1234 size_t outputStructCnt = 0; 1235 1236 1237 // Look up this command to see if it is valid 1238 pPrivCmd = FindPrivAVCAsyncCommand(me,pCommandObject); 1239 1240 // If we determined that the command object is valid, reinit it 1241 if (pPrivCmd) 1242 { 1243 // Don't allow if the command is in one of these "pending" states 1244 if ( (pPrivCmd->pCmd->cmdState == kAVCAsyncCommandStateRequestSent) || 1245 (pPrivCmd->pCmd->cmdState == kAVCAsyncCommandStateWaitingForResponse) || 1246 (pPrivCmd->pCmd->cmdState == kAVCAsyncCommandStateReceivedInterimResponse) ) 1247 { 1248 res = kIOReturnNotPermitted; 1249 } 1250 else 1251 { 1252 const uint64_t inArg = pPrivCmd->kernelAsyncAVCCommandHandle; 1253 res = IOConnectCallMethod(me->fConnection, 1254 kIOFWAVCUserClientReinitAsyncAVCCommand, 1255 &inArg, 1256 1, 1257 pPrivCmd->pCmd->pCommandBuf, 1258 pPrivCmd->pCmd->cmdLen, 1259 NULL, 1260 &outputCnt, 1261 NULL, 1262 &outputStructCnt); 1263 1264 if (res == kIOReturnSuccess) 1265 { 1266 // Update the user parts of the lib command object 1267 pPrivCmd->pCmd->cmdState = kAVCAsyncCommandStatePendingRequest; 1268 pPrivCmd->pCmd->pInterimResponseBuf = nil; 1269 pPrivCmd->pCmd->interimResponseLen = 0; 1270 pPrivCmd->pCmd->pFinalResponseBuf = nil; 1271 pPrivCmd->pCmd->finalResponseLen = 0; 1272 } 1273 } 1274 } 1275 1276 return res; 1277} 1278 1279////////////////////////////////////////////////////// 1280// AVCAsynchronousCommandReinitWithCommandBytes 1281////////////////////////////////////////////////////// 1282static IOReturn AVCAsynchronousCommandReinitWithCommandBytes(void * self, 1283 IOFireWireAVCLibAsynchronousCommand *pCommandObject, 1284 const UInt8 * command, 1285 UInt32 cmdLen) 1286{ 1287 AVCUnit *me = AVCUnit_getThis(self); 1288 AVCLibAsynchronousCommandPriv *pPrivCmd; 1289 IOReturn res = kIOReturnBadArgument; 1290 UInt8 *pNewCommandBuf; 1291 uint32_t outputCnt = 0; 1292 size_t outputStructCnt = 0; 1293 1294 // Do some parameter validation 1295 if(cmdLen == 0 || cmdLen > 512) 1296 return kIOReturnBadArgument; 1297 1298 // Look up this command to see if it is valid 1299 pPrivCmd = FindPrivAVCAsyncCommand(me,pCommandObject); 1300 1301 // If we determined that the command object is valid 1302 if (pPrivCmd) 1303 { 1304 // Malloc space for the new command buffer 1305 pNewCommandBuf = (UInt8*) malloc(cmdLen); 1306 if (pNewCommandBuf) 1307 { 1308 res = kIOReturnBadArgument; 1309 } 1310 else 1311 { 1312 // Don't allow if the command is in one of these "pending" states 1313 if ( (pPrivCmd->pCmd->cmdState == kAVCAsyncCommandStateRequestSent) || 1314 (pPrivCmd->pCmd->cmdState == kAVCAsyncCommandStateWaitingForResponse) || 1315 (pPrivCmd->pCmd->cmdState == kAVCAsyncCommandStateReceivedInterimResponse) ) 1316 { 1317 delete pNewCommandBuf; // We won't be needing this after all! 1318 res = kIOReturnNotPermitted; 1319 } 1320 else 1321 { 1322 // Save a copy of the new command bytes 1323 delete pPrivCmd->pCmd->pCommandBuf; 1324 pPrivCmd->pCmd->pCommandBuf = pNewCommandBuf; 1325 bcopy(command, pPrivCmd->pCmd->pCommandBuf, cmdLen); 1326 1327 const uint64_t inArg = pPrivCmd->kernelAsyncAVCCommandHandle; 1328 res = IOConnectCallMethod(me->fConnection, 1329 kIOFWAVCUserClientReinitAsyncAVCCommand, 1330 &inArg, 1331 1, 1332 pPrivCmd->pCmd->pCommandBuf, 1333 pPrivCmd->pCmd->cmdLen, 1334 NULL, 1335 &outputCnt, 1336 NULL, 1337 &outputStructCnt); 1338 1339 if (res == kIOReturnSuccess) 1340 { 1341 // Update the user parts of the lib command object 1342 pPrivCmd->pCmd->cmdState = kAVCAsyncCommandStatePendingRequest; 1343 pPrivCmd->pCmd->pInterimResponseBuf = nil; 1344 pPrivCmd->pCmd->interimResponseLen = 0; 1345 pPrivCmd->pCmd->pFinalResponseBuf = nil; 1346 pPrivCmd->pCmd->finalResponseLen = 0; 1347 } 1348 } 1349 } 1350 } 1351 1352 return res; 1353} 1354 1355////////////////////////////////////////////////////// 1356// AVCAsynchronousCommandCancel 1357////////////////////////////////////////////////////// 1358static IOReturn AVCAsynchronousCommandCancel(void * self, IOFireWireAVCLibAsynchronousCommand *pCommandObject) 1359{ 1360 AVCUnit *me = AVCUnit_getThis(self); 1361 AVCLibAsynchronousCommandPriv *pPrivCmd; 1362 IOReturn res = kIOReturnBadArgument; 1363 uint32_t outputCnt = 0; 1364 1365 // Look up this command to see if it is valid 1366 pPrivCmd = FindPrivAVCAsyncCommand(me,pCommandObject); 1367 1368 // If we determined that the command object is valid, release it 1369 if (pPrivCmd) 1370 { 1371 const uint64_t inArg = pPrivCmd->kernelAsyncAVCCommandHandle; 1372 res = IOConnectCallScalarMethod(me->fConnection, 1373 kIOFWAVCUserClientCancelAsyncAVCCommand, 1374 &inArg, 1375 1,NULL,&outputCnt); 1376 1377 pPrivCmd->pCmd->cmdState = kAVCAsyncCommandStateCanceled; 1378 } 1379 1380 return res; 1381} 1382 1383////////////////////////////////////////////////////// 1384// AVCAsynchronousCommandRelease 1385////////////////////////////////////////////////////// 1386static IOReturn AVCAsynchronousCommandRelease(void * self, IOFireWireAVCLibAsynchronousCommand *pCommandObject) 1387{ 1388 AVCUnit *me = AVCUnit_getThis(self); 1389 AVCLibAsynchronousCommandPriv *pPrivCmd; 1390 IOReturn res = kIOReturnBadArgument; 1391 CFIndex count = 0; 1392 CFIndex i = 0; 1393 bool found = false; 1394 uint32_t outputCnt = 0; 1395 1396 // First, see if this is a valid command object passed in by the client 1397 pthread_mutex_lock( &me->fAVCAsyncCommandArrayLock ); 1398 count = CFArrayGetCount( me->fAVCAsyncCommandArray ); 1399 for( i = 0; i < count; i++ ) 1400 { 1401 pPrivCmd = (AVCLibAsynchronousCommandPriv*) CFArrayGetValueAtIndex( me->fAVCAsyncCommandArray, i); 1402 if (pCommandObject == pPrivCmd->pCmd) 1403 { 1404 found = true; 1405 break; 1406 } 1407 } 1408 1409 // If we determined that the command object is valid, cancel it 1410 if (found == true) 1411 { 1412 const uint64_t inArg = pPrivCmd->kernelAsyncAVCCommandHandle; 1413 IOConnectCallScalarMethod(me->fConnection, 1414 kIOFWAVCUserClientReleaseAsyncAVCCommand, 1415 &inArg, 1416 1,NULL,&outputCnt); 1417 1418 // unmap the 1K response buffer 1419 if (pPrivCmd->pResponseBuf) 1420 //munmap( (void*)pPrivCmd->pResponseBuf, 1024 ) ; 1421 vm_deallocate(mach_task_self(), (vm_address_t) pPrivCmd->pResponseBuf,1024); 1422 1423 // delete the command byte buffer, and the user command 1424 if (pPrivCmd->pCmd) 1425 { 1426 if (pPrivCmd->pCmd->pCommandBuf) 1427 delete pPrivCmd->pCmd->pCommandBuf; 1428 delete pPrivCmd->pCmd; 1429 } 1430 1431 // Remove from array 1432 CFArrayRemoveValueAtIndex(me->fAVCAsyncCommandArray, i); 1433 1434 // Delete the private command 1435 delete pPrivCmd; 1436 1437 res = kIOReturnSuccess; 1438 } 1439 1440 pthread_mutex_unlock( &me->fAVCAsyncCommandArrayLock ); 1441 1442 return res; 1443} 1444 1445////////////////////////////////////////////////////// 1446// FindPrivAVCAsyncCommand 1447////////////////////////////////////////////////////// 1448AVCLibAsynchronousCommandPriv *FindPrivAVCAsyncCommand(AVCUnit *me, IOFireWireAVCLibAsynchronousCommand *pCommandObject) 1449{ 1450 CFIndex count = 0; 1451 CFIndex i = 0; 1452 AVCLibAsynchronousCommandPriv *pPrivCmd = NULL; 1453 bool found = false; 1454 1455 // First, see if this is a valid command object passed in by the client 1456 pthread_mutex_lock( &me->fAVCAsyncCommandArrayLock ); 1457 count = CFArrayGetCount( me->fAVCAsyncCommandArray ); 1458 for( i = 0; i < count; i++ ) 1459 { 1460 pPrivCmd = (AVCLibAsynchronousCommandPriv*) CFArrayGetValueAtIndex( me->fAVCAsyncCommandArray, i); 1461 if (pCommandObject == pPrivCmd->pCmd) 1462 { 1463 found = true; 1464 break; 1465 } 1466 } 1467 pthread_mutex_unlock( &me->fAVCAsyncCommandArrayLock ); 1468 1469 // If we determined that the command object is valid, cancel it 1470 if (found == true) 1471 return pPrivCmd; 1472 else 1473 return nil; 1474} 1475 1476// 1477// static interface table for IOCFPlugInInterface 1478// 1479static IOCFPlugInInterface sIOCFPlugInInterface = 1480{ 1481 0, 1482 &queryInterface, 1483 &addRef, 1484 &release, 1485 1, 0, // version/revision 1486 &probe, 1487 &start, 1488 &stop 1489}; 1490 1491// 1492// static interface table for IOFireWireAVCLibUnitInterface 1493// 1494static IOFireWireAVCLibUnitInterface sUnitInterface = 1495{ 1496 0, 1497 &queryInterface, 1498 &addRef, 1499 &release, 1500 4, 0, // version/revision 1501 &open, 1502 &openWithSessionRef, 1503 &getSessionRef, 1504 &close, 1505 &addIODispatcherToRunLoop, 1506 &removeIODispatcherFromRunLoop, 1507 &setMessageCallback, 1508 &AVCCommand, 1509 &AVCCommandInGeneration, 1510 &GetAncestorInterface, 1511 &GetProtocolInterface, 1512 &getAsyncConnectionPlugCounts, 1513 &createConsumerPlug, 1514 &updateAVCCommandTimeout, 1515 &makeP2PInputConnection, 1516 &breakP2PInputConnection, 1517 &makeP2POutputConnection, 1518 &breakP2POutputConnection, 1519 &createAVCAsynchronousCommand, 1520 &AVCAsynchronousCommandSubmit, 1521 &AVCAsynchronousCommandReinit, 1522 &AVCAsynchronousCommandCancel, 1523 &AVCAsynchronousCommandRelease, 1524 &AVCAsynchronousCommandReinitWithCommandBytes 1525}; 1526 1527// IOFireWireAVCLibUnitFactory 1528 1529////////////////////////////////////////////////////// 1530// alloc 1531// static allocator, called by factory method 1532////////////////////////////////////////////////////// 1533static IOCFPlugInInterface ** alloc() 1534{ 1535 AVCUnit * me; 1536 IOCFPlugInInterface ** interface = NULL; 1537 1538 me = (AVCUnit *)malloc(sizeof(AVCUnit)); 1539 if( me ) 1540 { 1541 bzero(me, sizeof(AVCUnit)); 1542 // we return an interface here. queryInterface will not be called. set refs to 1 1543 // init cf plugin ref counting 1544 me->fRefCount = 1; 1545 1546 // init user client connection 1547 me->fConnection = MACH_PORT_NULL; 1548 me->fService = MACH_PORT_NULL; 1549 1550 // create plugin interface map 1551 me->fIOCFPlugInInterface.pseudoVTable = (IUnknownVTbl *) &sIOCFPlugInInterface; 1552 me->fIOCFPlugInInterface.obj = me; 1553 1554 // create unit driver interface map 1555 me->fIOFireWireAVCLibUnitInterface.pseudoVTable 1556 = (IUnknownVTbl *) &sUnitInterface; 1557 me->fIOFireWireAVCLibUnitInterface.obj = me; 1558 1559 me->fSuspended = false; 1560 me->fHighPerfAVCCommands = false; 1561 1562 pthread_mutex_init( &me->fACObjectArrayLock, NULL ); 1563 me->fACObjectArray = CFArrayCreateMutable( kCFAllocatorDefault, 1564 2, // capacity 1565 IOFireWireAVCLibConsumer::getCFArrayCallbacks() ); 1566 1567 // Create the array to hold avc async commands, and the lock to protect it 1568 pthread_mutex_init( &me->fAVCAsyncCommandArrayLock, NULL ); 1569 me->fAVCAsyncCommandArray = CFArrayCreateMutable(kCFAllocatorDefault, 1570 0, // capacity 1571 NULL); 1572 1573 me->fFactoryId = kIOFireWireAVCLibUnitFactoryID; 1574 CFRetain( me->fFactoryId ); 1575 CFPlugInAddInstanceForFactory( me->fFactoryId ); 1576 interface = (IOCFPlugInInterface **) &me->fIOCFPlugInInterface.pseudoVTable; 1577 } 1578 1579 return interface; 1580} 1581 1582////////////////////////////////////////////////////// 1583// IOFireWireAVCLibUnitFactory 1584// factory method (only exported symbol) 1585////////////////////////////////////////////////////// 1586void *IOFireWireAVCLibUnitFactory( CFAllocatorRef allocator, CFUUIDRef typeID ) 1587{ 1588 if( CFEqual(typeID, kIOFireWireAVCLibUnitTypeID) ) 1589 return (void *) alloc(); 1590 else 1591 return NULL; 1592} 1593 1594