/*!--------------------------------------------------------------------------
 * \file	foo.c
 * \brief	Example driver for interrupt handling.
 */
/* © Copyright 2003, Logic Product Development, Inc. All Rights Reserved.
 *
 * NOTICE:
 *  This file contains source code, ideas, techniques, and information
 *  (the Information) which are Proprietary and Confidential Information
 *  of Logic Product Development, Inc.  This Information may not be used
 *  by or disclosed to any third party except under written license, and
 *  shall be subject to the limitations prescribed under license.
 *
 *-------------------------------------------------------------------------*/


#include <Windows.h>
#include <Pkfuncs.h>
#include <types.h>
#include <memory.h>
#include <nkintr.h>
#include <Ceddk.h>
#include <giisr.h>
#include "foo.h"
#include "registry.h"
#include "debug_zones.h"


DBGPARAM dpCurSettings = {
    TEXT("CAN"), {
        TEXT("Init"),TEXT("Open"),TEXT("Read"),TEXT("Write"),
        TEXT("Close"),TEXT("Ioctl"),TEXT("Thread"),TEXT("Events"),
        TEXT("CritSec"),TEXT("FlowCtrl"),TEXT("Infrared"),TEXT("User Read"),
        TEXT("Alloc"),TEXT("Function"),TEXT("Warning"),TEXT("Error")},
    0xffff
};


PVOID MmMapIoSpace(PHYSICAL_ADDRESS,ULONG,BOOLEAN);

/*
 * Required Function entry points for a "stream" Interface DLL
 */
BOOL DllMain(HANDLE hinstDLL, DWORD Op, LPVOID lpvReserved);
DWORD FOO_Init(DWORD Registry);
BOOL FOO_Deinit(DWORD DeviceContext);
DWORD FOO_Open(DWORD DeviceContext, DWORD AccessCode, DWORD ShareMode);
BOOL FOO_Close(DWORD DeviceContext);
DWORD FOO_Read(DWORD Handle, LPVOID Buffer, DWORD Count);
DWORD FOO_Write(DWORD Handle, LPCVOID Source, DWORD Count);
DWORD FOO_Seek(DWORD Handle, long Amount, WORD Type);
BOOL FOO_IOControl(DWORD Handle, DWORD Code, PBYTE BufIn, DWORD LenIn,
				   PBYTE BufOut, DWORD LenOut, PDWORD ActOut);
VOID FOO_PowerDown(DWORD DeviceContext);
VOID FOO_PowerUp(DWORD DeviceContext);


/*
 * Local functions
 */
/* Foo Interrupt Service Routine - using generic installable isr */
VOID FOO_Install_ISR(DWORD RegistryPath, BYTE IRQValue, DWORD SysIntrValue);

/* Foo Interrupt Service Thread */
static ULONG FooInterruptThread(VOID);

/* Port configuration routine */
static VOID Configure_Port_Ints(DWORD);

/* Hardware memory mapping */
static BOOL map_registers(DWORD RegistryPath);


/* Unfortunately, this driver requires the use of several global variables.
 * These are declared here along with some critical sections designed to
 * protect access to them. */
static CRITICAL_SECTION global_vars_critical_sect;
static CRITICAL_SECTION hardware_critical_sect;
static BOOL global_initialized = FALSE;
static CRITICAL_SECTION v_StateCritSect;

static HANDLE hFooInterrupt = INVALID_HANDLE_VALUE;		// Handle to the Foo Interrupt event.
static HANDLE hFooUserEvent = INVALID_HANDLE_VALUE;		// Handle to the event used to signal user processes.
static HANDLE hFooInterruptThread = INVALID_HANDLE_VALUE;	// Handle to thread for Interrupt event.
static DWORD FooIntr	= SYSINTR_NOP;  // Interrupt number
static DWORD dGlobalFlags = 0;

#define LOCK_STATE()  EnterCriticalSection(&v_StateCritSect);
#define UNLOCK_STATE()  LeaveCriticalSection(&v_StateCritSect);


/* This could be used for a chip's address base, or a specific register
 * Others could be added as needed.
 */
static volatile unsigned short *address_base	= NULL;





/*!--------------------------------------------------------------------------
 *
 * \brief	Entry for the Dll
 *
 *-------------------------------------------------------------------------*/
