#include <I2CHwCtxt.h>
#include <oal_i2cemul.h>
#include <stdlib.h>
#include <drvmsg.h>

//===== DEBUGGING MACRO DEFINITION =============================================================================
//#define TEST_MODE
#define TEST_IST	FALSE
//==============================================================================================================

//===== MACRRO DEFINITION ======================================================================================
//#define SDA_SETUP_TIME

#define DIVIDE_BY_16_SEL  	0
#define DIVIDE_BY_512_SEL 	1

#define ARBITRATION_FLAS 	(1<<3)
#define MATCHED_SADDR_FLAG	(1<<2)
#define ZERO_SADDR_FLAG		(1<<1)
#define ACK_NOT_RCVD_FLAG	(1<<0)

#define PRIO				(dwFIFOIdx-1)
#define CURR				(dwFIFOIdx)
#define NEXT				(dwFIFOIdx+1)
#define NEXT_NEXT			(dwFIFOIdx+2)

#define rIICCON				pI2CReg->IICCON
#define rIICSTAT			pI2CReg->IICSTAT
#define rIICDS				pI2CReg->IICDS
#define rIICLC				pI2CReg->IICLC

#define M_IDLE          	0x00    // Disable Rx/Tx
#define M_ACTIVE        	0x10    // Enable  Rx/Tx
#define MTX_START       	0xF0    // Master Tx Start
#define MTX_STOP        	0xD0    // Master Tx Stop
#define MRX_START       	0xB0    // Master Rx Start
#define MRX_STOP        	0x90    // Master Rx Stop

#define EDID_SEGMENT_ADDR   (0x60)
//==============================================================================================================

//===== GLOBAL VARIABLE DECLARTION =============================================================================
//==============================================================================================================

//===== LOCAL FUNCTION DECLARTION ==============================================================================
VOID CallI2CInterruptThread(I2CHWContext *pHWContext);
//==============================================================================================================

//===== IST TIME OUT ==============================================================================
int IST_TIMEOUT = 500; // suryeon.lim 20090407
//==============================================================================================================

//===== EXTERN FUNCTION DECLARTION =============================================================================
//==============================================================================================================
I2CObject::I2CObject()
{
	DBGMSG(IIC_FUNC, (L"[I2C:F] +++ I2CObject::I2CObject()\r\n"));
	
	Init();

	InitializeCriticalSection(&I2COB_CS);
	
	DBGMSG(IIC_FUNC, (L"[I2C:F] --- I2CObject::I2CObject()\r\n"));	
}

I2CObject::~I2CObject()
{
	DBGMSG(IIC_FUNC, (L"[I2C:F] +++ I2CObject::~I2CObject()\r\n"));
	
	do
	{
		DeleteCriticalSection(&I2COB_CS);
	} while(FALSE);
	
	DBGMSG(IIC_FUNC, (L"[I2C:F] --- I2CObject::~I2CObject()\r\n"));
}

VOID		
I2CObject::Init(VOID)
{
	wSlaveAddr 		= DEFAULT_SLAVE_ADDR;
	Mode			= I2CMODE_END;

	dwFIFOIdxCnt	= 0;

	pTxBuffer		= NULL;
	dwTxCount		= 0;
	pRxBuffer		= NULL;
	dwRxCount		= 0;		

	ClrStateFIFO();
}

DWORD		
I2CObject::Init(BOOL bEmulation, WORD wSlaveAddr, DWORD dwTempClockSpeed)
{
	Init();
	
	this->bEmulation = bEmulation;
	
	SetSlaveAddr(wSlaveAddr);
	SetClockSpeed(dwTempClockSpeed);

	bInitialized = TRUE;
	
	return dwClockSpeed;
}

VOID
I2CObject::SetClockSpeed(DWORD dwTempClockSpeed)
{
	DWORD dwTarget, dwTemp1, dwTemp2, dwTemp3;

	DBGMSG(IIC_FUNC, (L"[I2C_HW:F] +++ I2CObject::SetClockSpeed()\r\n"));

	if(bEmulation)
	{
		dwClockSpeed = dwTempClockSpeed;
	}
	else
	{
		if(dwTempClockSpeed >= ((SXXXXXX_PCLK/1000)/256))
		{
			dwClockPSSelBit = DIVIDE_BY_16_SEL;
			dwTarget = (SXXXXXX_PCLK/1000)/16;
			DBGMSG(IIC_INFO, (L"[I2C_HW:I] PRESCALE : DIVIDE_BY_16_SEL\r\n"));
		}
		else
		{
			dwClockPSSelBit = DIVIDE_BY_512_SEL;
			dwTarget = (SXXXXXX_PCLK/1000)/512;
			DBGMSG(IIC_INFO, (L"[I2C_HW:I] PRESCALE : DIVIDE_BY_512_SEL\r\n"));
		}

		dwTemp1 = 0xFFFFFFFF;
		dwClockSpeed = 0;
		dwClockValue = 0;
		for(DWORD i=0; i<16; i++)
		{
			dwTemp3 = dwTarget/(i+1);
			dwTemp2 = abs(dwTempClockSpeed - dwTemp3);
			if( (dwTemp1 >  dwTemp2) && (dwTemp3 <= dwTempClockSpeed) )
			{
				dwTemp1 = dwTemp2;
				dwClockValue = i;
				dwClockSpeed = dwTemp3;
				DBGMSG(IIC_INFO, (L"[I2C_HW:I] *SCALE[%d] : %dKhz\r\n", i, dwTemp3));
			}
			else
				DBGMSG(IIC_INFO, (L"[I2C_HW:I] SCALE[%d] : %dKhz\r\n", i, dwTemp3));
		}
	}

	DBGMSG(IIC_FUNC, (L"[I2C_HW:F] --- I2CObject::SetClockSpeed()\r\n"));
}

BOOL 		
I2CObject::SetSlaveAddr(WORD wAddr)
{
	DBGMSG(IIC_FUNC, (L"[I2C:F] +++ I2CObject::SetSlaveAddr()\r\n"));

	if((wAddr & GENERAL_ADDR_MASK) == GENERAL_ADDR)
	{
		ERRMSG((L"[I2C:E] UNSUPPORTABLE GERNERAL_ADDR\r\n"));
		return FALSE;
	}
	else if((wAddr & START_BYTE_MASK) == START_BYTE)
	{
		ERRMSG((L"[I2C:E] UNSUPPORTABLE START_BYTE\r\n"));
		return FALSE;
	}
	else if((wAddr & CBUS_ADDR_MASK) == CBUS_ADDR)
	{
		ERRMSG((L"[I2C:E] UNSUPPORTABLE CBUS_ADDR\r\n"));
		return FALSE;
	}
	else if((wAddr & FOR_OTHER_BUS_MASK) == FOR_OTHER_BUS)
	{
		ERRMSG((L"[I2C:E] UNSUPPORTABLE FOR_OTHER_BUS\r\n"));
		return FALSE;
	}
	else if((wAddr & FOR_FUTURE1_MASK) == FOR_FUTURE1)
	{
		ERRMSG((L"[I2C:E] UNSUPPORTABLE FOR_FUTURE1\r\n"));
		return FALSE;
	}
	else if((wAddr & HS_MODE_MASK) == HS_MODE)
	{
		ERRMSG((L"[I2C:E] UNSUPPORTABLE HS_MODE\r\n"));
		return FALSE;
	}
	else if((wAddr & FOR_FUTURE2_MASK) == FOR_FUTURE2)
	{
		ERRMSG((L"[I2C:E] UNSUPPORTABLE FOR_FUTURE2\r\n"));
		return FALSE;
	}
	else if((wAddr & TEN_BIT_ADDR_MASK) == TEN_BIT_ADDR)
	{
		ERRMSG((L"[I2C:E] UNSUPPORTABLE TEN_BIT_ADDR\r\n"));
		return FALSE;
	}
	else 
	{
		wSlaveAddr = (wAddr & 0xFE);
		DBGMSG(IIC_INFO, (L"[I2C:I] Slave Address : 0x%X \r\n", wSlaveAddr));
		return TRUE;
	}

	DBGMSG(IIC_FUNC, (L"[I2C:F] --- I2CObject::SetSlaveAddr()\r\n"));	
}

BOOL		
I2CObject::IsValidFIFOIdxCnt(VOID) 
{
	if(dwFIFOIdxCnt >= I2C_STATE_MAX) return FALSE;
	return TRUE;
}	

VOID		
I2CObject::ClrStateFIFO(VOID)
{
	dwFIFOIdxCnt = 0;
	for(DWORD i=0; i<I2C_STATE_MAX; ++i) 
	{
		StateFIFO[i].State 		= I2CSTATE_UNDEFINED;
		StateFIFO[i].pbtData 	= NULL;
        StateFIFO[i].btData     = 0;
        StateFIFO[i].dwTime     = 0;
	}

	pTxBuffer = NULL;
	dwTxCount = 0;
	pRxBuffer = NULL;
	dwRxCount = 0;		
}

