/*
 *  AppleOnboardAudioUserClient.cpp
 *  AppleOnboardAudio
 *
 *  Created by Aram Lindahl on Tue Apr 15 2003.
 *  Copyright (c) 2003 Apple Computer. All rights reserved.
 *
 */

#include "AppleOnboardAudioUserClient.h"
#include "AppleOnboardAudio.h"
#include "AudioHardwareUtilities.h"
#include "PlatformInterface.h"

const IOExternalMethod		AppleOnboardAudioUserClient::sMethods[] =
{
	//	get state, pass in selector
	{
		NULL,																// object
		( IOMethod ) &AppleOnboardAudioUserClient::getState,				// func
        kIOUCScalarIStructO,   												// Struct Input, Struct Output.
		2,																	// count of input parameters
        kUserClientStateStructSize, 										// The size of the input struct.
 	},
	//	set state, pass in selector for which state
	{
		NULL,																// object
		( IOMethod ) &AppleOnboardAudioUserClient::setState,				// func
		kIOUCScalarIStructI,												// flags
		2,																	// count of input parameters
        kUserClientStateStructSize, 										// The size of the input struct.
	},
	// get the current sample frame
	{
		NULL,																// object
		( IOMethod ) &AppleOnboardAudioUserClient::getCurrentSampleFrame,	// func
		kIOUCScalarIScalarO,												// flags
		0,																	// count of input parameters
		1																	// count of output parameters
	}
};

const IOItemCount 	AppleOnboardAudioUserClient::sMethodCount = sizeof (AppleOnboardAudioUserClient::sMethods) / sizeof (AppleOnboardAudioUserClient::sMethods[0]);

OSDefineMetaClassAndStructors( AppleOnboardAudioUserClient, IOUserClient )

//===========================================================================================================================
//	Create
//===========================================================================================================================

AppleOnboardAudioUserClient *	AppleOnboardAudioUserClient::Create( AppleOnboardAudio *inDriver, task_t inTask )
{
    AppleOnboardAudioUserClient *		userClient;
    
    userClient = new AppleOnboardAudioUserClient;
	if( !userClient )
	{
		debugIOLog (3,  "[AppleOnboardAudio] create user client object failed" );
		goto exit;
	}
    
    if( !userClient->initWithDriver( inDriver, inTask ) )
	{
		debugIOLog (3,  "[AppleOnboardAudio] initWithDriver failed" );
		
		userClient->release();
		userClient = NULL;
		goto exit;
	}
	
//	debugIOLog (3,  "[AppleOnboardAudio] User client created for task 0x%08lX", ( UInt32 ) inTask );
	
exit:
	return( userClient );
}

//===========================================================================================================================
//	initWithDriver
//===========================================================================================================================

bool	AppleOnboardAudioUserClient::initWithDriver( AppleOnboardAudio *inDriver, task_t inTask )
{
	bool		result;
	
//	debugIOLog (3,  "AppleOnboardAudioUserClient::initWithDriver (%p, %p)", inDriver, (void *)inTask);
	
	result = false;
    if( !initWithTask( inTask, NULL, 0 ) )
	{
		debugIOLog (3,  "   initWithTask failed" );
		goto exit;
    }
    if( !inDriver )
	{
		debugIOLog (3,  "   initWithDriver failed (null input driver)" );
        goto exit;
    }
    
    mDriver 	= inDriver;
    mClientTask = inTask;
    result		= true;
	
exit:
	return( result );
}

//===========================================================================================================================
//	free
//===========================================================================================================================

void	AppleOnboardAudioUserClient::free( void )
{
//	debugIOLog (3,  "AppleOnboardAudioUserClient::free ()" );
	
    IOUserClient::free();
}

//===========================================================================================================================
//	clientClose
//===========================================================================================================================

IOReturn	AppleOnboardAudioUserClient::clientClose( void )
{
//	debugIOLog (3,  "AppleOnboardAudioUserClient::clientClose ()" );
	
    if( !isInactive() )
	{
        mDriver = NULL;
    }
    return( kIOReturnSuccess );
}

//===========================================================================================================================
//	clientDied
//===========================================================================================================================

IOReturn	AppleOnboardAudioUserClient::clientDied( void )
{
//	debugIOLog (3,  "AppleOnboardAudioUserClient::clientDied ()" );
	
    return( clientClose() );
}

//===========================================================================================================================
//	getTargetAndMethodForIndex
//===========================================================================================================================

