IOFireWireUserClient.cpp   [plain text]


/*
 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 *
 * The contents of this file constitute Original Code as defined in and
 * are subject to the Apple Public Source License Version 1.1 (the
 * "License").  You may not use this file except in compliance with the
 * License.  Please obtain a copy of the License at
 * http://www.apple.com/publicsource and read it before using this file.
 *
 * This Original Code and all software distributed under the License are
 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License.
 *
 * @APPLE_LICENSE_HEADER_END@
 */
/*
 * Copyright (c) 1999 Apple Computer, Inc.  All rights reserved.
 *
 * HISTORY
 * 8 June 1999 wgulland created.
 *
 */
/*
 $Log: not supported by cvs2svn $
 Revision 1.161  2009/05/08 01:10:34  calderon
 <rdar://6863576> FireWire tracepoints should be inlined for performance
 
 Revision 1.160  2009/03/07 00:37:23  calderon
 Small change for 6641573 to give more useful debugging info
 Add Firelog info.plist file
 
 Revision 1.159  2009/03/06 18:45:15  calderon
 <rdar://problem/6641573> Panic in IOFireWireFamily/SL 10A286 when hot-plugging Mackie Onyx 1200F
 Add FireLog specific plist to work around XCode plist editor bug
 Bump version
 
 Revision 1.158  2008/12/12 04:43:57  collin
 user space compare swap command fixes
 
 Revision 1.157  2008/11/26 23:55:21  collin
 fix user physical address spaces on K64
 
 Revision 1.156  2008/11/20 01:59:12  calderon
 More tracepoint logging
 
 Revision 1.155  2008/11/11 01:12:03  calderon
 First part of tracepoints logging
 
 Revision 1.154  2008/05/07 03:27:59  collin
 64 bit session ref support
 
 Revision 1.153  2008/04/30 03:02:13  collin
 publicize the exporter
 
 Revision 1.152  2008/04/24 00:01:39  collin
 more K640
 
 Revision 1.151  2008/04/11 00:52:37  collin
 some K64 changes
 
 Revision 1.150  2008/04/02 01:42:50  collin
 fix build failure
 
 Revision 1.149  2007/10/16 16:50:21  ayanowit
 Removed existing "work-in-progress" support for buffer-fill isoch.
 
 Revision 1.148  2007/06/21 04:08:44  collin
 *** empty log message ***
 
 Revision 1.147  2007/05/04 06:05:26  collin
 *** empty log message ***
 
 Revision 1.146  2007/04/28 02:54:22  collin
 *** empty log message ***
 
 Revision 1.145  2007/04/28 01:42:35  collin
 *** empty log message ***
 
 Revision 1.144  2007/04/24 02:50:08  collin
 *** empty log message ***
 
 Revision 1.143  2007/03/14 01:01:13  collin
 *** empty log message ***
 
 Revision 1.142  2007/03/12 22:15:28  arulchan
 mach_vm_address_t & io_user_reference_t changes
 
 Revision 1.141  2007/03/10 07:48:25  collin
 *** empty log message ***
 
 Revision 1.140  2007/03/10 05:11:36  collin
 *** empty log message ***
 
 Revision 1.139  2007/03/10 04:15:25  collin
 *** empty log message ***
 
 Revision 1.138  2007/03/10 02:58:03  collin
 *** empty log message ***
 
 Revision 1.137  2007/03/09 23:57:53  collin
 *** empty log message ***
 
 Revision 1.136  2007/03/08 18:13:56  ayanowit
 Fix for 5047793. A problem where user-space CompareSwap() was not checking lock results.
 
 Revision 1.135  2007/03/08 02:37:09  collin
 *** empty log message ***
 
 Revision 1.134  2007/03/03 01:26:46  calderon
 pico
 
 Revision 1.133  2007/02/16 00:54:39  ayanowit
 Working IRMAllocation callbacks from user-space :)
 
 Revision 1.132  2007/02/16 00:28:25  ayanowit
 More work on IRMAllocation APIs
 
 Revision 1.131  2007/02/09 20:36:46  ayanowit
 More Leopard IRMAllocation changes.
 
 Revision 1.130  2007/02/07 06:35:20  collin
 *** empty log message ***
 
 Revision 1.129  2007/02/06 01:08:41  ayanowit
 More work on Leopard features such as new User-space IRM allocation APIs.
 
 Revision 1.128  2007/01/26 20:52:31  ayanowit
 changes to user-space isoch stuff to support 64-bit apps.
 
 Revision 1.127  2007/01/24 04:10:13  collin
 *** empty log message ***
 
 Revision 1.126  2007/01/05 00:11:00  ayanowit
 yet more 64-bit changes.
 
 Revision 1.124  2006/12/21 21:17:44  ayanowit
 More changes necessary to eventually get support for 64-bit apps working (4222965).
 
 Revision 1.123  2006/12/06 01:12:54  arulchan
 AsyncStream Listener Merges to Dispatcher
 
 Revision 1.122  2006/12/06 00:01:08  arulchan
 Isoch Channel 31 Generic Receiver
 
 Revision 1.121  2006/11/29 18:42:52  ayanowit
 Modified the IOFireWireUserClient to use the Leopard externalMethod method of dispatch.
 
 Revision 1.120  2006/09/09 01:59:56  collin
 *** empty log message ***
 
 Revision 1.119  2006/08/16 01:41:41  collin
 *** empty log message ***
 
 Revision 1.118  2006/07/07 20:18:25  calderon
 4227201: SpeedMap and HopCount table reductions.
 
 Revision 1.117  2006/02/27 19:03:18  niels
 *** empty log message ***
 
 Revision 1.116  2006/02/09 00:21:51  niels
 merge chardonnay branch to tot
 
 Revision 1.110.4.4  2006/01/31 04:49:51  collin
 *** empty log message ***
 
 Revision 1.110.4.2  2005/08/17 03:33:57  collin
 *** empty log message ***
 
 Revision 1.110.4.1  2005/07/23 00:30:44  collin
 *** empty log message ***
 
 Revision 1.110  2005/01/18 23:40:16  collin
 Revision 1.109  2004/09/16 04:28:21  collin
 Revision 1.108  2004/05/12 00:00:08  niels
 3626775 - Brego 7L8: Digidesign Pro Tools LE FireWire 002 system doesn't work
 3641955 - Digi 002 Pro Tools LE fails to launch on 10.3.4 7H46
 
 Revision 1.107  2004/03/25 00:08:59  niels
 fix panic allocating large physical address spaces
 
 Revision 1.106  2004/03/25 00:00:59  niels
 fix panic allocating large physical address spaces
 
 Revision 1.105  2004/03/25 00:00:23  niels
 fix panic allocating large physical address spaces
 
 Revision 1.104  2004/02/17 23:13:23  niels
 Revision 1.103  2004/02/17 23:12:26  niels
 Revision 1.102  2004/02/11 22:30:02  niels
 Revision 1.101  2004/02/11 22:13:08  niels
 fix final cut pro panic/object leak when calling TurnOffNotification on isoch channels in user space
 
 Revision 1.100  2004/01/28 22:13:32  niels
 Revision 1.99  2004/01/22 01:49:59  niels
 fix user space physical address space getPhysicalSegments
 
 Revision 1.98  2003/12/19 22:07:46  niels
 send force stop when channel dies/system sleeps
 
 Revision 1.97  2003/12/18 00:42:37  niels
 Revision 1.96  2003/11/14 01:00:53  collin
 Revision 1.95  2003/11/07 21:24:28  niels
 Revision 1.94  2003/11/07 21:01:18  niels
 Revision 1.93  2003/11/05 00:29:42  niels
 Revision 1.92  2003/11/03 19:11:35  niels
 fix local config rom reading; fix 3401223
 
 Revision 1.91  2003/10/31 02:40:58  niels
 Revision 1.90  2003/09/20 00:54:17  collin
 Revision 1.89  2003/09/16 21:40:51  collin
 Revision 1.88  2003/09/11 20:59:46  collin
 Revision 1.87  2003/09/04 19:43:34  collin
 Revision 1.86  2003/09/02 23:48:12  collin
 Revision 1.85  2003/09/02 22:58:55  collin
 Revision 1.84  2003/08/30 00:16:45  collin
 Revision 1.83  2003/08/26 05:23:34  niels
 Revision 1.82  2003/08/26 05:11:21  niels
 Revision 1.81  2003/08/25 08:39:16  niels
 Revision 1.80  2003/08/20 18:48:43  niels
 Revision 1.79  2003/08/19 01:48:54  niels
 Revision 1.78  2003/08/14 19:46:06  niels
 Revision 1.77  2003/08/14 17:47:33  niels
 Revision 1.76  2003/08/08 22:30:32  niels
 Revision 1.75  2003/08/08 21:03:27  gecko1
 Merge max-rec clipping code into TOT
 
 Revision 1.74  2003/07/26 04:47:24  collin
 Revision 1.73  2003/07/24 20:49:48  collin
 Revision 1.72  2003/07/24 06:30:58  collin
 Revision 1.71  2003/07/24 03:06:27  collin
 Revision 1.70  2003/07/22 10:49:47  niels
 Revision 1.69  2003/07/21 07:29:48  niels
 Revision 1.68  2003/07/21 06:52:59  niels
 merge isoch to TOT
 
 Revision 1.66.2.5  2003/07/21 06:44:45  niels
 Revision 1.66.2.4  2003/07/18 00:17:42  niels
 Revision 1.66.2.3  2003/07/11 18:15:34  niels
 Revision 1.66.2.2  2003/07/09 21:24:01  niels
 Revision 1.66.2.1  2003/07/01 20:54:07  niels
 isoch merge
 
 Revision 1.66  2003/06/12 21:27:14  collin
 Revision 1.65  2003/06/07 01:30:40  collin
 Revision 1.64  2003/06/05 01:19:31  niels
 fix crash on close
 
 Revision 1.63  2003/04/22 02:45:28  collin
 Revision 1.62  2003/03/17 01:05:22  collin
 Revision 1.61  2003/03/01 00:10:07  collin
 Revision 1.60  2002/11/20 00:34:27  niels
 fix minor bug in getAsyncTargetAndMethodForIndex
 
 Revision 1.59  2002/10/18 23:29:45  collin
 fix includes, fix cast which fails on new compiler
 
 Revision 1.58  2002/10/17 00:29:44  collin
 reenable FireLog
 
 Revision 1.57  2002/10/16 21:42:00  niels
 no longer panic trying to get config directory on local node.. still can't get the directory, however
 
 Revision 1.56  2002/09/25 00:27:25  niels
 flip your world upside-down
 
 Revision 1.55  2002/09/12 22:41:54  niels
 add GetIRMNodeID() to user client
 
 */

// public
#import "IOFireWireFamilyCommon.h"
#import "IOFireWireNub.h"
#import "IOLocalConfigDirectory.h"
#import "IOFireWireController.h"
#import "IOFireWireDevice.h"
#import "IOFWDCLProgram.h"

#import <sys/proc.h>
#import <IOKit/IOMessage.h>
#include <IOKit/IOKitKeysPrivate.h>

// protected
#import <IOKit/firewire/IOFireWireLink.h>

// private
#import "IOFireWireUserClient.h"
#import "IOFWUserPseudoAddressSpace.h"
#import "IOFWUserPhysicalAddressSpace.h"
#import "IOFWUserIsochChannel.h"
#import "IOFWUserIsochPort.h"
#import "IOFireWireLibPriv.h"
#import "IOFireWireLocalNode.h"
#import "IOFWUserCommand.h"
#import "IOFWUserObjectExporter.h"
#import "IOLocalConfigDirectory.h"
#import "IOFWUserAsyncStreamListener.h"
#import "IOFWUserVectorCommand.h"
#import "IOFWUserPHYPacketListener.h"

#if IOFIREWIREUSERCLIENTDEBUG > 0

#undef super
#define super OSObject

OSDefineMetaClassAndStructors( IOFWUserDebugInfo, OSObject )

bool
IOFWUserDebugInfo::init( IOFireWireUserClient & userClient )
{
	if ( ! super::init() )
		return false ;
	
	fUserClient = & userClient ;
	//	fIsochCallbacks = OSNumber::withNumber( (long long unsigned)0, 64 ) ;
	//	if ( !fIsochCallbacks )
	//		return false ;
	
	return true ;
}

bool
IOFWUserDebugInfo::serialize (
							  OSSerialize * s ) const
{
	s->clearText() ;
	
	const unsigned objectCount = 1 ;
	const OSObject * objects[ objectCount ] =
	{
		fUserClient->fExporter
		//		, fIsochCallbacks
	} ;
	
	const OSSymbol * keys[ objectCount ] =
	{
		OSSymbol::withCStringNoCopy("user objects")
		//		, OSSymbol::withCStringNoCopy( "total isoch callbacks" )
	} ;
	
	OSDictionary * dict = OSDictionary::withObjects( objects, keys, objectCount ) ;
	if ( !dict )
		return false ;
	
	bool result = dict->serialize( s ) ;
	dict->release() ;
	
	return result ;
}

void
IOFWUserDebugInfo::free ()
{
	//	if ( fIsochCallbacks )
	//		fIsochCallbacks->release() ;
	OSObject::free() ;
}

#endif

#pragma mark -

#undef super
#define super IOUserClient

OSDefineMetaClassAndStructors(IOFireWireUserClient, super ) ;


bool IOFireWireUserClient::initWithTask(
										task_t owningTask, void * securityToken, UInt32 type,
										OSDictionary * properties)
{
	if( properties )
		properties->setObject( "IOUserClientCrossEndianCompatible" , kOSBooleanTrue);
	
	bool res = IOUserClient::initWithTask( owningTask, securityToken, type, properties );
	
	fTask = owningTask;
	
	return res;
}

bool
IOFireWireUserClient::start( IOService * provider )
{
	if (!OSDynamicCast(IOFireWireNub, provider))
		return false ;
	
	if ( ! super::start ( provider ) )
		return false;
	
	fOwner = (IOFireWireNub *)provider;
	fOwner->retain();
	
	FWTrace( kFWTUserClient, kTPUserClientStart, (uintptr_t)(fOwner->getController()->getLink()), 0, 0, 0 );
	
	//
	// init object table
	//
	fObjectTable[0] = NULL ;
	fObjectTable[1] = this ;
	fObjectTable[2] = getOwner()->getBus() ;
	
	// initialize notification structures
	fBusResetAsyncNotificationRef[0] = 0 ;
	fBusResetDoneAsyncNotificationRef[0] = 0 ;
	
	bool result = true ;
	
	if( result )
	{
		if( !fOwner )
		{
			result = false;
		}
	}
	
	if( result )
	{
		fUserClientLock = IOLockAlloc ();
		if( !fUserClientLock )
		{
			result = false;
		}
	}
	
	if( result )
	{
		fController = fOwner->getController();
		if( fController == NULL )
		{
			result = false;
		}
	}
	
	if( result )
	{
		fController->retain();
	}
	
	if( result )
	{
		fExporter = IOFWUserObjectExporter::createWithOwner( this );
		
		if ( ! fExporter )
			result = false ;
	}
	
#if IOFIREWIREUSERCLIENTDEBUG > 0
	if (result)
	{
		fDebugInfo = OSTypeAlloc( IOFWUserDebugInfo );
		if ( fDebugInfo && ! fDebugInfo->init( *this ) )
		{
			fDebugInfo->release() ;
			fDebugInfo = NULL ;
			
			ErrorLog( "Couldn't create statistics object\n" ) ;
		}
		
		if ( fDebugInfo )
			setProperty( "Debug Info", fDebugInfo ) ;
	}
#endif
	
#if 0
	// turn off because sadly the proc structure is now opaque
	
	// borrowed from bsd/vm/vm_unix.c, function pid_for_task() which has some other weird crap
	// going on too... I just took this part:
	if ( result )
	{
		proc *				p 			= (proc *)get_bsdtask_info( fTask );
		OSNumber*			pidProp 	= OSNumber::withNumber( p->p_pid, sizeof(p->p_pid) * 8 ) ;
		if ( pidProp )
		{
			setProperty( "Owning PID", pidProp ) ;
			pidProp->release() ;			// property table takes a reference
		}
		else
			result = false ;
	}
#endif
	
	return result ;
}

void
IOFireWireUserClient::free()
{
	if ( fOwner ) {
		FWTrace( kFWTUserClient, kTPUserClientFree, (uintptr_t)(fOwner->getController()->getLink()), (uintptr_t)this, 0, 0 );
	} else {
		FWTrace( kFWTUserClient, kTPUserClientFree, 0xdeadbeef, (uintptr_t)this, 0, 0 );
	}
	
	DebugLog( "free user client %p\n", this ) ;
	
#if IOFIREWIREUSERCLIENTDEBUG > 0
	if ( fDebugInfo )
		fDebugInfo->release() ;
#endif
	
	if ( fExporter )
	{
		fExporter->release() ;
		fExporter = NULL ;
	}
	
	if( fController )
	{
		fController->release();
	}
	
	if( fUserClientLock )
	{
		IOLockFree( fUserClientLock );
		fUserClientLock = NULL;
	}
	
	if ( fOwner )
	{
		fOwner->release() ;
	}
	
	super::free () ;
}

IOReturn
IOFireWireUserClient::clientClose ()
{
	FWTrace( kFWTUserClient, kTPUserClientClientClose, (uintptr_t)(fOwner->getController()->getLink()), 0, 0, 0 );
	
	clipMaxRec2K( false );	// Make sure maxRec isn't clipped
	
	IOReturn	result = userClose() ;
	
	if ( getProvider() && fOwner->isOpen() )
	{
		DebugLog("IOFireWireUserClient::clientClose(): client left user client open, should call close. Closing...\n") ;
	}
	else if ( result == kIOReturnNotOpen )
	{
		result = kIOReturnSuccess ;
	}
	
	if ( !terminate() )
	{
		DebugLog("IOFireWireUserClient::clientClose: terminate failed!, getOwner()->isOpen( this ) returned %u\n", getOwner()->isOpen(this)) ;
	}
	
	return kIOReturnSuccess;
}