I2CObject& 
I2CObject::Begin(VOID)
{
	DBGMSG(IIC_FUNC, (L"[I2C:F] +++I2CObject::Begin(Slave Addr : 0x%X)\r\n", wSlaveAddr));

	if(!IsValidFIFOIdxCnt() || !bInitialized)
	{
		ERRMSG((L"[I2C:E] FIFO index count is INVALID or Initializing is INVALID\r\n"));
		bSuccess = FALSE;
		StateFIFO[dwFIFOIdxCnt].State = I2CSTATE_BEGIN | I2CERR_INVALID_INIT;
		return *this;
	}

	StateFIFO[dwFIFOIdxCnt].State = I2CSTATE_BEGIN;
	dwFIFOIdxCnt++;

	bSuccess = TRUE;

	DBGMSG(IIC_FUNC, (L"[I2C:F] ---I2CHWContext::Begin()\r\n"));
	return *this;
}

I2CObject& 
I2CObject::SetStartCustom(DWORD dwMode)
{	
	if(!bSuccess || !IsValidFIFOIdxCnt())
	{
		ERRMSG((L"[I2C_HW:E] Some error is occured before SetStart state\r\n"));
		bSuccess = FALSE;
		return *this;	
	}

	if((dwMode != I2CMODE_MASTER_READ) && (dwMode != I2CMODE_MASTER_WRITE))
	{
		ERRMSG((L"[I2C_HW:E] The mode should be I2CMODE_MASTER_READ or I2CMODE_MASTER_WRITE\r\n"));
		bSuccess = FALSE;
		return *this;	
	}

	StateFIFO[dwFIFOIdxCnt].State 	= I2CSTATE_START_CUSTOM;
	StateFIFO[dwFIFOIdxCnt].btData 	= (BYTE)dwMode;
	dwFIFOIdxCnt++;

	return *this;
}


I2CObject& 
I2CObject::SetStart(DWORD dwMode)
{	
	if(!bSuccess || !IsValidFIFOIdxCnt())
	{
		ERRMSG((L"[I2C_HW:E] Some error is occured before SetStart state\r\n"));
		bSuccess = FALSE;
		return *this;	
	}

	if((dwMode != I2CMODE_MASTER_READ) && (dwMode != I2CMODE_MASTER_WRITE))
	{
		ERRMSG((L"[I2C_HW:E] The mode should be I2CMODE_MASTER_READ or I2CMODE_MASTER_WRITE\r\n"));
		bSuccess = FALSE;
		return *this;	
	}

	StateFIFO[dwFIFOIdxCnt].State 	= I2CSTATE_START;
	StateFIFO[dwFIFOIdxCnt].btData 	= (BYTE)dwMode;
	dwFIFOIdxCnt++;

	if(bEmulation)
	{
		if(dwMode == I2CMODE_MASTER_WRITE)
		{
			StateFIFO[dwFIFOIdxCnt].State 	= I2CSTATE_SET_ADDR;
			StateFIFO[dwFIFOIdxCnt].btData 	= (BYTE)GetWriteSlaveAddr();
			dwFIFOIdxCnt++;
		}
		else
		{
			StateFIFO[dwFIFOIdxCnt].State 	= I2CSTATE_SET_ADDR;
			StateFIFO[dwFIFOIdxCnt].btData 	= (BYTE)GetReadSlaveAddr();
			dwFIFOIdxCnt++;
		}
	}

	return *this;
}

I2CObject& 
I2CObject::DetectSlave(VOID)
{
	StateFIFO[dwFIFOIdxCnt].State = I2CSTATE_SLAVE_DETECTION;
	dwFIFOIdxCnt++;

	
	return *this;
}

I2CObject& 
I2CObject::SetStop(VOID)
{	
	if(!bSuccess || !IsValidFIFOIdxCnt())
	{
		ERRMSG((L"[I2C_HW:E] Some error is occured before SetStop state\r\n"));
		bSuccess = FALSE;
		return *this;	
	}
	
	StateFIFO[dwFIFOIdxCnt].State = I2CSTATE_STOP;
	dwFIFOIdxCnt++;

	return *this;
}

I2CObject& 
I2CObject::SetData(VOID)
{
	if(!bSuccess || !IsValidFIFOIdxCnt())
	{
		ERRMSG((L"[I2C_HW:E] Some error is occured before SetData state\r\n"));
		bSuccess = FALSE;
		return *this;	
	}
	
	StateFIFO[dwFIFOIdxCnt].State 	= I2CSTATE_SET_DATA;
	dwFIFOIdxCnt++;

	return *this;
}

I2CObject& 
I2CObject::GetData(VOID)
{
	if(!bSuccess || !IsValidFIFOIdxCnt())
	{
		ERRMSG((L"[I2C_HW:E] Some error is occured before GetData state\r\n"));
		bSuccess = FALSE;
		return *this;	
	}

	StateFIFO[dwFIFOIdxCnt].State 	= I2CSTATE_GET_DATA;
	dwFIFOIdxCnt++;
	
	return *this;
}

I2CObject& 	
I2CObject::GetACK(PBYTE pbtACK)
{
	if(!bSuccess || !IsValidFIFOIdxCnt())
	{
		ERRMSG((L"[I2C_HW:E] Some error is occured before GetACK state\r\n"));
		bSuccess = FALSE;
		return *this;	
	}

	StateFIFO[dwFIFOIdxCnt].State 	= I2CSTATE_GET_ACK;
	StateFIFO[dwFIFOIdxCnt].pbtData = pbtACK;
	dwFIFOIdxCnt++;
	
	return *this;
}

I2CObject& 	
I2CObject::SetACK()
{
	if(!bSuccess || !IsValidFIFOIdxCnt())
	{
		ERRMSG((L"[I2C_HW:E] Some error is occured before SetACK state\r\n"));
		bSuccess = FALSE;
		return *this;	
	}

	if(bEmulation)
	{
		StateFIFO[dwFIFOIdxCnt].State = I2CSTATE_SET_ACK;
		dwFIFOIdxCnt++;	
	}
	else
	{
		StateFIFO[dwFIFOIdxCnt].State 	= StateFIFO[dwFIFOIdxCnt-1].State;
		StateFIFO[dwFIFOIdxCnt-1].State = I2CSTATE_SET_ACK;
		dwFIFOIdxCnt++;	
	}

	return *this;
}

I2CObject& 
I2CObject::SetNAK()
{
	if(!bSuccess || !IsValidFIFOIdxCnt())
	{
		ERRMSG((L"[I2C_HW:E] Some error is occured before SetNAK state\r\n"));
		bSuccess = FALSE;
		return *this;	
	}

	if(bEmulation)
	{
		StateFIFO[dwFIFOIdxCnt].State = I2CSTATE_SET_NAK;
		dwFIFOIdxCnt++;	
	}
	else
	{
		StateFIFO[dwFIFOIdxCnt].State 	= StateFIFO[dwFIFOIdxCnt-1].State;	
		StateFIFO[dwFIFOIdxCnt-1].State = I2CSTATE_SET_NAK;
		dwFIFOIdxCnt++;
	}
	
	return *this;
}

I2CObject& 
I2CObject::SetLoop(BYTE dwGoBackCnt, DWORD dwLoopCnt)
{
	if(!bSuccess || !IsValidFIFOIdxCnt())
	{
		ERRMSG((L"[I2C_HW:E] Some error is occured before GetData state\r\n"));
		bSuccess = FALSE;
		return *this;	
	}

	StateFIFO[dwFIFOIdxCnt].State  = I2CSTATE_SET_LOOP;
	StateFIFO[dwFIFOIdxCnt].btData = dwGoBackCnt + 1;
	StateFIFO[dwFIFOIdxCnt].dwTime = dwLoopCnt;
	dwFIFOIdxCnt++;
	
	return *this;
}

I2CObject& 	
I2CObject::WaitToReady(DWORD dwTimeToWait, PBOOL pbSlaveReady)
{
	if(!bSuccess || !IsValidFIFOIdxCnt())
	{
		ERRMSG((L"[I2C_HW:E] Some error is occured before WaitToReady state\r\n"));
		bSuccess = FALSE;
		return *this;	
	}

	StateFIFO[dwFIFOIdxCnt].State   = I2CSTATE_WAIT_TO_READY;
	StateFIFO[dwFIFOIdxCnt].pbtData = (PBYTE)pbSlaveReady;
	StateFIFO[dwFIFOIdxCnt].dwTime  = dwTimeToWait;
	dwFIFOIdxCnt++;
	
	return *this;		
}

BOOL 
I2CObject::End(VOID)
{
	DBGMSG(IIC_FUNC, (L"[I2C:F] +++I2CObject::End(Slave Addr : 0x%X)\r\n", wSlaveAddr));

	if(!bSuccess || !IsValidFIFOIdxCnt())
	{
		ERRMSG((L"[I2C_HW:E] Some error is occured before End state\r\n"));
		bSuccess = FALSE;
		return bSuccess;	
	}

	StateFIFO[dwFIFOIdxCnt].State   = I2CSTATE_END;
	dwFIFOIdxCnt++;

#ifdef TEST_MODE
	if(!CheckStateList()) 
	{
		ERRMSG((L"[I2C:F] STATE LIST IS INVALID\r\n"));
		PrintStateList();
		bSuccess = FALSE;
	}

	PrintStateList();
#endif

	DBGMSG(IIC_FUNC, (L"[I2C:F] ---I2CObject::End()\r\n"));
	
	return bSuccess;	
}

