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

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

//===== MACRRO DEFINITION ======================================================================================
//==============================================================================================================

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

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

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

//===== EXTERN FUNCTION DECLARTION =============================================================================
extern DWORD gdwISTPeriodTick;
extern DWORD gdwFUnderCount;
extern DWORD gdwSUnderCount;
extern DWORD gdwTUnderCount;
extern DWORD gdwIUnderCount;
//==============================================================================================================
OutNormalMode::OutNormalMode(
OutputDeviceContext *pDevCtxt, 
InModeInterfaceLayer** ppInMode,
PCB_MODEOP pStart, 
PCB_MODEOP pStop)
:OutModeInterfaceLayer(pDevCtxt, ppInMode, pStart, pStop)
{
    m_Mode = OUT_NORMAL_MODE;        
    m_dwStateIndex = OUT_NM_D0;
    m_CurrState = OUT_NM_D0;
    m_PrioState = OUT_NM_D0;
    m_bDMARunning = FALSE;
}

OutNormalMode::~OutNormalMode()
{
    
}

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

    DBGMSG(WAVE_NMMODE,(L"[WAV] +++Init()\r\n"));
    
    do
    {
        if(!MapRegister())
        {
            ERRMSG((L"[WAV:ERR] MapRegister is failed\n\r"));
            bInit = FALSE;
            break;
        }

        if(!MapDMABuffers((PVOID)NULL, SHORT_DMA_BUF_SIZE))
        {
            ERRMSG((L"[WAV:ERR] MapDMABuffers is failed\n\r"));
            bInit = FALSE;
            break;
        }

        DMA_initialize_register_address((PVOID)m_pDMAC0Reg, (PVOID)m_pDMAC1Reg,(PVOID)m_pDMACReg,  (PVOID)m_pSysConReg);

#ifdef WAV_I2S0

        //PRIMARY FIFO SETTING
        DMA_request_channel(&m_DMACtxt, DMAsrc_I2S_0_TX);
        DMA_initialize_channel(&m_DMACtxt, TRUE);
        DMA_set_channel_source(&m_DMACtxt, m_dwDMABufPhyPage[0], WORD_UNIT, BURST_1, INCREASE);
        DMA_set_channel_destination(&m_DMACtxt, IIS_get_output_physical_buffer_address(IIS_CH_0), WORD_UNIT, BURST_1, FIXED);
        DMA_set_channel_transfer_size(&m_DMACtxt, m_dwDMABufSize);
        DMA_initialize_LLI(&m_DMACtxt, 2);

        DMA_set_LLI_entry(&m_DMACtxt, 0, LLI_NEXT_ENTRY, m_dwDMABufPhyPage[DMA_BUFFER0],
                            IIS_get_output_physical_buffer_address(IIS_CH_0), m_dwDMABufSize);
        DMA_set_LLI_entry(&m_DMACtxt, 1, LLI_FIRST_ENTRY, m_dwDMABufPhyPage[DMA_BUFFER1],
                            IIS_get_output_physical_buffer_address(IIS_CH_0), m_dwDMABufSize);

#else //ifdef WAV_I2S1
        //PRIMARY FIFO SETTING
        DMA_request_channel(&m_DMACtxt, DMAsrc_I2S_1_TX);
        DMA_initialize_channel(&m_DMACtxt, TRUE);
        DMA_set_channel_source(&m_DMACtxt, m_dwDMABufPhyPage[0], WORD_UNIT, BURST_1, INCREASE);
        DMA_set_channel_destination(&m_DMACtxt, IIS_get_output_physical_buffer_address(IIS_CH_1), WORD_UNIT, BURST_1, FIXED);
        DMA_set_channel_transfer_size(&m_DMACtxt, m_dwDMABufSize);
        DMA_initialize_LLI(&m_DMACtxt, 2);

        DMA_set_LLI_entry(&m_DMACtxt, 0, LLI_NEXT_ENTRY, m_dwDMABufPhyPage[DMA_BUFFER0],
                            IIS_get_output_physical_buffer_address(IIS_CH_1), m_dwDMABufSize);
        DMA_set_LLI_entry(&m_DMACtxt, 1, LLI_FIRST_ENTRY, m_dwDMABufPhyPage[DMA_BUFFER1],
                            IIS_get_output_physical_buffer_address(IIS_CH_1), m_dwDMABufSize);


#endif

        if(!InitTransfer(lpActivePath, m_DMACtxt.dwIRQ))
        {
            ERRMSG((L"[WAV:ERR] InitTransfer1 is failed\n\r"));
            bInit = FALSE;
            break;
        }

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

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

BOOL    
OutNormalMode::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] DeinitTransfer1 is failed\n\r"));
            bDeinit = FALSE;
            break;
        }

        DMA_release_channel(&m_DMACtxt);
    } while(FALSE);

    return bDeinit;
}

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

    Lock();

    switch(PowerState)
    {
        case D0:
            SetState(OUT_NM_D0);
            break;
        case D2:
            SetState(OUT_NM_D2); 
            break;
        case D4:
            SetState(OUT_NM_D4); 
            break;
        case D1:
        case D3: 
        default:
            ERRMSG((L"[WAV] Unsupported Power State(SEF) : D%d\r\n", PowerState));
            bSetPower = FALSE;
            break;
    }

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

    m_bSelfPowerNotify = FALSE;

    Unlock();
    
    return bSetPower;
}

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

    do
    {
        ioPhysicalBase.LowPart = BASE_REG_PA_MDMA;
        m_pDMACReg = (DMAC_REG *)MmMapIoSpace(ioPhysicalBase, sizeof(DMAC_REG), FALSE);
        if (m_pDMACReg == NULL)
        {
            ERRMSG((L"[WAV:ERR] MapRegisters() : m_pDMACReg MmMapIoSpace() Failed\n\r"));
            bMapReg = FALSE;
            break;
        }

        ioPhysicalBase.LowPart = BASE_REG_PA_PDMA0;
        m_pDMAC0Reg = (DMAC_REG *)MmMapIoSpace(ioPhysicalBase, sizeof(DMAC_REG), FALSE);
        if (m_pDMAC0Reg == NULL)
        {
            ERRMSG((L"[WAV:ERR] MapRegisters() : m_pDMAC0Reg MmMapIoSpace() Failed\n\r"));
            bMapReg = FALSE;
            break;
        }

        // Alloc and Map DMAC1 SFR
        ioPhysicalBase.LowPart = BASE_REG_PA_PDMA1;
        m_pDMAC1Reg = (DMAC_REG *)MmMapIoSpace(ioPhysicalBase, sizeof(DMAC_REG), FALSE);
        if (m_pDMAC1Reg == NULL)
        {
            ERRMSG((L"[WAV:ERR] MapRegisters() : m_pDMAC1Reg MmMapIoSpace() Failed\n\r"));
            bMapReg = FALSE;
            break;
        }

        ioPhysicalBase.LowPart = BASE_REG_PA_CMU_CLK;
        m_pSysConReg = (CMU_CLK_REG *)MmMapIoSpace(ioPhysicalBase, sizeof(CMU_CLK_REG), FALSE);
        if (m_pSysConReg == NULL)
        {
            ERRMSG((L"[WAV:ERR] MapRegisters() : m_pSysConReg MmMapIoSpace() Failed\n\r"));
            bMapReg = FALSE;
            break;
        }

        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;
#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_COMMBOX2;
        m_pASSCommBoxReg = (PASS_CBOX2_REG)MmMapIoSpace(ioPhysicalBase, sizeof(ASS_CBOX2_REG), FALSE);
        if (m_pASSCommBoxReg == NULL)
        {
            ERRMSG((L"[WAV:ERR] MapRegisters() : m_pASSCommBoxReg MmMapIoSpace() Failed\n\r"));
            bMapReg = FALSE;
            break;
        }
    }while(FALSE); 

    return bMapReg;
}

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

    do
    {
        if(m_pDMAC0Reg)
        {
            MmUnmapIoSpace((PVOID)m_pDMAC0Reg, sizeof(DMAC_REG));
            m_pDMAC0Reg = NULL;
        }

        if(m_pDMAC1Reg)
        {
            MmUnmapIoSpace((PVOID)m_pDMAC1Reg, sizeof(DMAC_REG));
            m_pDMAC1Reg = NULL;
        }

        if(m_pDMACReg)
        {
            MmUnmapIoSpace((PVOID)m_pDMACReg, sizeof(DMAC_REG));
            m_pDMACReg = NULL;
        }

        if(m_pSysConReg)
        {
            MmUnmapIoSpace((PVOID)m_pSysConReg, sizeof(CMU_CLK_REG));
            m_pSysConReg = NULL;
        }

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

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

        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;
        }
    }while(FALSE); 

    return bUnmapReg;
}