IOReturn
IOFireWireUserClient::clientDied ()
{
	if ( fOwner ) {
		FWTrace( kFWTUserClient, kTPUserClientClientDied, (uintptr_t)(fOwner->getController()->getLink()), 1, 0, 0 );
	} else {
		FWTrace( kFWTUserClient, kTPUserClientClientDied, 0xdeadbeef, 1, 0, 0 );
	}
	
	if ( fOwner )
	{
		FWTrace( kFWTUserClient, kTPUserClientClientDied, (uintptr_t)(fOwner->getController()->getLink()), 2, 0, 0 );
		fOwner->getBus()->resetBus() ;
	}
	
	IOReturn error = clientClose () ;
	
	return error ;
}

IOReturn
IOFireWireUserClient::setProperties (
									 OSObject * properties )
{
	IOReturn result = kIOReturnSuccess ;
	
	OSDictionary*	dict = OSDynamicCast( OSDictionary, properties ) ;
	
	if ( dict )
	{
		OSObject*	value = dict->getObject( "unsafe bus resets" ) ;
		
		if ( value and OSDynamicCast(OSNumber, value ) )
		{
			fUnsafeResets = ( ((OSNumber*)value)->unsigned8BitValue() != 0 ) ;
		}
		else
		{
			result = super::setProperties ( properties ) ;
		}
	}
	else
		result = super::setProperties ( properties ) ;
	
	return result ;
}

#pragma mark -


static UInt32 getSelectorObjectLookupIndex(UInt32 selector)
{
	UInt32 selectorObjectLookupIndex = 1;  // Note: A 1 here specifies use of the IOFireWireUserClient object
	
	/////////////////////////////////////////////////////////////////////////////////////////////////////////
	// NOTE: If the selector is not in this lookup table, it is handled directly by the IOFireWireUserClient
	/////////////////////////////////////////////////////////////////////////////////////////////////////////
	switch (selector)
	{
			/////////////////////////////////////////////////////////////////////////
			// The follwing selectors all are handled by the IOFireWireBus
			/////////////////////////////////////////////////////////////////////////
		case kCycleTime:
		case kGetBusCycleTime:
			selectorObjectLookupIndex = 2;  // Note: A 2 here specifies use of the IOFireWireBus object
			break;
			
			/////////////////////////////////////////////////////////////////////////////////
			// The follwing selectors all are handled by object exporter managed objects
			/////////////////////////////////////////////////////////////////////////////////
		case kPhysicalAddrSpace_GetSegmentCount_d:			// Handled by a IOFWUserPhysicalAddressSpace object
		case kIsochPort_AllocatePort_d:						// Handled by a IOFWUserLocalIsochPort object
		case kIsochPort_ReleasePort_d:						// Handled by a IOFWUserLocalIsochPort object
		case kIsochPort_Start_d:							// Handled by a IOFWUserLocalIsochPort object
		case kIsochPort_Stop_d:								// Handled by a IOFWUserLocalIsochPort object
		case kLocalIsochPort_ModifyJumpDCL_d:				// Handled by a IOFWUserLocalIsochPort object
		case kLocalIsochPort_Notify_d:						// Handled by a IOFWUserLocalIsochPort object
		case kIsochChannel_UserReleaseChannelComplete_d:	// Handled by a IOFWUserIsochChannel object
		case kCommand_Cancel_d:								// Handled by a IOFWCommand object
		case kIsochPort_SetIsochResourceFlags_d:			// Handled by a IOFWLocalIsochPort object
		case kVectorCommandSubmit:							// Handled by a IOFWUserVectorCommand object
		case kVectorCommandSetBuffers:						// Handled by a IOFWUserVectorCommand object
		case kPHYPacketListenerSetPacketCallback:			// Handled by a IOFWUserPHYPacketListener object
		case kPHYPacketListenerSetSkippedCallback:			// Handled by a IOFWUserPHYPacketListener object
		case kPHYPacketListenerActivate:					// Handled by a IOFWUserPHYPacketListener object
		case kPHYPacketListenerDeactivate:					// Handled by a IOFWUserPHYPacketListener object
		case kPHYPacketListenerClientCommandIsComplete:		// Handled by a IOFWUserPHYPacketListener object
			selectorObjectLookupIndex = 0;  // Note: A 0 here specifies a lookup into the object exporter!
			break;
			
		default:
			// Any other selector is handled by the IOFireWireUserClient!
			break;
	};
	return selectorObjectLookupIndex;
}

