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