//
// Standard call to initiate a DLL
// For most drivers this is a no op section, actual
// initialization is done with the DriverEntry
//
BOOL __stdcall
DllMain(HANDLE hinstDLL, DWORD Op, LPVOID lpvReserved)
{
	switch (Op) {
	case DLL_PROCESS_ATTACH:
		DEBUGREGISTER(hinstDLL);
		FOOMSG(1, (TEXT("%s DllEntry : DLL_PROCESS_ATTACH\r\n"),
			DRVR_NAME));
		break;

	case DLL_PROCESS_DETACH:
		FOOMSG(1, (TEXT("%s DllEntry : DLL_PROCESS_DETACH\r\n"),
			DRVR_NAME));
		break;

	case DLL_THREAD_DETACH:
		break;

	case DLL_THREAD_ATTACH:
		break;

	default:
		break;
	}
	return TRUE;
}


/*++

Routine Description:

    This is the initialization routine for the Foo driver.  It is a
    "well known name" and is called by the OS when loaded.

    It creates an event which is associated with an interrupt.

    Queries the Registry to find out what IRQ to connect to.

    Creates an Interrupt service thread with a priority.

    Connects the primary functions to the driver.

    Initializes the Interrupt event.

Arguments:

    DriverObject - Pointer to driver object created by the system.

    RegistryPath - Path to the parameters for this driver in the registry.

Return Value:

    The Device Context Handle for this instance.  Example here does not
    support multiple instances of a driver.  Context handle would
    generally be related to either a construction of a class instance
    or the allocated memory structure to support multiple instances.
    The Context is passed to other stream functions to identify the
    particular instance.

--*/
DWORD
FOO_Init(DWORD RegistryPath)
{
	HKEY active_key = INVALID_HANDLE_VALUE;
	unsigned long irq, gpio_bit;
	unsigned long SysIntrValue;


	FOOMSG(ZONE_FUNCTION, (TEXT("%s +FOO_Init().\r\n"),
		DRVR_NAME));

	FOOMSG(ZONE_INIT | ZONE_FUNCTION, (TEXT("%s : Init (%s)\r\n"),
									   DRVR_NAME, (char *)RegistryPath));


	InitializeCriticalSection(&global_vars_critical_sect);
	InitializeCriticalSection(&hardware_critical_sect);
	global_initialized = TRUE;


	/* Open up the registry key which contains all of our configuration
	 * data. */
	active_key = get_active_reg_key(RegistryPath);
	if ( INVALID_HANDLE_VALUE == active_key )
		return (FALSE);
	FOOMSG(ZONE_INIT, (TEXT("%s Active_Key :%x.\r\n"),
		DRVR_NAME, active_key));

	/* Read the IRQ that the user wants us to use. */
	irq = read_irq_from_reg(active_key);
	if ( 0 == irq )
	{
		FOOMSG(ZONE_INIT|ZONE_ERROR|ZONE_WARN,
		(TEXT("%s Couldn't get valid irq from registry.\r\n"), DRVR_NAME));
		goto initialization_error;
	}

	/* Read the GPIO port pin that the interrupt is on. */
	gpio_bit = read_gpio_pin_from_reg(active_key);
	if ( gpio_bit > 31 )
	{
		FOOMSG(ZONE_INIT|ZONE_ERROR|ZONE_WARN,
		(TEXT("%s Couldn't get valid GpioIntPin from registry.\r\n"), DRVR_NAME));
		goto initialization_error;
	}

	/* map our hardware registers in*/
	if ( !map_registers(RegistryPath) )
	{
		FOOMSG(ZONE_INIT|ZONE_ERROR|ZONE_WARN,
		(TEXT("%s Error, couldn't map the registers\r\n"), DRVR_NAME));
		goto initialization_error;
	}

#if (CARD_ENGINE_SH7727_20 || CARD_ENGINE_SH7727_10)
	SysIntrValue = irq;
#else /* SH7760-10, LH7A404-11, LH7A400-10 */
	/* Get a valid SysIntr from the OAL. */
	KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR,
				(VOID *)(&irq), sizeof(irq),
				(VOID *)(&SysIntrValue), sizeof(SysIntrValue), NULL);