IOReturn
IOFireWireUserClient::externalMethod( uint32_t selector,
									 IOExternalMethodArguments * arguments,
									 IOExternalMethodDispatch * dispatch,
									 OSObject * target,
									 void * reference)
{
	IOReturn result = kIOReturnBadArgument;
	OSObject *targetObject = NULL;
	bool target_object_needs_release = false;
	
	UInt32 actualSelector = selector & 0xFFFF ;
	if ( actualSelector >= kNumMethods )
		return result;
	
	targetObject = fObjectTable[ getSelectorObjectLookupIndex(actualSelector)] ;
	
	if ( !targetObject )
	{
		const OSObject * userObject = fExporter->lookupObject( (UserObjectHandle)( selector >> 16 ) ) ;
		
		// sort of pointless to dynamic cast to OSObject
		targetObject = OSDynamicCast( OSObject, userObject );	// "interesting code" note:
		// when we don't have an object set in our method table,
		// the object handle is encoded in the upper 16 bits of the
		// method index...
		// We extract the object handle here to get the object to call...
		
		if (targetObject)
		{
			// exporter retains returned objects, need to remember to release it..
			target_object_needs_release = true;
		}
		else
			return result;
	}
	
	// Dispatch the method call
	switch (actualSelector)
	{
		case kOpen:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->userOpen();
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kOpenWithSessionRef:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->userOpenWithSessionRef((IOFireWireLib::UserObjectHandle) arguments->scalarInput[0]);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kClose:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->userClose();
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kReadQuad:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->readQuad((const ReadQuadParams*) arguments->structureInput,
										 (UInt32*) arguments->structureOutput);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kRead:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->read((const ReadParams*) arguments->structureInput,
									 (IOByteCount*) arguments->structureOutput);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kWriteQuad:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->writeQuad((const WriteQuadParams*) arguments->structureInput);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kWrite:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->write((const WriteParams*) arguments->structureInput,
									  (IOByteCount*) arguments->structureOutput);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kCompareSwap:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->compareSwap((const CompareSwapParams*) arguments->structureInput,
											(UInt32*) arguments->structureOutput);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kBusReset:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->busReset();
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kCycleTime:
		{
			UInt32 cycleTime = 0;
			UInt64 upTime = 0;
			IOFireWireController * fw_controller = OSDynamicCast( IOFireWireController, targetObject );
			if( fw_controller )
			{
				result = fw_controller->getCycleTimeAndUpTime(cycleTime, upTime);
				arguments->scalarOutput[0] = cycleTime;
				arguments->scalarOutput[1] = upTime;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kGetGenerationAndNodeID:
		{
			UInt32 outGeneration = 0;
			UInt32 outNodeID = 0;
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->getGenerationAndNodeID(&outGeneration,&outNodeID);
				arguments->scalarOutput[0] = outGeneration;
				arguments->scalarOutput[1] = outNodeID;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kGetLocalNodeID:
		{
			UInt32 outLocalNodeID = 0;
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->getLocalNodeID(&outLocalNodeID);
				arguments->scalarOutput[0] = outLocalNodeID;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kGetResetTime:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->getResetTime((AbsoluteTime*) arguments->structureOutput);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
		case kReleaseUserObject:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->releaseUserObject((UserObjectHandle)arguments->scalarInput[0]);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kGetOSStringData:
		{
			UInt32 outTextLength = 0;
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->getOSStringData((UserObjectHandle)arguments->scalarInput[0],
												(UInt32)arguments->scalarInput[1],
												(mach_vm_address_t)arguments->scalarInput[2],
												&outTextLength);
				arguments->scalarOutput[0] = outTextLength;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kGetOSDataData:
		{
			IOByteCount outDataLen = 0;
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->getOSDataData((UserObjectHandle)arguments->scalarInput[0],
											  (IOByteCount)arguments->scalarInput[1],
											  (mach_vm_address_t)arguments->scalarInput[2],
											  &outDataLen);
				arguments->scalarOutput[0] = outDataLen;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kLocalConfigDirectory_Create:
		{
			UserObjectHandle outDir = 0;
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->localConfigDirectory_Create(&outDir);
				arguments->scalarOutput[0] = (uint64_t) outDir;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kLocalConfigDirectory_AddEntry_Buffer:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->localConfigDirectory_addEntry_Buffer((UserObjectHandle)arguments->scalarInput[0],
																	 (int)arguments->scalarInput[1],
																	 (char *)arguments->scalarInput[2],
																	 (UInt32)arguments->scalarInput[3],
																	 (const char *)arguments->scalarInput[4],
																	 (UInt32)arguments->scalarInput[5]);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kLocalConfigDirectory_AddEntry_UInt32:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->localConfigDirectory_addEntry_UInt32((UserObjectHandle)arguments->scalarInput[0],
																	 (int)arguments->scalarInput[1],
																	 (UInt32)arguments->scalarInput[2],
																	 (const char *)arguments->scalarInput[3],
																	 (UInt32)arguments->scalarInput[4]);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kLocalConfigDirectory_AddEntry_FWAddr:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->localConfigDirectory_addEntry_FWAddr((UserObjectHandle)arguments->scalarInput[0],
																	 (int)arguments->scalarInput[1],
																	 (const char *)arguments->scalarInput[2],
																	 (UInt32)arguments->scalarInput[3],
																	 (FWAddress *) arguments->structureInput);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kLocalConfigDirectory_AddEntry_UnitDir:
			// TODO -  Note: This wasn't hooked-up in Tiger either!
			break;
			
		case kLocalConfigDirectory_Publish:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->localConfigDirectory_Publish((UserObjectHandle)arguments->scalarInput[0]);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kLocalConfigDirectory_Unpublish:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->localConfigDirectory_Unpublish((UserObjectHandle)arguments->scalarInput[0]);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kPseudoAddrSpace_Allocate:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->addressSpace_Create((AddressSpaceCreateParams *) arguments->structureInput,
													(UserObjectHandle *) arguments->structureOutput);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kPseudoAddrSpace_GetFWAddrInfo:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->addressSpace_GetInfo((UserObjectHandle)arguments->scalarInput[0],
													 (AddressSpaceInfo *) arguments->structureOutput);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kPseudoAddrSpace_ClientCommandIsComplete:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->addressSpace_ClientCommandIsComplete((UserObjectHandle)arguments->scalarInput[0],
																	 (FWClientCommandID)arguments->scalarInput[1],
																	 (IOReturn)arguments->scalarInput[2]);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kPhysicalAddrSpace_Allocate:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				UserObjectHandle outAddressSpaceHandle = 0;
				result = fw_uc->physicalAddressSpace_Create((mach_vm_size_t)arguments->scalarInput[0],
															(mach_vm_address_t)arguments->scalarInput[1],
															(UInt32)arguments->scalarInput[2],
															&outAddressSpaceHandle);
				arguments->scalarOutput[0] = (uint64_t) outAddressSpaceHandle;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kPhysicalAddrSpace_GetSegmentCount_d:
		{
			IOFWUserPhysicalAddressSpace * fw_phys_space = OSDynamicCast( IOFWUserPhysicalAddressSpace, targetObject );
			if( fw_phys_space )
			{
				UInt32 outSegmentCount = 0;
				result = fw_phys_space->getSegmentCount(&outSegmentCount);
				arguments->scalarOutput[0] = outSegmentCount;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kPhysicalAddrSpace_GetSegments:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				UInt32 outSegmentCount = 0;
				result = fw_uc->physicalAddressSpace_GetSegments((UserObjectHandle)arguments->scalarInput[0],
																 (UInt32)arguments->scalarInput[1],
																 (mach_vm_address_t)arguments->scalarInput[2],
																 &outSegmentCount);
				arguments->scalarOutput[0] = outSegmentCount;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kConfigDirectory_Create:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				UserObjectHandle outDirRef = 0;
				result = fw_uc->configDirectory_Create(&outDirRef);
				arguments->scalarOutput[0] = (uint64_t) outDirRef;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kConfigDirectory_GetKeyType:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				IOConfigKeyType outType = kConfigImmediateKeyType;
				result = fw_uc->configDirectory_GetKeyType((UserObjectHandle)arguments->scalarInput[0],
														   (int)arguments->scalarInput[1],
														   &outType);
				arguments->scalarOutput[0] = outType;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kConfigDirectory_GetKeyValue_UInt32:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				UInt32 outValue = 0;
				UserObjectHandle outTextHandle = 0;
				UInt32 outTextLength = 0;
				result = fw_uc->configDirectory_GetKeyValue_UInt32((UserObjectHandle)arguments->scalarInput[0],
																   (int)arguments->scalarInput[1],
																   (UInt32)arguments->scalarInput[2],
																   &outValue,
																   &outTextHandle,
																   &outTextLength);
				arguments->scalarOutput[0] = outValue;
				arguments->scalarOutput[1] = (uint64_t) outTextHandle;
				arguments->scalarOutput[2] = outTextLength;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kConfigDirectory_GetKeyValue_Data:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->configDirectory_GetKeyValue_Data((UserObjectHandle)arguments->scalarInput[0],
																 (int)arguments->scalarInput[1],
																 (UInt32)arguments->scalarInput[2],
																 (GetKeyValueDataResults *) arguments->structureOutput);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kConfigDirectory_GetKeyValue_ConfigDirectory:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				UserObjectHandle outDirHandle = 0;
				UserObjectHandle outTextHandle = 0;
				UInt32 outTextLength = 0;
				result = fw_uc->configDirectory_GetKeyValue_ConfigDirectory((UserObjectHandle)arguments->scalarInput[0],
																			(int)arguments->scalarInput[1],
																			(UInt32)arguments->scalarInput[2],
																			&outDirHandle,
																			&outTextHandle,
																			&outTextLength);
				arguments->scalarOutput[0] = (uint64_t) outDirHandle;
				arguments->scalarOutput[1] = (uint64_t) outTextHandle;
				arguments->scalarOutput[2] = outTextLength;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kConfigDirectory_GetKeyOffset_FWAddress:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->configDirectory_GetKeyOffset_FWAddress((UserObjectHandle)arguments->scalarInput[0],
																	   (int)arguments->scalarInput[1],
																	   (UInt32)arguments->scalarInput[2],
																	   (GetKeyOffsetResults *) arguments->structureOutput);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kConfigDirectory_GetIndexType:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				IOConfigKeyType outType = kConfigImmediateKeyType;
				result = fw_uc->configDirectory_GetIndexType((UserObjectHandle)arguments->scalarInput[0],
															 (int)arguments->scalarInput[1],
															 &outType);
				arguments->scalarOutput[0] = (IOConfigKeyType) outType;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
			
		case kConfigDirectory_GetIndexKey:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				int outKey = 0;
				result = fw_uc->configDirectory_GetIndexKey((UserObjectHandle)arguments->scalarInput[0],
															(int)arguments->scalarInput[1],
															&outKey);
				arguments->scalarOutput[0] = outKey;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kConfigDirectory_GetIndexValue_UInt32:
			// configDirectory_GetIndexValue_UInt32
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				UInt32 outKey = 0;
				result = fw_uc->configDirectory_GetIndexValue_UInt32((UserObjectHandle)arguments->scalarInput[0],
																	 (int)arguments->scalarInput[1],
																	 &outKey);
				arguments->scalarOutput[0] = outKey;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kConfigDirectory_GetIndexValue_Data:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				UserObjectHandle outDataHandle  = 0;
				IOByteCount outDataLen = 0;
				result = fw_uc->configDirectory_GetIndexValue_Data((UserObjectHandle)arguments->scalarInput[0],
																   (int)arguments->scalarInput[1],
																   &outDataHandle,
																   &outDataLen);
				arguments->scalarOutput[0] = (uint64_t) outDataHandle;
				arguments->scalarOutput[1] = outDataLen;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kConfigDirectory_GetIndexValue_String:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				UserObjectHandle outTextHandle = 0;
				UInt32 outTextLength = 0;
				result = fw_uc->configDirectory_GetIndexValue_String((UserObjectHandle)arguments->scalarInput[0],
																	 (int)arguments->scalarInput[1],
																	 &outTextHandle,
																	 &outTextLength);
				arguments->scalarOutput[0] = (uint64_t) outTextHandle;
				arguments->scalarOutput[1] = outTextLength;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kConfigDirectory_GetIndexValue_ConfigDirectory:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				UserObjectHandle outDirHandle = 0;
				result = fw_uc->configDirectory_GetIndexValue_ConfigDirectory((UserObjectHandle)arguments->scalarInput[0],
																			  (int)arguments->scalarInput[1],
																			  &outDirHandle);
				arguments->scalarOutput[0] = (uint64_t) outDirHandle;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kConfigDirectory_GetIndexOffset_FWAddress:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->configDirectory_GetIndexOffset_FWAddress((UserObjectHandle)arguments->scalarInput[0],
																		 (int)arguments->scalarInput[1],
																		 (FWAddress *) arguments->structureOutput);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kConfigDirectory_GetIndexOffset_UInt32:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				UInt32 outValue = 0;
				result = fw_uc->configDirectory_GetIndexOffset_UInt32((UserObjectHandle)arguments->scalarInput[0],
																	  (int)arguments->scalarInput[1],
																	  &outValue);
				arguments->scalarOutput[0] = outValue;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kConfigDirectory_GetIndexEntry:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				UInt32 outValue = 0;
				result = fw_uc->configDirectory_GetIndexEntry((UserObjectHandle)arguments->scalarInput[0],
															  (int)arguments->scalarInput[1],
															  &outValue);
				arguments->scalarOutput[0] = outValue;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kConfigDirectory_GetSubdirectories:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				UserObjectHandle outIteratorHandle = 0;
				result = fw_uc->configDirectory_GetSubdirectories((UserObjectHandle)arguments->scalarInput[0],
																  &outIteratorHandle);
				arguments->scalarOutput[0] = (uint64_t) outIteratorHandle;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kConfigDirectory_GetKeySubdirectories:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				UserObjectHandle outIteratorHandle = 0;
				result = fw_uc->configDirectory_GetKeySubdirectories((UserObjectHandle)arguments->scalarInput[0],
																	 (int)arguments->scalarInput[1],
																	 &outIteratorHandle);
				arguments->scalarOutput[0] = (uint64_t) outIteratorHandle;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kConfigDirectory_GetType:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				int outType = 0;
				result = fw_uc->configDirectory_GetType((UserObjectHandle)arguments->scalarInput[0],&outType);
				arguments->scalarOutput[0] = outType;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kConfigDirectory_GetNumEntries:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				int outNumEntries = 0;
				result = fw_uc->configDirectory_GetNumEntries((UserObjectHandle)arguments->scalarInput[0],&outNumEntries);
				arguments->scalarOutput[0] = outNumEntries;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kIsochPort_GetSupported:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				IOFWSpeed outMaxSpeed = kFWSpeed100MBit;
				UInt32 outChanSupportedHi = 0;
				UInt32 outChanSupportedLo = 0;
				result = fw_uc->localIsochPort_GetSupported((UserObjectHandle)arguments->scalarInput[0],
															&outMaxSpeed,
															&outChanSupportedHi,
															&outChanSupportedLo);
				arguments->scalarOutput[0] = outMaxSpeed;
				arguments->scalarOutput[1] = outChanSupportedHi;
				arguments->scalarOutput[2] = outChanSupportedLo;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kIsochPort_AllocatePort_d:
		{
			IOFWUserLocalIsochPort * fw_isoch_port = OSDynamicCast( IOFWUserLocalIsochPort, targetObject );
			if( fw_isoch_port )
			{
				result = fw_isoch_port->allocatePort((IOFWSpeed)arguments->scalarInput[0],
													 (UInt32)arguments->scalarInput[1]);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kIsochPort_ReleasePort_d:
		{
			IOFWUserLocalIsochPort * fw_isoch_port = OSDynamicCast( IOFWUserLocalIsochPort, targetObject );
			if( fw_isoch_port )
			{
				result = fw_isoch_port->releasePort();
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kIsochPort_Start_d:
		{
			IOFWUserLocalIsochPort * fw_isoch_port = OSDynamicCast( IOFWUserLocalIsochPort, targetObject );
			if( fw_isoch_port )
			{
				result = fw_isoch_port->start();
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kIsochPort_Stop_d:
		{
			IOFWUserLocalIsochPort * fw_isoch_port = OSDynamicCast( IOFWUserLocalIsochPort, targetObject );
			if( fw_isoch_port )
			{
				result = fw_isoch_port->stop();
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kLocalIsochPort_Allocate:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->localIsochPort_Create((LocalIsochPortAllocateParams*) arguments->structureInput,
													  (UserObjectHandle*) arguments->structureOutput);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kLocalIsochPort_ModifyJumpDCL_d:
		{
			IOFWUserLocalIsochPort * fw_isoch_port = OSDynamicCast( IOFWUserLocalIsochPort, targetObject );
			if( fw_isoch_port )
			{
				result = fw_isoch_port->modifyJumpDCL((UInt32)arguments->scalarInput[0],
													  (UInt32)arguments->scalarInput[1]);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kLocalIsochPort_Notify_d:
		{
			IOFWUserLocalIsochPort * fw_isoch_port = OSDynamicCast( IOFWUserLocalIsochPort, targetObject );
			if( fw_isoch_port )
			{
				if (arguments->scalarInput[0] == kFWNuDCLModifyNotification)
				{
					IOMemoryDescriptor * userDCLExportDesc = NULL ;
					IOReturn error ;
					UInt8 *pUserImportDCLBuffer = NULL;
					userDCLExportDesc = IOMemoryDescriptor::withAddressRange( arguments->scalarInput[2],
																			 arguments->scalarInput[3],
																			 kIODirectionOut,
																			 getOwningTask() ) ;
					// get map of program export data
					if ( userDCLExportDesc )
					{
						error = userDCLExportDesc->prepare() ;
					}
					else
						error = kIOReturnVMError;
					
					if ( !error )
					{
						pUserImportDCLBuffer = new UInt8[ arguments->scalarInput[3] ] ;
						if ( !pUserImportDCLBuffer )
						{
							error = kIOReturnVMError ;
						}
					}
					
					if ( !error )
					{
						unsigned byteCount = (unsigned)userDCLExportDesc->readBytes( 0, (void*)pUserImportDCLBuffer, arguments->scalarInput[3] ) ;
						if ( byteCount < arguments->scalarInput[3] )
						{
							error = kIOReturnVMError ;
						}
					}
					
					if ( !error )
					{
						result = fw_isoch_port->userNotify((UInt32)arguments->scalarInput[0],
														   (UInt32)arguments->scalarInput[1],
														   (void *) pUserImportDCLBuffer,
														   arguments->scalarInput[3]);
						userDCLExportDesc->complete() ;
						userDCLExportDesc->release();
						delete [] pUserImportDCLBuffer;
					}
					else
					{
						result = kIOReturnVMError;
					}
				}
				else
				{	result = fw_isoch_port->userNotify((UInt32)arguments->scalarInput[0],
													   (UInt32)arguments->scalarInput[1],
													   (void *) arguments->structureInput,
													   arguments->structureInputSize);
				}
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kLocalIsochPort_SetChannel:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->localIsochPort_SetChannel((UserObjectHandle)arguments->scalarInput[0],
														  (UserObjectHandle)arguments->scalarInput[1]);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kIsochChannel_Allocate:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				UserObjectHandle outChannelHandle = 0;
				result = fw_uc->isochChannel_Create((bool)arguments->scalarInput[0],
													(UInt32)arguments->scalarInput[1],
													(IOFWSpeed)arguments->scalarInput[2],
													&outChannelHandle);
				arguments->scalarOutput[0] = (uint64_t) outChannelHandle;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kIsochChannel_UserAllocateChannelBegin:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				UInt32 outSpeed = 0;
				UInt32 outChannel = 0;
				result = fw_uc->
				isochChannel_AllocateChannelBegin((UserObjectHandle)arguments->scalarInput[0],
												  (UInt32)arguments->scalarInput[1],
												  (UInt32)arguments->scalarInput[2],
												  (UInt32)arguments->scalarInput[3],
												  &outSpeed,
												  &outChannel);
				arguments->scalarOutput[0] = outSpeed;
				arguments->scalarOutput[1] = outChannel;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kIsochChannel_UserReleaseChannelComplete_d:
		{
			IOFWUserIsochChannel * fw_isoch_channel = OSDynamicCast( IOFWUserIsochChannel, targetObject );
			if( fw_isoch_channel )
			{
				result = fw_isoch_channel->releaseChannelComplete();
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kCommand_Cancel_d:
		{
			IOFWCommand * fw_command = OSDynamicCast( IOFWCommand, targetObject );
			if( fw_command )
			{
				result = fw_command->cancel((IOReturn)arguments->scalarInput[0]);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kSeize:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->seize((IOOptionBits) arguments->scalarInput[0]);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kFireLog:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->firelog((const char*) arguments->structureInput,arguments->structureInputSize);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kGetBusCycleTime:
		{
			IOFireWireBus * fw_bus = OSDynamicCast( IOFireWireBus, targetObject );
			if( fw_bus )
			{
				UInt32 busTime = 0;
				UInt32 cycleTime = 0;
				result = fw_bus->getBusCycleTime(busTime,cycleTime);
				arguments->scalarOutput[0] = busTime;
				arguments->scalarOutput[1] = cycleTime;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kGetBusGeneration:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				UInt32 outGeneration = 0;
				result = fw_uc->getBusGeneration(&outGeneration);
				arguments->scalarOutput[0] = outGeneration;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kGetLocalNodeIDWithGeneration:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				UInt32 outLocalNodeID = 0;
				result = fw_uc->getLocalNodeIDWithGeneration((UInt32)arguments->scalarInput[0],&outLocalNodeID);
				arguments->scalarOutput[0] = outLocalNodeID;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kGetRemoteNodeID:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				UInt32 outRemoteNodeID = 0;
				result = fw_uc->getRemoteNodeID((UInt32)arguments->scalarInput[0],&outRemoteNodeID);
				arguments->scalarOutput[0] = outRemoteNodeID;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kGetSpeedToNode:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				UInt32 outSpeed = 0;
				result = fw_uc->getSpeedToNode((UInt32)arguments->scalarInput[0],&outSpeed);
				arguments->scalarOutput[0] = outSpeed;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kGetSpeedBetweenNodes:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				UInt32 outSpeed = 0;
				result = fw_uc->getSpeedBetweenNodes((UInt32)arguments->scalarInput[0],
													 (UInt32)arguments->scalarInput[1],
													 (UInt32)arguments->scalarInput[2],
													 &outSpeed);
				arguments->scalarOutput[0] = outSpeed;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kGetIRMNodeID:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				UInt32 irmNodeID = 0;
				result = fw_uc->getIRMNodeID((UInt32)arguments->scalarInput[0],&irmNodeID);
				arguments->scalarOutput[0] = irmNodeID;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kClipMaxRec2K:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->clipMaxRec2K((Boolean) arguments->scalarInput[0]);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kIsochPort_SetIsochResourceFlags_d:
		{
			IOFWLocalIsochPort * fw_isoch_port = OSDynamicCast( IOFWLocalIsochPort, targetObject );
			if( fw_isoch_port )
			{
				result = fw_isoch_port->setIsochResourceFlags((IOFWIsochResourceFlags) arguments->scalarInput[0]);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kGetSessionRef:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				IOFireWireSessionRef sessionRef=NULL;
				result = fw_uc->getSessionRef(&sessionRef);
				arguments->scalarOutput[0] = (uint64_t) sessionRef;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kAllocateIRMBandwidth:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->allocateIRMBandwidthInGeneration((UInt32)arguments->scalarInput[0], (UInt32)arguments->scalarInput[1]);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kReleaseIRMBandwidth:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->releaseIRMBandwidthInGeneration((UInt32)arguments->scalarInput[0], (UInt32)arguments->scalarInput[1]);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kAllocateIRMChannel:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->allocateIRMChannelInGeneration((UInt32)arguments->scalarInput[0], (UInt32)arguments->scalarInput[1]);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kReleaseIRMChannel:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->releaseIRMChannelInGeneration((UInt32)arguments->scalarInput[0], (UInt32)arguments->scalarInput[1]);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kAsyncStreamListener_Allocate:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->asyncStreamListener_Create((FWUserAsyncStreamListenerCreateParams*) arguments->structureInput,
														   (UserObjectHandle*) arguments->structureOutput);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kAsyncStreamListener_ClientCommandIsComplete:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->asyncStreamListener_ClientCommandIsComplete((UserObjectHandle)arguments->scalarInput[0],
																			(FWClientCommandID)arguments->scalarInput[1]);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kAsyncStreamListener_GetOverrunCounter:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				UInt32 counter = 0;
				result = fw_uc->asyncStreamListener_GetOverrunCounter((UserObjectHandle)arguments->scalarInput[0], &counter);
				arguments->scalarOutput[0] = counter;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kAsyncStreamListener_SetFlags:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->asyncStreamListener_SetFlags((UserObjectHandle)arguments->scalarInput[0],
															 (UInt32)arguments->scalarInput[1]);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kAsyncStreamListener_GetFlags:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				UInt32 outFlags = 0;
				result = fw_uc->asyncStreamListener_GetFlags((UserObjectHandle)arguments->scalarInput[0], &outFlags);
				arguments->scalarOutput[0] = outFlags;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kAsyncStreamListener_TurnOnNotification:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->asyncStreamListener_TurnOnNotification((UserObjectHandle)arguments->scalarInput[0]);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kAsyncStreamListener_TurnOffNotification:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->asyncStreamListener_TurnOffNotification((UserObjectHandle)arguments->scalarInput[0]);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kSetAsyncRef_BusReset:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->setAsyncRef_BusReset(arguments->asyncReference,
													 (mach_vm_address_t)arguments->scalarInput[0],
													 (io_user_reference_t)arguments->scalarInput[1],
													 NULL,NULL,NULL,NULL);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kSetAsyncRef_BusResetDone:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->setAsyncRef_BusResetDone(arguments->asyncReference,
														 (mach_vm_address_t)arguments->scalarInput[0],
														 (io_user_reference_t)arguments->scalarInput[1],
														 NULL,NULL,NULL,NULL);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kSetAsyncRef_Packet:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->setAsyncRef_Packet(arguments->asyncReference,
												   (UserObjectHandle)arguments->scalarInput[0],
												   (mach_vm_address_t)arguments->scalarInput[1],
												   (io_user_reference_t)arguments->scalarInput[2],
												   NULL,NULL,NULL);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
			
			
		case kSetAsyncRef_SkippedPacket:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->setAsyncRef_SkippedPacket(arguments->asyncReference,
														  (UserObjectHandle)arguments->scalarInput[0],
														  (mach_vm_address_t)arguments->scalarInput[1],
														  (io_user_reference_t)arguments->scalarInput[2],
														  NULL,NULL,NULL);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kSetAsyncRef_Read:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->setAsyncRef_Read(arguments->asyncReference,
												 (UserObjectHandle)arguments->scalarInput[0],
												 (mach_vm_address_t)arguments->scalarInput[1],
												 (io_user_reference_t)arguments->scalarInput[2],
												 NULL,NULL,NULL);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kCommand_Submit:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->userAsyncCommand_Submit(arguments->asyncReference,
														(CommandSubmitParams*)arguments->structureInput,
														(CommandSubmitResult*)arguments->structureOutput,
														(IOByteCount) arguments->structureInputSize,
														(IOByteCount*) &arguments->structureOutputSize);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kSetAsyncRef_IsochChannelForceStop:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->setAsyncRef_IsochChannelForceStop(arguments->asyncReference,
																  (UserObjectHandle)arguments->scalarInput[0]);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kSetAsyncRef_DCLCallProc:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->setAsyncRef_DCLCallProc(arguments->asyncReference,
														(UserObjectHandle)arguments->scalarInput[0]);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kSetAsyncStreamRef_Packet:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->setAsyncStreamRef_Packet(arguments->asyncReference,
														 (UserObjectHandle)arguments->scalarInput[0],
														 (mach_vm_address_t)arguments->scalarInput[1],
														 (io_user_reference_t)arguments->scalarInput[2],
														 NULL,NULL,NULL);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kSetAsyncStreamRef_SkippedPacket:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->setAsyncStreamRef_SkippedPacket(arguments->asyncReference,
																(UserObjectHandle)arguments->scalarInput[0],
																(mach_vm_address_t)arguments->scalarInput[1],
																(io_user_reference_t)arguments->scalarInput[2],
																NULL,NULL,NULL);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
			
		case kIRMAllocation_Allocate:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				UserObjectHandle outDataHandle = 0;
				result = fw_uc->irmAllocation_Create(arguments->scalarInput[0],&outDataHandle);
				arguments->scalarOutput[0] = (uint64_t) outDataHandle;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kIRMAllocation_AllocateResources:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->irmAllocation_AllocateResources((UserObjectHandle)arguments->scalarInput[0],
																arguments->scalarInput[1],
																(UInt32)arguments->scalarInput[2]);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
			
		case kIRMAllocation_DeallocateResources:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->irmAllocation_DeallocateResources((UserObjectHandle)arguments->scalarInput[0]);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kIRMAllocation_areResourcesAllocated:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				UInt8 isochChannel = 0;
				UInt32 bandwidthUnits = 0;
				result = fw_uc->irmAllocation_areResourcesAllocated((UserObjectHandle)arguments->scalarInput[0], &isochChannel , &bandwidthUnits);
				arguments->scalarOutput[1] = (uint64_t) isochChannel;
				arguments->scalarOutput[2] = (uint64_t) bandwidthUnits;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kIRMAllocation_setDeallocateOnRelease:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				fw_uc->irmAllocation_setDeallocateOnRelease((UserObjectHandle)arguments->scalarInput[0],arguments->scalarInput[1]);
				result = kIOReturnSuccess;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kIRMAllocation_SetRef:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc && arguments->asyncReference )
			{
				result = fw_uc->irmAllocation_setRef(arguments->asyncReference,
													 (UserObjectHandle)arguments->scalarInput[0],
													 arguments->scalarInput[1],
													 arguments->scalarInput[2]);
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kCommandCreateAsync:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->createAsyncCommand( arguments->asyncReference,
												   (CommandSubmitParams*)arguments->structureInput,
												   (UserObjectHandle*)arguments->structureOutput );
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kVectorCommandCreate:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				result = fw_uc->createVectorCommand( (UserObjectHandle*)arguments->structureOutput );
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kVectorCommandSubmit:
		{
			IOFWUserVectorCommand * fw_vector_cmd = OSDynamicCast( IOFWUserVectorCommand, targetObject );
			if( fw_vector_cmd )
			{
				result = fw_vector_cmd->submit(	arguments->asyncReference,
											   (mach_vm_address_t)arguments->scalarInput[0],
											   (io_user_reference_t)arguments->scalarInput[1] );
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kVectorCommandSetBuffers:
		{
			IOFWUserVectorCommand * fw_vector_cmd = OSDynamicCast( IOFWUserVectorCommand, targetObject );
			if( fw_vector_cmd )
			{
				result = fw_vector_cmd->setBuffers(	(mach_vm_address_t)arguments->scalarInput[0],
												   (mach_vm_size_t)arguments->scalarInput[1],
												   (mach_vm_address_t)arguments->scalarInput[2],
												   (mach_vm_size_t)arguments->scalarInput[3]  );
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kPHYPacketListenerCreate:
		{
			IOFireWireUserClient * fw_uc = OSDynamicCast( IOFireWireUserClient, targetObject );
			if( fw_uc )
			{
				UserObjectHandle kernel_ref = 0;
				result = fw_uc->createPHYPacketListener( (UInt32)arguments->scalarInput[0],
														&kernel_ref );
				arguments->scalarOutput[0] = (uint64_t)kernel_ref;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kPHYPacketListenerSetPacketCallback:
		{
			IOFWUserPHYPacketListener * phy_listener = OSDynamicCast( IOFWUserPHYPacketListener, targetObject );
			if( phy_listener )
			{
				result = phy_listener->setPacketCallback(	arguments->asyncReference,
														 (mach_vm_address_t)arguments->scalarInput[0],
														 (io_user_reference_t)arguments->scalarInput[1] );
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kPHYPacketListenerSetSkippedCallback:
		{
			IOFWUserPHYPacketListener * phy_listener = OSDynamicCast( IOFWUserPHYPacketListener, targetObject );
			if( phy_listener )
			{
				result = phy_listener->setSkippedCallback(	arguments->asyncReference,
														  (mach_vm_address_t)arguments->scalarInput[0],
														  (io_user_reference_t)arguments->scalarInput[1] );
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kPHYPacketListenerActivate:
		{
			IOFWUserPHYPacketListener * phy_listener = OSDynamicCast( IOFWUserPHYPacketListener, targetObject );
			if( phy_listener )
			{
				result = phy_listener->activate();
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kPHYPacketListenerDeactivate:
		{
			IOFWUserPHYPacketListener * phy_listener = OSDynamicCast( IOFWUserPHYPacketListener, targetObject );
			if( phy_listener )
			{
				phy_listener->deactivate();
				result = kIOReturnSuccess;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		case kPHYPacketListenerClientCommandIsComplete:
		{
			IOFWUserPHYPacketListener * phy_listener = OSDynamicCast( IOFWUserPHYPacketListener, targetObject );
			if( phy_listener )
			{
				phy_listener->clientCommandIsComplete( (FWClientCommandID)arguments->scalarInput[0] );
				result = kIOReturnSuccess;
			}
			else
			{
				result = kIOReturnBadArgument;
			}
			break;
		}
			
		default:
			// NONE OF THE ABOVE :(
			break;
	};
	
	if( target_object_needs_release && targetObject )
	{
		(targetObject)->release();    // exporter retains returned objects, we have to release it here..
		targetObject = NULL;
	}
	
	return result;
}

IOReturn
IOFireWireUserClient::registerNotificationPort(
											   mach_port_t port,
											   UInt32		/* type */,
											   UInt32		refCon)
{
	fNotificationPort = port ;
	fNotificationRefCon = refCon ;
	
	return( kIOReturnUnsupported);
}

#pragma mark -

IOReturn
IOFireWireUserClient::
copyUserData (
			  mach_vm_address_t		userBuffer,
			  mach_vm_address_t		kernBuffer,
			  mach_vm_size_t 			bytes ) const
{
	if( (userBuffer == 0) || (kernBuffer == 0) )
	{
		return kIOReturnNoMemory;
	}
	
	if( bytes == 0 )
	{
		return kIOReturnSuccess;
	}
	
	IOMemoryDescriptor *	desc 	= IOMemoryDescriptor::withAddressRange (	userBuffer, bytes, kIODirectionOut,
																			fTask ) ;
	if ( ! desc )
	{
		ErrorLog ( "Couldn't create descriptor\n" ) ;
		return kIOReturnNoMemory ;
	}
	
	// copy user space range list to in kernel list
	IOReturn error = desc->prepare () ;
	
	if ( ! error )
	{
		if ( bytes != desc->readBytes ( 0, (void*)kernBuffer, bytes ) )
			error = kIOReturnVMError ;
		
		desc->complete() ;
		desc->release() ;
	}
	
	return error ;
}

IOReturn
IOFireWireUserClient::copyToUserBuffer (
										IOVirtualAddress 		kernelBuffer,
										mach_vm_address_t		userBuffer,
										IOByteCount 			bytes,
										IOByteCount & 			bytesCopied )
{
	if( (userBuffer == 0) || (kernelBuffer == 0) )
	{
		return kIOReturnNoMemory;
	}
	
	if( bytes == 0 )
	{
		return kIOReturnSuccess;
	}
	
	IOMemoryDescriptor *	mem = IOMemoryDescriptor::withAddressRange( userBuffer, bytes, kIODirectionIn, fTask ) ;
	if ( ! mem )
		return kIOReturnNoMemory ;
	
	IOReturn error = mem->prepare () ;
	
	if ( !error )
	{
		bytesCopied = mem->writeBytes ( 0, (void*)kernelBuffer, bytes ) ;
		mem->complete() ;
	}
	
	mem->release() ;
	
	return error ;
}

#pragma mark -
#pragma mark OPEN/CLOSE

IOReturn
IOFireWireUserClient::userOpen ()
{
	IOReturn error = kIOReturnSuccess ;
	
	// do the open...
	
	IOFireWireNub * provider = OSDynamicCast( IOFireWireNub, getOwner() ) ;
	if ( ! provider )
	{
		ErrorLog( "Couldn't find provider!\b" ) ;
		return kIOReturnError ;
	}
	
	if ( getOwner()->open( this ) )
	{
		IOFWUserObjectExporter * exporter = fOwner->getController()->getSessionRefExporter();
		error = exporter->addObject( this, NULL, &fSessionRef );
		if( error == kIOReturnSuccess )
		{
			fSelfOpenCount = 1 ;
			fOpenClient = this ;
		}
	}
	else
	{
		ErrorLog( "couldn't open provider\n" ) ;
		error = kIOReturnExclusiveAccess ;
	}
	
	return error ;
}

IOReturn
IOFireWireUserClient::userOpenWithSessionRef ( IOFireWireLib::UserObjectHandle sessionRef )
{
	IOReturn	result = kIOReturnSuccess ;
	
	if (getOwner ()->isOpen())
	{
		IOFWUserObjectExporter * exporter = fOwner->getController()->getSessionRefExporter();
		IOService * open_client = (IOService*) exporter->lookupObjectForType( sessionRef, OSTypeID(IOService) );
		IOService * client = open_client;
		
		if (!client)
			result = kIOReturnBadArgument ;
		else
		{
			while (client != NULL)
			{
				if (client == getOwner ())
				{
					fOpenClient = open_client ;	// sessionRef is the originally passed in user object
					
					if ( fOpenClient == this )
					{
						++fSelfOpenCount ;
					}
					
					break ;
				}
				
				client = client->getProvider() ;
			}
		}
		
		if( open_client )
		{
			open_client->release();
			open_client = NULL;
		}
	}
	else
		result = kIOReturnNotOpen ;
	
	return result ;
}

IOReturn
IOFireWireUserClient::userClose ()
{
	IOReturn result = kIOReturnSuccess ;
	
	if ( getProvider() == NULL )
		return kIOReturnSuccess ;
	
	if ( fOpenClient == this )
	{
		if ( !fOwner->isOpen( this ) )
		{
			result = kIOReturnNotOpen ;
		}
		else
		{
			if ( fSelfOpenCount > 0 )
			{
				if ( --fSelfOpenCount == 0 )
				{
					IOFWUserObjectExporter * exporter = fOwner->getController()->getSessionRefExporter();
					exporter->removeObject( fSessionRef );
					fSessionRef = 0;
					fOwner->close(this) ;
					fOpenClient = NULL ;
				}
			}
			else
			{
				return kIOReturnNotOpen ;
			}
		}
	}
	
	return result ;
}

#pragma mark -
#pragma mark GENERAL

IOReturn
IOFireWireUserClient::readQuad ( const ReadQuadParams* params, UInt32* outVal )
{
	IOReturn 				err ;
	IOFWReadQuadCommand*	cmd ;
	
	if ( params->isAbs )
		cmd = this->createReadQuadCommand( params->generation, params->addr, outVal, 1, NULL, NULL ) ;
	else
	{
		if ( (cmd = getOwner ()->createReadQuadCommand( params->addr, outVal, 1, NULL, NULL, params->failOnReset )) )
			cmd->setGeneration( params->generation ) ;
	}
	
	if(!cmd)
		return kIOReturnNoMemory;
	
	err = cmd->submit();        // We block here until the command finishes
	
	if( !err )
		err = cmd->getStatus();
	
	cmd->release();
	
	return err;
}

IOReturn
IOFireWireUserClient::read ( const ReadParams* params, IOByteCount* outBytesTransferred )
{
	IOReturn 					err ;
	IOMemoryDescriptor *		mem ;
	IOFWReadCommand*			cmd ;
	
	*outBytesTransferred = 0 ;
	
	mem = IOMemoryDescriptor::withAddressRange(params->buf, params->size, kIODirectionIn, fTask);
	if(!mem)
	{
		return kIOReturnNoMemory;
	}
	
	{
		IOReturn error = mem->prepare() ;
		if ( kIOReturnSuccess != error )
		{
			mem->release() ;
			return error ;
		}
	}
	
	if ( params->isAbs )
		cmd = this->createReadCommand( params->generation, params->addr, mem, NULL, NULL ) ;
	else
	{
		if ( (cmd = getOwner ()->createReadCommand( params->addr, mem, NULL, NULL, params->failOnReset )) )
			cmd->setGeneration(params->generation) ;
	}
	
	if(!cmd)
	{
		mem->complete() ;
		mem->release() ;
		return kIOReturnNoMemory;
	}
	
	err = mem->prepare() ;
	
	if ( err )
	{
		DebugLog("%s %u: IOFireWireUserClient::read: prepare failed\n", __FILE__, __LINE__) ;
	}
	else
	{
		err = cmd->submit();	// We block here until the command finishes
		mem->complete() ;
	}
	
	if( !err )
		err = cmd->getStatus();
	
	*outBytesTransferred = cmd->getBytesTransferred() ;
	
	cmd->release();
	mem->release();
	
	return err;
}

IOReturn
IOFireWireUserClient::writeQuad( const WriteQuadParams* params)
{
	IOReturn 				err;
	IOFWWriteQuadCommand*	cmd ;
	
	if ( params->isAbs )
		cmd = this->createWriteQuadCommand( params->generation, params->addr, (UInt32*) & params->val, 1, NULL, NULL ) ;
	else
	{
		cmd = getOwner ()->createWriteQuadCommand( params->addr, (UInt32*)&params->val, 1, NULL, NULL, params->failOnReset ) ;
		cmd->setGeneration( params->generation ) ;
	}
	
	if(!cmd)
		return kIOReturnNoMemory;
	
	
	err = cmd->submit();	// We block here until the command finishes
	
	if( err )
		err = cmd->getStatus();
	
	cmd->release();
	
	return err;
}

IOReturn
IOFireWireUserClient::write( const WriteParams* params, IOByteCount* outBytesTransferred )
{
	IOMemoryDescriptor *	mem ;
	IOFWWriteCommand*		cmd ;
	
	*outBytesTransferred = 0 ;
	
	mem = IOMemoryDescriptor::withAddressRange(params->buf, params->size, kIODirectionOut, fTask);
	if(!mem)
	{
		return kIOReturnNoMemory;
	}
	
	{
		IOReturn error = mem->prepare() ;
		if ( kIOReturnSuccess != error )
		{
			mem->release() ;
			return error ;
		}
	}
	
	if ( params->isAbs )
	{
		cmd = this->createWriteCommand( params->generation, params->addr, mem, NULL, NULL ) ;
	}
	else
	{
		if ( (cmd = getOwner ()->createWriteCommand( params->addr, mem, NULL, NULL, params->failOnReset )) )
			cmd->setGeneration( params->generation ) ;
	}
	
	if( !cmd )
	{
		mem->complete() ;
		mem->release() ;
		return kIOReturnNoMemory;
	}
	
	IOReturn error ;
	error = cmd->submit();
	
	// We block here until the command finishes
	if( !error )
		error = cmd->getStatus();
	
	if ( !error )
		*outBytesTransferred = cmd->getBytesTransferred() ;
	
	cmd->release();
	
	mem->complete() ;
	mem->release() ;
	
	return error ;
}

IOReturn
IOFireWireUserClient::compareSwap( const CompareSwapParams* params, UInt32* oldVal )
{
	IOReturn 							err ;
	IOFWCompareAndSwapCommand*			cmd ;
	
	if ( params->size > 2 )
		return kIOReturnBadArgument ;
	
	if ( params->isAbs )
	{
		cmd = this->createCompareAndSwapCommand( params->generation, params->addr, (UInt32*)& params->cmpVal,
												(UInt32*)& params->swapVal, params->size, NULL, NULL ) ;
	}
	else
	{
		if ( (cmd = getOwner ()->createCompareAndSwapCommand( params->addr, (UInt32*)& params->cmpVal, (UInt32*)& params->swapVal,
															 params->size, NULL, NULL, params->failOnReset )) )
		{
			cmd->setGeneration( params->generation ) ;
		}
	}
	
	if(!cmd)
		return kIOReturnNoMemory;
	
	err = cmd->submit();
	
	// We block here until the command finishes
	if( !err )
	{
		cmd->locked(oldVal) ;
		err = cmd->getStatus();
		//		if(kIOReturnSuccess == err && !cmd->locked((UInt32*)oldVal))
		//			err = kIOReturnCannotLock;
	}
	
	cmd->release();
	
	return err ;
}

IOReturn
IOFireWireUserClient::busReset()
{
	FWTrace( kFWTUserClient, kTPUserClientBusReset, (uintptr_t)(getOwner()->getController()->getLink()), fUnsafeResets , 0, 0);
	
	if ( fUnsafeResets )
		return getOwner ()->getController()->getLink()->resetBus();
	
	return getOwner ()->getController()->resetBus();
}

IOReturn
IOFireWireUserClient::getGenerationAndNodeID(
											 UInt32*					outGeneration,
											 UInt32*					outNodeID) const
{
	UInt16	nodeID ;
	
	getOwner ()->getNodeIDGeneration(*outGeneration, nodeID);
	if (!getOwner ()->getController()->checkGeneration(*outGeneration))
		return kIOReturnNotFound ;	// nodeID we got was stale...
	
	*outNodeID = (UInt32)nodeID ;
	
	return kIOReturnSuccess ;
}

IOReturn
IOFireWireUserClient::getLocalNodeID(
									 UInt32*					outLocalNodeID) const
{
	*outLocalNodeID = (UInt32)(getOwner ()->getController()->getLocalNodeID()) ;
	return kIOReturnSuccess ;
}

IOReturn
IOFireWireUserClient::getResetTime(
								   AbsoluteTime*	outResetTime) const
{
	*outResetTime = *getOwner ()->getController()->getResetTime() ;
	
	return kIOReturnSuccess ;
}

IOReturn
IOFireWireUserClient::releaseUserObject (
										 UserObjectHandle		obj )
{
	fExporter->removeObject( obj ) ;
	
	return kIOReturnSuccess ;
}

#pragma mark -
#pragma mark CONVERSION HELPERS

IOReturn
IOFireWireUserClient::getOSStringData (
									   UserObjectHandle 			stringHandle,
									   UInt32 						stringLen,
									   mach_vm_address_t 			stringBuffer,
									   UInt32 * 					outTextLength )
{
	*outTextLength = 0 ;
	
	const OSObject * object = fExporter->lookupObject( stringHandle ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	OSString * string = OSDynamicCast ( OSString, object ) ;
	if ( ! string )
	{
		object->release() ;
		return kIOReturnBadArgument ;
	}
	
	IOByteCount len = min( stringLen, string->getLength() ) ;
	IOByteCount outLen = 0;
	IOReturn error = copyToUserBuffer (	(IOVirtualAddress) string->getCStringNoCopy(),
									   stringBuffer,
									   len,
									   outLen ) ;
	*outTextLength = (UInt32)outLen;
	
	fExporter->removeObject( stringHandle ) ;
	string->release() ;
	
	return error ;
}

IOReturn
IOFireWireUserClient::getOSDataData (
									 UserObjectHandle		dataHandle,
									 IOByteCount				dataLen,
									 mach_vm_address_t		dataBuffer,
									 IOByteCount*			outDataLen)
{
	const OSObject * object = fExporter->lookupObject( dataHandle ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	OSData * data = OSDynamicCast( OSData, object ) ;
	if ( !data )
	{
		object->release() ;
		return kIOReturnBadArgument ;
	}
	
	IOReturn error = copyToUserBuffer (	(IOVirtualAddress) data->getBytesNoCopy(),
									   dataBuffer,
									   min( data->getLength(), dataLen ),
									   *outDataLen ) ;
	fExporter->removeObject( dataHandle ) ;
	
	object->release() ;		// this is retained when we call lookupObject; "I must release you"
	
	return error ;
}

#pragma mark -
#pragma mark LOCAL CONFIG DIRECTORY

//	Config Directory methods

IOReturn
IOFireWireUserClient::localConfigDirectory_Create ( UserObjectHandle* outDir )
{
	IOLocalConfigDirectory * dir = IOLocalConfigDirectory::create () ;
	
	if ( ! dir )
	{
		DebugLog( "IOLocalConfigDirectory::create returned NULL\n" ) ;
		return kIOReturnNoMemory ;
	}
	
	IOReturn error = fExporter->addObject ( dir, (IOFWUserObjectExporter::CleanupFunction)&IOLocalConfigDirectory::exporterCleanup, outDir ) ;
	
	dir->release() ;
	
	return error ;
}

IOReturn
IOFireWireUserClient::localConfigDirectory_addEntry_Buffer (
															UserObjectHandle		dirHandle,
															int 					key,
															char * 					buffer,
															UInt32 					kr_size,
															const char *			descCString,
															UInt32					descLen ) const
{
	
	const OSObject * object = fExporter->lookupObject( dirHandle ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	IOLocalConfigDirectory * dir = OSDynamicCast ( IOLocalConfigDirectory, object ) ;
	if ( ! dir )
	{
		object->release() ;
		return kIOReturnBadArgument ;
	}
	
	IOReturn error = kIOReturnSuccess ;
	OSData * data = OSData::withCapacity( kr_size ) ;
	if ( !data )
	{
		error = kIOReturnNoMemory ;
	}
	else
	{
		data->appendBytes( NULL, kr_size );  // force internal buffer allocation
		copyUserData( (IOVirtualAddress)buffer, (IOVirtualAddress)data->getBytesNoCopy(), kr_size ) ;
		
		OSString * desc = NULL ;
		// 23545302
		// check descLen  RBX: 0x00000000ffffffff
		if ( descCString && (descLen < 1024) && (descLen > 0) )
		{
			char * cStr = new char[ descLen ];
			if ( cStr  )
			{
				copyUserData( (IOVirtualAddress)descCString, (IOVirtualAddress)cStr, descLen ) ;
				
				cStr[ descLen-1 ] = 0 ;
				desc = OSString::withCString( cStr ) ;
				
				delete [] cStr;
			}
		}
		
		error = dir->addEntry ( key, data, desc ) ;
		
		data->release() ;
	}
	
	dir->release() ;
	
	return error ;
}

IOReturn
IOFireWireUserClient::localConfigDirectory_addEntry_UInt32 (
															UserObjectHandle 		dirHandle,
															int 					key,
															UInt32 					value,
															const char *			descCString,
															UInt32					descLen ) const
{
	const OSObject * object = fExporter->lookupObject( dirHandle ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	IOLocalConfigDirectory * dir = OSDynamicCast ( IOLocalConfigDirectory, object ) ;
	if ( ! dir )
	{
		object->release() ;
		return kIOReturnBadArgument ;
	}
	
	OSString * desc = NULL ;
	if ( descCString && (descLen < 1024) && (descLen > 0) )
	{
		char * cStr = new char[ descLen ];
		if ( cStr )
		{
			copyUserData( (IOVirtualAddress)descCString, (IOVirtualAddress)cStr, descLen ) ;
			
			cStr[ descLen-1 ] = 0 ;
			desc = OSString::withCString( cStr ) ;
			
			delete [] cStr;
		}
	}
	
	IOReturn error = dir->addEntry(key, value, desc) ;
	
	dir->release() ;
	
	return error ;
}

IOReturn
IOFireWireUserClient::localConfigDirectory_addEntry_FWAddr (
															UserObjectHandle	dirHandle,
															int					key,
															const char *		descCString,
															UInt32				descLen,
															FWAddress *			value ) const
{
	const OSObject * object = fExporter->lookupObject( dirHandle ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	IOLocalConfigDirectory * dir = OSDynamicCast ( IOLocalConfigDirectory, object ) ;
	if ( ! dir )
	{
		object->release() ;
		return kIOReturnBadArgument ;
	}
	
	OSString * desc = NULL ;
	if ( descCString && (descLen < 1024) && (descLen > 0) )
	{
		char * cStr = new char[ descLen ];
		if ( cStr )
		{
			copyUserData( (IOVirtualAddress)descCString, (IOVirtualAddress)cStr, descLen ) ;
			
			cStr[ descLen-1 ] = 0 ;
			desc = OSString::withCString( cStr ) ;
			
			delete [] cStr;
		}
	}
	
	IOReturn error = dir->addEntry( key, *value, desc ) ;
	
	dir->release() ;
	
	return error ;
}

IOReturn
IOFireWireUserClient::localConfigDirectory_addEntry_UnitDir (
															 UserObjectHandle	dirHandle,
															 int 				key,
															 UserObjectHandle 	valueHandle,
															 const char *		descCString,
															 UInt32				descLen ) const
{
	IOLocalConfigDirectory * dir ;
	{
		const OSObject * object = fExporter->lookupObject( dirHandle ) ;
		if ( !object )
		{
			return kIOReturnBadArgument ;
		}
		
		dir = OSDynamicCast( IOLocalConfigDirectory, object ) ;
		if ( ! dir )
		{
			object->release() ;
			return kIOReturnBadArgument ;
		}
	}
	
	IOReturn error ;
	IOLocalConfigDirectory * value ;
	
	{
		const OSObject * object = fExporter->lookupObject( valueHandle ) ;
		if ( !object )
		{
			return kIOReturnBadArgument ;
		}
		
		value = OSDynamicCast( IOLocalConfigDirectory, object ) ;
		
		if ( ! value )
		{
			object->release() ;
			error = kIOReturnBadArgument ;
		}
		else
		{
			OSString * desc = NULL ;
			
			if ( descCString && (descLen < 1024) && (descLen > 0) )
			{
				char * cStr = new char[ descLen ];
				if ( cStr )
				{
					copyUserData( (IOVirtualAddress)descCString, (IOVirtualAddress)cStr, descLen ) ;
					
					cStr[ descLen-1 ] = 0 ;
					desc = OSString::withCString( cStr ) ;
					
					delete [] cStr;
				}
			}
			
			error = dir->addEntry( key, value, desc ) ;
			
			value->release() ;
		}
	}
	
	dir->release() ;	// lookupObject retains the object
	
	return error ;
}

IOReturn
IOFireWireUserClient::localConfigDirectory_Publish ( UserObjectHandle dirHandle ) const
{
	const OSObject * object = fExporter->lookupObject( dirHandle ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	IOLocalConfigDirectory * dir = OSDynamicCast ( IOLocalConfigDirectory, object ) ;
	if ( ! dir )
	{
		object->release() ;
		object=NULL;
		return kIOReturnBadArgument ;
	}
	
	IOReturn error = getOwner ()->getController()->AddUnitDirectory( dir ) ;
	
	dir->release() ;	// lookupObject retains result; "I must release you"
	
	return error ;
}

IOReturn
IOFireWireUserClient::localConfigDirectory_Unpublish ( UserObjectHandle dirHandle ) const
{
	const OSObject * object = fExporter->lookupObject( dirHandle ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	IOLocalConfigDirectory * dir = OSDynamicCast ( IOLocalConfigDirectory, object ) ;
	if ( ! dir )
	{
		object->release() ;
		return kIOReturnBadArgument ;
	}
	
	IOReturn error = getOwner ()->getBus()->RemoveUnitDirectory ( dir ) ;
	
	dir->release() ;	// lookupObject retains result; "I must release you"
	
	return error ;
}

#pragma mark -
#pragma mark ADDRESS SPACES

//
// Address Space methods
//

IOReturn
IOFireWireUserClient::addressSpace_Create (
										   AddressSpaceCreateParams *	params,
										   UserObjectHandle *			outAddressSpaceHandle )
{
	IOFWUserPseudoAddressSpace * addressSpace = OSTypeAlloc( IOFWUserPseudoAddressSpace );
	
	if ( addressSpace &&
		( params->isInitialUnits ?
		 !addressSpace->initFixed( this, params ) : !addressSpace->initPseudo( this, params ) ) )
	{
		return kIOReturnNoMemory ;
	}
	
	IOReturn error = addressSpace->activate() ;
	
	if ( !error )
		error = fExporter->addObject ( addressSpace,
									  &IOFWUserPseudoAddressSpace::exporterCleanup,
									  outAddressSpaceHandle ) ;		// nnn needs cleanup function?
	
	if ( error )
		addressSpace->deactivate() ;
	
	addressSpace->release() ;
	
	return error ;
}

IOReturn
IOFireWireUserClient::addressSpace_GetInfo (
											UserObjectHandle		addressSpaceHandle,
											AddressSpaceInfo *		outInfo )
{
	const OSObject *  object = fExporter->lookupObject( addressSpaceHandle ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	IOFWUserPseudoAddressSpace *	me 		= OSDynamicCast( IOFWUserPseudoAddressSpace, object ) ;
	if (!me)
	{
		object->release() ;
		object = NULL;
		return kIOReturnBadArgument ;
	}
	
	outInfo->address = me->getBase() ;
	
	me->release() ;
	
	return kIOReturnSuccess ;
}

IOReturn
IOFireWireUserClient::addressSpace_ClientCommandIsComplete (
															UserObjectHandle		addressSpaceHandle,
															FWClientCommandID		inCommandID,
															IOReturn				inResult)
{
	const OSObject * object = fExporter->lookupObject( addressSpaceHandle ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	IOReturn	result = kIOReturnSuccess ;
	IOFWUserPseudoAddressSpace *	me	= OSDynamicCast( IOFWUserPseudoAddressSpace, object ) ;
	if (!me)
	{
		object->release() ;
		object = NULL;
		return kIOReturnBadArgument ;
	}
	
	me->clientCommandIsComplete ( inCommandID, inResult ) ;
	me->release() ;
	
	return result ;
}

IOReturn
IOFireWireUserClient::setAsyncRef_Packet (
										  OSAsyncReference64		asyncRef,
										  UserObjectHandle		addressSpaceHandle,
										  mach_vm_address_t		inCallback,
										  io_user_reference_t		inUserRefCon,
										  void*,
										  void*,
										  void*)
{
	if( asyncRef == NULL )
	{
		return kIOReturnBadArgument;
	}
	
	const OSObject * object = fExporter->lookupObject ( addressSpaceHandle ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	IOFWUserPseudoAddressSpace * me = OSDynamicCast ( IOFWUserPseudoAddressSpace, object ) ;
	if ( ! me )
	{
		object->release() ;
		return kIOReturnBadArgument ;
	}
	
	if ( inCallback )
		super::setAsyncReference64 ( asyncRef, (mach_port_t) asyncRef[0], inCallback, inUserRefCon ) ;
	else
		asyncRef[0] = 0 ;
	
	me->setAsyncRef_Packet(asyncRef) ;
	me->release() ;
	
	return kIOReturnSuccess ;
}

IOReturn
IOFireWireUserClient::setAsyncRef_SkippedPacket(
												OSAsyncReference64		asyncRef,
												UserObjectHandle		inAddrSpaceRef,
												mach_vm_address_t		inCallback,
												io_user_reference_t		inUserRefCon,
												void*,
												void*,
												void*)
{
	if( asyncRef == NULL )
	{
		return kIOReturnBadArgument;
	}
	
	const OSObject * object = fExporter->lookupObject ( inAddrSpaceRef ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	IOReturn						result	= kIOReturnSuccess ;
	IOFWUserPseudoAddressSpace * me = OSDynamicCast ( IOFWUserPseudoAddressSpace, object ) ;
	
	if ( !me )
	{
		object->release() ;
		result = kIOReturnBadArgument ;
	}
	
	if ( kIOReturnSuccess == result )
	{
		if (inCallback)
			super::setAsyncReference64 ( asyncRef, (mach_port_t) asyncRef[0], (mach_vm_address_t) inCallback, (io_user_reference_t)inUserRefCon ) ;
		else
			asyncRef[0] = 0 ;
		
		me->setAsyncRef_SkippedPacket(asyncRef) ;
	}
	
	if( me )
	{
		me->release();
	}
	
	return result ;
}

IOReturn
IOFireWireUserClient::setAsyncRef_Read(
									   OSAsyncReference64		asyncRef,
									   UserObjectHandle		inAddrSpaceRef,
									   mach_vm_address_t		inCallback,
									   io_user_reference_t		inUserRefCon,
									   void*,
									   void*,
									   void*)
{
	if( asyncRef == NULL )
	{
		return kIOReturnBadArgument;
	}
	
	const OSObject * object = fExporter->lookupObject ( inAddrSpaceRef ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	IOReturn						result	= kIOReturnSuccess ;
	IOFWUserPseudoAddressSpace * me = OSDynamicCast ( IOFWUserPseudoAddressSpace, object ) ;
	
	if ( !me )
	{
		object->release() ;
		result = kIOReturnBadArgument ;
	}
	
	if ( kIOReturnSuccess == result )
	{
		if (inCallback)
			super::setAsyncReference64 ( asyncRef, (mach_port_t) asyncRef[0], inCallback, inUserRefCon ) ;
		else
			asyncRef[0] = 0 ;
		
		me->setAsyncRef_Read(asyncRef) ;
	}
	
	if( me )
	{
		me->release();
	}
	
	return result ;
}

IOReturn
IOFireWireUserClient::setAsyncRef_BusReset(
										   OSAsyncReference64		asyncRef,
										   mach_vm_address_t		inCallback,
										   io_user_reference_t		inRefCon,
										   void*,
										   void*,
										   void*,
										   void*)
{
	if( asyncRef == NULL )
	{
		return kIOReturnBadArgument;
	}
	
	super::setAsyncReference64 ( asyncRef, (mach_port_t) asyncRef[0], (mach_vm_address_t)inCallback, (io_user_reference_t)inRefCon ) ;
	
	bcopy(asyncRef, fBusResetAsyncNotificationRef, sizeof(OSAsyncReference64)) ;
	
	return kIOReturnSuccess ;
}

IOReturn
IOFireWireUserClient::setAsyncRef_BusResetDone(
											   OSAsyncReference64		inAsyncRef,
											   mach_vm_address_t		inCallback,
											   io_user_reference_t		inRefCon,
											   void*,
											   void*,
											   void*,
											   void*)
{
	if( inAsyncRef == NULL )
	{
		return kIOReturnBadArgument;
	}
	
	super::setAsyncReference64 ( inAsyncRef, (mach_port_t) inAsyncRef[0], inCallback, (io_user_reference_t)inRefCon ) ;
	
	bcopy(inAsyncRef, fBusResetDoneAsyncNotificationRef, sizeof(OSAsyncReference64)) ;
	
	return kIOReturnSuccess ;
}

#pragma mark -
#pragma mark PHYSICAL ADDRESS SPACES
//
// --- physical addr spaces ----------
//

IOReturn
IOFireWireUserClient::physicalAddressSpace_Create (
												   //	PhysicalAddressSpaceCreateParams *	params,
												   mach_vm_size_t				size,
												   mach_vm_address_t			backingStore,
												   UInt32						flags,
												   UserObjectHandle * 			outAddressSpaceHandle )
{
	// *** MEM: IOFireWireUserClient::physicalAddressSpace_Create - this kIODirectionPrepareToPhys32 mem desc will be passed into IOFWUserPhysicalAddressSpace::initWithDesc (and there associated w/ a DMA command)
	DebugLog("// *** TEST: IOFireWireUserClient<%p>::physicalAddressSpace_Create\n", this ) ;
	
	IOMemoryDescriptor * mem = IOMemoryDescriptor::withAddressRange( backingStore, size, kIODirectionInOut, fTask ) ;
	if ( ! mem )
	{
		return kIOReturnNoMemory ;
	}
	
	IOReturn error = mem->prepare( kIODirectionPrepareToPhys32 );
	if ( error )
	{
		mem->release() ;
		return error ;
	}	
	
	IOFWUserPhysicalAddressSpace * addrSpace = OSTypeAlloc( IOFWUserPhysicalAddressSpace );
	if ( addrSpace && !addrSpace->initWithDesc( getOwner()->getController(), mem ) )
	{
		addrSpace->release() ;
		addrSpace = NULL ;
	}
	
	if ( ! addrSpace )
	{
		error = kIOReturnNoMemory ;
	}
	else
	{
		error = addrSpace->activate() ;
		
		if ( ! error )
			error = fExporter->addObject( addrSpace,
										 &IOFWUserPhysicalAddressSpace::exporterCleanup,
										 outAddressSpaceHandle );
		
		addrSpace->release () ;	// fExporter will retain this
	}
	
	mem->release() ;		// address space will retain this if it needs it.. in any case, we're done with it.
	
	return error ;
	
}

IOReturn
IOFireWireUserClient::physicalAddressSpace_GetSegments (
														UserObjectHandle					addressSpaceHandle,
														UInt32								inSegmentCount,
														mach_vm_address_t					outSegments,
														UInt32*								outSegmentCount)
{
	DebugLog("// *** TEST: IOFireWireUserClient<%p>::physicalAddressSpace_GetSegments\n", this ) ;

	const OSObject * object = fExporter->lookupObject( addressSpaceHandle ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	IOFWUserPhysicalAddressSpace* addressSpace = OSDynamicCast(	IOFWUserPhysicalAddressSpace, object ) ;
	
	if ( ! addressSpace )
	{
		object->release() ;
		return kIOReturnBadArgument ;
	}
	
	UInt32 segmentCount	;
	IOReturn error = addressSpace->getSegmentCount( &segmentCount ) ;
	if ( error == kIOReturnSuccess )
	{
		segmentCount = min( segmentCount, inSegmentCount ) ;
		
		FWPhysicalSegment32 * segments = new FWPhysicalSegment32[ segmentCount ] ;
		
		if ( !segments )
		{
			error = kIOReturnNoMemory ;
		}
		
		if ( !error )
		{
			error = addressSpace->getSegments( & segmentCount, segments ) ;
		}
		
		if ( ! error )
		{
			IOByteCount bytesCopied ;
			error = copyToUserBuffer( (IOVirtualAddress)segments, outSegments, sizeof( FWPhysicalSegment32 ) * segmentCount, bytesCopied ) ;
			
			*outSegmentCount = (UInt32)(bytesCopied / sizeof( FWPhysicalSegment32 )) ;
		}
		
		delete[] segments ;
	}
	
	addressSpace->release() ; // retained by call to lookupObject()
	
	return error ;
}

#pragma mark
#pragma mark CONFIG DIRECTORY

IOReturn
IOFireWireUserClient::configDirectory_Create ( UserObjectHandle * outDirRef )
{
	IOConfigDirectory * configDir ;
	IOReturn error = getOwner ()->getConfigDirectoryRef ( configDir );
	
	if ( error )
		return error ;
	
	if ( !configDir )
		error = kIOReturnNoMemory ;
	else
	{
		error = fExporter->addObject ( configDir, NULL, outDirRef ) ;
		configDir->release () ;
	}
	
	return error ;
}

IOReturn
IOFireWireUserClient::configDirectory_GetKeyType (
												  UserObjectHandle	dirHandle,
												  int					key,
												  IOConfigKeyType *	outType) const
{
	const OSObject * object = fExporter->lookupObject( dirHandle ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	IOConfigDirectory * dir = OSDynamicCast( IOConfigDirectory, object ) ;
	if ( !dir )
	{
		object->release() ;
		return kIOReturnBadArgument ;
	}
	
	IOReturn error = dir->getKeyType(key, *outType) ;
	
	dir->release() ;
	
	return error ;
}

IOReturn
IOFireWireUserClient::configDirectory_GetKeyValue_UInt32 (
														  UserObjectHandle 		dirHandle,
														  int 					key,
														  UInt32 					wantText,
														  UInt32 * 				outValue,
														  UserObjectHandle * 		outTextHandle,
														  UInt32 * 				outTextLength ) const
{
	const OSObject * object = fExporter->lookupObject( dirHandle ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	IOConfigDirectory * dir = OSDynamicCast ( IOConfigDirectory, object ) ;
	if ( ! dir )
	{
		object->release() ;
		return kIOReturnBadArgument ;
	}
	
	OSString * outString = NULL ;
	IOReturn error = dir->getKeyValue( key, *outValue, ((bool)wantText) ? & outString : NULL ) ;
	
	if ( outString && !error )
	{
		error = fExporter->addObject( outString, NULL, outTextHandle ) ;
		
		outString->release () ;
		
		if ( ! error )
			*outTextLength = outString->getLength() ;
	}
	
	dir->release() ;
	
	return error ;
}

IOReturn
IOFireWireUserClient::configDirectory_GetKeyValue_Data (
														UserObjectHandle			dirHandle,
														int 						key,
														UInt32 						wantText,
														GetKeyValueDataResults *	results ) const
{
	const OSObject * object = fExporter->lookupObject( dirHandle ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	IOConfigDirectory * dir = OSDynamicCast ( IOConfigDirectory, object ) ;
	if ( ! dir )
	{
		object->release() ;
		return kIOReturnBadArgument ;
	}
	
	OSData * outData = NULL ;
	OSString * outText = NULL ;
	IOReturn error = dir->getKeyValue ( key, outData, ((bool)wantText) ? & outText : NULL ) ;
	
	if ( outText )
	{
		if ( ! error )
		{
			error = fExporter->addObject( outText, NULL, &results->text ) ;
			results->textLength = outText->getLength() ;
		}
		
		outText->release() ;
	}
	
	if ( outData )
	{
		if ( ! error )
		{
			error = fExporter->addObject( outData, NULL, &results->data ) ;
			results->dataLength = outData->getLength() ;
		}
		
		outData->release() ;
	}
	
	dir->release() ;
	
	return error ;
}

IOReturn
IOFireWireUserClient::configDirectory_GetKeyValue_ConfigDirectory(
																  UserObjectHandle 		dirHandle,
																  int 						key,
																  UInt32 						wantText,
																  UserObjectHandle * 	outDirHandle,
																  UserObjectHandle * 			outTextHandle,
																  UInt32 * 					outTextLength ) const
{
	const OSObject * object = fExporter->lookupObject( dirHandle ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	IOConfigDirectory * dir = OSDynamicCast ( IOConfigDirectory, object ) ;
	if ( ! dir )
	{
		object->release() ;
		return kIOReturnBadArgument ;
	}
	
	OSString * outText = NULL ;
	IOConfigDirectory * outDir = NULL ;
	IOReturn error = dir->getKeyValue ( key, outDir, ((bool)wantText) ? & outText : NULL ) ;
	
	if ( outText )
	{
		if ( ! error )
		{
			*outTextLength = outText->getLength() ;
			error = fExporter->addObject( outText, NULL, outTextHandle ) ;
		}
		
		outText->release() ;
	}
	
	if ( outDir )
	{
		if ( ! error )
			error = fExporter->addObject( outDir, NULL, outDirHandle ) ;
		
		outDir->release() ;
	}
	
	dir->release() ;
	
	return error ;
}

IOReturn
IOFireWireUserClient::configDirectory_GetKeyOffset_FWAddress (
															  UserObjectHandle	dirHandle,
															  int 					key,
															  UInt32 					wantText,
															  GetKeyOffsetResults * 	results ) const
{
	const OSObject * object = fExporter->lookupObject( dirHandle ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	IOConfigDirectory * dir = OSDynamicCast ( IOConfigDirectory, object ) ;
	if ( ! dir )
	{
		object->release() ;
		return kIOReturnBadArgument ;
	}
	
	OSString * outText = NULL ;
	IOReturn error = dir->getKeyOffset ( key, results->address, ((bool)wantText) ? & outText : NULL) ;
	
	if ( outText )
	{
		if ( ! error )
		{
			results->length = outText->getLength() ;
			error = fExporter->addObject( outText, NULL, &results->text ) ;
		}
		
		outText->release() ;
	}
	
	dir->release() ;
	
	return error ;
}

IOReturn
IOFireWireUserClient::configDirectory_GetIndexType (
													UserObjectHandle	dirHandle,
													int					index,
													IOConfigKeyType*	outType ) const
{
	const OSObject * object = fExporter->lookupObject( dirHandle ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	IOConfigDirectory * dir = OSDynamicCast ( IOConfigDirectory, object ) ;
	if ( ! dir )
	{
		object->release() ;
		return kIOReturnBadArgument ;
	}
	
	IOReturn error = dir->getIndexType(index, *outType) ;
	
	dir->release() ;
	
	return error ;
}

IOReturn
IOFireWireUserClient::configDirectory_GetIndexKey (
												   UserObjectHandle	dirHandle,
												   int					index,
												   int *				outKey ) const
{
	const OSObject * object = fExporter->lookupObject( dirHandle ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	IOConfigDirectory * dir = OSDynamicCast ( IOConfigDirectory, object ) ;
	if ( ! dir )
	{
		object->release() ;
		return kIOReturnBadArgument ;
	}
	
	IOReturn error = dir->getIndexKey(index, *outKey) ;
	
	dir->release() ;
	
	return error ;
}

IOReturn
IOFireWireUserClient::configDirectory_GetIndexValue_UInt32 (
															UserObjectHandle	dirHandle,
															int					index,
															UInt32*				outKey ) const
{
	const OSObject * object = fExporter->lookupObject( dirHandle ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	IOConfigDirectory * dir = OSDynamicCast ( IOConfigDirectory, object ) ;
	if ( ! dir )
	{
		object->release() ;
		return kIOReturnBadArgument ;
	}
	
	IOReturn error = dir->getIndexValue(index, *outKey) ;
	
	dir->release() ;
	
	return error ;
}

IOReturn
IOFireWireUserClient::configDirectory_GetIndexValue_Data (
														  UserObjectHandle		dirHandle,
														  int						index,
														  UserObjectHandle *		outDataHandle,
														  IOByteCount *			outDataLen ) const
{
	const OSObject * object = fExporter->lookupObject( dirHandle ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	IOConfigDirectory * dir = OSDynamicCast ( IOConfigDirectory, object ) ;
	if ( ! dir )
	{
		object->release() ;
		return kIOReturnBadArgument ;
	}
	
	OSData * outData = NULL ;
	IOReturn error = dir->getIndexValue( index, outData ) ;
	
	if ( !error && outData )
	{
		error = fExporter->addObject( outData, NULL, outDataHandle ) ;
		*outDataLen = outData->getLength() ;
		
		outData->release() ;
	}
	
	dir->release() ;
	
	return error ;
}

IOReturn
IOFireWireUserClient::configDirectory_GetIndexValue_String (
															UserObjectHandle 		dirHandle,
															int 					index,
															UserObjectHandle * 		outTextHandle,
															UInt32 * 				outTextLength ) const
{
	InfoLog("IOFireWireUserClient<%p>::configDirectory_GetIndexValue_String, index=%d, outTextHandle=%p\n", this ) ;
	
	const OSObject * object = fExporter->lookupObject( dirHandle ) ;
	if ( !object )
	{
		DebugLog("IOFireWireUserClient<%p>::configDirectory_GetIndexValue_String() -- dir handle is invalid\n", this ) ;
		return kIOReturnBadArgument ;
	}
	
	IOConfigDirectory * dir = OSDynamicCast ( IOConfigDirectory, object ) ;
	if ( ! dir )
	{
		DebugLog("IOFireWireUserClient<%p>::configDirectory_GetIndexValue_String() -- dir handle is not a config directory object!\n", this ) ;
		
		object->release() ;
		return kIOReturnBadArgument ;
	}
	
	OSString * outText = NULL ;
	IOReturn error = dir->getIndexValue( index, outText ) ;
	
	InfoLog("a. IOFireWireUserClient<%p>::configDirectory_GetIndexValue_String error=%x\n", this, error ) ;
	
	if ( !error && outText )
	{
		*outTextLength = outText->getLength() ;
		
		error = fExporter->addObject( outText, NULL, outTextHandle ) ;
		
		outText->release() ;
	}
	
	dir->release() ;
	
	return error ;
}

IOReturn
IOFireWireUserClient::configDirectory_GetIndexValue_ConfigDirectory (
																	 UserObjectHandle		dirHandle,
																	 int						index,
																	 UserObjectHandle *		outDirHandle ) const
{
	const OSObject * object = fExporter->lookupObject( dirHandle ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	IOConfigDirectory * dir = OSDynamicCast ( IOConfigDirectory, object ) ;
	if ( ! dir )
	{
		object->release() ;
		return kIOReturnBadArgument ;
	}
	
	IOConfigDirectory * outDir = NULL ;
	IOReturn error = dir->getIndexValue( index, outDir ) ;
	
	if ( ! error && outDir )
	{
		error = fExporter->addObject ( outDir, NULL, outDirHandle ) ;
		outDir->release() ;
	}
	
	dir->release() ;
	
	return error ;
}

IOReturn
IOFireWireUserClient::configDirectory_GetIndexOffset_FWAddress (
																UserObjectHandle	dirHandle,
																int					index,
																FWAddress *			outAddress ) const
{
	const OSObject * object = fExporter->lookupObject( dirHandle ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	IOConfigDirectory * dir = OSDynamicCast ( IOConfigDirectory, object ) ;
	if ( ! dir )
	{
		object->release() ;
		return kIOReturnBadArgument ;
	}
	
	IOReturn result = dir->getIndexOffset( index, *outAddress ) ;
	
	dir->release() ;
	
	return result ;
}

IOReturn
IOFireWireUserClient::configDirectory_GetIndexOffset_UInt32 (
															 UserObjectHandle	dirHandle,
															 int					index,
															 UInt32*				outValue) const
{
	const OSObject * object = fExporter->lookupObject( dirHandle ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	IOConfigDirectory * dir = OSDynamicCast ( IOConfigDirectory, object ) ;
	if ( ! dir )
	{
		object->release() ;
		return kIOReturnBadArgument ;
	}
	
	IOReturn error = dir->getIndexOffset(index, *outValue) ;
	
	dir->release() ;
	
	return error ;
}

IOReturn
IOFireWireUserClient::configDirectory_GetIndexEntry (
													 UserObjectHandle	dirHandle,
													 int					index,
													 UInt32*				outValue) const
{
	const OSObject * object = fExporter->lookupObject( dirHandle ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	IOConfigDirectory * dir = OSDynamicCast ( IOConfigDirectory, object ) ;
	if ( ! dir )
	{
		object->release() ;
		return kIOReturnBadArgument ;
	}
	
	IOReturn error = dir->getIndexEntry(index, *outValue) ;
	
	dir->release() ;
	
	return error ;
}

IOReturn
IOFireWireUserClient::configDirectory_GetSubdirectories (
														 UserObjectHandle		dirHandle,
														 UserObjectHandle*		outIteratorHandle ) const
{
	const OSObject * object = fExporter->lookupObject( dirHandle ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	IOConfigDirectory * dir = OSDynamicCast ( IOConfigDirectory, object ) ;
	if ( ! dir )
	{
		object->release() ;
		return kIOReturnBadArgument ;
	}
	
	OSIterator * outIterator = NULL ;
	IOReturn error = dir->getSubdirectories( outIterator ) ;
	
	if ( outIterator )
	{
		if ( ! error )
			error = fExporter->addObject( outIterator, NULL, outIteratorHandle ) ;
		
		outIterator->release () ;
	}
	
	dir->release() ;
	
	return error ;
}

IOReturn
IOFireWireUserClient::configDirectory_GetKeySubdirectories (
															UserObjectHandle		dirHandle ,
															int							key,
															UserObjectHandle*			outIteratorHandle ) const
{
	const OSObject * object = fExporter->lookupObject( dirHandle ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	IOConfigDirectory * dir = OSDynamicCast ( IOConfigDirectory, object ) ;
	if ( ! dir )
	{
		object->release() ;
		return kIOReturnBadArgument ;
	}
	
	OSIterator * outIterator = NULL ;
	IOReturn error = dir->getKeySubdirectories( key, outIterator ) ;
	
	if ( outIterator )
	{
		if ( ! error )
			error = fExporter->addObject( outIterator, NULL, outIteratorHandle ) ;
		
		outIterator->release() ;
	}
	
	dir->release() ;
	
	return error ;
}

IOReturn
IOFireWireUserClient::configDirectory_GetType (
											   UserObjectHandle		dirHandle,
											   int*					outType) const
{
	const OSObject * object = fExporter->lookupObject( dirHandle ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	IOConfigDirectory * dir = OSDynamicCast ( IOConfigDirectory, object ) ;
	if ( ! dir )
	{
		object->release() ;
		return kIOReturnBadArgument ;
	}
	
	*outType = dir->getType();
	
	dir->release() ;
	
	return kIOReturnSuccess ;
}

IOReturn
IOFireWireUserClient::configDirectory_GetNumEntries (
													 UserObjectHandle		dirHandle,
													 int*					outNumEntries) const
{
	const OSObject * object = fExporter->lookupObject( dirHandle ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	IOConfigDirectory * dir = OSDynamicCast ( IOConfigDirectory, object ) ;
	if ( ! dir )
	{
		object->release() ;
		return kIOReturnBadArgument ;
	}
	
	*outNumEntries = dir->getNumEntries() ;
	dir->release() ;
	
	return kIOReturnSuccess ;
}

#pragma mark -
#pragma mark LOCAL ISOCH PORT

IOReturn
IOFireWireUserClient::localIsochPort_GetSupported(
												  UserObjectHandle		portHandle,
												  IOFWSpeed*				outMaxSpeed,
												  UInt32*					outChanSupportedHi,
												  UInt32*					outChanSupportedLo) const
{
	const OSObject * object = fExporter->lookupObject( portHandle ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	IOFWUserLocalIsochPort * port = OSDynamicCast ( IOFWUserLocalIsochPort, object ) ;
	if ( ! port )
	{
		object->release() ;
		return kIOReturnBadArgument ;
	}
	
	UInt64		chanSupported ;
	IOReturn	result			= kIOReturnSuccess ;
	
	result = port->getSupported( *outMaxSpeed, chanSupported ) ;
	
	*outChanSupportedHi = (UInt32)( chanSupported >> 32 ) ;
	*outChanSupportedLo	= (UInt32)( chanSupported & 0xFFFFFFFF ) ;
	
	port->release() ;
	
	return result ;
}


IOReturn
IOFireWireUserClient::localIsochPort_Create (
											 LocalIsochPortAllocateParams*	params,
											 UserObjectHandle*				outPortHandle )
{
	DebugLog("IOFireWireUserClient<%p>::localIsochPort_Create\n", this );
	
	IOFWUserLocalIsochPort * port = OSTypeAlloc( IOFWUserLocalIsochPort );
	if ( port && ! port->initWithUserDCLProgram( params, *this, *getOwner()->getController() ) )
	{
		port->release() ;
		port = NULL ;
	}
	
	if ( !port )
	{
		DebugLog( "couldn't create local isoch port\n" ) ;
		return kIOReturnError ;
	}
	
	IOReturn error = fExporter->addObject( port,
										  &IOFWUserLocalIsochPort::exporterCleanup,
										  outPortHandle ) ;
	
	port->release() ;
	
	return error ;
}

IOReturn
IOFireWireUserClient::localIsochPort_SetChannel (
												 UserObjectHandle	portHandle,
												 UserObjectHandle	channelHandle )
{
	InfoLog("IOFireWireUserClient<%p>::localIsochPort_SetChannel\n", this ) ;
	
	const OSObject * object1 = fExporter->lookupObject( portHandle ) ;
	IOFWUserLocalIsochPort * port = OSDynamicCast ( IOFWUserLocalIsochPort, object1 ) ;
	IOReturn error = kIOReturnSuccess ;
	
	if ( !port )
	{
		error = kIOReturnBadArgument ;
	}
	
	const OSObject * object2 = NULL ;
	IOFWUserIsochChannel * channel = NULL ;
	
	if ( !error )
	{
		object2 = fExporter->lookupObject( channelHandle ) ;
		
		channel = OSDynamicCast( IOFWUserIsochChannel, object2 ) ;
		
		if ( !channel )
		{
			error = kIOReturnBadArgument ;
		}
	}
	
	if ( !error )
	{
		IODCLProgram * program = port->getProgramRef() ;
		if ( program )
		{
			program->setForceStopProc( (IOFWIsochChannel::ForceStopNotificationProc*)&IOFWUserIsochChannel::isochChannel_ForceStopHandler, channel, channel ) ;
			
			program->release() ;
		}
	}
	
	if ( object1 )
	{
		object1->release() ;
	}
	
	if ( object2 )
	{
		object2->release() ;
	}
	
	return error ;
}

IOReturn
IOFireWireUserClient::setAsyncRef_DCLCallProc (
											   OSAsyncReference64 			asyncRef,
											   UserObjectHandle 			portHandle )
{
	InfoLog("IOFireWireUserClient<%p>::setAsyncRef_DCLCallProc\n", this ) ;
	
	const OSObject * object =  fExporter->lookupObject( portHandle ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	IOFWUserLocalIsochPort * port = OSDynamicCast( IOFWUserLocalIsochPort, object ) ;
	if ( ! port )
	{
		object->release() ;
		return kIOReturnBadArgument ;
	}
	
	IOReturn error = port->setAsyncRef_DCLCallProc( asyncRef ) ;
	
	port->release() ;	// loopkupObject retains the return value for thread safety
	
	return error ;
}

#pragma mark -
#pragma mark ISOCH CHANNEL

IOReturn
IOFireWireUserClient::isochChannel_Create (
										   bool					inDoIRM,
										   UInt32					inPacketSize,
										   IOFWSpeed				inPrefSpeed,
										   UserObjectHandle *	outChannelHandle )
{
	// this code the same as IOFireWireController::createIsochChannel
	// must update this code when controller changes. We do this because
	// we are making IOFWUserIsochChannel objects, not IOFWIsochChannel
	// objects
	
	IOReturn error = kIOReturnSuccess ;
	IOFWUserIsochChannel * channel = OSTypeAlloc( IOFWUserIsochChannel );
	if ( channel )
	{
		if ( channel->init(	getOwner()->getController(), inDoIRM, inPacketSize, inPrefSpeed ) )
		{
			fExporter->addObject( channel,
								 (IOFWUserObjectExporter::CleanupFunction) & IOFWUserIsochChannel::s_exporterCleanup,
								 outChannelHandle ) ;
		}
		
		channel->release() ;	// addObject retains the object
	}
	else
	{
		error = kIOReturnNoMemory ;
	}
	
	return error ;
}

IOReturn
IOFireWireUserClient::isochChannel_AllocateChannelBegin(
														UserObjectHandle		channelRef,
														UInt32 					speed,
														UInt32 					chansHi,
														UInt32 					chansLo,
														UInt32 * 				outSpeed,
														UInt32 * 				outChannel )
{
	InfoLog("IOFireWireUserClient<%p>::isochChannel_AllocateChannelBegin\n", this ) ;
	
	IOReturn error = kIOReturnSuccess ;
	const OSObject * object = fExporter->lookupObject( channelRef ) ;
	
	IOFWUserIsochChannel * channel = OSDynamicCast( IOFWUserIsochChannel, object ) ;
	
	if ( ! channel )
	{
		error = kIOReturnBadArgument ;
	}
	
	if ( !error )
	{
		UInt64 allowedChans = ((UInt64)chansHi << 32) | (UInt64)chansLo ;
		error = channel->allocateChannelBegin( (IOFWSpeed)speed, allowedChans, outChannel ) ;
		*outSpeed = speed;
	}
	
	if ( object )
	{
		object->release() ;	// lookup retains object, so we have to release it.
	}
	
	return error ;
}

IOReturn
IOFireWireUserClient::setAsyncRef_IsochChannelForceStop(
														OSAsyncReference64		inAsyncRef,
														UserObjectHandle		channelRef )
{
	
	IOReturn error = kIOReturnSuccess;
	
	const OSObject * object = fExporter->lookupObject( channelRef ) ;
	
	IOFWUserIsochChannel * channel = OSDynamicCast( IOFWUserIsochChannel, object ) ;
	
	if ( !channel )
	{
#if __LP64__
		DebugLog("IOFireWireUserClient<%p>::setAsyncRef_IsochChannelForceStop() -- invalid channel ref %llx\n", this, (UInt64)channelRef ) ;
#else
		DebugLog("IOFireWireUserClient<%p>::setAsyncRef_IsochChannelForceStop() -- invalid channel ref %lx\n", this, (UInt32)channelRef ) ;
#endif
		error = kIOReturnBadArgument ;
	}
	
	if( error == kIOReturnSuccess )
	{
		if( inAsyncRef == NULL )
		{
			error = kIOReturnBadArgument;
		}
	}
	
	io_user_reference_t * asyncRef = NULL;
	if( error == kIOReturnSuccess )
	{
		asyncRef = new io_user_reference_t[ kOSAsyncRefCount ] ;
		
		if ( !asyncRef )
		{
			error = kIOReturnNoMemory ;
		}
	}
	
	if( error == kIOReturnSuccess )
	{
		bcopy( inAsyncRef, asyncRef, sizeof( OSAsyncReference64 ) ) ;
		
		io_user_reference_t * oldAsyncRef = channel->getUserAsyncRef() ;
		
		channel->setUserAsyncRef( asyncRef ) ;
		
		delete [] oldAsyncRef ;
	}
	
	if( channel != NULL )
	{
		channel->release();
	}
	
	return error;
}

#pragma mark -
#pragma mark COMMAND OBJECTS

// createAsyncCommand
//
//

IOReturn
IOFireWireUserClient::createAsyncCommand(	OSAsyncReference64 asyncRef,
										 CommandSubmitParams * params,
										 UserObjectHandle * kernel_ref )
{
	IOReturn status = kIOReturnSuccess;
	
	if( status == kIOReturnSuccess )
	{
		if( asyncRef == NULL )
		{
			status = kIOReturnBadArgument;
		}
	}
	
	IOFWUserCommand * cmd = NULL;
	if( status == kIOReturnSuccess )
	{
		cmd = IOFWUserCommand::withSubmitParams( params, this );
		if( !cmd )
			status = kIOReturnNoMemory;
	}
	
	if( status == kIOReturnSuccess )
	{
		status = fExporter->addObject( cmd, NULL, kernel_ref );
	}
	
	if( status == kIOReturnSuccess )
	{
		cmd->setRefCon( (mach_vm_address_t)params->refCon);
	}
	
	if( status == kIOReturnSuccess )
	{
		setAsyncReference64( asyncRef, (mach_port_t) asyncRef[0], (mach_vm_address_t)params->callback, (io_user_reference_t)params->refCon);
		
		cmd->setAsyncReference64( asyncRef );
	}
	
	if( cmd )
	{
		cmd->release();		// we need to release this in all cases
		cmd = NULL;
	}
	
	return status;
}


IOReturn
IOFireWireUserClient::userAsyncCommand_Submit(
											  OSAsyncReference64			asyncRef,
											  CommandSubmitParams *		params,
											  CommandSubmitResult *		outResult,
											  IOByteCount					paramsSize,
											  IOByteCount *				outResultSize)
{
	IOFWUserCommand * cmd = NULL ;
	
	IOReturn error = kIOReturnSuccess ;
	
	if( asyncRef == NULL )
	{
		return kIOReturnBadArgument;
	}
	
	if( fUserClientLock == NULL )
	{
		// should have bailed out in start if fUserClientLock is NULL, but just to be extra safe...
		return kIOReturnCannotLock;
	}
	
	IOLockLock( fUserClientLock );
	
	if ( params->kernCommandRef )
	{
		const OSObject * object = fExporter->lookupObject( params->kernCommandRef ) ;
		if ( !object )
		{
			error = kIOReturnBadArgument ;
		}
		else
		{
			cmd = OSDynamicCast( IOFWUserCommand, object ) ;
			if ( ! cmd )
			{
				object->release() ;
				error = kIOReturnBadArgument ;
			}
		}
	}
	else
	{
		cmd = IOFWUserCommand::withSubmitParams( params, this ) ;
		
		if ( ! cmd )
			error = kIOReturnNoMemory ;
		else
		{
			UserObjectHandle command_ref;
			error = fExporter->addObject( cmd, NULL, &command_ref );
			outResult->kernCommandRef = command_ref;
		}
	}
	
	if ( cmd )
	{
		if ( !error )
		{
			super::setAsyncReference64( asyncRef, (mach_port_t) asyncRef[0], (mach_vm_address_t)params->callback, (io_user_reference_t)params->refCon) ;
			
			cmd->setAsyncReference64( asyncRef ) ;
			cmd->setRefCon( (mach_vm_address_t)params->refCon);
			
			error = cmd->submit( params, outResult ) ;
		}
		
		cmd->release() ;		// we need to release this in all cases
	}
	
	IOLockUnlock( fUserClientLock );
	
	return error ;
}

//
// --- absolute address firewire commands ----------
//
IOFWReadCommand*
IOFireWireUserClient::createReadCommand(
										UInt32 					generation,
										FWAddress 				devAddress,
										IOMemoryDescriptor*		hostMem,
										FWDeviceCallback	 		completion,
										void*					refcon ) const
{
	IOFWReadCommand* result = OSTypeAlloc( IOFWReadCommand );
	if ( result && !result->initAll( getOwner ()->getController(), generation, devAddress, hostMem, completion, refcon ) )
	{
		result->release() ;
		result = NULL ;
	}
	
	return result ;
}

IOFWReadQuadCommand*
IOFireWireUserClient::createReadQuadCommand(
											UInt32 					generation,
											FWAddress 				devAddress,
											UInt32 *				quads,
											int 					numQuads,
											FWDeviceCallback 		completion,
											void *					refcon ) const
{
	IOFWReadQuadCommand* result = OSTypeAlloc( IOFWReadQuadCommand );
	if ( result && !result->initAll( getOwner ()->getController(), generation, devAddress, quads, numQuads, completion, refcon ) )
	{
		result->release() ;
		return NULL ;
	}
	
	return result ;
}

IOFWWriteCommand*
IOFireWireUserClient::createWriteCommand(
										 UInt32 					generation,
										 FWAddress 				devAddress,
										 IOMemoryDescriptor*		hostMem,
										 FWDeviceCallback 		completion,
										 void*					refcon ) const
{
	IOFWWriteCommand* result = OSTypeAlloc( IOFWWriteCommand );
	if ( result && !result->initAll( getOwner ()->getController(), generation, devAddress, hostMem, completion, refcon ) )
	{
		result->release() ;
		return NULL ;
	}
	
	return result ;
}

IOFWWriteQuadCommand*
IOFireWireUserClient::createWriteQuadCommand(
											 UInt32 					generation,
											 FWAddress 				devAddress,
											 UInt32 *				quads,
											 int 					numQuads,
											 FWDeviceCallback 		completion,
											 void *					refcon ) const
{
	IOFWWriteQuadCommand* result = OSTypeAlloc( IOFWWriteQuadCommand );
	if ( result && !result->initAll( getOwner ()->getController(), generation, devAddress, quads, numQuads, completion, refcon ) )
	{
		result->release() ;
		return NULL ;
	}
	
	return result ;
}

// size is 1 for 32 bit compare, 2 for 64 bit.
IOFWCompareAndSwapCommand*
IOFireWireUserClient::createCompareAndSwapCommand(
												  UInt32 					generation,
												  FWAddress 				devAddress,
												  const UInt32 *			cmpVal,
												  const UInt32 *			newVal,
												  int 					size,
												  FWDeviceCallback 		completion,
												  void *					refcon ) const
{
	IOFWCompareAndSwapCommand* result = OSTypeAlloc( IOFWCompareAndSwapCommand );
	if ( result && !result->initAll( getOwner ()->getController(), generation, devAddress, cmpVal, newVal, size, completion, refcon ) )
	{
		result->release() ;
		return NULL ;
	}
	
	return result ;
}

#pragma mark -

IOReturn
IOFireWireUserClient::firelog( const char* string, IOByteCount bufSize ) const
{
	// DEPRECATED
	
	return kIOReturnSuccess;
}

IOReturn
IOFireWireUserClient::getBusGeneration( UInt32* outGeneration )
{
	*outGeneration = getOwner () -> getController () -> getGeneration () ;
	return kIOReturnSuccess ;
}

IOReturn
IOFireWireUserClient::getLocalNodeIDWithGeneration( UInt32 testGeneration, UInt32* outLocalNodeID )
{
	if ( ! getOwner () -> getController () -> checkGeneration ( testGeneration ) )
		return kIOFireWireBusReset ;
	
	*outLocalNodeID = (UInt32) getOwner () -> getController () -> getLocalNodeID () ;
	
	// did generation change when we weren't looking?
	if ( ! getOwner () -> getController () -> checkGeneration ( testGeneration ) )
		return kIOFireWireBusReset ;
	
	return kIOReturnSuccess ;
}

IOReturn
IOFireWireUserClient::getRemoteNodeID( UInt32 testGeneration, UInt32* outRemoteNodeID )
{
	UInt32 generation ;
	UInt16 nodeID ;
	
	IOReturn error = getOwner () -> getNodeIDGeneration ( generation, nodeID ) ;
	if (error)
		return error ;
	if ( generation != testGeneration )
		return kIOFireWireBusReset ;
	
	*outRemoteNodeID = (UInt32)nodeID ;
	
	// did generation change when we weren't looking?
	if ( ! getOwner () -> getController () -> checkGeneration ( generation ) )
		return kIOFireWireBusReset ;
	
	return error ;
}

IOReturn
IOFireWireUserClient::getSpeedToNode( UInt32 generation, UInt32* outSpeed )
{
	if ( ! getOwner () -> getController () -> checkGeneration ( generation ) )
		return kIOFireWireBusReset ;
	
	UInt16 nodeID ;
	getOwner () -> getNodeIDGeneration( generation, nodeID ) ;
	
	*outSpeed = (UInt32) getOwner () -> getController () -> FWSpeed ( nodeID ) ;
	
	// did generation change when we weren't looking?
	if ( ! getOwner () -> getController () -> checkGeneration ( generation ) )
		return kIOFireWireBusReset ;
	
	return kIOReturnSuccess ;
}

IOReturn
IOFireWireUserClient::getSpeedBetweenNodes( UInt32 generation, UInt32 fromNode, UInt32 toNode, UInt32* outSpeed )
{
	if ( ! getOwner () -> getController () -> checkGeneration ( generation ) )
		return kIOFireWireBusReset ;
	
	*outSpeed = (UInt32)getOwner ()->getController()->FWSpeed( (UInt16)fromNode, (UInt16)toNode ) ;
	// did generation change when we weren't looking?
	if (!getOwner ()->getController()->checkGeneration(generation))
		return kIOFireWireBusReset ;
	
	return kIOReturnSuccess ;
}

IOReturn
IOFireWireUserClient::getIRMNodeID( UInt32 generation, UInt32* irmNodeID )
{
	UInt16 tempNodeID ;
	UInt32 tempGeneration ;
	
	IOReturn error = (UInt32)getOwner ()->getController()->getIRMNodeID( tempGeneration, tempNodeID ) ;
	if (error)
		return error ;
	
	if ( tempGeneration != generation )
		return kIOFireWireBusReset ;
	
	*irmNodeID = (UInt32)tempNodeID ;
	
	return kIOReturnSuccess ;
}

IOReturn
IOFireWireUserClient::clipMaxRec2K( Boolean clipMaxRec )
{
	//DebugLog("IOFireWireUserClient::clipMaxRec2K\n");
	
	if( fClippedMaxRec == clipMaxRec )
		return kIOReturnSuccess;		// Already set the way we want, no need to do it again
	
	IOReturn error = (UInt32)fOwner->getController()->clipMaxRec2K( clipMaxRec ) ;
	if (error)
		return error ;
	
	fClippedMaxRec = clipMaxRec;
	
	return kIOReturnSuccess ;
}

IOReturn
IOFireWireUserClient::seize( IOOptionBits inFlags )
{
	if ( ! OSDynamicCast(IOFireWireDevice, getOwner ()))
		return kIOReturnUnsupported ;
	
	if ( kIOReturnSuccess != clientHasPrivilege( fTask, kIOClientPrivilegeAdministrator ) )
		return kIOReturnNotPrivileged ;
	
	// message all clients that have the device open that
	// the device is going away. It's not really going away, but we
	// want them to think so...
	if ( getOwner ()->isOpen() )
	{
		OSIterator*			clientIterator =  getOwner ()->getOpenClientIterator() ;
		if (!clientIterator)
		{
			DebugLog("IOFireWireUserClient::seize: couldn't make owner client iterator\n") ;
			return kIOReturnError ;
		}
		
		{
			IOService*			client = (IOService*)clientIterator->getNextObject() ;
			
			while ( client )
			{
				if ( client != this )
				{
					client->message( kIOFWMessageServiceIsRequestingClose, getOwner () ) ;
					client->message( kIOMessageServiceIsRequestingClose, getOwner () ) ;
					
					client->terminate() ;
				}
				
				client = (IOService*)clientIterator->getNextObject() ;
			}
		}
		
		clientIterator->release() ;
	}
	
	if ( getOwner ()->isOpen() )
	{
		OSIterator*			clientIterator =  getOwner ()->getClientIterator() ;
		if (!clientIterator)
		{
			DebugLog("IOFireWireUserClient::seize: couldn't make owner client iterator\n") ;
			return kIOReturnError ;
		}
		
		{
			IOService*			client = (IOService*)clientIterator->getNextObject() ;
			
			while ( client )
			{
				if ( client != this )
				{
					client->message( kIOFWMessageServiceIsRequestingClose, getOwner () ) ;
					client->message( kIOMessageServiceIsRequestingClose, getOwner () ) ;
					
					client->terminate() ;
				}
				
				client = (IOService*)clientIterator->getNextObject() ;
			}
		}
		
		clientIterator->release() ;
	}
	
	return kIOReturnSuccess ;
}

IOReturn IOFireWireUserClient::message( UInt32 type, IOService * provider, void * arg )
{
	switch(type)
	{
		case kIOMessageServiceIsSuspended:
			if (fBusResetAsyncNotificationRef[0])
				sendAsyncResult64(fBusResetAsyncNotificationRef, kIOReturnSuccess, NULL, 0) ;
			break ;
		case kIOMessageServiceIsResumed:
			if (fBusResetDoneAsyncNotificationRef[0])
				sendAsyncResult64(fBusResetDoneAsyncNotificationRef, kIOReturnSuccess, NULL, 0) ;
			break ;
		case kIOFWMessageServiceIsRequestingClose:
			getOwner ()->messageClients(kIOMessageServiceIsRequestingClose) ;
			break;
			
	}
	
	super::message ( type, provider ) ;
	
	return kIOReturnSuccess;
}

IOReturn
IOFireWireUserClient::getSessionRef( IOFireWireSessionRef * sessionRef )
{
	IOReturn error = kIOReturnSuccess;
	
	if( !fOwner->isOpen( this ) )
	{
		return kIOReturnNotOpen ;
	}
	
	*sessionRef = (IOFireWireSessionRef)(uintptr_t)fSessionRef;
	
	return error ;
}

#pragma mark -
#pragma mark ASYNC STREAM LISTENER

//
// Async Stream Listener
//

IOReturn
IOFireWireUserClient::setAsyncStreamRef_Packet (
												OSAsyncReference64		asyncRef,
												UserObjectHandle		asyncStreamListenerHandle,
												mach_vm_address_t		inCallback,
												io_user_reference_t		inUserRefCon,
												void*,
												void*,
												void*
												)
{
	IOReturn result = kIOReturnBadArgument;
	
	if( asyncRef == NULL )
	{
		return kIOReturnBadArgument;
	}
	
	const OSObject * object = fExporter->lookupObject ( asyncStreamListenerHandle ) ;
	if ( !object )
	{
		return result ;
	}
	
	IOFWUserAsyncStreamListener * me = OSDynamicCast ( IOFWUserAsyncStreamListener, object ) ;
	if ( ! me )
	{
		object->release() ;
		return result ;
	}
	
	if ( inCallback )
		super::setAsyncReference64 ( asyncRef, (mach_port_t) asyncRef[0], inCallback, inUserRefCon ) ;
	else
		asyncRef[0] = 0 ;
	
	me->setAsyncStreamRef_Packet(asyncRef) ;
	me->release() ;
	
	return kIOReturnSuccess ;
}

IOReturn
IOFireWireUserClient::setAsyncStreamRef_SkippedPacket (
													   OSAsyncReference64		asyncRef,
													   UserObjectHandle		inAsyncStreamListenerRef,
													   mach_vm_address_t		inCallback,
													   io_user_reference_t		inUserRefCon,
													   void*,
													   void*,
													   void*)
{
	IOReturn result = kIOReturnBadArgument;
	
	if( asyncRef == NULL )
	{
		return kIOReturnBadArgument;
	}
	
	const OSObject * object = fExporter->lookupObject ( inAsyncStreamListenerRef ) ;
	if ( !object )
	{
		return result ;
	}
	
	result	= kIOReturnSuccess ;
	IOFWUserAsyncStreamListener * me = OSDynamicCast ( IOFWUserAsyncStreamListener, object ) ;
	
	if ( !me )
	{
		object->release() ;
		result = kIOReturnBadArgument ;
	}
	
	if ( kIOReturnSuccess == result )
	{
		if (inCallback)
			super::setAsyncReference64 ( asyncRef, (mach_port_t) asyncRef[0], inCallback, inUserRefCon ) ;
		else
			asyncRef[0] = 0 ;
		
		me->setAsyncStreamRef_SkippedPacket(asyncRef) ;
	}
	
	if( me )
	{
		me->release();
	}
	
	return result ;
}

IOReturn
IOFireWireUserClient::asyncStreamListener_Create (
												  FWUserAsyncStreamListenerCreateParams*	params,
												  UserObjectHandle*						outAsyncStreamListenerHandle )
{
	IOFWUserAsyncStreamListener * asyncStreamListener = OSTypeAlloc( IOFWUserAsyncStreamListener );
	
	if ( asyncStreamListener == NULL )
		return kIOReturnNoMemory ;
	
	if ( not asyncStreamListener->initAsyncStreamListener( this, params ) )
	{
		asyncStreamListener->release();
		return kIOReturnNoMemory ;
	}
	
	IOReturn error = fExporter->addObject ( asyncStreamListener,
										   (IOFWUserObjectExporter::CleanupFunction)&IOFWUserAsyncStreamListener::exporterCleanup,
										   outAsyncStreamListenerHandle ) ;		// nnn needs cleanup function?
	
	if ( error )
		asyncStreamListener->deactivate() ;
	
	asyncStreamListener->release() ;
	
	return error ;
}

IOReturn
IOFireWireUserClient::asyncStreamListener_ClientCommandIsComplete (
																   UserObjectHandle		asyncStreamListenerHandle,
																   FWClientCommandID		inCommandID )
{
	const OSObject * object = fExporter->lookupObject( asyncStreamListenerHandle ) ;
	if ( !object )
	{
		return kIOReturnBadArgument ;
	}
	
	IOReturn	result = kIOReturnSuccess ;
	IOFWUserAsyncStreamListener *me	= OSDynamicCast( IOFWUserAsyncStreamListener, object ) ;
	if (!me)
	{
		object->release() ;
		return kIOReturnBadArgument ;
	}
	
	me->clientCommandIsComplete ( inCommandID ) ;
	me->release() ;
	
	return result ;
}

IOReturn
IOFireWireUserClient::asyncStreamListener_GetOverrunCounter (
															 UserObjectHandle		asyncStreamListenerHandle,
															 UInt32					*overrunCounter )
{
	IOReturn	result = kIOReturnBadArgument ;
	
	const OSObject * object = fExporter->lookupObject( asyncStreamListenerHandle ) ;
	if ( !object )
	{
		return result ;
	}
	
	IOFWUserAsyncStreamListener *me	= OSDynamicCast( IOFWUserAsyncStreamListener, object ) ;
	if ( !me )
	{
		object->release() ;
		return result ;
	}
	
	*overrunCounter = me->getOverrunCounter( ) ;
	me->release() ;
	
	result = kIOReturnSuccess;
	
	return result ;
	
}

IOReturn
IOFireWireUserClient::asyncStreamListener_SetFlags (
													UserObjectHandle		asyncStreamListenerHandle,
													UInt32					flags )
{
	IOReturn	result = kIOReturnBadArgument ;
	
	const OSObject * object = fExporter->lookupObject( asyncStreamListenerHandle ) ;
	if ( !object )
	{
		return result ;
	}
	
	IOFWUserAsyncStreamListener *me	= OSDynamicCast( IOFWUserAsyncStreamListener, object ) ;
	if (!me)
	{
		object->release() ;
		return result;
	}
	
	result = kIOReturnSuccess;
	me->setFlags( flags ) ;
	me->release() ;
	
	return result ;
}

IOReturn
IOFireWireUserClient::asyncStreamListener_GetFlags (
													UserObjectHandle		asyncStreamListenerHandle,
													UInt32					*flags )
{
	IOReturn	result = kIOReturnBadArgument ;
	
	const OSObject * object = fExporter->lookupObject( asyncStreamListenerHandle ) ;
	if ( !object )
	{
		return result ;
	}
	
	IOFWUserAsyncStreamListener *me	= OSDynamicCast( IOFWUserAsyncStreamListener, object ) ;
	if (!me)
	{
		object->release() ;
		return result ;
	}
	
	result = kIOReturnSuccess;
	*flags = me->getFlags( ) ;
	me->release() ;
	
	return result ;
}

IOReturn
IOFireWireUserClient::asyncStreamListener_TurnOnNotification (
															  UserObjectHandle		asyncStreamListenerHandle )
{
	IOReturn	result = kIOReturnBadArgument ;
	
	const OSObject * object = fExporter->lookupObject( asyncStreamListenerHandle ) ;
	if ( !object )
	{
		return result ;
	}
	
	IOFWUserAsyncStreamListener *me	= OSDynamicCast( IOFWUserAsyncStreamListener, object ) ;
	if (!me)
	{
		object->release() ;
		return result ;
	}
	
	result = kIOReturnSuccess;
	me->TurnOnNotification() ;
	me->release() ;
	
	return result ;
}

IOReturn
IOFireWireUserClient::asyncStreamListener_TurnOffNotification (
															   UserObjectHandle		asyncStreamListenerHandle )
{
	IOReturn	result = kIOReturnBadArgument ;
	
	const OSObject * object = fExporter->lookupObject( asyncStreamListenerHandle ) ;
	if ( !object )
	{
		return result ;
	}
	
	IOFWUserAsyncStreamListener *me	= OSDynamicCast( IOFWUserAsyncStreamListener, object ) ;
	if (!me)
	{
		object->release() ;
		return result ;
	}
	
	result = kIOReturnSuccess;
	me->TurnOffNotification() ;
	me->release() ;
	
	return result ;
}

#pragma mark -
#pragma mark IRM ALLOCATIONS

IOReturn
IOFireWireUserClient::allocateIRMBandwidthInGeneration(UInt32 bandwidthUnits, UInt32 generation)
{
	return getOwner () -> getController () -> allocateIRMBandwidthInGeneration(bandwidthUnits, generation);
}

IOReturn
IOFireWireUserClient::releaseIRMBandwidthInGeneration(UInt32 bandwidthUnits, UInt32 generation)
{
	return getOwner () -> getController () -> releaseIRMBandwidthInGeneration(bandwidthUnits, generation);
}

IOReturn
IOFireWireUserClient::allocateIRMChannelInGeneration(UInt8 isochChannel, UInt32 generation)
{
	return getOwner () -> getController () -> allocateIRMChannelInGeneration(isochChannel, generation);
}

IOReturn
IOFireWireUserClient::releaseIRMChannelInGeneration(UInt8 isochChannel, UInt32 generation)
{
	return getOwner () -> getController () -> releaseIRMChannelInGeneration(isochChannel, generation);
}

typedef struct UserIRMAllocationParamsStruct
{
	io_user_reference_t asyncRef[kOSAsyncRef64Count];
	Boolean userNotificationEnabled;
	IOFireWireUserClient *pUserClient;
} UserIRMAllocationParams;

static void UserIRMAllocationCleanupFunction( const OSObject * obj )
{
	IOFireWireIRMAllocation * pIrmAllocation = (IOFireWireIRMAllocation *) obj;
	
	UserIRMAllocationParams *pUserIRMAllocationParams = (UserIRMAllocationParams*) pIrmAllocation->GetRefCon();
	delete pUserIRMAllocationParams;
}

static IOReturn UserIRMAllocationLostNotification(void* refCon, class IOFireWireIRMAllocation* allocation)
{
	UserIRMAllocationParams *pUserIRMAllocationParams = (UserIRMAllocationParams*) refCon;
	if (pUserIRMAllocationParams->userNotificationEnabled)
		pUserIRMAllocationParams->pUserClient->sendAsyncResult64(pUserIRMAllocationParams->asyncRef, kIOReturnSuccess, NULL, 0) ;
	return kIOReturnSuccess;
}

IOReturn
IOFireWireUserClient::irmAllocation_Create(Boolean releaseIRMResourcesOnFree, UserObjectHandle* outIRMAllocationHandle)
{
	UserIRMAllocationParams *pUserIRMAllocationParams = new UserIRMAllocationParams;
	if (!pUserIRMAllocationParams)
		return kIOReturnNoMemory ;
	else
	{
		pUserIRMAllocationParams->userNotificationEnabled = false;
		pUserIRMAllocationParams->pUserClient = this;
	}
	
	IOFireWireIRMAllocation * irmAllocation = OSTypeAlloc( IOFireWireIRMAllocation );
	if (!irmAllocation)
	{
		delete pUserIRMAllocationParams;
		return kIOReturnNoMemory ;
	}
	
	if (!irmAllocation->init(getOwner()->getController(), releaseIRMResourcesOnFree, UserIRMAllocationLostNotification, pUserIRMAllocationParams))
	{
		irmAllocation->release();
		delete pUserIRMAllocationParams;
		return kIOReturnNoMemory ;
	}
	
	IOReturn error = fExporter->addObject ( irmAllocation, UserIRMAllocationCleanupFunction, outIRMAllocationHandle ) ;
	irmAllocation->release() ;
	
	return error ;
}

IOReturn
IOFireWireUserClient::irmAllocation_AllocateResources(UserObjectHandle irmAllocationHandle, UInt8 isochChannel, UInt32 bandwidthUnits)
{
	IOReturn	result = kIOReturnBadArgument ;
	
	
	
	const OSObject * object = fExporter->lookupObject( irmAllocationHandle ) ;
	if ( !object )
	{
		return result ;
	}
	
	IOFireWireIRMAllocation *me	= OSDynamicCast( IOFireWireIRMAllocation, object ) ;
	if (!me)
	{
		object->release() ;
		return result ;
	}
	
	result = me->allocateIsochResources(isochChannel, bandwidthUnits) ;
	
	me->release() ;
	
	return result ;
}

IOReturn
IOFireWireUserClient::irmAllocation_DeallocateResources(UserObjectHandle irmAllocationHandle)
{
	IOReturn	result = kIOReturnBadArgument ;
	
	const OSObject * object = fExporter->lookupObject( irmAllocationHandle ) ;
	if ( !object )
	{
		return result ;
	}
	
	IOFireWireIRMAllocation *me	= OSDynamicCast( IOFireWireIRMAllocation, object ) ;
	if (!me)
	{
		object->release() ;
		return result ;
	}
	
	result = me->deallocateIsochResources();
	
	me->release() ;
	
	return result ;
}

Boolean
IOFireWireUserClient::irmAllocation_areResourcesAllocated(UserObjectHandle irmAllocationHandle, UInt8 *pIsochChannel, UInt32 *pBandwidthUnits)
{
	Boolean	result = false ;
	
	const OSObject * object = fExporter->lookupObject( irmAllocationHandle ) ;
	if ( !object )
	{
		return false ;
	}
	
	IOFireWireIRMAllocation *me	= OSDynamicCast( IOFireWireIRMAllocation, object ) ;
	if (!me)
	{
		object->release() ;
		return false ;
	}
	
	result = me->areIsochResourcesAllocated(pIsochChannel, pBandwidthUnits);
	
	me->release() ;
	
	return result ;
}

void
IOFireWireUserClient::irmAllocation_setDeallocateOnRelease(UserObjectHandle irmAllocationHandle, Boolean doDeallocationOnRelease)
{
	const OSObject * object = fExporter->lookupObject( irmAllocationHandle ) ;
	if ( !object )
	{
		return;
	}
	
	IOFireWireIRMAllocation *me	= OSDynamicCast( IOFireWireIRMAllocation, object ) ;
	if (!me)
	{
		object->release() ;
		return;
	}
	
	me->setReleaseIRMResourcesOnFree(doDeallocationOnRelease);
	
	me->release() ;
	
	return;
}

/*
 /Users/fabioduchene/iofirewirefamily/IOFireWireFamily.kmodproj/IOFireWireUserClient.cpp:5547:6: error: no matching function for call to 'copyin'
 if (copyin(p, buf, len)) {
 ^~~~~~
 In file included from <built-in>:327:
 In file included from <command line>:7:
 In file included from /Users/fabioduchene/iofirewirefamily/IOFireWireFamily.kmodproj/prefix.h:23:
 In file included from /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.Internal.sdk/System/Library/Frameworks/Kernel.framework/PrivateHeaders/IOKit/system.h:57:
 /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.Internal.sdk/System/Library/Frameworks/Kernel.framework/PrivateHeaders/libkern/libkern.h:170:5: note:
 candidate function not viable: no known conversion from 'unsigned long long *' to 'const user_addr_t' (aka 'const unsigned long long') for 1st argument; dereference the argument
 with *
 int     copyin(const user_addr_t uaddr, void *kaddr, size_t len);
 ^
 
 */
/*
 int isBufferValid (const user_addr_t p, unsigned int len)
 {
 unsigned char buf[kOSAsyncRef64Count * sizeof(void *)];
 
 if (len != kOSAsyncRef64Count * sizeof(void *)) {
 return 0;
 }
 
 // if copyin fails (and returns a non-zero code) then the buffer is not valid
 
 if (copyin((const user_addr_t) p, buf, len)) {
 return 0;
 }
 
 return 1;
 }*/


IOReturn
IOFireWireUserClient::irmAllocation_setRef(OSAsyncReference64 asyncRef,
										   UserObjectHandle irmAllocationHandle,
										   io_user_reference_t inCallback,
										   io_user_reference_t inUserRefCon)
{
	IOReturn	result = kIOReturnBadArgument ;
	
	
	/*if (!isBufferValid((unsigned char *) asyncRef, kOSAsyncRef64Count * sizeof(void *))) {
	 return result;
	 }*/
	
	const OSObject * object = fExporter->lookupObject( irmAllocationHandle ) ;
	if ( !object )
	{
		return result ;
	}
	
	IOFireWireIRMAllocation *me	= OSDynamicCast( IOFireWireIRMAllocation, object ) ;
	if (!me)
	{
		object->release() ;
		return result ;
	}
	
	UserIRMAllocationParams *pUserIRMAllocationParams = (UserIRMAllocationParams*) me->GetRefCon();
	
	for (UInt32 i=0;i<kOSAsyncRef64Count;i++)
		pUserIRMAllocationParams->asyncRef[i] = asyncRef[i];
	
	pUserIRMAllocationParams->asyncRef[ kIOAsyncCalloutFuncIndex ] = (mach_vm_address_t)inCallback ;
	pUserIRMAllocationParams->asyncRef[ kIOAsyncCalloutRefconIndex ] = inUserRefCon ;
	if (inCallback)
		pUserIRMAllocationParams->userNotificationEnabled = true;
	else
		pUserIRMAllocationParams->userNotificationEnabled = false;
	
	me->release() ;
	
	return result ;
}

// createVectorCommand
//
//

IOReturn
IOFireWireUserClient::createVectorCommand( UserObjectHandle * kernel_ref )
{
	IOReturn status = kIOReturnSuccess;
	
	IOFWUserVectorCommand * cmd = NULL;
	if( status == kIOReturnSuccess )
	{
		cmd = IOFWUserVectorCommand::withUserClient( this );
		if( !cmd )
			status = kIOReturnNoMemory;
	}
	
	if( status == kIOReturnSuccess )
	{
		status = fExporter->addObject( cmd, NULL, kernel_ref );
	}
	
	if( cmd )
	{
		cmd->release();		// we need to release this in all cases
		cmd = NULL;
	}
	
	return status;
}

// createPHYPacketListener
//
//

IOReturn
IOFireWireUserClient::createPHYPacketListener( UInt32 queue_count, UserObjectHandle * kernel_ref )
{
	IOReturn status = kIOReturnSuccess;
	
	IOFWUserPHYPacketListener * listener = NULL;
	if( status == kIOReturnSuccess )
	{
		listener = IOFWUserPHYPacketListener::withUserClient( this, queue_count );
		if( !listener )
			status = kIOReturnNoMemory;
	}
	
	if( status == kIOReturnSuccess )
	{
		status = fExporter->addObject( listener, (IOFWUserObjectExporter::CleanupFunction)&IOFWUserPHYPacketListener::exporterCleanup, kernel_ref );
	}
	
	if( listener )
	{
		listener->release();		// we need to release this in all cases
		listener = NULL;
	}
	
	return status;
}