BOOL    
OutNormalMode::IsBufferInXfer(DWORD dwBufNum)
{
    DWORD dwCurrSAddr, dwInUseBufNumer;
    
    if(dwBufNum > DMA_BUFFER1) return FALSE;

    DMA_get_current_channel_sourceaddress(&m_DMACtxt, m_dwDMABufPhyPage[DMA_BUFFER0], (unsigned int *)&dwCurrSAddr, (unsigned int *)&dwInUseBufNumer);

    if(dwBufNum == dwInUseBufNumer)
        return TRUE;
    else
        return FALSE;
}

BOOL    
OutNormalMode::ULPASet(VOID)
{
#if 1
    m_pIISReg->IISCON &= ~(1<<04); //TX_S FIFO NO PAUSE(0)
    m_pIISReg->IISCON |= (1<<00); //IIS ACTIVE(1)

    m_pIISReg->IISMOD |= (1<<28); //OPMUX : APB(0), IDMA(1)

    m_pIISReg->IISSTR0 = 0xEEC00000;
    m_pIISReg->IISSTR1 = 0xEED00000;

    m_pIISReg->IISAHB |= (1<<06)| //DISABLE STR TOGGLING(0), ENABLE STR TOGGLING(1)
                         (1<<05)| //DISABLE AUTO RELOAD(0), ENALBE AUTO RELOAD(1)
                         (1<<00); //DMA EN(1)
#else
    m_pIISReg->IISCON |= (1);
	m_pIISReg->IISCON &= ~(1 << 4);
	m_pIISReg->IISMOD |= (1 << 28);		// APB -> iDMA
	m_pIISReg->IISAHB |= (1 << 5|1);		// IIS AHB DMA Control Reg. : [5] IISDMARLD (1:enable), [0] IISDMAEN (1
#endif
//	g_pAssIISReg->IISAHB &= ~(1 <<3);
    return TRUE;
}

