#include <LowPowerableMode.h>
#include <pm.h>
#include <pmplatform.h>
#include <register_map.h>
#include <bsp_args.h>
#include <image_cfg.h>
#include <NormalMode.h>
#include "iis_interface.h"

//===== DEBUGGING MACRO DEFINITION =============================================================================
//#define MODE_CHANGE_TEST
//#define LP_MODE_TEST
//#define DEBUG_MODE

#ifdef DEBUG_MODE
#define TEASER_TIME 1//second
#else
#define TEASER_TIME 5//second
#endif
//==============================================================================================================

//===== MACRRO DEFINITION ======================================================================================
#define LP_SRAM_ADDR 0xC0000000
#define DECREASE_METHOD 1
//==============================================================================================================

//===== GLOBAL VARIABLE DECLARTION =============================================================================
DWORD gdwISTPeriodTick = 0;
DWORD gdwFUnderCount = 0;
DWORD gdwSUnderCount = 0;
DWORD gdwTUnderCount = 0;
DWORD gdwIUnderCount = 0;

#ifdef MODE_CHANGE_TEST
DWORD gdwModeState = 0;
BOOL  gbLPState = FALSE;
BOOL  gbCreepState = FALSE;
#endif
//==============================================================================================================

//===== LOCAL FUNCTION DECLARTION ==============================================================================
//==============================================================================================================

//===== IST TIME OUT ===========================================================================================
//==============================================================================================================

//===== EXTERN FUNCTION DECLARTION =============================================================================
//==============================================================================================================
#ifdef MODE_CHANGE_TEST
time_t time(time_t *inTT)   
{   
    SYSTEMTIME sysTimeStruct;   
    FILETIME fTime;   
    ULARGE_INTEGER int64time;   
    time_t locTT = 0;   
  
    if ( inTT == NULL )   
    {   
         inTT = &locTT;   
    }   
  
    GetSystemTime( &sysTimeStruct );   
  
    if ( SystemTimeToFileTime( &sysTimeStruct, &fTime ) )   
    {   
         memcpy( &int64time, &fTime, sizeof( FILETIME ) );   
         /* Subtract the value for 1970-01-01 00:00 (UTC) */  
         int64time.QuadPart -= 0x19db1ded53e8000;   
         /* Convert to seconds. */  
         int64time.QuadPart /= 10000000;   
         *inTT = (time_t)int64time.QuadPart;   
    }   
    return *inTT;   
}   
#endif

OutLowPowerableMode::OutLowPowerableMode(
    BOOL bEnableLowPower,
    OutputDeviceContext *pDevCtxt, 
    InModeInterfaceLayer** ppInMode,
    PCB_MODEOP pStart, 
    PCB_MODEOP pStop)
    :OutModeInterfaceLayer(pDevCtxt, ppInMode, pStart, pStop)
{
    m_Mode = OUT_LOWPOWER_MODE;
    m_dwStateIndex = OUT_LP_D0;
    m_CurrState = OUT_LP_D0;
    m_PrioState = OUT_LP_D0;

    m_bLowPower = bEnableLowPower;
    m_bDMARunning = FALSE;

    m_bOnIncBuf = FALSE;
    m_bOnDecBuf = FALSE;

    m_dwDPIdleCnt = 0;

    m_dwTeaserTime = (44000*2*2)*TEASER_TIME;
    m_dwElapsedTime = 0;
}

OutLowPowerableMode::~OutLowPowerableMode()
{
}

BOOL 
OutLowPowerableMode::Init(LPWSTR lpActivePath)
{
    BOOL bInit = TRUE;

    DBGMSG(WAVE_LPMODE,(L"[WAV] +++LP_Init()\r\n"));
    
    do
    {
#ifdef MODE_CHANGE_TEST
        srand(time(NULL));
#endif 
        if(!MapRegister())
        {
            ERRMSG((L"[WAV:ERR] MapRegister is failed\n\r"));
            bInit = FALSE;
            break;
        }

#if 1
        if(!MapDMABuffers((PVOID)LP_SRAM_ADDR, SHORT_DMA_BUF_SIZE))
        {
            ERRMSG((L"[WAV:ERR] MapDMABuffers is failed\n\r"));
            bInit = FALSE;
            break;
        }
#else
        if(!MapDMABuffers((PVOID)NULL, SHORT_DMA_BUF_SIZE))
        {
            ERRMSG((L"[WAV:ERR] MapDMABuffers is failed\n\r"));
            bInit = FALSE;
            break;
        }
#endif
#ifdef WAV_I2S0
	    if(!InitTransfer(lpActivePath, IRQ_I2S0))	//IRQ_I2S0  --->IRQ_I2S1/modified by terry 20111001         	// change to I2S0 FOR EASY210
#else //ifdef WAV_I2S1		
	    if(!InitTransfer(lpActivePath, IRQ_I2S1))		
#endif	
        {
            ERRMSG((L"[WAV:ERR] InitTransfer is failed\n\r"));
            bInit = FALSE;
            break;
        }

        DBGMSG(WAVE_LPMODE,(L"[WAV] Init is successful\r\n"));
    } while(FALSE);

    DBGMSG(WAVE_LPMODE,(L"[WAV] ---LP_Init()\r\n"));
    
    return bInit;
}