IOExternalMethod *	AppleOnboardAudioUserClient::getTargetAndMethodForIndex( IOService **outTarget, UInt32 inIndex )
{
	IOExternalMethod *		methodPtr;
	
	methodPtr = NULL;
	if( inIndex <= sMethodCount )  {
        *outTarget = this;
		methodPtr = ( IOExternalMethod * ) &sMethods[ inIndex ];
    } else {
		debugIOLog (3,  "[AppleOnboardAudio] getTargetAndMethodForIndex - bad index (index=%lu)", inIndex );
	}
	return( methodPtr );
}


//===========================================================================================================================
//	getState - 2 scalar in, 1 struct out
//===========================================================================================================================

IOReturn AppleOnboardAudioUserClient::getState (UInt32 selector, UInt32 arg2, void * outState) {
	IOReturn						err;
	
	err = kIOReturnError;

	if ( NULL != mDriver && NULL != outState ) {
		switch (selector) {
			case kPlatformSelector:
				err = mDriver->getPlatformState ( arg2, (PlatformStateStructPtr)outState );
				break;
			case kHardwarePluginSelector:
				err = mDriver->getPluginState ( (HardwarePluginType)arg2, (HardwarePluginDescriptorPtr)outState );
				break;
			case kDMASelector:
				err = mDriver->getDMAStateAndFormat ( arg2, outState );
				break;
			case kSoftwareProcessingSelector:
				err = mDriver->getSoftwareProcessingState ( arg2, outState );
				break;
			case kRealTimeCPUUsage:
				err = mDriver->getRealTimeCPUUsage ( arg2, outState );
				break;
			case kAppleOnboardAudioSelector:
				err = mDriver->getAOAState ( arg2, outState );
				break;
			case kTransportInterfaceSelector:
				err = mDriver->getTransportInterfaceState ( arg2, outState );
				break;
			default:
				debugIOLog (3, "Unknown user client selector (%ld)", selector);
				break;
		}
	}
	return (err);
}

//===========================================================================================================================
//	setState - 2 scalar in, 1 struct in
//===========================================================================================================================

IOReturn AppleOnboardAudioUserClient::setState (UInt32 selector, UInt32 arg2, void * inState) {
	IOReturn						err;
	
	err = kIOReturnError;

	if ( NULL != mDriver ) {
		switch (selector) {
			case kPlatformSelector:
				err = mDriver->setPlatformState ( arg2, (PlatformStateStructPtr)inState );
				break;
			case kHardwarePluginSelector:
				err = mDriver->setPluginState ( (HardwarePluginType)arg2, (HardwarePluginDescriptorPtr)inState );
				break;
			case kDMASelector:
				err = mDriver->setDMAStateAndFormat ( arg2, inState );
				break;
			case kSoftwareProcessingSelector:
				err = mDriver->setSoftwareProcessingState ( arg2, inState );
				break;
			case kAppleOnboardAudioSelector:
				err = mDriver->setAOAState ( arg2, inState );
				break;
			case kTransportInterfaceSelector:
				err = mDriver->setTransportInterfaceState ( arg2, inState );
				break;
			default:
				debugIOLog (3, "Unknown user client selector (%ld)", selector);
				break;
		}
	}
	if ( kIOReturnSuccess != err ) {
		debugIOLog ( 5, "AppleOnboardAudioUserClient::setState ( %d, %d, %p ) returns %lX", selector, arg2, inState, err );
	}
	return (err);
}

//===========================================================================================================================
//	getCurrentSampleFrame - 0 scalar in, 1 scalar out
//===========================================================================================================================

IOReturn AppleOnboardAudioUserClient::getCurrentSampleFrame (UInt32 * outCurrentSampleFrame) {
	IOReturn						err;
	
	err = kIOReturnError;
	
	if ( NULL != mDriver && NULL != outCurrentSampleFrame ) {
		*outCurrentSampleFrame = mDriver->getCurrentSampleFrame ();
		err = kIOReturnSuccess;
	}
	
	return (err);
}


#if 0
//===========================================================================================================================
//		The following code goes into whatever application wants to call into AppleOnboardAudio
//===========================================================================================================================

//===========================================================================================================================
//	Private constants
//===========================================================================================================================

enum
{
	kAOAUserClientGetStateIndex	 		=	0,		//	returns data from gpio																
	kAOAUserClientSetStateIndex,						//	writes data to gpio
	kAOAUserClientGetCurrentSampleFrame				// returns TRUE if gpio is active high													
};

//===========================================================================================================================
//	Private prototypes
//===========================================================================================================================