BOOL    
OutNormalMode::ULPAClr(VOID)
{
    m_pIISReg->IISMOD &= ~(1<<28); //OPMUX : APB(0), IDMA(1)
    
    m_pIISReg->IISAHB &= ~((1<<05)| //DISABLE AUTO RELOAD(0), ENALBE AUTO RELOAD(1)
                           (1<<00));//DMA DISALBE(0), DMA EN(1)

    return TRUE;
}

BOOL 
OutNormalMode::StartTransfer()
{
    ULONG dwXferedCnt;

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

    //2 1. Member variable initialization
    m_bDMARunning = TRUE;
    m_dwElapsedTime = 0;
    
    m_dwTransfered[DMA_BUFFER0] = 0;
    m_dwTransfered[DMA_BUFFER1] = 0;
    m_dwDMAStatus = (DMA_DONE0 | DMA_DONE1) & ~DMA_BIU;
    dwXferedCnt = TransferBuffer();

    if(dwXferedCnt)
    {
        //2 2. I2S Setting
        //PRIMARY FIFO

        //OP_MUX_SEL 
        
        IIS_set_tx_mode_control(IIS_TRANSFER_NOPAUSE);
        DMA_channel_start(&m_DMACtxt);
    DBGMSG(0, (L"[WAV] I2S Setting..................\r\n"));
        //DBGMSG(WAVE_NMMODE,(L"[WAV] IB%d\r\n", ((g_pIISReg->IISFIC>>8)&0x3F)));
        IIS_set_active_on();
    }
    else
    {
        ERRMSG((L"WAV:ERR] NOM_StartTransfer() : There is no data to transfer\r\n"));
		    DBGMSG(1, (L"WAV:ERR] NOM_StartTransfer() : There is no data to transfer\r\n"));
        m_bDMARunning = FALSE;
    }

#ifdef DEBUG_MODE
    gdwISTPeriodTick = GetTickCount();
#endif

    DBGMSG(1, (L"[WAV] ---NOM_StartTransfer()\r\n"));
    Unlock();

    return m_bDMARunning;
}