BOOL    
OutLowPowerableMode::Deinit(VOID)
{
    BOOL bDeinit = TRUE;

    do
    {
        if(!UnmapRegister())
        {
            ERRMSG((L"[WAV:ERR] UnmapRegister is failed\n\r"));
            bDeinit = FALSE;
            break;
        }
    
        if(!UnmapDMABuffers())
        {
            ERRMSG((L"[WAV:ERR] UnMapDMABuffers is failed\n\r"));
            bDeinit = FALSE;
            break;
        }

        if(!DeinitTransfer())
        {
            ERRMSG((L"[WAV:ERR] DeinitTransfer is failed\n\r"));
            bDeinit = FALSE;
            break;
        }
    } while(FALSE);

    return bDeinit;
}

BOOL 
OutLowPowerableMode::MapRegister(VOID)
{
    BOOL bMapReg = TRUE;
    PHYSICAL_ADDRESS ioPhysicalBase = {0,0};

    do
    {
        ioPhysicalBase.LowPart = IMAGE_SHARE_ARGS_PA_START;
        m_pBSPArgs = (BSP_ARGS *)MmMapIoSpace(ioPhysicalBase, sizeof(BSP_ARGS), FALSE);
        if (m_pBSPArgs == NULL)
        {
            ERRMSG((L"[WAV:ERR] MapRegisters() : m_pBSPArgs MmMapIoSpace() Failed\n\r"));
            bMapReg = FALSE;
            break;
        }
#ifdef WAV_I2S0
        ioPhysicalBase.LowPart = BASE_REG_PA_I2S0;   // modified by terry for esay210 i2s0 2012.03.13 
#else //ifdef WAV_I2S1
        ioPhysicalBase.LowPart = BASE_REG_PA_I2S1;  
#endif

        m_pIISReg = (PIIS_REG)MmMapIoSpace(ioPhysicalBase, sizeof(IIS_REG), FALSE);
        if (m_pIISReg == NULL)
        {
            ERRMSG((L"[WAV:ERR] MapRegisters() : m_pIISReg MmMapIoSpace() Failed\n\r"));
            bMapReg = FALSE;
            break;
        }
    
        ioPhysicalBase.LowPart = BASE_REG_PA_ASS_CLKCON;
        m_pASSClkReg = (ASS_CLK_REG *)MmMapIoSpace(ioPhysicalBase, sizeof(ASS_CLK_REG), FALSE);
        if (m_pASSClkReg == NULL)
        {
            ERRMSG((L"[WAV:ERR] MapRegisters() : m_pASSClkReg MmMapIoSpace() Failed\n\r"));
            bMapReg = FALSE;
            break;
        }

        ioPhysicalBase.LowPart = BASE_REG_PA_ASS_COMMBOX3;
        m_pASSCommBoxReg = (PASS_CBOX3_REG)MmMapIoSpace(ioPhysicalBase, sizeof(ASS_CBOX3_REG), FALSE);
        if (m_pASSCommBoxReg == NULL)
        {
            ERRMSG((L"[WAV:ERR] MapRegisters() : m_pASSCommBoxReg MmMapIoSpace() Failed\n\r"));
            bMapReg = FALSE;
            break;
        }

        ioPhysicalBase.LowPart = BASE_REG_PA_PMU_MISC;
        m_pMISCReg = (PPMU_MISC_REG)MmMapIoSpace(ioPhysicalBase, sizeof(PMU_MISC_REG), FALSE);
        if (m_pMISCReg == NULL)
        {
            ERRMSG((L"[WAV:ERR] MapRegisters() : m_pASSClkReg MmMapIoSpace() Failed\n\r"));
            bMapReg = FALSE;
            break;
        }
    }while(FALSE); 

    return bMapReg;
}

BOOL    
OutLowPowerableMode::UnmapRegister(VOID)
{
    BOOL bUnmapReg = TRUE;

    do
    {
        if(m_pBSPArgs)
        {
            MmUnmapIoSpace((PVOID)m_pBSPArgs, sizeof(BSP_ARGS));
            m_pBSPArgs = NULL;
        }

        if(m_pIISReg)
        {
            MmUnmapIoSpace((PVOID)m_pIISReg, sizeof(IIS_REG));
            m_pIISReg = NULL;
        }

        if(m_pASSClkReg)
        {
            MmUnmapIoSpace((PVOID)m_pASSClkReg, sizeof(ASS_CLK_REG));
            m_pASSClkReg = NULL;
        }

        if(m_pMISCReg)
        {
            MmUnmapIoSpace((PVOID)m_pMISCReg, sizeof(PMU_MISC_REG));
            m_pMISCReg = NULL;
        }

        if(m_pASSCommBoxReg)
        {
            MmUnmapIoSpace((PVOID)m_pASSCommBoxReg, sizeof(ASS_CBOX2_REG));
            m_pASSCommBoxReg = NULL;
        }
    }while(FALSE); 

    return bUnmapReg;
}