#endif

	if ( SYSINTR_UNDEFINED == SysIntrValue )
	{

		FOOMSG(ZONE_INIT|ZONE_ERROR|ZONE_WARN,
			(TEXT("%s Couldn't get valid SysIntr.\r\n"), DRVR_NAME));
		goto initialization_error;
	}
	else
	{
		FOOMSG(ZONE_INIT, (TEXT("%s Using SysIntr %d (%xh) for IRQ %d  (%xh).\r\n"),
		DRVR_NAME, SysIntrValue,SysIntrValue, irq,irq));
	}

	FooIntr = SysIntrValue;

	//
	// Create an event handle for an interrupt
	//
	hFooInterrupt = CreateEvent(NULL, FALSE, FALSE, NULL);
	if (hFooInterrupt == NULL)
		goto initialization_error;

	/*
	*  Initialize any hardware here if needed
	*/

	/* configure interrupt pins if needed */
	Configure_Port_Ints(gpio_bit);

//		EnterCriticalSection(hardware_critical_sect);
//		if ( !init_hardware() )
//		{
//			FOOMSG(ZONE_INIT|ZONE_ERROR|ZONE_WARN,
//			(TEXT("%s Error, initialize the hardware.\r\n"), DRVR_NAME));
//			goto initialization_error;
//		}
//		LeaveCriticalSection(hardware_critical_sect);


	//
	// Associate the Sysintr and event handle
	//
	if(!InterruptInitialize(FooIntr, hFooInterrupt, NULL, 0))
	{
		FOOMSG(ZONE_WARN, (TEXT("%s Couldn't Initialize interrupt.\r\n"), DRVR_NAME));
		goto initialization_error;
	}

	//
	// Create a thread to service the interrupt and set its priority
	//
	hFooInterruptThread =
		CreateThread((LPSECURITY_ATTRIBUTES)NULL,
					 			0,
								(LPTHREAD_START_ROUTINE)FooInterruptThread,
					 			NULL,
					 			0,
					 			NULL);
	if (hFooInterruptThread == NULL || hFooInterruptThread == INVALID_HANDLE_VALUE ) {
		FOOMSG(ZONE_INIT|ZONE_ERROR|ZONE_WARN,
			(TEXT("%s  Init : Failed to create IST\r\n"), DRVR_NAME));
		goto initialization_error;
	}

	// can't use "THREAD_PRIORTIY_HIGHEST" anymore since
	// those defines are mapped to the lowest 8 priority
	// levels available.
	// lets set the priority somewhere below 100
	SetThreadPriority(hFooInterruptThread, 95);


	//
	// Create an event handle to signal user process
	//
	hFooUserEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
	if (hFooUserEvent == NULL)
		goto initialization_error;


	FOO_Install_ISR(RegistryPath,(unsigned char)irq, FooIntr);


	FOOMSG(ZONE_INIT, (TEXT("%s -FOO_Init().\r\n"),
		DRVR_NAME));

	return (TRUE);


initialization_error:
	FOOMSG(ZONE_INIT, (TEXT("%s Initialization Error.\r\n"),
		DRVR_NAME));
	DeleteCriticalSection(&global_vars_critical_sect);
	DeleteCriticalSection(&hardware_critical_sect);

	/* Free any memory mapped registers. */
	if ( NULL != address_base )
		MmUnmapIoSpace((void *)address_base, sizeof(*address_base));

	/* Ensure that the global SysIntrs have an invalid value*/
	FooIntr			= SYSINTR_NOP;
	global_initialized	= FALSE;

	FOOMSG(ZONE_INIT, (TEXT("%s -FOO_Init().\r\n"),
		DRVR_NAME));

	return (FALSE);

}