BOOL    
OutNormalMode::PauseTransfer(DWORD dwParam)
{
    BOOL bPause = TRUE;
    POutLowPowerableMode pLowPower;

    Lock();
    DBGMSG(WAVE_LPMODE, (L"[WAV] +++PauseTransfer()\r\n"));
    
    if((GetCurrState() >= OUT_NM_D0) && (GetCurrState() <= OUT_NM_D2_REQ))
    {
        DWORD dwBufferInUse;
        DWORD dwStoppedAddr;
        DWORD dwXferedCnt;
        
        DMA_channel_stop(&m_DMACtxt);    
        DMA_get_current_channel_sourceaddress(&m_DMACtxt, m_dwDMABufPhyPage[0], (unsigned int *)&dwStoppedAddr, (unsigned int *)&dwBufferInUse);
        dwXferedCnt = dwStoppedAddr & (SHORT_DMA_BUF_SIZE-1);
        //DBGMSG(WAVE_INFO,(L"[WAV] Stopped Addr : 0x%X\r\n", dwStoppedAddr));

        m_pIISReg->IISCON &= ~((1<<16)| //PRIMARY FIFOn UNDER_RUN INT EN
                               (1<<02));//PRIMARY FIFOn EXT_DMA ACTIVE
        
        if(dwBufferInUse == DMA_BUFFER0)
        {
            m_dwDMAStatus = DMA_CLEAR;
            m_bDMARunning = FALSE;
            pLowPower = (POutLowPowerableMode)m_pModeChangeParam1;
            pLowPower->SavePCMBuffer(m_pDMABufVirPage[0] + dwXferedCnt, m_dwDMABufSize - dwXferedCnt);
            pLowPower->StartTransfer();
        }
        else if(dwBufferInUse == DMA_BUFFER1)
        {
            m_dwDMAStatus = DMA_CLEAR;
            m_bDMARunning = FALSE;
            pLowPower = (POutLowPowerableMode)m_pModeChangeParam1;
            pLowPower->SavePCMBuffer(m_pDMABufVirPage[1] + dwXferedCnt, m_dwDMABufSize - dwXferedCnt);
            pLowPower->StartTransfer();
        }
        else
        {
            ERRMSG((L"[WAV] PauseTransfer : Unresolved Buffer Index(%d)\r\n", dwBufferInUse));
            bPause = FALSE;
        }
    }
    else
    {
        ERRMSG((L"[WAV] PauseTransfer : Current State(%d) can not be Pause\r\n", GetCurrState()));
        bPause = FALSE;
    }
    
    DBGMSG(WAVE_LPMODE, (L"[WAV] ---PauseTransfer()\r\n"));
    Unlock();
    
    return bPause;
}

BOOL 
OutNormalMode::ResumeTransfer(VOID)
{
    DBGMSG(WAVE_NMMODE, (L"[WAV] +++NOM_ResumeTransfer()\r\n"));
    
    m_pIISReg->IISMOD &= ~(1<<28); //TXn FROM EXT_DMA

    DMA_channel_start(&m_DMACtxt);

    m_pIISReg->IISCON |= 
        (1<<31)| //UNRESET
        (1<<23)| //S_FIFO UNDER_RUN INT EN
        (1<<18)| //S_FIFO EXT_DMA ACTIVE
        (1<<0);  //IIS ACTIVE

    SetInterruptEvent(m_dwSysIntr);

    DBGMSG(WAVE_NMMODE, (L"[WAV] ---NOM_ResumeTransfer()\r\n"));

    return TRUE;
}

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

    DBGMSG(WAVE_NMMODE, (L"[WAV] +++NOM_StopTransfer()\r\n"));

    m_dwDMAStatus = DMA_CLEAR;
    DMA_channel_stop(&m_DMACtxt);

    m_pIISReg->IISCON &= ~((1<<16)| //PRIMARY FIFOn UNDER_RUN INT EN
                           (1<<02));//PRIMARY FIFOn EXT_DMA ACTIVE
            
    if(bMediumOff) IIS_set_active_off();

    m_bDMARunning = FALSE;

    DBGMSG(WAVE_NMMODE, (L"[WAV] ---NOM_StopTransfer()\r\n"));

    return bStop;
}

