/* 
 *   Creation Date: <2002/01/09 23:02:27 samuel>
 *   Time-stamp: <2002/01/20 21:54:11 samuel>
 *   
 *	<MolUserClient.cpp>
 *	
 *	
 *   
 *   Copyright (C) 2002 Samuel Rydh (samuel@ibrium.se)
 *   
 *   This program is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU General Public License
 *   as published by the Free Software Foundation
 *   
 */

#include "archinclude.h"

#include "MolUserClient.h"
#include "MolExt.h"

extern "C" {
#include "version.h"
#include "kernel_vars.h"
#include "misc.h"
#include "alloc.h"
#include <sys/systm.h>
}

#define super IOUserClient
OSDefineMetaClassAndStructors(MolUserClient, IOUserClient);


IOUserClient *
MolUserClient::withTask( task_t owning_task )
{
	MolUserClient *me = new MolUserClient;

	if( me && !me->initWithTask(owning_task) ){
		me->release();
		return 0;
	}
	return me;
}

bool
MolUserClient::initWithTask( task_t owning_task )
{
	if( !super::init() )
		return false;

	molTask = owning_task;
	sessId = -1;			// Not initialized yet
	kvarMap = 0;
	
	return true;	
}

void
MolUserClient::free()
{
	IOLog("MolUserClient::free\n");

	if( kvarMap )
		kvarMap->release();
	super::free();
}

bool
MolUserClient::start( IOService *_owner )
{
	IOLog("MolUserClient::start\n");

	if( !super::start(owner) )
		return false;

	isRunning = true;
	
	owner = (MolExt*)_owner;
	return true;
}

void
MolUserClient::stop( IOService *_owner )
{
	if( !isRunning )
		return;
	
	IOLog("MolUserClient::stop\n");

	if( kvarMap ) {
		kvarMap->release();
		kvarMap = 0;
	}
		
	destroy_session( sessId );
	sessId = -1;
	
	super::stop( _owner );
	isRunning = false;
}

IOReturn
MolUserClient::clientClose( void )
{
	IOLog("clientClose\n");
	clientDied();
	
	return kIOReturnSuccess;
}

IOReturn
MolUserClient::clientDied( void )
{
	IOLog("clientDied\n");

	stop( owner );
	detach( owner );
	
	return kIOReturnSuccess;
}

IOExternalMethod *
MolUserClient::getTargetAndMethodForIndex( IOService ** targetP, UInt32 index )
{
	static const IOExternalMethod methodTemplate[] = {
	  /* 0 */  { NULL, (IOMethod) &MolUserClient::ccGetMolModVersion, kIOUCScalarIScalarO,	0, 1 },
	  /* 1 */  { NULL, (IOMethod) &MolUserClient::ccInit, kIOUCScalarIScalarO, 		2, 0 },
	  /* 2 */  { NULL, (IOMethod) &MolUserClient::ccCleanup, kIOUCScalarIScalarO,		0, 0 },
	  /* 3 */  { NULL, (IOMethod) &MolUserClient::ccMapMregs, kIOUCScalarIScalarO,		0, 1 },
	  /* 4 */  { NULL, (IOMethod) &MolUserClient::ccTest, kIOUCScalarIScalarO,		1, 0 },
#if 0
	  /* 0 */  { NULL, (IOMethod) &MolExt::clientFunc0, kIOUCScalarIScalarO,	0, 0 },
	  /* 1 */  { NULL, (IOMethod) &MolExt::clientFunc1, kIOUCScalarIScalarO,	2, 0 },
	  /* 2 */  { NULL, (IOMethod) &MolExt::clientFunc2, kIOUCScalarIScalarO,	1, 1 },
	  /* 3 */  { NULL, (IOMethod) &MolExt::clientFunc3, kIOUCScalarIStructI, 	2, -1 },

	  /* 4 */  { NULL, (IOMethod) &MolExt::clientFunc4, kIOUCStructIStructO, 	-1, -1 },
	  /* 5 */  { NULL, (IOMethod) &MolExt::clientFunc5, kIOUCScalarIStructO, 	2, sizeof(int) },
	  /* 6 */  { NULL, (IOMethod) &MolExt::clientFunc6, kIOUCScalarIStructO, 	2, 0xffffffff },
#endif
	};

	IOLog("getTargetAndMethodForIndex %ld\n", index);
	if( index > (sizeof(methodTemplate) / sizeof(methodTemplate[0])))
		return( NULL );

	*targetP = this;
	return( (IOExternalMethod *)(methodTemplate + index) );
}


/************************************************************************/
/*	Client Functions						*/
/************************************************************************/
#define CHECK_SESS_ID	if( sessId < 0 ) return kIOReturnError

IOReturn
MolUserClient::ccGetMolModVersion( int *ret )
{
	IOLog("MolUserClient::ccGetModVersion\n");
	*ret = MOL_VERSION;
	return kIOReturnSuccess;
}

IOReturn
MolUserClient::ccInit( int wanted_sess_id, int sess_magic )
{
	int ret;
	IOLog("MolUserClient::ccInit\n");

	if( !(ret=initialize_session( wanted_sess_id, sess_magic )) )
		sessId = wanted_sess_id;
	return ret;
}

IOReturn
MolUserClient::ccCleanup()
{
	IOLog("MolUserClient::ccCleanup\n");

	stop( owner );
	detach( owner );
	IOLog("MolUserClient::Out\n");
	return kIOReturnSuccess;
}

IOReturn
MolUserClient::ccMapMregs( char **ret_addr ) 
{
	IOLog("MolUserClient::ccMapMregs\n");	
	CHECK_SESS_ID;
	kernel_vars_t *kv = g_sesstab->kvars[sessId];

	if( !kvarMap ) {
		IOMemoryDescriptor *desc;
		int size = (sizeof(mac_regs_t) + 0xfff) / 0x1000;
		if( !(desc = IOMemoryDescriptor::withAddress( &kv->mregs, size, kIODirectionOutIn )) ) {
			return kIOReturnError;
		}
		kvarMap = desc->map( molTask, NULL, kIOMapAnywhere | kIOMapCopybackCache );
		desc->release();
	}
	if( !kvarMap ){
		return kIOReturnError;
	}

	*ret_addr = (char*)kvarMap->getVirtualAddress();
	return kIOReturnSuccess;
}

IOReturn
MolUserClient::ccTest( ulong value )
{
	CHECK_SESS_ID;
	return kIOReturnSuccess;
}