BOOL    
OutLowPowerableMode::SetPowerState(CEDEVICE_POWER_STATE PowerState)
{
    BOOL bSetPower = TRUE;

    Lock();

    if(m_bSelfPowerNotify)
    {
        switch(PowerState)
        {
            case D0:
                SetState(OUT_LP_D0);
                break;
            case D2:
                SetState(OUT_LP_D2); 
                break;
            case D1:
            case D3: 
            case D4:
            default:
                ERRMSG((L"[WAV] Unsupported Power State(SEF) : D%d\r\n", PowerState));
                bSetPower = FALSE;
                break;
        }
    }
    else
    {
        switch(PowerState)
        {
            case D0:
                SetState(OUT_LP_D0_FRC);
                break;
            case D2:
                SetState(OUT_LP_D2_FRC);
                break;
            case D4:
                SetState(OUT_LP_D4_FRC);
                break;
            case D1:
            case D3: 
            default:
                ERRMSG((L"[WAV] Unsupported Power State(FRC) : D%d\r\n", PowerState)); 
                bSetPower = FALSE;
                break;
        }
    }

    if(bSetPower)
        m_PowerState = PowerState;
    else
        SelfPowerNotify(m_PowerState);

    m_bSelfPowerNotify = FALSE;

    Unlock();
    
    return bSetPower;
}


BOOL 
OutLowPowerableMode::StartTransfer()
{
    DWORD dwXferedCnt;

    Lock();
    DBGMSG(1, (L"[WAV] +++LP_StartTransfer()\r\n"));

#ifdef DEBUG_MODE
    m_hDumpFile = CreateFile(L"WaveDebugDump.wav",
                             GENERIC_READ|GENERIC_WRITE,
	                         FILE_SHARE_READ|FILE_SHARE_WRITE,
	                         NULL, OPEN_ALWAYS, 0, 0);
#endif

    //2 1. Member variable initialization
    m_bDMARunning = TRUE;
    m_dwElapsedTime = 0;
    
    m_dwDMABufSize = SHORT_DMA_BUF_SIZE;
    m_dwDMABufPhyPage[DMA_BUFFER1] = m_PhyDMABufAddr.LowPart + SHORT_DMA_BUF_SIZE;
    m_pDMABufVirPage[DMA_BUFFER1] = m_pVirDMABufAddr + SHORT_DMA_BUF_SIZE;

    m_dwTransfered[DMA_BUFFER0] = 0;
    m_dwTransfered[DMA_BUFFER1] = 0;
    m_dwDMAStatus = (DMA_DONE0 | DMA_DONE1) & ~DMA_BIU;
    dwXferedCnt = TransferBuffer();

    if(dwXferedCnt)
    {
        //2 2. ASS Setting
        m_pASSCommBoxReg->MISC &= ~(1<<3); //AUDIO DECODER SELECT : RP(1), ARM(0)
            
        //2 3. I2S Setting   
        m_pIISReg->IISMOD |= (1<<28); //TXn FROM IDMA

       //masked by terry 20111001  
#ifdef WAV_I2S0	   
       m_pIISReg->IISSTR0 = m_PhyDMABufAddr.LowPart;	   
#else //ifdef WAV_I2S1		
	  m_pIISReg->IISSTR1 = m_PhyDMABufAddr.LowPart;  // modified by terry for esay210 i2s0         2012.03.13 
#endif	
        m_pIISReg->IISSIZE = SHORT_DMA_DBUF_WSIZE<<16;        
        
        m_pIISReg->IISAHB = 
            (0<<6)|  //STR0 -> STR0 ...
            (1<<5)|  //AUTO RELOAD
            (1<<3)|  //DMA REQUEST INT MASK EN
            (1<<1)|  //CLR DMA INT
            (1<<0);  //ENALBE INTERNAL DMA
        
        m_pIISReg->IISCON |= 
            (1<<23)| //S_FIFO UNDER_RUN INT EN
            (1<<0);  //IIS ACTIVE
    DBGMSG(1, (L"[WAV] LP_StartTransfer()--------1\r\n"));
        while(m_pIISReg->IISTRNCNT <= 1)	;
    DBGMSG(1, (L"[WAV] LP_StartTransfer()--------2\r\n"));
        m_pIISReg->IISLVL0ADDR = m_dwDMABufPhyPage[DMA_BUFFER0];
        m_pIISReg->IISLVL1ADDR = m_dwDMABufPhyPage[DMA_BUFFER1];
        m_pIISReg->IISAHB |= 
            (1<<25)| //LVL1 INT EN
            (1<<24); //LVL0 INT EN
    }
    else
    {
        ERRMSG((L"[WAV:ERR] OutLowPowerableMode::StartTransfer() : There is no data to transfer\r\n"));
        m_bDMARunning = FALSE;
    }

#ifdef DEBUG_MODE
    gdwISTPeriodTick = GetTickCount();
#endif


	ERRMSG((L"[WAV:ERR] StartTransferr\r\n"));
    IIS_print_all();
    DBGMSG(1, (L"[WAV] ---LP_StartTransfer()\r\n"));

	Unlock();

    return m_bDMARunning;
}