BOOL 
OutNormalMode::StateChange(DWORD IntSrc)
{
    BOOL bRender = TRUE;

    do
    {
        if(!((m_PowerState == D0) || (m_PowerState == D2)))
        {
            ERRMSG((L"[WAV] Unresolved PowerState : %d\r\n", m_PowerState));
            bRender = FALSE;
            break;
        }

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

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

    ERRMSG((L"[WAV] OutNormalMode InterruptThread is created\r\n"));

    while(TRUE)
    {
        WaitForSingleObject(m_hXferEvent, INFINITE);

        Lock();

        __try
        {
          
            DMA_clear_interrupt_pending(&m_DMACtxt);
            DMA_set_interrupt_mask(&m_DMACtxt);
            InterruptDone(m_dwSysIntr);
            DMA_clear_interrupt_mask(&m_DMACtxt);

#ifdef DEBUG_MODE
            {
                DWORD dwTemp = GetTickCount();
                DWORD dwBufNum = (m_dwDMAStatus & DMA_BIU) ? 1 : 0;
                DBGMSG(WAVE_NMMODE,(L"[WAV] NO%d B%dKB IB%d T%dms\r\n", dwBufNum, (GetBufferedPCMSize()/1024), ((m_pIISReg->IISFIC>>8)&0x3F), (gdwISTPeriodTick - dwTemp) ));
                gdwISTPeriodTick = dwTemp;
            }
#endif

            if(!GetRunningStatus())
            {
                ERRMSG((L"[WAV] ----------GetRunningStatus==0--------------------\r\n"));
                Unlock();
                continue;
            }

            if(StateChange(m_dwDMAStatus))
            {
                if(m_dwDMAStatus & DMA_BIU)
                {
                    m_dwDMAStatus |= DMA_DONE1;
                    m_dwDMAStatus &= ~DMA_BIU;        // Buffer A is in use
                    dwInUseBufNumer = DMA_BUFFER0;
                }
                else
                {
                    m_dwDMAStatus |= DMA_DONE0;
                    m_dwDMAStatus |= DMA_BIU;        // Buffer B is in use
                    dwInUseBufNumer = DMA_BUFFER1;
                }

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

                dwXferedCnt = TransferBuffer();
                m_dwElapsedTime += dwXferedCnt;
            }            
        }
        __except(EXCEPTION_EXECUTE_HANDLER)
        {
            ERRMSG((L"WAVDEV2.DLL:InterruptThreadOutputDMA() - EXCEPTION: %d", GetExceptionCode()));
        }

        Unlock();
    }

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

InNormalMode::InNormalMode(
InputDeviceContext *pDevCtxt, 
OutModeInterfaceLayer** ppOutMode,
PCB_MODEOP pStart, 
PCB_MODEOP pStop)
:InModeInterfaceLayer(pDevCtxt, ppOutMode, pStart, pStop)
{
    m_Mode = IN_NORMAL_MODE;
    m_bDMARunning = FALSE;
}

InNormalMode::~InNormalMode()
{
}

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

    DBGMSG(WAVE_NMMODE,(L"[WAV] +++Init()\r\n"));
    
    do
    {
        if(!MapRegister())
        {
            ERRMSG((L"[WAV:ERR] MapRegister is failed\n\r"));
            bInit = FALSE;
            break;
        }

        if(!MapDMABuffers((PVOID)NULL, SHORT_DMA_BUF_SIZE))
        {
            ERRMSG((L"[WAV:ERR] MapDMABuffers is failed\n\r"));
            bInit = FALSE;
            break;
        }
#ifdef WAV_I2S0
        //Normal Mode DMA setting
        DMA_initialize_register_address((PVOID)m_pDMAC0Reg, (PVOID)m_pDMAC1Reg,(PVOID)m_pDMACReg,  (PVOID)m_pSysConReg);
        DMA_request_channel(&m_DMACtxt, DMAsrc_I2S_0_RX);
        DMA_initialize_channel(&m_DMACtxt, TRUE);
        DMA_set_channel_source(&m_DMACtxt, IIS_get_input_physical_buffer_address(IIS_CH_0), WORD_UNIT, BURST_1, FIXED);
        DMA_set_channel_destination(&m_DMACtxt, m_dwDMABufPhyPage[0], WORD_UNIT, BURST_1, INCREASE);
        DMA_set_channel_transfer_size(&m_DMACtxt, m_dwDMABufSize);
        DMA_initialize_LLI(&m_DMACtxt, 2);
        DMA_set_LLI_entry(&m_DMACtxt, 0, LLI_NEXT_ENTRY, IIS_get_input_physical_buffer_address(IIS_CH_0),
                            m_dwDMABufPhyPage[DMA_BUFFER0], m_dwDMABufSize);
        DMA_set_LLI_entry(&m_DMACtxt, 1, LLI_FIRST_ENTRY, IIS_get_input_physical_buffer_address(IIS_CH_0),
                            m_dwDMABufPhyPage[DMA_BUFFER1], m_dwDMABufSize);
#else //ifdef WAV_I2S0
        //Normal Mode DMA setting
        DMA_initialize_register_address((PVOID)m_pDMAC0Reg, (PVOID)m_pDMAC1Reg,(PVOID)m_pDMACReg,  (PVOID)m_pSysConReg);
        DMA_request_channel(&m_DMACtxt, DMAsrc_I2S_1_RX);
        DMA_initialize_channel(&m_DMACtxt, TRUE);
        DMA_set_channel_source(&m_DMACtxt, IIS_get_input_physical_buffer_address(IIS_CH_1), WORD_UNIT, BURST_1, FIXED);
        DMA_set_channel_destination(&m_DMACtxt, m_dwDMABufPhyPage[0], WORD_UNIT, BURST_1, INCREASE);
        DMA_set_channel_transfer_size(&m_DMACtxt, m_dwDMABufSize);
        DMA_initialize_LLI(&m_DMACtxt, 2);
        DMA_set_LLI_entry(&m_DMACtxt, 0, LLI_NEXT_ENTRY, IIS_get_input_physical_buffer_address(IIS_CH_1),
                            m_dwDMABufPhyPage[DMA_BUFFER0], m_dwDMABufSize);
        DMA_set_LLI_entry(&m_DMACtxt, 1, LLI_FIRST_ENTRY, IIS_get_input_physical_buffer_address(IIS_CH_1),
                            m_dwDMABufPhyPage[DMA_BUFFER1], m_dwDMABufSize);
 
#endif       
        if(!InitTransfer(lpActivePath, m_DMACtxt.dwIRQ))
        {
            ERRMSG((L"[WAV:ERR] InitTransfer is failed\n\r"));
            bInit = FALSE;
            break;
        }

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

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

BOOL    
InNormalMode::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;
        }

        DMA_release_channel(&m_DMACtxt);
    } while(FALSE);

    return bDeinit;
}