static ULONG
FooInterruptThread(VOID)
{

/*If we're on the PXA270 Card Engine we'll need to reset the */
#if CARD_ENGINE_PXA270_10

	volatile GPIOREGS 		*gpio;
	PHYSICAL_ADDRESS phy_addr;
	static volatile unsigned short *pGPIOregs	= NULL;

		FOOMSG(ZONE_INIT,
			(TEXT("%s  IST (PXA): Entering Interrupt Service Thread\r\n"), DRVR_NAME));

	phy_addr.LowPart  = GPIO_BASE;
	phy_addr.HighPart = 0;
	pGPIOregs = MmMapIoSpace(phy_addr, GPIO_SIZE, FALSE);
	if (  NULL == pGPIOregs )
	{
		FOOMSG(ZONE_ERROR|ZONE_WARN,
			(TEXT("%s Error, couldn't map pGPIOregs.\r\n"), DRVR_NAME));
		return FALSE;
	}

	gpio = (volatile GPIOREGS  *)pGPIOregs;
#else /* End of if CARD_ENGINE_PXA270_10 */

		FOOMSG(ZONE_INIT,
			(TEXT("%s  IST : Entering Interrupt Service Thread\r\n"), DRVR_NAME));

#endif

	while ( !(dGlobalFlags & UNLOAD_THREADS) ) {
		WaitForSingleObject(hFooInterrupt, INFINITE);
		LOCK_STATE();
		FOOMSG(ZONE_EVENTS,
			(TEXT("%s  IST : Got hFooInterrupt, IST running..\r\n"), DRVR_NAME));

		/*
		 * The only thing we do in this driver is signal the named event
		 * that, possibly, the example User program (FooApp) is waiting on.
		 *
		 * NOTE: the processes waiting on this event are not guaranteed to
		 *		 run before this event happens again.  especially since this
		 *		 interrupt can happen very frequently and doesn't depend on
		 *		 anything.
		 */
		PulseEvent(hFooUserEvent);

		/* Hardcoded to clear IRQA on PXA270*/
#if CARD_ENGINE_PXA270_10
		/* If set, clear Edge Detect Status Register bit by writing Logic 1*/
		
		/* For IRQA*/
		if (gpio->gedr0 == DEF_GEDR0_PS012){
			FOOMSG(ZONE_EVENTS,
				(TEXT("%s  IST : PXA IRQA\r\n"), DRVR_NAME));
			gpio->gedr0 = DEF_GEDR0_PS012;
		}
		
        /* For IRQB */
        if (gpio->gedr0 == DEF_GEDR0_PS022){
			FOOMSG(ZONE_EVENTS,
				(TEXT("%s  IST : PXA IRQB\r\n"), DRVR_NAME));
        gpio->gedr0 = DEF_GEDR0_PS022;
		}
        
        /* For IRQC */
        if (gpio->gedr0 == DEF_GEDR0_PS027){
			FOOMSG(ZONE_EVENTS,
				(TEXT("%s  IST : PXA IRQC\r\n"), DRVR_NAME));
        gpio->gedr0 = DEF_GEDR0_PS027;
		}
        
        /* For IRQD */
        if (gpio->gedr3 == DEF_GEDR3_PS099){
			FOOMSG(ZONE_EVENTS,
				(TEXT("%s  IST : PXA IRQD\r\n"), DRVR_NAME));
        gpio->gedr3 = DEF_GEDR3_PS099;
        }
        
#endif
		InterruptDone(FooIntr);
		UNLOCK_STATE();
	}

	return TRUE;
}

BOOL
FOO_Deinit(DWORD DeviceContext)
{
		FOOMSG(ZONE_INIT,
			(TEXT("%s  Deinit : Entry\r\n"), DRVR_NAME));

	if (hFooInterrupt) {
		dGlobalFlags |= UNLOAD_THREADS;
		SetEvent(hFooInterrupt);
		CloseHandle(hFooInterrupt);
		hFooInterrupt = NULL;
	}

	DeleteCriticalSection(&v_StateCritSect);

	return (TRUE);
}

DWORD
FOO_Open(DWORD DeviceContext, DWORD AccessCode, DWORD ShareMode)
{
	FOOMSG(ZONE_INIT,
			(TEXT("%s  Open : Stub Entry\r\n"), DRVR_NAME));
	return (1);
}

BOOL
FOO_Close(DWORD DeviceContext)
{
	return (TRUE);
}

DWORD
FOO_Read(DWORD Handle, LPVOID Buffer, DWORD Count)
{
	/* insert code here to read from the
	 * peripheral chip data buffer and return
	 * to upper level parsing routines
	 */
	return (1);
}

DWORD
FOO_Write(DWORD Handle, LPCVOID Source, DWORD Count)
{
	/* insert code here to write data to the
	 * peripheral chip.
	 */
	return (1);
}

DWORD
FOO_Seek(DWORD Handle, long Amount, WORD Type)
{
	return (1);
}

/*
 * This allows the user to select which edge they want to receive
 * interrupt events on.
 *
 */