BOOL    
OutLowPowerableMode::PauseTransfer(DWORD dwParam)
{
    BOOL bPause = TRUE;
    POutNormalMode pNormal;

    Lock();
    DBGMSG(WAVE_LPMODE, (L"[WAV] +++PauseTransfer()\r\n"));

    if((GetCurrState() >= OUT_LP_D0) && (GetCurrState() <= OUT_LP_D2_FRC))
    {
        if(dwParam == IIS_INT_LVL0)
        {
            m_pIISReg->IISAHB &= ~((1<<25)|  //LVL1 INT DISABLE
                                   (1<<24)|  //LVL0 INT DISABLE
                                   (1<<05)); //AUDO RELOAD OFF
                                   
            m_pIISReg->IISSIZE = (SHORT_DMA_BUF_WSIZE<<16)|0x1; 
            while(m_pIISReg->IISTRNCNT != SHORT_DMA_BUF_WSIZE);

            m_pIISReg->IISAHB =   ((1<<07)| //RESET START ADDRESS
                                   (1<<03)| //DISABLE INTERRUPT REQUEST SIGNAL
                                   (1<<00));//DISABLE IIS INTERNAL DMA

            m_pIISReg->IISCON &= ~((1<<23)| //S_FIFO UNDER_RUN INT EN
                                   (1<<18));//S_FIFO EXT_DMA ACTIVE

            m_dwDMAStatus = DMA_CLEAR;
            m_bDMARunning = FALSE;
            pNormal = (POutNormalMode)m_pModeChangeParam1;
            pNormal->StartTransfer();
        }
        else if(dwParam == IIS_INT_LVL1)
        {
            m_pIISReg->IISAHB &= ~((1<<25)|  //LVL1 INT DISABLE
                                   (1<<24)|  //LVL0 INT DISABLE
                                   (1<<05)); //AUDO RELOAD OFF

            while(m_pIISReg->IISTRNCNT != SHORT_DMA_DBUF_WSIZE);

            m_pIISReg->IISAHB =   ((1<<07)| //RESET START ADDRESS
                                   (1<<03)| //DISABLE INTERRUPT REQUEST SIGNAL
                                   (1<<00));//DISABLE IIS INTERNAL DMA

            m_pIISReg->IISCON &= ~((1<<23)| //S_FIFO UNDER_RUN INT EN
                                   (1<<18));//S_FIFO EXT_DMA ACTIVE

            m_dwDMAStatus = DMA_CLEAR;
            m_bDMARunning = FALSE;
            pNormal = (POutNormalMode)m_pModeChangeParam1;
            pNormal->StartTransfer();
        }
        else
        {
            ERRMSG((L"[WAV] Unresolved Interrupt Source(%d)\r\n", dwParam));
            bPause = FALSE;
        }
    }
    else
    {
        ERRMSG((L"[WAV] Current State(%d) can not be Pause\r\n", GetCurrState()));
        bPause = FALSE;
    }
    
    DBGMSG(WAVE_LPMODE, (L"[WAV] ---PauseTransfer()\r\n"));
    Unlock();
    
    return bPause;
}

BOOL 
OutLowPowerableMode::ResumeTransfer(VOID)
{
    DBGMSG(WAVE_LPMODE, (L"[WAV] +++LP_ResumeTransfer()\r\n"));

    m_pIISReg->IISMOD |= (1<<28); //TXn FROM IDMA

	
 
#ifdef WAV_I2S0	 
    m_pIISReg->IISSTR0 = m_PhyDMABufAddr.LowPart;		// modified by terry for esay210 i2s0 2012.03.13 
#else //ifdef WAV_I2S1	 
    m_pIISReg->IISSTR1 = m_PhyDMABufAddr.LowPart;
#endif

    m_pIISReg->IISSIZE = (SHORT_DMA_DBUF_WSIZE<<16)|0x1;        
    
    m_pIISReg->IISAHB = 
        (0<<6)|  //STR0 -> STR0 ...
        (1<<5)|  //AUTO RELOAD
        (1<<3)|  //DMA REQUEST INT MASK EN
        (1<<1)|  //CLR DMA INT
        (1<<0);  //ENALBE INTERNAL DMA

    m_pIISReg->IISLVL0ADDR = m_dwDMABufPhyPage[DMA_BUFFER0];
    m_pIISReg->IISLVL1ADDR = m_dwDMABufPhyPage[DMA_BUFFER1];
    m_pIISReg->IISAHB |= 
        (1<<25)| //LVL1 INT EN
        (1<<24); //LVL0 INT EN

    SetInterruptEvent(m_dwSysIntr);

    DBGMSG(WAVE_LPMODE, (L"[WAV] ---LP_ResumeTransfer()\r\n"));

    return TRUE;
}