BOOL    
InNormalMode::SetPowerState(CEDEVICE_POWER_STATE PowerState)
{
    m_PowerState = PowerState;
    return TRUE;
}

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

    do
    {
        ioPhysicalBase.LowPart = BASE_REG_PA_MDMA;
        m_pDMACReg = (DMAC_REG *)MmMapIoSpace(ioPhysicalBase, sizeof(DMAC_REG), FALSE);
        if (m_pDMACReg == NULL)
        {
            ERRMSG((L"[WAV:ERR] MapRegisters() : m_pDMACReg MmMapIoSpace() Failed\n\r"));
            bMapReg = FALSE;
            break;
        }

        ioPhysicalBase.LowPart = BASE_REG_PA_PDMA0;
        m_pDMAC0Reg = (DMAC_REG *)MmMapIoSpace(ioPhysicalBase, sizeof(DMAC_REG), FALSE);
        if (m_pDMAC0Reg == NULL)
        {
            ERRMSG((L"[WAV:ERR] MapRegisters() : m_pDMAC0Reg MmMapIoSpace() Failed\n\r"));
            bMapReg = FALSE;
            break;
        }

        // Alloc and Map DMAC1 SFR
        ioPhysicalBase.LowPart = BASE_REG_PA_PDMA1;
        m_pDMAC1Reg = (DMAC_REG *)MmMapIoSpace(ioPhysicalBase, sizeof(DMAC_REG), FALSE);
        if (m_pDMAC1Reg == NULL)
        {
            ERRMSG((L"[WAV:ERR] MapRegisters() : m_pDMAC1Reg MmMapIoSpace() Failed\n\r"));
            bMapReg = FALSE;
            break;
        }

        ioPhysicalBase.LowPart = BASE_REG_PA_CMU_CLK;
        m_pSysConReg = (CMU_CLK_REG *)MmMapIoSpace(ioPhysicalBase, sizeof(CMU_CLK_REG), FALSE);
        if (m_pSysConReg == NULL)
        {
            ERRMSG((L"[WAV:ERR] MapRegisters() : m_pSysConReg MmMapIoSpace() Failed\n\r"));
            bMapReg = FALSE;
            break;
        }

        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;
        }

        ioPhysicalBase.LowPart = BASE_REG_PA_I2S0;
        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;
        }
    }while(FALSE); 

    return bMapReg;
}

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

    do
    {
        if(m_pDMAC0Reg)
        {
            MmUnmapIoSpace((PVOID)m_pDMAC0Reg, sizeof(DMAC_REG));
            m_pDMAC0Reg = NULL;
        }

        if(m_pDMAC1Reg)
        {
            MmUnmapIoSpace((PVOID)m_pDMAC1Reg, sizeof(DMAC_REG));
            m_pDMAC1Reg = NULL;
        }

        if(m_pDMACReg)
        {
            MmUnmapIoSpace((PVOID)m_pDMACReg, sizeof(DMAC_REG));
            m_pDMACReg = NULL;
        }

        if(m_pSysConReg)
        {
            MmUnmapIoSpace((PVOID)m_pSysConReg, sizeof(CMU_CLK_REG));
            m_pSysConReg = NULL;
        }

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

        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;
        }
    }while(FALSE); 

    return bUnmapReg;
}