BOOL
FOO_IOControl(DWORD Handle,
			  DWORD Code,
			  PBYTE BufIn,
			  DWORD LenIn,
			  PBYTE BufOut,
			  DWORD LenOut,
			  PDWORD ActOut)
{

	DWORD dIoctlCode = 0;
	DWORD dBytesReturned;
	BOOL bRet;

  	switch (Code) {
	case SET_DATA_FILTER:
		FOOMSG(ZONE_IOCTL,
				(TEXT("%s  IOControl: custom IOCTL: %d\r\n"), DRVR_NAME,  Code));
		return TRUE;
		break;
	case NULL:
		return TRUE;
		break;
	default:
		FOOMSG(ZONE_WARN,
			(TEXT("%s  IOControl: unknown IOCTL: %d\r\n"), DRVR_NAME,  Code));
		break;
	}

	/*
	 * if we drop through, go ahead and call into the OAL - maybe they can
	 * handle it.
	 */
	bRet = KernelIoControl(dIoctlCode, NULL, 0, NULL, 0, &dBytesReturned);
	if (!bRet) {
		FOOMSG(ZONE_ERROR,
			(TEXT("%s  IOControl:  KernelIoControl failed\r\n"), DRVR_NAME));
		return FALSE;
	}

	return TRUE;
}

VOID
FOO_PowerDown(DWORD DeviceContext)
{
}

VOID
FOO_PowerUp(DWORD DeviceContext)
{
}

/*!--------------------------------------------------------------------------
 * FOO_Install_ISR
 * \brief	Initializes the ISR handler
 *
 * \b Purpose:
 *
 *	This function tells the OS to load the generic installable isr handler
 *	with parameters set to configure it for our use.
 *
 *-------------------------------------------------------------------------*/



VOID
FOO_Install_ISR(DWORD RegistryPath, BYTE IRQValue, DWORD SysIntrValue)
{

//	#define FOO_ISR_REG			TEXT("\\Drivers\\Builtin\\Foo")
//	#define FOO_INT_MASK		0x01		/* using bogus value to test */
//	#define IRQA_INT_REGISTER	0xAC000000	/* using bogus value to test */
	GIISR_INFO		isr_info;
	WCHAR 			*isr_dll;
	WCHAR 			*isr_handler;
	HANDLE          	hIsr=INVALID_HANDLE_VALUE;
	HKEY active_key = INVALID_HANDLE_VALUE;

	active_key = get_active_reg_key(RegistryPath);
	//
	//  Read the IsrDll and IsrHandler
	//
	isr_dll = read_isr_dll_from_reg(active_key);

	FOOMSG(1,(TEXT("%s Install_ISR - IRQ: %d , SysIntr: %d\r\n"),
		DRVR_NAME, IRQValue, SysIntrValue));

	if ( isr_dll )
	{
		FOOMSG(ZONE_INIT, (TEXT("%s Installable ISR DLL is %s.\r\n"),
			DRVR_NAME, (LPCTSTR)isr_dll));
	}

	/* Get the name of the ISR's interrupt handler from the registry. */
	isr_handler = read_isr_handler_from_reg(active_key);

	if ( isr_handler )
	{
		FOOMSG(ZONE_INIT,(TEXT("%s Installable ISR handler is %s.\r\n"),
			DRVR_NAME, (LPCTSTR)isr_handler));
	}


	//
	//  Load the installable ISR..
	//  And if it is GIISR (the helper or generic ISR) then it needs
	//  GIISR_INFO.
	//

	if ( ((WCHAR *)NULL != isr_dll) && ((WCHAR *)NULL != isr_handler) )
	{
		/* The user specified what look to be a valid DLL and handler
		 * name. Lets try and install the ISR. */
		hIsr =
		LoadIntChainHandler((LPCWSTR)isr_dll,
							(LPCWSTR)isr_handler,
							IRQValue); /*IRQValue is the interrupt line that is hooked in the OAL*/

		if (hIsr == NULL || hIsr == INVALID_HANDLE_VALUE )
		{
		FOOMSG(ZONE_ERROR,
			(TEXT("%s  Install_ISR : Error loading installable ISR [%s]!!!, Error Code: %u\r\n"),
					DRVR_NAME,  isr_dll, GetLastError() ));
			return;
		}
		{
			FOOMSG(ZONE_INIT,
			(TEXT("%s Install_ISR : LoadIntChainHandler() passed. ISR installed\r\n"), DRVR_NAME));
		}

		/* Fill in the information structure for the ISR. */
		isr_info.SysIntr			= SysIntrValue;
		/*
		*  Set CheckPort to FALSE, which will have the ISR return the SysIntr.
		*  If a register needs to be checked, it will need to be changed to
		*  TRUE and the PortAddress and Mask will need to be set up correctly
		*/
		isr_info.CheckPort		= FALSE;  							//This can be added to the registry
		isr_info.UseMaskReg	= FALSE;  							//This can be added to the registry
		isr_info.PortAddr			= 0x00000000;   								//This can be added to the registry
		isr_info.PortSize			= sizeof(DWORD);  				//This can be added to the registry
		isr_info.Mask				= 0x0000;					 				//This can be added to the registry


		if (!KernelLibIoControl(
					hIsr,
					IOCTL_GIISR_INFO,
					&isr_info,
					sizeof(isr_info),
					NULL,
					0,
					NULL))
		{
			FOOMSG(ZONE_ERROR,
			(TEXT("%s Install_ISR : Failed KernelLibIoControl() : ErrorCode [%u]\r\n"), DRVR_NAME, GetLastError()));
		}

	}
	else
	{
			FOOMSG(ZONE_INIT|ZONE_EVENTS,
			(TEXT("%s Install_ISR : ISR_Dll or ISR_Handler invalid\r\n"), DRVR_NAME));

	}
	/* Cleanup and return. */
	return;
}