BOOL			
I2CObject::CheckStateList(VOID)
{
	DWORD dwTempIdx, end;

	do
	{
		if(StateFIFO[0].State != I2CSTATE_BEGIN)
		{
			StateFIFO[0].State |= I2CERR_INVALID_SEQUENCE;
			bSuccess = FALSE;
			break;
		}
		
		if(StateFIFO[1].State != I2CSTATE_START)
		{
			StateFIFO[1].State |= I2CERR_INVALID_SEQUENCE;
			bSuccess = FALSE;
			break;
		}
		
		if(StateFIFO[dwFIFOIdxCnt-1].State != I2CSTATE_END)
		{
			StateFIFO[dwFIFOIdxCnt-1].State |= I2CERR_INVALID_SEQUENCE;
			bSuccess = FALSE;
			break;
		}

		for(dwTempIdx=2, end = dwFIFOIdxCnt-1; dwTempIdx < end; ++dwTempIdx)
		{
			switch(StateFIFO[dwTempIdx].State)
			{
				case I2CSTATE_BEGIN:
					break;
				case I2CSTATE_END:
					break;
				case I2CSTATE_START:
					break;
				case I2CSTATE_SET_DATA:
					break;
				case I2CSTATE_GET_DATA:
					break;
				case I2CSTATE_GET_ACK:
					if(StateFIFO[dwTempIdx-1].State != I2CSTATE_SET_DATA)
					{
						StateFIFO[dwTempIdx].State |= I2CERR_INVALID_SEQUENCE;
						bSuccess = FALSE;
						goto EXIT;
					}
					break;					
				case I2CSTATE_SET_ACK:
				case I2CSTATE_SET_NAK:
					/*if(StateFIFO[dwTempIdx+1].State != I2CSTATE_GET_DATA)
					{
						StateFIFO[dwTempIdx].State |= I2CSTATE_ERROR_INVALID_SEQUENCE;
						bSuccess = FALSE;
						goto EXIT;
					}*/
					break;
				case I2CSTATE_STOP:
				case I2CSTATE_WAIT_TO_READY:
					break;
				default:
					break;
			
			}
		}
	} while(FALSE);

EXIT:

	return bSuccess;
}

VOID			
I2CObject::PrintStateList(VOID)
{
	if(bSuccess) 	DBGMSG(IIC_USR1, (L"\r\nVALID : "));
	else			DBGMSG(IIC_USR1, (L"\r\nINVALID : "));

	for(DWORD dwTempIdx=0 ; dwTempIdx < dwFIFOIdxCnt; ++dwTempIdx)
	{
		if(StateFIFO[dwTempIdx].State & I2CERR_ERROR_MASK) DBGMSG(IIC_USR1, (L"[E:0x%X]", StateFIFO[dwTempIdx].State));
		switch(StateFIFO[dwTempIdx].State & I2CSTATE_MASK)
		{
			case I2CSTATE_BEGIN:
				DBGMSG(IIC_USR1, (L"BEGIN + "));
				break;
			case I2CSTATE_START:
				DBGMSG(IIC_USR1, (L"S + "));
				break;
			case I2CSTATE_SET_ADDR:
				DBGMSG(IIC_USR1, (L"A + "));
				break;	
			case I2CSTATE_SLAVE_DETECTION:
				DBGMSG(IIC_USR1, (L"SD + "));
				break;		
			case I2CSTATE_SET_DATA:
				DBGMSG(IIC_USR1, (L"W + "));
				break;
			case I2CSTATE_GET_ACK:
				DBGMSG(IIC_USR1, (L"GET_ACK + "));
				break;
			case I2CSTATE_GET_DATA:
				DBGMSG(IIC_USR1, (L"R + "));
				break;
			case I2CSTATE_SET_ACK:
				DBGMSG(IIC_USR1, (L"SET_ACK + "));
				break;
			case I2CSTATE_SET_NAK:
				DBGMSG(IIC_USR1, (L"SET_NAK + "));
				break;
			case I2CSTATE_SET_LOOP:
				DBGMSG(IIC_USR1, (L"LP + "));
				break;	
			case I2CSTATE_STOP:
				DBGMSG(IIC_USR1, (L"P + "));
				break;
			case I2CSTATE_WAIT_TO_READY:
				DBGMSG(IIC_USR1, (L"WAIT + "));
				break;
			case I2CSTATE_END:	
				DBGMSG(IIC_USR1, (L"END"));
				break;
			default:
				break;
		
		}
	}

	DBGMSG(IIC_USR1, (L"\r\n"));
}

I2CCtrlContext::I2CCtrlContext()
{
	DBGMSG(IIC_FUNC, (L"[I2C:F] +++ I2CCtrlContext::I2CCtrlContext()\r\n"));

	pGPIOReg 			= NULL;	
	pCurrServObj		= NULL;
	
    dwChannel			= 0;
	dwSpeed				= 0;
	dwTxDataCount		= 0;
	dwRxDataCount		= 0;
	dwFIFOIdx			= 0;
	dwMethod			= I2C_METHOD_INTERRUPT;

	hI2CEvent			= 0;
	hI2CDoneEvent		= 0;
	hI2CThread			= 0;
	dwI2CThreadPriority = 100;
    LastError           = I2CERR_NO_ERROR;
	I2CThreadState		= I2C_THREAD_STATE_INVALID;
	bInitialized 			= FALSE;
	PowerState          		= D4;
	InitializeCriticalSection(&I2CHW_CS);

	DBGMSG(IIC_FUNC, (L"[I2C:F] --- I2CCtrlContext::I2CCtrlContext()\r\n"));
}

I2CCtrlContext::~I2CCtrlContext()
{
	DBGMSG(IIC_FUNC, (L"[I2C:F] +++ I2CCtrlContext::~I2CCtrlContext()\r\n"));
	
	DeleteCriticalSection(&I2CHW_CS);
	
	DBGMSG(IIC_FUNC, (L"[I2C:F] --- I2CCtrlContext::~I2CCtrlContext()\r\n"));	
}

DWORD 
I2CCtrlContext::I2CProcessException(LPEXCEPTION_POINTERS pException) 
{

	EXCEPTION_RECORD *pExceptionRecord;

	pExceptionRecord = pException->ExceptionRecord;

	while(pExceptionRecord != NULL) 
	{
	    	RETAILMSG(1, (TEXT("I2CBusDriver: Exception caught ExceptionCode:0x%08X, flags:0x%08X, Code Address 0x%08X \r\n"), 
	        pExceptionRecord->ExceptionCode, pExceptionRecord->ExceptionFlags,
	        pExceptionRecord->ExceptionAddress));

		switch(pExceptionRecord->ExceptionCode) 
		{
			case  EXCEPTION_ACCESS_VIOLATION :
				RETAILMSG(1, ((TEXT("        Exception: EXCEPTION_ACCESS_VIOLATION \r\n" ))));
				break;
			case  EXCEPTION_DATATYPE_MISALIGNMENT :
				RETAILMSG(1, ((TEXT("        Exception: EXCEPTION_DATATYPE_MISALIGNMENT \r\n" ))));
				break;
			case  EXCEPTION_BREAKPOINT :
				RETAILMSG(1, ((TEXT("        Exception: EXCEPTION_BREAKPOINT \r\n" ))));
				break;
			case  EXCEPTION_SINGLE_STEP :
				RETAILMSG(1, ((TEXT("        Exception: EXCEPTION_SINGLE_STEP \r\n" ))));
				break;
			case  EXCEPTION_ARRAY_BOUNDS_EXCEEDED :
				RETAILMSG(1, ((TEXT("        Exception: EXCEPTION_ARRAY_BOUNDS_EXCEEDED \r\n" ))));
				break;
			case  EXCEPTION_FLT_DENORMAL_OPERAND  :
				RETAILMSG(1, ((TEXT("        Exception: EXCEPTION_FLT_DENORMAL_OPERAND \r\n" ))));
				break;
			case  EXCEPTION_FLT_DIVIDE_BY_ZERO  :
				RETAILMSG(1, ((TEXT("        Exception: EXCEPTION_FLT_DIVIDE_BY_ZERO \r\n" ))));
				break;
			case  EXCEPTION_FLT_INEXACT_RESULT  :
				RETAILMSG(1, ((TEXT("        Exception: EXCEPTION_FLT_INEXACT_RESULT \r\n" ))));
				break;
			case  EXCEPTION_FLT_INVALID_OPERATION  :
				RETAILMSG(1, ((TEXT("        Exception: EXCEPTION_FLT_INVALID_OPERATION \r\n" ))));
				break;
			case  EXCEPTION_FLT_OVERFLOW :
				RETAILMSG(1, ((TEXT("        Exception: EXCEPTION_FLT_OVERFLOW \r\n" ))));
				break;
			case  EXCEPTION_FLT_STACK_CHECK :
				RETAILMSG(1, ((TEXT("        Exception: EXCEPTION_FLT_STACK_CHECK \r\n" ))));
				break;
			case  EXCEPTION_FLT_UNDERFLOW :
				RETAILMSG(1, ((TEXT("        Exception: EXCEPTION_FLT_UNDERFLOW \r\n" ))));
				break;
			case  EXCEPTION_INT_DIVIDE_BY_ZERO:
				RETAILMSG(1, ((TEXT("        Exception: EXCEPTION_INT_DIVIDE_BY_ZERO \r\n" ))));
				break;
			case  EXCEPTION_INT_OVERFLOW :
				RETAILMSG(1, ((TEXT("        Exception: EXCEPTION_INT_OVERFLOW \r\n" ))));
				break;
			case  EXCEPTION_PRIV_INSTRUCTION :
				RETAILMSG(1, ((TEXT("        Exception: EXCEPTION_PRIV_INSTRUCTION \r\n" ))));
				break;
			case  EXCEPTION_IN_PAGE_ERROR :
				RETAILMSG(1, ((TEXT("        Exception: EXCEPTION_IN_PAGE_ERROR \r\n" ))));
				break;
			case  EXCEPTION_ILLEGAL_INSTRUCTION :
				RETAILMSG(1, ((TEXT("        Exception: EXCEPTION_ILLEGAL_INSTRUCTION \r\n" ))));
				break;
			case  EXCEPTION_NONCONTINUABLE_EXCEPTION :
				RETAILMSG(1, ((TEXT("        Exception: EXCEPTION_NONCONTINUABLE_EXCEPTION \r\n" ))));
				break;
			case  EXCEPTION_STACK_OVERFLOW :
				RETAILMSG(1, ((TEXT("        Exception: EXCEPTION_STACK_OVERFLOW \r\n" ))));
				break;
			case  EXCEPTION_INVALID_DISPOSITION :
				RETAILMSG(1, ((TEXT("        Exception: EXCEPTION_INVALID_DISPOSITION \r\n" ))));
				break;
			case  EXCEPTION_GUARD_PAGE :
				RETAILMSG(1, ((TEXT("        Exception: EXCEPTION_GUARD_PAGE \r\n" ))));
				break;
			case  EXCEPTION_INVALID_HANDLE :
				RETAILMSG(1, ((TEXT("        Exception: EXCEPTION_INVALID_HANDLE \r\n" ))));
				break;
			default:
				RETAILMSG(1, ((TEXT("        Exception: UNKNOWN \r\n" ))));
		}

		if (pExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) 
		{
			if (pExceptionRecord->NumberParameters >= 2) 
			{
				// figure if this was a read or write and dump the virtual address
				if (pExceptionRecord->ExceptionInformation[0] == 0) 
				{
					RETAILMSG(1, (TEXT("        Read Access Exceptioned at VAddress : 0x%08X \r\n" ),pExceptionRecord->ExceptionInformation[1]));
				} 
				else 
				{
					RETAILMSG(1, (TEXT("        Write Access Exceptioned at VAddress : 0x%08X \r\n" ),pExceptionRecord->ExceptionInformation[1]));
				}
			} 
			else 
			{
				RETAILMSG(1, (TEXT(" EXCEPTION_ACCESS_VIOLATION raised but not enough parameters %d \r\n" ),pExceptionRecord->NumberParameters));
			}
		}
		pExceptionRecord = pExceptionRecord->ExceptionRecord;    
	}

	return EXCEPTION_EXECUTE_HANDLER;
}