BOOL 
OutLowPowerableMode::StopTransfer(BOOL bMediumOff)
{
    BOOL bStop = TRUE;

    Lock();
    DBGMSG(WAVE_LPMODE, (L"[WAV] +++LP_StopTransfer(%d)\r\n", bMediumOff));

#ifdef DEBUG_MODE
    CloseHandle(m_hDumpFile);
#endif

    m_pIISReg->IISAHB =
            (1<<07)| //DMA START ADDRESS RESET
            (1<<03)| //DISABLE IST REQUEST SIGNAL
            (1<<01)| //CLR DMAINT
            (0<<00); //DISABLE IIS INTERNAL DMA
    
    if(bMediumOff)
    {
        m_pIISReg->IISCON &= ~(
                (1<<23)| //S_FIFO UNDER_RUN INT EN
                (1<<00));//IIS ACTIVE
    }
    else
    {
        m_pIISReg->IISCON &= ~(
                (1<<23));//S_FIFO UNDER_RUN INT EN
    }
    
    m_dwDMAStatus = DMA_CLEAR;
    m_bDMARunning = FALSE;

    DBGMSG(WAVE_LPMODE, (L"[WAV] ---LP_StopTransfer()\r\n"));
    Unlock();

    return bStop;
}

BOOL    
OutLowPowerableMode::IncreaseBufSize(DWORD dwParam)
{
    BOOL bRender;
    
    DBGMSG(WAVE_LPMODE,(L"[WAV] +++IncreaseBufSize(%d)\r\n", dwParam));
               
    if(dwParam == IIS_INT_LVL0)
    {
        m_dwDMABufSize = LONG_DMA_BUF_SIZE;
        m_dwDMABufPhyPage[DMA_BUFFER1] = (DWORD)(m_PhyDMABufAddr.LowPart + LONG_DMA_BUF_SIZE);
        m_pDMABufVirPage[DMA_BUFFER1] = (PBYTE)(m_pVirDMABufAddr + LONG_DMA_BUF_SIZE);

        m_pIISReg->IISSIZE = LONG_DMA_DBUF_WSIZE<<16; 
        m_pIISReg->IISLVL1ADDR = m_dwDMABufPhyPage[DMA_BUFFER1];

        m_dwDMAStatus = DMA_CLEAR;
        FillBuffer((m_pDMABufVirPage[DMA_BUFFER0] + SHORT_DMA_BUF_SIZE), (LONG_DMA_DBUF_SIZE - SHORT_DMA_BUF_SIZE));
        m_dwTransfered[DMA_BUFFER0] = m_dwTransfered[DMA_BUFFER1] = LONG_DMA_BUF_SIZE;
        bRender = FALSE;
    }
    else
    {  
        m_dwDMABufSize = LONG_DMA_BUF_SIZE;
        m_dwDMABufPhyPage[DMA_BUFFER1] = (DWORD)(m_PhyDMABufAddr.LowPart + LONG_DMA_BUF_SIZE);
        m_pDMABufVirPage[DMA_BUFFER1] = (PBYTE)(m_pVirDMABufAddr + LONG_DMA_BUF_SIZE);

        m_pIISReg->IISSIZE = LONG_DMA_DBUF_WSIZE<<16; 
        m_pIISReg->IISLVL1ADDR = m_dwDMABufPhyPage[DMA_BUFFER1];

        m_dwDMAStatus = DMA_CLEAR;
        FillBuffer((m_pDMABufVirPage[DMA_BUFFER0] + SHORT_DMA_DBUF_SIZE), (LONG_DMA_DBUF_SIZE - SHORT_DMA_DBUF_SIZE));
        m_dwTransfered[DMA_BUFFER0] = m_dwTransfered[DMA_BUFFER1] = LONG_DMA_BUF_SIZE;
        bRender = FALSE;
    }  

    DBGMSG(WAVE_LPMODE,(L"[WAV] ---IncreaseBufSize()\r\n"));

    return bRender;
}