BOOL 
InNormalMode::StartTransfer()
{
    DBGMSG(WAVE_NMMODE, (L"[WAV] +++NIM_StartTransfer()\r\n"));

    m_bDMARunning = TRUE;
    
    m_dwTransfered[DMA_BUFFER0] = 0;
    m_dwTransfered[DMA_BUFFER1] = 0;
    m_dwDMAStatus = DMA_CLEAR;

    IIS_set_rx_mode_control(IIS_TRANSFER_NOPAUSE);
    DMA_channel_start(&m_DMACtxt);
    IIS_set_active_on();

    DBGMSG(WAVE_NMMODE, (L"[WAV] ---NIM_StartTransfer()\r\n"));

    return TRUE;
}

BOOL 
InNormalMode::ResumeTransfer(VOID)
{
    return TRUE;
}

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

    DBGMSG(WAVE_NMMODE, (L"[WAV] +++NIM_StopTransfer()\r\n"));

    m_dwDMAStatus = DMA_CLEAR;
    DMA_channel_stop(&m_DMACtxt);
    IIS_set_rx_mode_control(IIS_TRANSFER_PAUSE);
    if(bMediumOff) IIS_set_active_off();     

    m_bDMARunning = FALSE;

    DBGMSG(WAVE_NMMODE, (L"[WAV] ---NIM_StopTransfer()\r\n"));

    return bStop;
}

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

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

    while(TRUE)
    {
        WaitForSingleObject(m_hXferEvent, INFINITE);

        Lock();

        __try
        {
            
            DMA_clear_interrupt_pending(&m_DMACtxt);
            DMA_set_interrupt_mask(&m_DMACtxt);
            InterruptDone(m_dwSysIntr);
            DMA_clear_interrupt_mask(&m_DMACtxt);

#ifdef DEBUG_MODE
            {
                DWORD dwBufNum = (m_dwDMAStatus & DMA_BIU) ? 1 : 0;
                DBGMSG(WAVE_NMMODE,(L"[WAV] NI%d B%dKB IB%d T%dms\r\n", dwBufNum));
            }
#endif

            if(m_dwDMAStatus & DMA_BIU)
            {
                m_dwDMAStatus |= DMA_DONE1;
                m_dwDMAStatus &= ~DMA_BIU;        // Buffer A is in use
                dwInUseBufNumer = DMA_BUFFER0;
            }
            else
            {
                m_dwDMAStatus |= DMA_DONE0;
                m_dwDMAStatus |= DMA_BIU;        // Buffer B is in use
                dwInUseBufNumer = DMA_BUFFER1;
            }
            
            dwXferedCnt = TransferBuffer();           
        }
        __except(EXCEPTION_EXECUTE_HANDLER)
        {
            ERRMSG((L"WAVDEV2.DLL:InterruptThreadOutputDMA() - EXCEPTION: %d", GetExceptionCode()));
        }

        Unlock();
    }

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