/*-------------------------------------------------------------------------*/
/*!
 * \brief	Maps the hardware registers that we need to access.
 *
 * \b Purpose:
 *
 *	This function takes care of mapping all of the hardware registers that
 *	the driver needs to access.
 *
 * \return	TRUE upon success, FALSE otherwise.
 */
/*-------------------------------------------------------------------------*/
static
BOOL map_registers(DWORD RegistryPath)
{
	BOOL  ret_val;
	DWORD tmp;
	PHYSICAL_ADDRESS phy_addr;
	HKEY active_key = INVALID_HANDLE_VALUE;
	ret_val = TRUE;

	/* Open up the registry key which contains all of our configuration
	 * data. */

	active_key = get_active_reg_key(RegistryPath);
	if ( INVALID_HANDLE_VALUE == active_key )
		return (FALSE);
	FOOMSG(ZONE_INIT, (TEXT("%s Active_Key :%x.\r\n"),
		DRVR_NAME, active_key));

	/* Map each of the registers we are interested in. Note, we don't
	 * compare this to zero because we may very well wan't to set this
	 * to the base of Flash memory, which happens to be 0x00000000. */
	tmp = read_address_base_from_reg(active_key);
//	if ( tmp )
//	{
		phy_addr.LowPart  = tmp;
		phy_addr.HighPart = 0;
		address_base = MmMapIoSpace(phy_addr, sizeof(*address_base), FALSE);
		if (  NULL == address_base )
		{
			FOOMSG(ZONE_ERROR|ZONE_WARN,
				(TEXT("%s Error, couldn't map address_base.\r\n"), DRVR_NAME));
			ret_val = FALSE;
		}
		else
		{
			FOOMSG(ZONE_INIT|ZONE_ALLOC,
				(TEXT("%s Mapped address_base at 0x%x to 0x%x.\r\n"),
				DRVR_NAME, tmp, address_base));

		}
//	}
//	else
//	{
//		ret_val = FALSE;
//	}

	/* Clean up and return. */
	RegCloseKey(active_key);
	return (ret_val);

} /* end map_registers() */



/*-------------------------------------------------------------------------*/
/*!
 * \brief	Configures the port to enable interrupts.
 *
 * \b Purpose:
 *
 *	This function takes care of configuring an I/O port to enable the pin
 *		to interrupt and sets the interrupt type
 *
 * \return	none, void
 */
/*-------------------------------------------------------------------------*/