BOOL    
OutLowPowerableMode::DecreaseBufSize(DWORD dwParam)
{
    BOOL bRender;

    DBGMSG(WAVE_LPMODE,(L"[WAV] +++DecreaseBufSize(%d)\r\n", dwParam));
    
    if(dwParam == IIS_INT_LVL0)
    {
#if(DECREASE_METHOD==1)
        m_dwDMABufSize = SHORT_DMA_BUF_SIZE;
        m_dwDMABufPhyPage[DMA_BUFFER1] = (DWORD)(m_PhyDMABufAddr.LowPart + SHORT_DMA_BUF_SIZE);
        m_pDMABufVirPage[DMA_BUFFER1] = (PBYTE)(m_pVirDMABufAddr + SHORT_DMA_BUF_SIZE);

        m_pIISReg->IISSIZE = SHORT_DMA_DBUF_WSIZE<<16; 
        m_pIISReg->IISLVL1ADDR = m_dwDMABufPhyPage[DMA_BUFFER1];

        m_dwDMAStatus = DMA_CLEAR;
        SavePCMBuffer((m_pDMABufVirPage[DMA_BUFFER0] + SHORT_DMA_DBUF_SIZE), (LONG_DMA_BUF_SIZE - SHORT_DMA_DBUF_SIZE), FALSE);
       
        bRender = FALSE;
#else
        m_pIISReg->IISAHB &= ~((1<<25)|     //LVL1 INT DISABLE
                               (1<<24)|     //LVL0 INT DISABLE
                               (1<<05));    //AUTO RELOAD OFF
        m_pIISReg->IISSIZE = (LONG_DMA_BUF_WSIZE<<16)|0x1; 
    
        m_dwDMABufSize = SHORT_DMA_BUF_SIZE;
        m_dwDMABufPhyPage[DMA_BUFFER1] = (DWORD)(m_PhyDMABufAddr.LowPart + SHORT_DMA_BUF_SIZE);
        m_pDMABufVirPage[DMA_BUFFER1] = (PBYTE)(m_pVirDMABufAddr + SHORT_DMA_BUF_SIZE);
        m_dwDMAStatus = DMA_DONE0 | DMA_BIU;

        while(m_pIISReg->IISTRNCNT <= SHORT_DMA_BUF_WSIZE);

        FillBuffer(DMA_BUFFER0);

        while(m_pIISReg->IISTRNCNT != LONG_DMA_BUF_WSIZE);
        
        m_pIISReg->IISLVL1ADDR = m_dwDMABufPhyPage[DMA_BUFFER1];
        m_pIISReg->IISSIZE = (SHORT_DMA_DBUF_WSIZE<<16)|0x1; 

        m_pIISReg->IISAHB |= ((1<<24)|
                              (1<<25)|  //LVL1 INT ENABLE
                              (1<<05)|  //AUDO RELOAD ON
                              (1<<00)); //IISDMAEN ON


        bRender = FALSE;
#endif
    }
    else
    {
#if(DECREASE_METHOD==1)
        //3 I can make this more efficiently like the upper, but ... pass don't bother me
        m_pIISReg->IISAHB &= ~((1<<25)|     //LVL1 INT DISABLE
                               (1<<24)|     //LVL0 INT DISABLE
                               (1<<05));    //AUTO RELOAD OFF
    
        m_dwDMABufSize = SHORT_DMA_BUF_SIZE;
        m_dwDMABufPhyPage[DMA_BUFFER1] = (DWORD)(m_PhyDMABufAddr.LowPart + SHORT_DMA_BUF_SIZE);
        m_pDMABufVirPage[DMA_BUFFER1] = (PBYTE)(m_pVirDMABufAddr + SHORT_DMA_BUF_SIZE);
        m_dwDMAStatus = DMA_DONE0 | DMA_BIU;
        FillBuffer(DMA_BUFFER0);

        while(m_pIISReg->IISTRNCNT != LONG_DMA_DBUF_WSIZE);

        m_pIISReg->IISLVL1ADDR = m_dwDMABufPhyPage[DMA_BUFFER1];
        m_pIISReg->IISSIZE = (SHORT_DMA_DBUF_WSIZE<<16)|0x1; 

        m_pIISReg->IISAHB |= ((1<<25)|  //LVL1 INT ENABLE
                              (1<<24)|  //LVL0 INT ENABLE
                              (1<<05)|  //AUDO RELOAD ON
                              (1<<00)); //IISDMAEN ON

        bRender = FALSE;
#else
        m_pIISReg->IISAHB &= ~((1<<25)|     //LVL1 INT DISABLE
                               (1<<24)|     //LVL0 INT DISABLE
                               (1<<05));    //AUTO RELOAD OFF
    
        m_dwDMABufSize = SHORT_DMA_BUF_SIZE;
        m_dwDMABufPhyPage[DMA_BUFFER1] = (DWORD)(m_PhyDMABufAddr.LowPart + SHORT_DMA_BUF_SIZE);
        m_pDMABufVirPage[DMA_BUFFER1] = (PBYTE)(m_pVirDMABufAddr + SHORT_DMA_BUF_SIZE);
        m_dwDMAStatus = DMA_DONE0 | DMA_BIU;
        FillBuffer(DMA_BUFFER0);

        while(m_pIISReg->IISTRNCNT != LONG_DMA_DBUF_WSIZE);

        m_pIISReg->IISLVL1ADDR = m_dwDMABufPhyPage[DMA_BUFFER1];
        m_pIISReg->IISSIZE = (SHORT_DMA_DBUF_WSIZE<<16)|0x1; 

        m_pIISReg->IISAHB |= ((1<<25)|  //LVL1 INT ENABLE
                              (1<<24)|  //LVL0 INT ENABLE
                              (1<<05)|  //AUDO RELOAD ON
                              (1<<00)); //IISDMAEN ON

        bRender = FALSE;
#endif
    }

    DBGMSG(WAVE_LPMODE,(L"[WAV] ---DecreaseBufSize()\r\n"));
    
    return bRender;
}

BOOL    
OutLowPowerableMode::IsBufferInXfer(DWORD dwBuffer)
{
    DWORD dwInUseBuffer;

    if(m_pIISReg->IISTRNCNT >= (m_dwDMABufSize>>2))
    {
        dwInUseBuffer = DMA_BUFFER1;
    }
    else
    {
        dwInUseBuffer = DMA_BUFFER0;
    }

    if(dwBuffer == dwInUseBuffer)
        return TRUE;
    else
        return FALSE;
}