I2CHWContext::I2CHWContext()
{
	DBGMSG(IIC_FUNC, (L"[I2C:F] +++ I2CHWContext::I2CHWContext()\r\n"));

	pI2CReg 			= NULL;
	pSYSCLKReg			= NULL;

	hI2CHWEvent 	= NULL;
	dwI2CSysIntr	= 0;

	DBGMSG(IIC_FUNC, (L"[I2C:F] --- I2CHWContext::I2CHWContext()\r\n"));
}

I2CHWContext::~I2CHWContext()
{
	DBGMSG(IIC_FUNC, (L"[I2C:F] +++ I2CHWContext::~I2CHWContext()\r\n"));

	DBGMSG(IIC_FUNC, (L"[I2C:F] --- I2CHWContext::~I2CHWContext()\r\n"));	
}

BOOL            
I2CHWContext::CreateI2CThread(VOID)
{
	DWORD dwIrq;
	BOOL bCreate = TRUE;

	DBGMSG(IIC_FUNC, (L"[I2C:F] +++I2CHWContext::CreateI2CThread()\r\n"));

	do
	{
		if(dwMethod == I2C_METHOD_INTERRUPT)
        {
			if(!(hI2CHWEvent = CreateEvent(0,FALSE,FALSE,NULL)))
			{
				bCreate = FALSE;
				ERRMSG((L"[I2C_HW:E] It's failed to create hI2CHWEvent\r\n"));
				break;
			}
			
			if(dwChannel == 0)
				dwIrq = SXXXXXX_IRQ_I2C0;
			else if(dwChannel == 1)
				dwIrq = SXXXXXX_IRQ_I2C1;
            else if(dwChannel == 2)
				dwIrq = SXXXXXX_IRQ_I2C2;
            else
				dwIrq = SXXXXXX_IRQ_I2C3;
			
			if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &dwIrq, sizeof(DWORD), &dwI2CSysIntr, sizeof(DWORD), NULL))
			{
				bCreate = FALSE;
				dwI2CSysIntr = SYSINTR_UNDEFINED;
				ERRMSG((L"[I2C_HW:E] It's failed to request to alloc I2C sysintr\r\n"));
				break;
			}	

			if( !InterruptInitialize(dwI2CSysIntr, hI2CHWEvent, NULL, 0) )
	    	{
				bCreate = FALSE;
				ERRMSG((L"[I2C_HW:E] Interrupt Initializing is failed\r\n"));
		        break;
	    	}
        }

		if ( (hI2CThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CallI2CInterruptThread, (LPVOID)this, 0, NULL)) == NULL)
    	{
			bCreate = FALSE;
			ERRMSG((L"[I2C_HW:E] Unable to create IST\r\n"));
			break;
    	}

		if(!CeSetThreadPriority(hI2CThread, dwI2CThreadPriority))
		{
			bCreate = FALSE;
			ERRMSG((L"[I2C_HW:E] Changing IIC Thread Priority is failed\n"));
			break;
		}	
	} while(FALSE);

	if(bCreate)
	{
		I2CThreadState = I2C_THREAD_STATE_INIT;
		DBGMSG(IIC_INFO, (L"[I2C:F] Creating I2C Thread is SUCCESS\r\n"));
	}
	else
		ERRMSG((L"[I2C:F] Creating I2C Thread is FAIL\r\n"));

	DBGMSG(IIC_FUNC, (L"[I2C:F] ---I2CHWContext::CreateI2CThread()\r\n"));

	return bCreate;
}

BOOL            
I2CHWContext::DestroyI2CThread(VOID)
{
	BOOL bDestroy = TRUE;

	DBGMSG(IIC_FUNC, (L"[I2C:F] +++I2CHWContext::DestroyI2CThread()\r\n"));

	do
	{
		if(dwMethod == I2C_METHOD_INTERRUPT)
		{
			InterruptDisable(dwI2CSysIntr);

			if (!KernelIoControl(IOCTL_HAL_RELEASE_SYSINTR, &dwI2CSysIntr, sizeof(dwI2CSysIntr), NULL, 0, NULL))
			{
				ERRMSG((L"[I2C_HW:E] It's failed to request to release I2C sysintr\r\n"));
				bDestroy = FALSE;
				break;
			}

			if(!CloseHandle(hI2CHWEvent))
			{
				ERRMSG((L"[I2C:E] It's failed to close hI2CHWEvent\r\n"));
				bDestroy = FALSE;
				break;
			}
		}
	
		if(!TerminateThread(hI2CThread, 0))
		{
			ERRMSG((L"Terminatting I2C Thread is failed\n"));
			bDestroy = FALSE;
			break;
		}

		if(!CloseHandle(hI2CThread))
		{
			ERRMSG((L"[I2C:E] It's failed to close hI2CThread\r\n"));
			bDestroy = FALSE;
			break;
		}
	}while(FALSE);

	if(bDestroy)
	{
		I2CThreadState = I2C_THREAD_STATE_INVALID;
		DBGMSG(1, (L"[I2C:F] Destroying I2C Thread is SUCCESS\r\n"));
	}
	else
		DBGMSG(1, (L"[I2C:F] Destroying I2C Thread is FAIL\r\n"));

	DBGMSG(IIC_FUNC, (L"[I2C:F] ---I2CHWContext::DestroyI2CThread()\r\n"));

	return bDestroy;
}