static IOReturn	SetupUserClient( void );
static void		TearDownUserClient( void );

//===========================================================================================================================
//	Globals
//===========================================================================================================================

static mach_port_t		gMasterPort		= 0;
static io_object_t		gDriverObject	= 0;
static io_connect_t		gDataPort 		= 0;

//===========================================================================================================================
//	SetupUserClient
//===========================================================================================================================

static IOReturn	SetupUserClient( void )
{
	IOReturn			err;
	CFDictionaryRef		matchingDictionary;
	io_iterator_t		serviceIter;
	
	// Initialize variables for easier cleanup.
	
	err					= kIOReturnSuccess;
	matchingDictionary 	= NULL;
	serviceIter			= NULL;
	
	// Exit quickly if we're already set up.
	
	if( gDataPort )
	{
		goto exit;
	}
	
	// Get a port so we can communicate with IOKit.
	
	err = IOMasterPort( NULL, &gMasterPort );
	if( err != kIOReturnSuccess ) goto exit;
	
	// Build a dictionary of all the services matching our service name. Note that we do not release the dictionary
	// if IOServiceGetMatchingServices succeeds because it does the release itself.
	
	err = kIOReturnNotFound;
	matchingDictionary = IOServiceNameMatching( "AppleOnboardAudio" );
	if( !matchingDictionary ) goto exit;
	
	err = IOServiceGetMatchingServices( gMasterPort, matchingDictionary, &serviceIter );
	if( err != kIOReturnSuccess ) goto exit;
	matchingDictionary = NULL;
	
	err = kIOReturnNotFound;
	gDriverObject = IOIteratorNext( serviceIter );
	if( !gDriverObject ) goto exit;
	
	// Open a connection to our service so we can talk to it.
	
	err = IOServiceOpen( gDriverObject, mach_task_self(), 0, &gDataPort );
	if( err != kIOReturnSuccess ) goto exit;
	
	// Success. Clean up stuff and we're done.
	
exit:
	if( serviceIter )
	{
		IOObjectRelease( serviceIter );
	}
	if( matchingDictionary )
	{
		CFRelease( matchingDictionary );
	}
	if( err != kIOReturnSuccess )
	{
		TearDownUserClient();
	}
	return( err );
}

//===========================================================================================================================
//	TearDownUserClient
//===========================================================================================================================

static void	TearDownUserClient( void )
{
	if( gDataPort )
	{
		IOServiceClose( gDataPort );
		gDataPort = 0;
	}
	if( gDriverObject )
	{
		IOObjectRelease( gDriverObject );
		gDriverObject = NULL;
	}
	if( gMasterPort )
	{
		mach_port_deallocate( mach_task_self(), gMasterPort );
		gMasterPort = 0;
	}
}

//===========================================================================================================================
//	getState
//===========================================================================================================================

OSStatus	getState( UInt32 selector, UInt32 target, UInt32 arg2, void * outState )
{	
	OSStatus		err;
	
	// Set up user client if not already set up.
	
	err = SetupUserClient();
	if( err != noErr ) goto exit;
	
	// RPC to the kernel.
	
	err = IOConnectMethodScalarIStructO( gDataPort, kGetStateIndex, 2, kAOAUserClientStructSize, selector, target, outState );
	if( err != noErr ) goto exit;
	
exit:
	return( err );
}

//===========================================================================================================================
//	setState
//===========================================================================================================================

OSStatus	setState( UInt32 selector, UInt32 target, UInt32 arg2 void * inState )
{	
	OSStatus		err;
	
	// Set up user client if not already set up.
	
	err = SetupUserClient();
	if( err != noErr ) goto exit;
	
	// RPC to the kernel.
	
	err = IOConnectMethodScalarIStructI( gDataPort, kSetStateIndex, 2, kAOAUserClientStructSize, selector, target, inState );
	if( err != noErr ) goto exit;
	
exit:
	return( err );
}

//===========================================================================================================================
//	getCurrentSampleFrame
//===========================================================================================================================

OSStatus	getCurrentSampleFrame( UInt32 selector, UInt32 * outCurrentSampleFrame )
{
	OSStatus		err;
	
	// Set up user client if not already set up.
	
	err = SetupUserClient();
	if( err != noErr ) goto exit;
	
	// RPC to the kernel.
	
	err = IOConnectMethodScalarIScalarO( gDataPort, kgpiogetAddressIndex, 2, selector, outCurrentSampleFrame );
	if( err != noErr ) goto exit;
	
exit:
	return( err );
}
#endif