static VOID Configure_Port_Ints(DWORD gpio_bit){

#if (CARD_ENGINE_LHA400_10 || CARD_ENGINE_LHA404_11)
/* SH7760, SH7727 interrupts are dedicated, so only
 * need to set this up on LH7A40x systems
 */
	volatile GPIOREGS 		*gpio;
	PHYSICAL_ADDRESS phy_addr;
	static volatile unsigned short *pGPIOregs	= NULL;
	unsigned long bitmask;

	bitmask = 1 << gpio_bit;

	FOOMSG(ZONE_INIT, (TEXT("%s Configure Port Ints using Port bit %d, bitmask 0x%X.\r\n"),
		DRVR_NAME, gpio_bit, bitmask));

	phy_addr.LowPart  = GPIO_BASE;
	phy_addr.HighPart = 0;
	pGPIOregs = MmMapIoSpace(phy_addr, GPIO_SIZE, FALSE);
	if (  NULL == pGPIOregs )
	{
		FOOMSG(ZONE_ERROR|ZONE_WARN,
			(TEXT("%s Error, couldn't map pGPIOregs.\r\n"), DRVR_NAME));
		return;
	}


	gpio = (volatile GPIOREGS  *)pGPIOregs;

	/* set interrupts as level sensitive */
	gpio->inttype1 &=  ~bitmask;

	/* set interrupts as low level active */
	gpio->inttype2 &=  ~bitmask;

	/* disable debounce as we are level sensitive */
	gpio->gpiodb &=  ~bitmask;

	/* set pins as inputs */
	gpio->pfdd &=  ~bitmask;

	/* clear eoi bits */
	gpio->gpiofeoi |= bitmask;

	/* enable interrupts on portF */
	gpio->gpiointen |= bitmask;

	MmUnmapIoSpace((void *)pGPIOregs, GPIO_SIZE);

#endif /* closes #if (CARD_ENGINELHA400_10 || CARD_ENGINE_LHA404_11) */

#if CARD_ENGINE_PXA270_10

	volatile GPIOREGS 		*gpio;
	PHYSICAL_ADDRESS phy_addr;
	static volatile unsigned short *pGPIOregs	= NULL;

	phy_addr.LowPart  = GPIO_BASE;
	phy_addr.HighPart = 0;
	pGPIOregs = MmMapIoSpace(phy_addr, GPIO_SIZE, FALSE);
	if (  NULL == pGPIOregs )
	{
		FOOMSG(ZONE_ERROR|ZONE_WARN,
			(TEXT("%s Error, couldn't map pGPIOregs.\r\n"), DRVR_NAME));
		return;
	}

	gpio = (volatile GPIOREGS  *)pGPIOregs;

    /* IRQA is GPIO12 */
	/* IRQB is GPIO22 */
    /* IRQC is GPIO27 */
    /* IRQD is GPIO99 */
 
/* The following register writes perform the following:*/
/* Set GPIO pin as input */
/* Clear any alternate function so it is regular GPIO. */
/* Clear rising-edge detect and set falling-edge detect. */

/* Comment out the IRQs that should not be initialized */
/* Also, don't forget to do the same in FooInterruptThread() above!*/

 	/*For IRQA*/
	gpio->gpdr0 &= ~(DEF_GPDR0_PS012); 
 	gpio->gafr0_l &= ~(DEF_GAFR0L_AF012(3));
 	gpio->grer0 &= ~(DEF_GFER0_PS012);
	gpio->gfer0 |=  (DEF_GFER0_PS012);
	
	/* For IRQB */
	gpio->gpdr0 &= ~(DEF_GPDR0_PS022);
 	gpio->gafr0_u &= ~(DEF_GAFR0U_AF022(3));
 	gpio->grer0 &= ~(DEF_GFER0_PS022);
	gpio->gfer0 |=  (DEF_GFER0_PS022);

	/* For IRQC */
	gpio->gpdr0 &= ~(DEF_GPDR0_PS027);
 	gpio->gafr0_u &= ~(DEF_GAFR0U_AF027(3));
 	gpio->grer0 &= ~(DEF_GFER0_PS027);
	gpio->gfer0 |=  (DEF_GFER0_PS027);
	/*
	*/
	
	/* For IRQD */
	gpio->gpdr3 &= ~(DEF_GPDR3_PS099);
 	gpio->gafr3_l &= ~(DEF_GAFR3L_AF099(3));
 	gpio->grer3 &= ~(DEF_GFER3_PS099);
	gpio->gfer3 |=  (DEF_GFER3_PS099);
	
	MmUnmapIoSpace((void *)pGPIOregs, GPIO_SIZE);
	
#endif /* closes #if (CARD_ENGINE_PXA270_10) */

	return;
}