BOOL
I2CHWContext::Open(DWORD dwChannel, DWORD dwMethod, DWORD dwThreadPriority, WORD wSlaveAddr, PSXXXXXX_I2C_REG pI2CReg, PSXXXXXX_GPIO_REG pGPIOReg, PSXXXXXX_SYSCLK_REG pSYSCLKReg, PSXXXXXX_BSP_ARG pBSPArgs)
{
	DBGMSG(IIC_FUNC, (L"[I2C:F] +++I2CHWContext::Open()\r\n"));

	bInitialized = TRUE;

	this->pI2CReg 		= pI2CReg;
	this->pGPIOReg 		= pGPIOReg;	
	this->pSYSCLKReg	= pSYSCLKReg;
	this->dwChannel		= dwChannel;
	this->pBSPArgs		= pBSPArgs;
    this->dwMethod      = dwMethod;
    dwI2CThreadPriority = dwThreadPriority;

	if(dwChannel == 0)
	{
		Set_PinFunction(pGPIOReg, SXXXXXX_I2C0_SCL_GPIO);
		Set_PinFunction(pGPIOReg, SXXXXXX_I2C0_SDA_GPIO);
	}
	else if(dwChannel == 1)
	{
		Set_PinFunction(pGPIOReg, SXXXXXX_I2C1_SCL_GPIO);
		Set_PinFunction(pGPIOReg, SXXXXXX_I2C1_SDA_GPIO);
                Set_PinPullUD(pGPIOReg, SXXXXXX_I2C1_SCL_GPIO, sgip_PULL_DISABLE);   
                Set_PinPullUD(pGPIOReg, SXXXXXX_I2C1_SDA_GPIO, sgip_PULL_DISABLE);   
		
	}
    else if(dwChannel == 2)
	{
		Set_PinFunction(pGPIOReg, SXXXXXX_I2C2_SCL_GPIO);
		Set_PinFunction(pGPIOReg, SXXXXXX_I2C2_SDA_GPIO);
	}
    else
	{
		//Set_PinFunction(pGPIOReg, SXXXXXX_I2C3_SCL_GPIO);
		//Set_PinFunction(pGPIOReg, SXXXXXX_I2C3_SDA_GPIO);
	}

	do
	{
		if(	!I2CBUS_SetSlaveAddr(wSlaveAddr))
		{
			I2CBUS_SetSlaveAddr(DEFAULT_SLAVE_ADDR);
			ERRMSG((L"[I2C_HW:E] slave address of registry is invalid, but it's setted to default slave address 0x%X\r\n", DEFAULT_SLAVE_ADDR));
		}
	
		if(!(hI2CEvent = CreateEvent(0,FALSE,FALSE,NULL)))
		{
			bInitialized = FALSE;
			ERRMSG((L"[I2C_HW:E] It's failed to create hI2CEvent\r\n"));
			break;
		}

		if(!(hI2CDoneEvent = CreateEvent(0,FALSE,FALSE,NULL)))
		{
			bInitialized = FALSE;
			ERRMSG((L"[I2C_HW:E] It's failed to create hI2CDoneEvent\r\n"));
			break;
		}	

        if(!CreateI2CThread())
		{
			bInitialized = FALSE;
			ERRMSG((L"[I2C_HW:E] Creating I2C thread is failed\r\n"));
			break;
		}	
	} while(FALSE);

	DBGMSG(IIC_FUNC, (L"[I2C_HW:F] ---I2CHWContext::Open()\r\n"));
	
	return bInitialized;
}

BOOL
I2CHWContext::Close(VOID)
{
	BOOL bClose = TRUE;

	if(!bInitialized) return FALSE;

	do
	    {
		if(!DestroyI2CThread())
        {
        	bClose = FALSE;
			ERRMSG((L"[I2C_HW:E] Creating I2C thread is failed\r\n"));
	        break;
	    }

		if(!CloseHandle(hI2CEvent))
	    {
			ERRMSG((L"[I2C:E] It's failed to close hI2CEvent\r\n"));
			bClose = FALSE;
	        break;
	    }

		if(!CloseHandle(hI2CDoneEvent))
		{
			ERRMSG((L"[I2C:E] It's failed to close hI2CDoneEvent\r\n"));
			bClose = FALSE;
			break;
		}		

	} while(FALSE);
	
	return bClose;
}

VOID
I2CHWContext::PrintI2CRegList(VOID)
{
	DBGMSG(1, (L"\r\n[I2C:I] IICCON : 0x%X 0x%X\r\n", pI2CReg->IICCON, I2CReg.IICCON));	
	DBGMSG(1, (L"[I2C:I] IICSTAT : 0x%X 0x%X\r\n", pI2CReg->IICSTAT, I2CReg.IICSTAT));
	DBGMSG(1, (L"[I2C:I] IICLC : 0x%X 0x%X\r\n", pI2CReg->IICLC, I2CReg.IICLC));
	DBGMSG(1, (L"[I2C:I] IICDS : 0x%X 0x%X\r\n", pI2CReg->IICDS, I2CReg.IICDS));
}

BOOL			
I2CHWContext::PowerUp(VOID)
{
	DBGMSG(IIC_PM,(L"[I2C:PM] I2CHWContext::PowerUp%d+++\r\n", dwChannel));
    
    //+++MODIFY HERE FOR PORTING
    if(dwChannel == 0)
    {
        pSYSCLKReg->CLK_GATE.CLK_GATE_IP3 |= (0x1 << BP_CLK_IP_I2C0);
    }
    else if(dwChannel == 1)
    {
        pSYSCLKReg->CLK_GATE.CLK_GATE_IP3 |= (0x1 << BP_CLK_IP_I2C_HDMI_DDC);
    }
    else if(dwChannel == 2)
    {
        pSYSCLKReg->CLK_GATE.CLK_GATE_IP3 |= (0x1 << BP_CLK_IP_I2C2);
    }
    else
    {
        pSYSCLKReg->CLK_GATE.CLK_GATE_IP3 |= (0x1 << BP_CLK_IP_I2C_HDMI_PHY);
    }
    //---MODIFY HERE FOR PORTING
    
	dwSpeed	= 0;
	rIICSTAT = M_IDLE;
	rIICLC = 0x4;

	SetPowerState(D0);
	
	//---MODIFY HERE FOR PORTING
	DBGMSG(IIC_PM,(L"[I2C:PM] I2CHWContext::PowerUp%d---\r\n", dwChannel));
	return TRUE;
}

BOOL			
I2CHWContext::PowerDown(VOID)
{
	DBGMSG(IIC_PM,(L"[I2C:PM] I2CHWContext::PowerDown%d+++\r\n", dwChannel));

    //+++MODIFY HERE FOR PORTING
    

    //---MODIFY HERE FOR PORTING

	SetPowerState(D4);

	DBGMSG(IIC_PM,(L"[I2C:PM] I2CHWContext::PowerDown---\r\n", dwChannel));
	return TRUE;
}