BOOL 
OutLowPowerableMode::StateChange(IIS_INTR_SRC IntSrc)
{
    BOOL bRender = TRUE;

    if(IntSrc > IIS_INT_LVL2)
    {
        return FALSE;
    }

    if(m_bModeChange)
    {
        PauseTransfer(IntSrc);
        m_bModeChange = FALSE;
        SetEvent(m_hWaveEvent);
        return FALSE;
    }

    switch(GetCurrState())
    {
        case OUT_LP_D0_REQ:
            break;

        case OUT_LP_D0_FRC: 
#ifdef LP_MODE_TEST
            gbLPState = FALSE;
            gbCreepState = FALSE;
            gdwModeState = 0;
            DBGMSG(TRUE,(L"[WAV] UNDERRUN STATUS : %d %d %d %d\r\n", gdwFUnderCount, gdwSUnderCount, gdwTUnderCount, gdwIUnderCount));
#endif
            if((GetPrioState() == OUT_LP_D2_DPL) && (m_dwDMABufSize == LONG_DMA_BUF_SIZE))
            {
                bRender = DecreaseBufSize(IntSrc);
            }
            SetState(OUT_LP_D0);
            m_dwElapsedTime = 0;
            break;
            
        case OUT_LP_D0:
            if((m_dwElapsedTime >= m_dwTeaserTime) && !(*m_ppInMode)->GetRunningStatus())
            {
                DBGMSG(WAVE_LPMODE,(L"[WAV] ElapsedTime is expired\r\n"));
                m_pBSPArgs->dwCreepModeInfo = 20;  
                SelfPowerNotify(D2);
            }
            break;

        case OUT_LP_D2_REQ:
            break;

        case OUT_LP_D2_FRC:
            SetState(OUT_LP_D2);
            break;

        case OUT_LP_D2:
#ifdef MODE_CHANGE_TEST
            if(m_bLowPower &&
               gbLPState && 
               gbCreepState &&
               IsAllStreamReady(2*LONG_DMA_DBUF_SIZE))
#else
            if(m_bLowPower &&
               m_pBSPArgs->bAugStateLPMode && 
               m_pBSPArgs->bAugStateCreepMode &&
               IsAllStreamReady(2*LONG_DMA_DBUF_SIZE))
#endif
            {
                bRender = IncreaseBufSize(IntSrc);
                SetState(OUT_LP_D2_DPL);
            }
            break;
        
         case OUT_LP_D2_DPL:
#ifdef MODE_CHANGE_TEST
            if(!gbLPState)
#else
            if(!m_pBSPArgs->bAugStateLPMode)
#endif
            {       
                bRender = DecreaseBufSize(IntSrc);
                m_dwElapsedTime = 0;
                SelfPowerNotify(D0);
            }
            break;

        case OUT_LP_D4:
            ERRMSG((L"[WAV] 1sldfjasldfjasdklfjsadlfj;asdkfjsd\r\n"));
            break;
        case OUT_LP_D4_FRC:
            ERRMSG((L"[WAV] 2sldfjasldfjasdklfjsadlfj;asdkfjsd\r\n"));
            break;

        default:
            bRender = FALSE;
            break;
    }

    return bRender;
}