BOOL			
I2CHWContext::StartTransfer(PI2CObject pServiceObj)
{
	DWORD dwResult;
	DBGMSG(IIC_USR3, (L"[I2C_HW:F] +++ I2CHWContext::StartTransfer(Slave Addr : 0x%X)\r\n", pServiceObj->GetSlaveAddr()));	

	do
	{
		bSuccess = TRUE;
		
		if(!bInitialized)
		{
			ERRMSG((L"[I2C_HW:E] I2C HW CONTEXT IS NOT INITIALIZED\r\n"));
			bSuccess = FALSE;
			break;
		}

		if(I2CThreadState != I2C_THREAD_STATE_INIT)
		{
			ERRMSG((L"[I2C_HW:E] Thread is already running(State : %d)\r\n", I2CThreadState));
			bSuccess = FALSE;
			I2CBUS_SetStop();
			I2CBUS_ClrIntrPending();
			PrintI2CRegList();
			DestroyI2CThread();
			CreateI2CThread();
			PowerDown();
			PowerUp();
			break;
		}
		
		/*if(GetPowerState() != D0)
		{
			ERRMSG((L"[I2C_HW:E] I2C Power State is not D0\r\n"));
			bSuccess = FALSE;
			break;
		}*/
		
		pCurrServObj = pServiceObj;
		dwTxDataCount = 0;
		dwRxDataCount = 0;	
		dwFIFOIdx = 1;

		I2CReg.IICCON = 0;
		I2CBUS_SetClockSpeed(&I2CReg, CurrServObj.GetClockPSSelBit(), CurrServObj.GetClockValue());
		I2CBUS_InterruptEnable(&I2CReg, TRUE);
		I2CBUS_AckEnable(&I2CReg, TRUE);

		if(CurrServObj[CURR].State == I2CSTATE_START)
		{
			if(CurrServObj[CURR].btData == I2CMODE_MASTER_WRITE)
			{
				I2CReg.IICDS = (CurrServObj.GetWriteSlaveAddr() & 0xFF);
				I2CReg.IICSTAT = MTX_START;
				if(CurrServObj.dwTxCount > (1024*64))  //Transfer 64K Data for 5M Camera FW Update  by sr.lim
				{
					DBGMSG(1, (L"[I2C_HW:F][SlaveAddr = 0x%x][dwCount=%d] \r\n",CurrServObj.GetSlaveAddr(),CurrServObj.dwTxCount));
					IST_TIMEOUT = 3500;
				}
			    else
					IST_TIMEOUT = 500;
			
			}
			else if(CurrServObj[CURR].btData == I2CMODE_MASTER_READ)
			{
				I2CReg.IICDS = (CurrServObj.GetReadSlaveAddr() & 0xFF);
				I2CReg.IICSTAT = MRX_START;
				if(CurrServObj.dwRxCount > (1024*64))  //Receive 64K Data for 5M Camera FW Update  by sr.lim
				{
					DBGMSG(1, (L"[I2C_HW:F][SlaveAddr = 0x%x][dwCount=%d] \r\n",CurrServObj.GetSlaveAddr(),CurrServObj.dwTxCount));
					IST_TIMEOUT = 3500;
				}
				else
					IST_TIMEOUT = 500;
			}
			else
			{
				ERRMSG((L"[I2C_HW:E] INVALID MODE SETTING\r\n"));
				CurrServObj[NEXT].State |= I2CERR_INVALID_SEQUENCE;
				bSuccess = FALSE;
				break;
			}
			dwFIFOIdx++;
		}		
		else if(CurrServObj[CURR].State == I2CSTATE_START_CUSTOM )
		{
			if(CurrServObj[CURR].btData == I2CMODE_MASTER_WRITE)
			{
				I2CReg.IICDS = (EDID_SEGMENT_ADDR & 0xFF);
				I2CReg.IICSTAT = MTX_START;
				if(CurrServObj.dwTxCount > (1024*64))  //Transfer 64K Data for 5M Camera FW Update  by sr.lim
				{
					DBGMSG(1, (L"[I2C_HW:F][SlaveAddr = 0x%x][dwCount=%d] \r\n",CurrServObj.GetSlaveAddr(),CurrServObj.dwTxCount));
					IST_TIMEOUT = 3500;
				}
			    else
					IST_TIMEOUT = 3000;  //if 500 I2C write timesout for EDID segment write (EDID read)
			
			}
			else if(CurrServObj[CURR].btData == I2CMODE_MASTER_READ)
			{
				I2CReg.IICDS = ((EDID_SEGMENT_ADDR + 0x1) & 0xFF);
				I2CReg.IICSTAT = MRX_START;
				if(CurrServObj.dwRxCount > (1024*64))  //Receive 64K Data for 5M Camera FW Update  by sr.lim
				{
					DBGMSG(1, (L"[I2C_HW:F][SlaveAddr = 0x%x][dwCount=%d] \r\n",CurrServObj.GetSlaveAddr(),CurrServObj.dwTxCount));
					IST_TIMEOUT = 3500;
				}
				else
					IST_TIMEOUT = 500;
			}
			else
			{
				ERRMSG((L"[I2C_HW:E] INVALID MODE SETTING\r\n"));
				CurrServObj[NEXT].State |= I2CERR_INVALID_SEQUENCE;
				bSuccess = FALSE;
				break;
			}
			dwFIFOIdx++;
		}		
		else
		{
			ERRMSG((L"[I2C_HW:E] UNRESOLVED STATE LIST\r\n"));
			CurrServObj[NEXT].State |= I2CERR_INVALID_SEQUENCE;
			bSuccess = FALSE;
			break;
		}

		DBGMSG(IIC_FUNC, (L"[I2C_HW:F] START IST(Channel : %d, Slave : 0x%X)\r\n", dwChannel, CurrServObj.GetSlaveAddr()));
		ResetEvent(hI2CEvent);
		ResetEvent(hI2CDoneEvent);
		SetEvent(hI2CEvent);			
		dwResult = WaitForSingleObject(hI2CDoneEvent, IST_TIMEOUT);
		
		if(dwResult == WAIT_FAILED)
		{
			ERRMSG((L"[I2C_HW:E] WaitForSingleObject : WAIT_FAILED\r\n"));
			LastError = I2CERR_WAIT_FAILED;
			bSuccess = FALSE;		
            if(CloseHandle(hI2CDoneEvent))
    		{
    		    hI2CDoneEvent = CreateEvent(0,FALSE,FALSE,NULL);
    		}	
            else
            {
                ERRMSG((L"[I2C_HW:E] hI2CDoneEvent can't be recreated\r\n"));
			bInitialized = FALSE;
            }
			break;
		}
		else if(dwResult == WAIT_TIMEOUT)
		{
			ERRMSG((L"[I2C_HW:E] WaitForSingleObject : WAIT_TIMEOUT(Slave Addr : 0x%X)\r\n", CurrServObj.GetSlaveAddr()));
			ERRMSG((L"[I2C_HW:E] INDEX : %d, STATE : %d\r\n", dwFIFOIdx, CurrServObj[dwFIFOIdx].State));
			ERRMSG((L"[I2C_HW:E] Thread State : %d\r\n", I2CThreadState));
			LastError = I2CERR_WAIT_TIMEOUT;
			bSuccess = FALSE;
			I2CBUS_SetStop();
			I2CBUS_ClrIntrPending();
            PrintI2CRegList();
			DestroyI2CThread();
			CreateI2CThread();
			PowerDown();
			PowerUp();
			break;
		}

		DBGMSG(IIC_FUNC, (L"[I2C_HW:F] END IST(Channel : %d, Slave : 0x%X)\r\n", dwChannel, CurrServObj.GetSlaveAddr()));	
	} while(FALSE);
	
	CurrServObj.ClrStateFIFO();		

	DBGMSG(IIC_USR3, (L"[I2C_HW:F] --- I2CHWContext::StartTransfer(Slave Addr : 0x%X)\r\n", pServiceObj->GetSlaveAddr()));

	pCurrServObj = NULL;

	return bSuccess;
}

VOID InternalBusyWaitForOneClock(DWORD dwArmClk, DWORD dwSpeed)
{
	DWORD dwBusyCount = (dwArmClk*250)/dwSpeed; //need 2 clock per one loop, therefore divide by 500
	dwBusyCount -= 10;
	while(dwBusyCount-- > 0);
}

VOID
CallI2CInterruptThread(I2CHWContext *pHWContext)
{
	if(pHWContext->GetMethod() == I2C_METHOD_INTERRUPT)
	    pHWContext->I2CInterruptThread();
	else
		pHWContext->I2CPollingThread();
}

VOID 
I2CHWContext::I2CInterruptThread(VOID)
{
	DWORD		dwIICSTAT;
	DWORD		dwCount;
	BOOL		bRequestComplete;
	BOOL		bExit;
	BYTE		btACK;

	DBGMSG(IIC_FUNC, (L"[IIC_IST:F] +++ I2C_IST()\r\n"));

	SetProcPermissions(0xFFFFFFFF);

	do
	{
		__try
		{
			if(WAIT_FAILED == WaitForSingleObject(hI2CEvent, INFINITE))
			{
				ERRMSG((L"[IIC_IST:E] WaitForSingleObject : WAIT_FAILED\r\n"));	
				break;
			}

			I2CThreadState = I2C_THREAD_STATE_READY;

			InterruptDone(dwI2CSysIntr);
			ResetEvent(hI2CHWEvent);

			rIICCON = I2CReg.IICCON;
			rIICSTAT = M_ACTIVE;
			rIICDS = I2CReg.IICDS;
			rIICSTAT = I2CReg.IICSTAT;

			bRequestComplete = FALSE;
			
			do
			{
				if(WAIT_FAILED == WaitForSingleObject(hI2CHWEvent, INFINITE))
				{
					ERRMSG((L"[IIC_IST:E] WaitForSingleObject : WAIT_FAILED\r\n"));	
					break;
				}

				I2CThreadState = I2C_TRHEAD_STATE_RUNNING;

				dwIICSTAT = pI2CReg->IICSTAT;

				if (dwIICSTAT & ARBITRATION_FLAS) 
				{
					ERRMSG((L"[IIC_IST:E] ARBITRATION_FLAS IS SETTED\r\n"));
				}

				if (dwIICSTAT & MATCHED_SADDR_FLAG) 
				{
					ERRMSG((L"[IIC_IST:E] MATCHED_SADDR_FLAG IS SETTED\r\n"));
				}

				if (dwIICSTAT & ZERO_SADDR_FLAG) 
				{
					ERRMSG((L"[IIC_IST:E] ZERO_SADDR_FLAG IS SETTED\r\n"));
				}

				do
				{
					//DBGMSG(TEST_IST, (L"[IIC_IST:I] STATE : %d, Index : %d\r\n", CurrServObj[CURR].State, dwFIFOIdx));
					bExit = FALSE;
					switch(CurrServObj[CURR].State)
					{
						case I2CSTATE_START_CUSTOM:
							DBGMSG(TEST_IST, (L"[IIC_IST:I] STATE(%d) : START\r\n", dwFIFOIdx));
     						        I2CBUS_SetData((BYTE) (EDID_SEGMENT_ADDR & 0xFF));
							rIICSTAT = MTX_START;
							rIICCON = I2CReg.IICCON;
							bExit = TRUE;
							break;

						case I2CSTATE_START:
							DBGMSG(TEST_IST, (L"[IIC_IST:I] STATE(%d) : START\r\n", dwFIFOIdx));
							if(CurrServObj[CURR].btData == I2CMODE_MASTER_WRITE)
							{
								I2CBUS_SetData((BYTE) (CurrServObj.GetWriteSlaveAddr() & 0xFF));
								rIICSTAT = MTX_START;
							}
							else
							{
								I2CBUS_SetData((BYTE) (CurrServObj.GetReadSlaveAddr() & 0xFF));
								rIICSTAT = MRX_START;
							}
							rIICCON = I2CReg.IICCON;
							bExit = TRUE;
							break;
						case I2CSTATE_SLAVE_DETECTION:	
							I2CBUS_GetACK(&btACK);
							if(btACK == I2C_NAK)
							{
								ERRMSG((L"[IIC_IST:E] SLAVE(0x%X) DETECTION IS FAILED & RECOVERY STAGE\r\n", CurrServObj.GetSlaveAddr()));
								bSuccess = FALSE;
								CurrServObj[NEXT].State = I2CSTATE_STOP;
								CurrServObj[NEXT_NEXT].State = I2CSTATE_END;
							}
							else
								DBGMSG(TEST_IST, (L"[IIC_IST:I] SLAVE DETECTION IS SUCCESS\r\n"));
							break;
						case I2CSTATE_SET_DATA:
							DBGMSG(TEST_IST, (L"[IIC_IST:I] STATE(%d) : SET_DATA(0x%x)\r\n", dwFIFOIdx, CurrServObj.pTxBuffer[dwTxDataCount]));
							I2CBUS_SetData(&CurrServObj.pTxBuffer[dwTxDataCount]);
							//FOR SDA SETUP TIME(require 250ns delay)
#ifdef SDA_SETUP_TIME
							for(volatile DWORD delay = 0; delay<10; ++delay);
#endif							
							dwTxDataCount++;
							I2CBUS_ClrIntrPending();
							bExit = TRUE;
							break;
						case I2CSTATE_GET_ACK:
							DBGMSG(TEST_IST, (L"[IIC_IST:I] STATE(%d) : GET_ACK\r\n", dwFIFOIdx));
							if(*CurrServObj[CURR].pbtData == I2C_ACK)
							{
								I2CBUS_GetACK(CurrServObj[CURR].pbtData);
								if(*CurrServObj[CURR].pbtData == I2C_NAK)
								{
									ERRMSG((L"[IIC_IST:E] 0x%x Slave didn't send ACK(%dth data phase), but it's pass\r\n", CurrServObj.GetSlaveAddr(), dwTxDataCount));
								}
							}
							break;
						case I2CSTATE_GET_DATA:
							I2CBUS_GetData(&CurrServObj.pRxBuffer[dwRxDataCount]);
							dwRxDataCount++;
							DBGMSG(TEST_IST, (L"[IIC_IST:I] STATE(%d) : GET_DATA(0x%x)\r\n", dwFIFOIdx, CurrServObj.pRxBuffer[dwRxDataCount-1]));
							break;
						case I2CSTATE_SET_ACK:
							DBGMSG(TEST_IST, (L"[IIC_IST:I] STATE(%d) : SET_ACK\r\n", dwFIFOIdx));
							I2CBUS_AckEnable(TRUE);
							I2CBUS_ClrIntrPending();
							bExit = TRUE;
							break;
						case I2CSTATE_SET_NAK:
							DBGMSG(TEST_IST, (L"[IIC_IST:I] STATE(%d) : SET_NAK\r\n", dwFIFOIdx));
							I2CBUS_AckEnable(FALSE);
							I2CBUS_ClrIntrPending();
							bExit = TRUE;
							break;
						case I2CSTATE_SET_LOOP:	
							DBGMSG(TEST_IST, (L"[IIC_IST:I] STATE(%d) : SET_LOOP\r\n", dwFIFOIdx));
							DBGMSG(TEST_IST, (L"[IIC_IST:I] BACK INDEX : %d, Time : %d\r\n", (dwFIFOIdx - CurrServObj[CURR].btData), CurrServObj[CURR].dwTime));
							if(CurrServObj[CURR].dwTime > 0)
							{
								CurrServObj[CURR].dwTime--;
								dwFIFOIdx -= CurrServObj[CURR].btData;
							}
							break;
						case I2CSTATE_STOP:
							DBGMSG(TEST_IST, (L"[IIC_IST:I] STATE(%d) : STOP\r\n", dwFIFOIdx));
							I2CBUS_SetStop();
							I2CBUS_ClrIntrPending();
							bRequestComplete = TRUE;
							bExit = TRUE;
							break;
						case I2CSTATE_WAIT_TO_READY:
							DBGMSG(TEST_IST, (L"[IIC_IST:I] STATE(%d) : WAIT(Count : %d, ArmClk : %d)\r\n", dwFIFOIdx, CurrServObj[CURR].dwTime, pBSPArgs->SystemClocks.ARM_CLK));
							if(*CurrServObj[CURR].pbtData == TRUE)
							{
								dwCount = CurrServObj[CURR].dwTime;
								while(dwCount)
								{
#if EMULATION_ENABLE
        							GeneralBusyWaitForOneClock(pBSPArgs->SystemClocks.ARM_CLK, CurrServObj.GetClockSpeed());
#else
                                    InternalBusyWaitForOneClock(pBSPArgs->SystemClocks.ARM_CLK, CurrServObj.GetClockSpeed());
#endif
									--dwCount;
								}
								*CurrServObj[CURR].pbtData = TRUE;
							}
							break;
						case I2CSTATE_BEGIN:
							DBGMSG(TEST_IST, (L"[IIC_IST:I] STATE(%d) : BEGIN\r\n", dwFIFOIdx));
							break;
						case I2CSTATE_END:
							DBGMSG(TEST_IST, (L"[IIC_IST:I] STATE(%d) : END\r\n", dwFIFOIdx));
							break;		
						case I2CSTATE_UNDEFINED:
							ERRMSG((L"[IIC_IST:E] UNDEFINED STATE & RECOVERY STAGE\r\n"));
                            LastError = I2CERR_UNKNOWN;
							bSuccess = FALSE;
							dwFIFOIdx = 0;
							CurrServObj[NEXT].State = I2CSTATE_STOP;
							CurrServObj[NEXT_NEXT].State = I2CSTATE_END;
							break;
						default:
							ERRMSG((L"[IIC_IST:E] UNKNOWN STATE & RECOVERY STAGE\r\n"));
                            LastError = I2CERR_UNKNOWN;
							bSuccess = FALSE;
							dwFIFOIdx = 0;
							CurrServObj[NEXT].State = I2CSTATE_STOP;
							CurrServObj[NEXT_NEXT].State = I2CSTATE_END;
							break;
					}
					dwFIFOIdx++;
				} while(!bExit);
				
				InterruptDone(dwI2CSysIntr);

			}while(!bRequestComplete);
		}__except(I2CProcessException(GetExceptionInformation()))
		{
			ERRMSG((L"EXCEPTION IS INVOKED(HW %d Channel)\r\n", dwChannel));
			ERRMSG((L"Fifo Index : %d\r\n", dwFIFOIdx));
			ERRMSG((L"bRequestComplete : %d\r\n", bRequestComplete));
			ERRMSG((L"Currnet Tx Count : %d\r\n", dwTxDataCount));
			ERRMSG((L"Currnet Rx Count : %d\r\n", dwRxDataCount));
			ERRMSG((L"Current Service Obj : 0x%X\r\n", pCurrServObj));
			if(pCurrServObj)
			{
				ERRMSG((L"Tx Data Addr & size : 0x%X %d\r\n", pCurrServObj->pTxBuffer, pCurrServObj->dwTxCount));
				ERRMSG((L"Rx Data Addr & size : 0x%X %d\r\n", pCurrServObj->pRxBuffer, pCurrServObj->dwRxCount));
			}
			bSuccess = FALSE;
			PrintI2CRegList();
			I2CBUS_SetStop();
			I2CBUS_ClrIntrPending();
		}

		I2CThreadState = I2C_THREAD_STATE_INIT;
		
		SetEvent(hI2CDoneEvent);
		
	}while(TRUE);

	bSuccess = FALSE;	
	bInitialized = FALSE;
	SetEvent(hI2CDoneEvent);
	ERRMSG((L"[IIC_IST:E] I2C IST TERMINATED\r\n"));
	DBGMSG(IIC_FUNC, (L"[IIC_IST:F] --- I2C_IST()\r\n"));
}