VOID 
OutLowPowerableMode::InterruptThread(VOID)
{
    DWORD dwXferedCnt;
    DWORD dwBufferInUse;
    IIS_INTR_SRC eIntPend;
    
#if (_WIN32_WCE < 600)
    // Fast way to access embedded pointers in wave headers in other processes.
    SetProcPermissions((DWORD)-1);
#endif

    DBGMSG(WAVE_LPMODE,(L"[WAV] InterruptThread is created\r\n"));

    while(TRUE)
    {
        if(m_pBSPArgs->bAugStateLPMode)
        {
            if(WaitForSingleObject(m_hXferEvent, 40)!=WAIT_OBJECT_0)
            {
                continue;
            }
        }
        else
        {
            WaitForSingleObject(m_hXferEvent, INFINITE);
        }

        Lock();


    DBGMSG(1,(L"[WAV] WaitForSingleObject is m_hXferEvent  occurt---------------------\r\n"));


        __try
        {
            
            IIS_Get_Interrupt_Pending(&eIntPend);

            IIS_ClearIntPending(eIntPend);
            
            InterruptDone(m_dwSysIntr);

#ifdef DEBUG_MODE
            {
                DWORD dwTemp = GetTickCount();
                //DBGMSG(WAVE_LPMODE,(L"[WAV] L%d B%dKB IB%d T%dms D%d\r\n", eIntPend, (gdwBufferedPCMSize/1024), ((m_pIISReg->IISFICS>>8)&0x3F), (gdwISTPeriodTick - dwTemp), (m_pBSPArgs->dwDIDLECnt - m_dwDPIdleCnt)));
                DBGMSG(WAVE_LPMODE,(L"[WAV] L%d B%dKB IB%d T%dms D%d\r\n", eIntPend, GetBufferedPCMSize()/1024, ((m_pIISReg->IISFICS>>8)&0x3F), (gdwISTPeriodTick - dwTemp), m_PowerState));
                //DBGMSG(WAVE_LPMODE,(L"[WAV] L%d B%dKB IB%d T%dms\r\n", eIntPend, (gdwBufferedPCMSize/1024), ((m_pIISReg->IISFICS>>8)&0x3F), (gdwISTPeriodTick - dwTemp)));
                //DBGMSG(TRUE,(L"%d\r\n", GetBufferedPCMSize()/1024));
                m_dwDPIdleCnt = m_pBSPArgs->dwDIDLECnt;
                gdwISTPeriodTick = dwTemp;
            }
#endif

            if(eIntPend == IIS_INT_UDR_TXn)
            {
                ERRMSG((L"[WAV] **************************************************\r\n"));
                ERRMSG((L"[WAV] P**********************U**************************\r\n"));
                ERRMSG((L"[WAV] R**********************N**************************\r\n"));
                ERRMSG((L"[WAV] I**********************D**************************\r\n"));
                ERRMSG((L"[WAV] M**********************E**************************\r\n"));
                ERRMSG((L"[WAV] A**********************R**************************\r\n"));
                ERRMSG((L"[WAV] R*************************************************\r\n"));
                ERRMSG((L"[WAV] Y**********************R**************************\r\n"));
                ERRMSG((L"[WAV] ***********************U**************************\r\n"));
                ERRMSG((L"[WAV] ***********************N**************************\r\n"));
                ERRMSG((L"[WAV] **************************************************\r\n"));
                gdwFUnderCount++;
            }
            else if(eIntPend == IIS_INT_UDR_TXS)
            {
                ERRMSG((L"[WAV] **************************************************\r\n"));
                ERRMSG((L"[WAV] S**********************U**************************\r\n"));
                ERRMSG((L"[WAV] E**********************N**************************\r\n"));
                ERRMSG((L"[WAV] C**********************D**************************\r\n"));
                ERRMSG((L"[WAV] O**********************E**************************\r\n"));
                ERRMSG((L"[WAV] N**********************R**************************\r\n"));
                ERRMSG((L"[WAV] D*************************************************\r\n"));
                ERRMSG((L"[WAV] A**********************R**************************\r\n"));
                ERRMSG((L"[WAV] R**********************U**************************\r\n"));
                ERRMSG((L"[WAV] Y**********************N**************************\r\n"));
                ERRMSG((L"[WAV] **************************************************\r\n"));
                gdwSUnderCount++;
            }

            if(!GetRunningStatus())
            {
                if((eIntPend != IIS_INT_LVL0) && (eIntPend != IIS_INT_LVL1))
                {
                    ERRMSG((L"[WAV] %d IIS_INT is occured on ULP or NORMAL mode\r\n", eIntPend));
                    gdwTUnderCount++;
                }
                Unlock();
                continue;
            }

            if(StateChange(eIntPend))
            {
                if(m_dwDMAStatus & DMA_BIU) //BUFFER1 has been used
                {
                    m_dwDMAStatus |= DMA_DONE1;
                    m_dwDMAStatus &= ~DMA_BIU;       
                    dwBufferInUse = DMA_BUFFER0;
                }
                else //BUFFER0 has been used
                {
                    m_dwDMAStatus |= DMA_DONE0;
                    m_dwDMAStatus |= DMA_BIU;
                    dwBufferInUse = DMA_BUFFER1;
                }

                if(!IsBufferInXfer(dwBufferInUse))
                {
                    if(dwBufferInUse == DMA_BUFFER0)
                    {
                        DBGMSG(WAVE_LPMODE,(L"[WAV] LONG_UNDERRUN is occured(Skip : DMA_BUFFER1)\r\n"));
                        m_dwDMAStatus = DMA_DONE0 | DMA_BIU;
                    }
                    else
                    {
                        DBGMSG(WAVE_LPMODE,(L"[WAV] LONG_UNDERRUN is occured(Skip : DMA_BUFFER0)\r\n"));
                        m_dwDMAStatus = DMA_DONE1 & ~DMA_BIU;
                    }
                    gdwIUnderCount++;
                }
                
                dwXferedCnt = TransferBuffer();
                m_dwElapsedTime += dwXferedCnt;
            }

#ifdef MODE_CHANGE_TEST
            DWORD dwNum;
            if(gdwModeState == 2)
            {
                dwNum = rand() % 5;
                if(dwNum == 4)
                {
#ifndef LP_MODE_TEST
                    gbLPState = FALSE;
                    gbCreepState = FALSE;
                    gdwModeState = 0;
                    DBGMSG(WAVE_LPMODE,(L"[WAV] UNDERRUN STATUS : %d %d %d %d\r\n", gdwFUnderCount, gdwSUnderCount, gdwTUnderCount, gdwIUnderCount));
#endif
                }
            }
            else if(gdwModeState == 1)
            {
                dwNum = rand() % 10;
                if(dwNum == 9)
                {
                    gdwModeState = 2;
                    gbLPState = TRUE;
                    gbCreepState = TRUE;
                }
            }
            else if(gdwModeState == 0)
            {
                dwNum = rand() % 10;
                if(dwNum == 9)
                {
                    //srand(time(NULL));
                    gdwModeState = 1;
                    gbLPState = TRUE;
                    gbCreepState = FALSE;
                }
            }
#endif
        }
        __except(EXCEPTION_EXECUTE_HANDLER)
        {
            ERRMSG((L"[WAV] LOWPOWER IST - EXCEPTION: %d", GetExceptionCode()));
        }

        Unlock();
    }

    DBGMSG(WAVE_LPMODE,(L"[WAV] InterruptThread is destroyed\r\n"));
    
}