VOID 
I2CHWContext::I2CPollingThread(VOID)
{
	DWORD		dwIICSTAT;
	DWORD		dwCount;
	BOOL		bRequestComplete;
	BOOL		bExit;
	BYTE		btACK;

	DBGMSG(IIC_FUNC, (L"[IIC_IST:F] +++ I2C_IST()\r\n"));

	SetProcPermissions(0xFFFFFFFF);

	do
	{
		__try
		{
    		if(WAIT_FAILED == WaitForSingleObject(hI2CEvent, INFINITE))
    		{
    			ERRMSG((L"[IIC_IST:E] WaitForSingleObject : WAIT_FAILED\r\n"));	
    			break;
    		}
            
            I2CThreadState = I2C_THREAD_STATE_READY;
            
			rIICCON = I2CReg.IICCON;
			rIICSTAT = M_ACTIVE;
			rIICDS = I2CReg.IICDS;
			rIICSTAT = I2CReg.IICSTAT;

			bRequestComplete = FALSE;

			do
			{
				while(!I2CBUS_IsIntrPending());

                I2CThreadState = I2C_TRHEAD_STATE_RUNNING;

        		dwIICSTAT = pI2CReg->IICSTAT;

                if (dwIICSTAT & ARBITRATION_FLAS) 
                {
                	ERRMSG((L"[IIC_IST:E] ARBITRATION_FLAS IS SETTED\r\n"));
                }

                if (dwIICSTAT & MATCHED_SADDR_FLAG) 
        		{
        			ERRMSG((L"[IIC_IST:E] MATCHED_SADDR_FLAG IS SETTED\r\n"));
                }

                if (dwIICSTAT & ZERO_SADDR_FLAG) 
        		{
        			ERRMSG((L"[IIC_IST:E] ZERO_SADDR_FLAG IS SETTED\r\n"));
                }

        		do
        		{
        			//DBGMSG(TEST_IST, (L"[IIC_IST:I] STATE : %d, Index : %d\r\n", CurrServObj[CURR].State, dwFIFOIdx));
        			bExit = FALSE;
        			switch(CurrServObj[CURR].State)
        			{
        				case I2CSTATE_START:
        					DBGMSG(TEST_IST, (L"[IIC_IST:I] STATE(%d) : START\r\n", dwFIFOIdx));
        					if(CurrServObj[CURR].btData == I2CMODE_MASTER_WRITE)
        					{
        						I2CBUS_SetData((BYTE) (CurrServObj.GetWriteSlaveAddr() & 0xFF));
								rIICSTAT = MTX_START;
							}
        					else
							{
        						I2CBUS_SetData((BYTE) (CurrServObj.GetReadSlaveAddr() & 0xFF));
								rIICSTAT = MRX_START;
							}
							rIICCON = I2CReg.IICCON;
        					bExit = TRUE;
        					break;
        				case I2CSTATE_SLAVE_DETECTION:	
        					I2CBUS_GetACK(&btACK);
        					if(btACK == I2C_NAK)
        					{
        						ERRMSG((L"[IIC_IST:E] SLAVE DETECTION IS FAILED & RECOVERY STAGE\r\n"));
        						bSuccess = FALSE;
								CurrServObj[NEXT].State = I2CSTATE_STOP;
								CurrServObj[NEXT_NEXT].State = I2CSTATE_END;
        					}
        					else
        						DBGMSG(TEST_IST, (L"[IIC_IST:I] SLAVE DETECTION IS SUCCESS\r\n"));
        					break;
        				case I2CSTATE_SET_DATA:
        					DBGMSG(TEST_IST, (L"[IIC_IST:I] STATE(%d) : SET_DATA(0x%x)\r\n", dwFIFOIdx, CurrServObj.pTxBuffer[dwTxDataCount]));
        					I2CBUS_SetData(&CurrServObj.pTxBuffer[dwTxDataCount]);
        					//FOR SDA SETUP TIME(require 250ns delay)
#ifdef SDA_SETUP_TIME
        					for(volatile DWORD delay = 0; delay<10; ++delay);
#endif
        					dwTxDataCount++;
        					I2CBUS_ClrIntrPending();
        					bExit = TRUE;
        					break;
        				case I2CSTATE_GET_ACK:
        					DBGMSG(TEST_IST, (L"[IIC_IST:I] STATE(%d) : GET_ACK\r\n", dwFIFOIdx));
        					if(*CurrServObj[CURR].pbtData == I2C_ACK)
        					{
        						I2CBUS_GetACK(CurrServObj[CURR].pbtData);
        						if(*CurrServObj[CURR].pbtData == I2C_NAK)
        						{
        							ERRMSG((L"[IIC_IST:E] 0x%x Slave didn't send ACK(%dth data phase), but it's pass\r\n", CurrServObj.GetSlaveAddr(), dwTxDataCount));
        						}
        					}
        					break;
        				case I2CSTATE_GET_DATA:
        					I2CBUS_GetData(&CurrServObj.pRxBuffer[dwRxDataCount]);
        					dwRxDataCount++;
        					DBGMSG(TEST_IST, (L"[IIC_IST:I] STATE(%d) : GET_DATA(0x%x)\r\n", dwFIFOIdx, CurrServObj.pRxBuffer[dwRxDataCount-1]));
        					break;
        				case I2CSTATE_SET_ACK:
        					DBGMSG(TEST_IST, (L"[IIC_IST:I] STATE(%d) : SET_ACK\r\n", dwFIFOIdx));
        					I2CBUS_AckEnable(TRUE);
        					I2CBUS_ClrIntrPending();
        					bExit = TRUE;
        					break;
        				case I2CSTATE_SET_NAK:
        					DBGMSG(TEST_IST, (L"[IIC_IST:I] STATE(%d) : SET_NAK\r\n", dwFIFOIdx));
        					I2CBUS_AckEnable(FALSE);
        					I2CBUS_ClrIntrPending();
        					bExit = TRUE;
        					break;
        				case I2CSTATE_SET_LOOP:	
        					DBGMSG(TEST_IST, (L"[IIC_IST:I] STATE(%d) : SET_LOOP\r\n", dwFIFOIdx));
        					DBGMSG(TEST_IST, (L"[IIC_IST:I] BACK INDEX : %d, Time : %d\r\n", (dwFIFOIdx - CurrServObj[CURR].btData), CurrServObj[CURR].dwTime));
        					if(CurrServObj[CURR].dwTime > 0)
        					{
        						CurrServObj[CURR].dwTime--;
        						dwFIFOIdx -= CurrServObj[CURR].btData;
        					}
        					break;
        				case I2CSTATE_STOP:
        					DBGMSG(TEST_IST, (L"[IIC_IST:I] STATE(%d) : STOP\r\n", dwFIFOIdx));
        					I2CBUS_SetStop();
        					I2CBUS_ClrIntrPending();
        					bRequestComplete = TRUE;
        					bExit = TRUE;
        					break;
        				case I2CSTATE_WAIT_TO_READY:
        					DBGMSG(TEST_IST, (L"[IIC_IST:I] STATE(%d) : WAIT(Count : %d, ArmClk : %d)\r\n", dwFIFOIdx, CurrServObj[CURR].dwTime, pBSPArgs->SystemClocks.ARM_CLK));
        					if(*CurrServObj[CURR].pbtData == TRUE)
        					{
        						dwCount = CurrServObj[CURR].dwTime;
        						while(dwCount)
        						{
#if EMULATION_ENABLE
        							GeneralBusyWaitForOneClock(pBSPArgs->SystemClocks.ARM_CLK, CurrServObj.GetClockSpeed());
#else
                                    InternalBusyWaitForOneClock(pBSPArgs->SystemClocks.ARM_CLK, CurrServObj.GetClockSpeed());
#endif
        							--dwCount;
        						}
        						*CurrServObj[CURR].pbtData = TRUE;
        					}
        					break;
        				case I2CSTATE_BEGIN:
        					DBGMSG(TEST_IST, (L"[IIC_IST:I] STATE(%d) : BEGIN\r\n", dwFIFOIdx));
        					break;
        				case I2CSTATE_END:
        					DBGMSG(TEST_IST, (L"[IIC_IST:I] STATE(%d) : END\r\n", dwFIFOIdx));
        					break;		
                        case I2CSTATE_UNDEFINED:
							ERRMSG((L"[IIC_IST:E] UNDEFINED STATE & RECOVERY STAGE\r\n"));
							bSuccess = FALSE;
							dwFIFOIdx = 0;
							CurrServObj[NEXT].State = I2CSTATE_STOP;
							CurrServObj[NEXT_NEXT].State = I2CSTATE_END;
							break;    
        				default:
                            ERRMSG((L"[IIC_IST:E] UNKNOWN STATE & RECOVERY STAGE\r\n"));
        					bSuccess = FALSE;
        							dwFIFOIdx = 0;
        				CurrServObj[NEXT].State = I2CSTATE_STOP;
        				CurrServObj[NEXT_NEXT].State = I2CSTATE_END;
        							break;
        			}
        			dwFIFOIdx++;
        		} while(!bExit);
    		}while(!bRequestComplete);
		}__except(I2CProcessException(GetExceptionInformation()))
		{
			ERRMSG((L"EXCEPTION IS INVOKED(HW %d Channel)\r\n", dwChannel));
			ERRMSG((L"Fifo Index : %d\r\n", dwFIFOIdx));
			ERRMSG((L"bRequestComplete : %d\r\n", bRequestComplete));
			ERRMSG((L"Currnet Tx Count : %d\r\n", dwTxDataCount));
			ERRMSG((L"Currnet Rx Count : %d\r\n", dwRxDataCount));
			ERRMSG((L"Current Service Obj : 0x%X\r\n", pCurrServObj));
			if(pCurrServObj)
			{
				ERRMSG((L"Tx Data Addr & size : 0x%X %d\r\n", pCurrServObj->pTxBuffer, pCurrServObj->dwTxCount));
				ERRMSG((L"Rx Data Addr & size : 0x%X %d\r\n", pCurrServObj->pRxBuffer, pCurrServObj->dwRxCount));
			}
			bSuccess = FALSE;
			PrintI2CRegList();
			I2CBUS_SetStop();
			I2CBUS_Enable(FALSE);
			I2CBUS_ClrIntrPending();
		}

        I2CThreadState = I2C_THREAD_STATE_INIT;

		SetEvent(hI2CDoneEvent);

	}while(TRUE);

	bSuccess = FALSE;	
	bInitialized = FALSE;
	SetEvent(hI2CDoneEvent);
	ERRMSG((L"[IIC_IST:E] I2C IST TERMINATED\r\n"));
	DBGMSG(IIC_FUNC, (L"[IIC_IST:F] --- I2C_IST()\r\n"));
}

