#include <ModeInterfaceLayer.h>
#include <ceddk.h>
#include <Wavemain.h>
#include <Drvmsg.h>

//#define DEBUG_MODE

extern"C" VOID BurstCopy(PDWORD pDst, PDWORD pSrc, DWORD dwSize);

void CallInterruptThread(PModeInterfaceLayer pModeCtxt)
{
    pModeCtxt->InterruptThread();
}

ModeInterfaceLayer::ModeInterfaceLayer()
{
    m_bSelfPowerNotify = FALSE;
    
    m_dwDMABufPhyPage[0] = 0;
    m_dwDMABufPhyPage[1] = 0;
    m_pDMABufVirPage[0] = NULL;
    m_pDMABufVirPage[1] = NULL;
    m_dwTransfered[0] = 0;
    m_dwTransfered[1] = 0;

    m_PhyDMABufAddr.LowPart = NULL;
    m_pVirDMABufAddr = NULL;

    m_bDMARunning = FALSE;
    m_dwDMAStatus = DMA_CLEAR;

    m_hXferThread = NULL;
    m_dwThreadPriority = 95;
        
    InitializeCriticalSection(&m_CriticalSection);
}

ModeInterfaceLayer::~ModeInterfaceLayer()
{
    DeleteCriticalSection(&m_CriticalSection);
}

BOOL
ModeInterfaceLayer::InitTransfer(LPWSTR lpActivePath, DWORD dwIrq)
{
    BOOL bInit = TRUE;

    DBGMSG(WAVE_INFO, (L"[WAV] +++InitTransfer()\r\n"));

    do
    {
        if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &dwIrq, sizeof(DWORD), &m_dwSysIntr, sizeof(DWORD), NULL))
        {
            ERRMSG((L"[WAV:ERR] IOCTL_HAL_REQUEST_SYSINTR is failed \n\r"));
            bInit = FALSE;
            break;
        }

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

        if (!InterruptInitialize(m_dwSysIntr, m_hXferEvent, NULL, 0))
        {
            ERRMSG((L"[WAV:ERR] InterruptInitialize is failed \n\r"));
            bInit = FALSE;
            break;
        }    

        m_hXferThread = CreateThread((LPSECURITY_ATTRIBUTES)NULL, 0, (LPTHREAD_START_ROUTINE)CallInterruptThread, this, 0, NULL);
        if (m_hXferThread == NULL)
        {
            ERRMSG((L"[WAV:ERR] CreateThread is failed \n\r"));
            bInit = FALSE;
            break;
        }

        m_dwThreadPriority = GetInterruptThreadPriority(lpActivePath);

        CeSetThreadPriority(m_hXferThread, m_dwThreadPriority);
    } while(FALSE);

    DBGMSG(WAVE_INFO, (L"[WAV] ---InitTransfer()\r\n"));

    return bInit;
}

BOOL    
ModeInterfaceLayer::InitTransfer(LPWSTR lpActivePath, DWORD dwIrq, PDWORD pdwSysIntr, PHANDLE phXferEvent, PHANDLE phXferThread, LPTHREAD_START_ROUTINE CallInterruptThread)
{
    BOOL bInit = TRUE;

    DBGMSG(WAVE_INFO, (L"[WAV] +++InitTransfer()\r\n"));

    do
    {
        if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &dwIrq, sizeof(DWORD), pdwSysIntr, sizeof(DWORD), NULL))
        {
            ERRMSG((L"[WAV:ERR] IOCTL_HAL_REQUEST_SYSINTR is failed \n\r"));
            bInit = FALSE;
            break;
        }

        *phXferEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
        if (*phXferEvent == NULL)
        {
            ERRMSG((L"[WAV:ERR] CreateEvent is failed \n\r"));
            bInit = FALSE;
            break;
        }    

        if (!InterruptInitialize(*pdwSysIntr, *phXferEvent, NULL, 0))
        {
            ERRMSG((L"[WAV:ERR] InterruptInitialize is failed \n\r"));
            bInit = FALSE;
            break;
        }    

        *phXferThread = CreateThread((LPSECURITY_ATTRIBUTES)NULL, 0, CallInterruptThread, this, 0, NULL);
        if (*phXferThread == NULL)
        {
            ERRMSG((L"[WAV:ERR] CreateThread is failed \n\r"));
            bInit = FALSE;
            break;
        }

        m_dwThreadPriority = GetInterruptThreadPriority(lpActivePath);

        CeSetThreadPriority(*phXferThread, m_dwThreadPriority);
    } while(FALSE);

    DBGMSG(WAVE_INFO, (L"[WAV] ---InitTransfer()\r\n"));

    return bInit;
}

BOOL    
ModeInterfaceLayer::DeinitTransfer(VOID)
{
    BOOL bDeinit = TRUE;

    DBGMSG(WAVE_INFO, (L"[WAV] +++DeinitTransfer()\r\n"));

    do
    {
		InterruptDisable(m_dwSysIntr);

		if (!KernelIoControl(IOCTL_HAL_RELEASE_SYSINTR, &m_dwSysIntr, sizeof(m_dwSysIntr), NULL, 0, NULL))
		{
			ERRMSG((L"[WAV] It's failed to request to release sysintr\r\n"));
			bDeinit = FALSE;
			break;
		}

		if(!CloseHandle(m_hXferEvent))
		{
			ERRMSG((L"[WAV] It's failed to close m_hXferEvent\r\n"));
			bDeinit = FALSE;
			break;
		}
	
		if(!TerminateThread(m_hXferThread, 0))
		{
			ERRMSG((L"[WAV] Terminatting Thread is failed\n"));
			bDeinit = FALSE;
			break;
		}

		if(!CloseHandle(m_hXferThread))
		{
			ERRMSG((L"[WAV] It's failed to close m_hXferThread\r\n"));
			bDeinit = FALSE;
			break;
		}
    } while(FALSE);

    DBGMSG(WAVE_INFO, (L"[WAV] ---DeinitTransfer()\r\n"));

    return bDeinit;
}

BOOL
ModeInterfaceLayer::DeinitTransfer(DWORD dwSysIntr, HANDLE hXferEvent, HANDLE hXferThread)
{
    BOOL bDeinit = TRUE;

    DBGMSG(WAVE_INFO, (L"[WAV] +++DeinitTransfer()\r\n"));

    do
    {
		InterruptDisable(dwSysIntr);

		if (!KernelIoControl(IOCTL_HAL_RELEASE_SYSINTR, &m_dwSysIntr, sizeof(m_dwSysIntr), NULL, 0, NULL))
		{
			ERRMSG((L"[WAV] It's failed to request to release sysintr\r\n"));
			bDeinit = FALSE;
			break;
		}

		if(!CloseHandle(hXferEvent))
		{
			ERRMSG((L"[WAV] It's failed to close m_hXferEvent\r\n"));
			bDeinit = FALSE;
			break;
		}
	
		if(!TerminateThread(hXferThread, 0))
		{
			ERRMSG((L"[WAV] Terminatting Thread is failed\n"));
			bDeinit = FALSE;
			break;
		}

		if(!CloseHandle(hXferThread))
		{
			ERRMSG((L"[WAV] It's failed to close m_hXferThread\r\n"));
			bDeinit = FALSE;
			break;
		}
    } while(FALSE);

    DBGMSG(WAVE_INFO, (L"[WAV] ---DeinitTransfer()\r\n"));

    return bDeinit;
}

BOOL
ModeInterfaceLayer::MapDMABuffers(PVOID pBufPhyAddr, DWORD dwBufSize)
{
    BOOL bAlloc = TRUE;

    DBGMSG(WAVE_INFO,(L"[WAV] ---MapDMABuffers()\n\r"));

    do
    {
        if(pBufPhyAddr)
        {
            m_PhyDMABufAddr.LowPart = (DWORD)pBufPhyAddr;
            m_pVirDMABufAddr = (PBYTE)MmMapIoSpace(m_PhyDMABufAddr, LONG_DMA_DBUF_SIZE, FALSE);
            if (m_pVirDMABufAddr == NULL)
            { 
                ERRMSG((L"[WAV] m_pVirDMABufAddr MmMapIoSpace() Failed\n\r"));
                bAlloc = FALSE;
                break;
            }
        }
        else
        {
            DMA_ADAPTER_OBJECT Adapter;
            
            memset(&Adapter, 0, sizeof(DMA_ADAPTER_OBJECT));
            Adapter.ObjectSize = sizeof(DMA_ADAPTER_OBJECT);
            Adapter.InterfaceType = Internal;

            m_pVirDMABufAddr = (PBYTE)HalAllocateCommonBuffer(&Adapter, (dwBufSize*2), &m_PhyDMABufAddr, FALSE);
            if (m_pVirDMABufAddr == NULL)
            { 
                ERRMSG((L"[WAV:ERR] MapDMABuffers() : DMA Buffer Allocation Failed\n\r"));
                bAlloc = FALSE;
                break;
            }
        }

        m_dwDMABufPhyPage[DMA_BUFFER0] = (DWORD)(m_PhyDMABufAddr.LowPart);
        m_dwDMABufPhyPage[DMA_BUFFER1] = (DWORD)(m_PhyDMABufAddr.LowPart + dwBufSize);

        m_pDMABufVirPage[DMA_BUFFER0] = (PBYTE)(m_pVirDMABufAddr);
        m_pDMABufVirPage[DMA_BUFFER1] = (PBYTE)(m_pVirDMABufAddr + dwBufSize);

        m_dwDMABufSize = dwBufSize;

        DBGMSG(WAVE_INFO,(L"[WAV] MAP TABLE\n\r"));
        DBGMSG(WAVE_INFO,(L"[WAV] A BUFFER(PHY) : 0x%X\n\r", m_dwDMABufPhyPage[DMA_BUFFER0]));
        DBGMSG(WAVE_INFO,(L"[WAV] B BUFFER(PHY) : 0x%X\n\r", m_dwDMABufPhyPage[DMA_BUFFER1]));
        DBGMSG(WAVE_INFO,(L"[WAV] A BUFFER(VIR) : 0x%X\n\r", m_pDMABufVirPage[DMA_BUFFER0]));
        DBGMSG(WAVE_INFO,(L"[WAV] B BUFFER(VIR) : 0x%X\n\r", m_pDMABufVirPage[DMA_BUFFER1]));
    } while(FALSE);

    //DEBUGGING FOR MEMORY TEST
    /*
    {
        DMA_ADAPTER_OBJECT Adapter;
        
        memset(&Adapter, 0, sizeof(DMA_ADAPTER_OBJECT));
        Adapter.ObjectSize = sizeof(DMA_ADAPTER_OBJECT);
        Adapter.InterfaceType = Internal;

        m_pVirXferBufAddr = (PBYTE)HalAllocateCommonBuffer(&Adapter, (LONG_DMA_BUF_SIZE), &m_PhyXferBufAddr, FALSE);
        if (m_pVirXferBufAddr == NULL)
        { 
            ERRMSG((L"[WAV:ERR] MapDMABuffers() : DMA Buffer Allocation Failed\n\r"));
            bInit = FALSE;
            break;
        }
    }
    */

    DBGMSG(WAVE_INFO,(L"[WAV] ---MapDMABuffers()\n\r"));
    
    return bAlloc;
}

BOOL
ModeInterfaceLayer::UnmapDMABuffers()
{
    if(m_PhyDMABufAddr.LowPart)
    {
        HalFreeCommonBuffer(0, 0, m_PhyDMABufAddr, m_pVirDMABufAddr, FALSE);
    }
    else
    {
        MmUnmapIoSpace(m_pVirDMABufAddr, LONG_DMA_DBUF_SIZE);
    }
    
    return TRUE;
}

DWORD
ModeInterfaceLayer::GetInterruptThreadPriority(LPWSTR lpActivePath)
{
    HKEY hDevKey;
    DWORD dwValType;
    DWORD dwValLen;
    DWORD dwPrio = INTERRUPT_THREAD_PRIORITY_DEFAULT;

    hDevKey = OpenDeviceKey(lpActivePath);
    if (hDevKey)
    {
        dwValLen = sizeof(DWORD);
        if(RegQueryValueEx(hDevKey, TEXT("Priority256"), NULL, &dwValType, (PUCHAR)&dwPrio, &dwValLen))
        {
            dwPrio = 95;
        }
        
        RegCloseKey(hDevKey);
    }
    else
    {
        ERRMSG((L"[WAV:ERR] GetInterruptThreadPriority() : OpenDeviceKey() Failed\n\r"));
    }

    return dwPrio;
}

OutModeInterfaceLayer::OutModeInterfaceLayer(
    OutputDeviceContext *pDevCtxt, 
    PPInModeInterfaceLayer ppInMode,
    PCB_MODEOP pStart, 
    PCB_MODEOP pStop)
    :ModeInterfaceLayer()
{
    m_ppInMode = ppInMode;
    m_pOutDevCtxt = pDevCtxt;
    m_pStartPlayback = pStart;
    m_pStopPlayback = pStop;

    m_dwFillSize = 0;
    m_pSBCurrPtr = NULL;
    memset(m_SavingBuffer, 0x0, sizeof(m_SavingBuffer));
    
    m_bModeChange = FALSE;
    m_pModeChangeParam1 = NULL;

    m_hWaveEvent = CreateEvent(NULL, FALSE, FALSE, WAVE_EVENT_NAME);
}

OutModeInterfaceLayer::~OutModeInterfaceLayer()
{
    CloseHandle(m_hWaveEvent);
}

BOOL 
OutModeInterfaceLayer::IsAllStreamReady(DWORD dwMinBuffedSize)
{
    return m_pOutDevCtxt->IsAllStreamReady(dwMinBuffedSize);
}

DWORD   
OutModeInterfaceLayer::GetBufferedPCMSize(VOID)
{
    return m_pOutDevCtxt->GetBufferedPCMSize();
}


BOOL 
OutModeInterfaceLayer::SavePCMBuffer(PBYTE pSrc, DWORD dwSize, BOOL bCopy)
{
    BOOL bSave = TRUE;
    //PDWORD pdwXferedDst, pdwXferedSrc;
    //DWORD dwBurstXferCnt;
    //DWORD dwByteXferCnt;

    //DBGMSG(WAVE_INFO,(L"[WAV] +++SavePCMBuffer(0x%X, 0x%X)\r\n", pSrc, dwLength));
    
    do
    {
        if(!IS_WORD_ALIGNMENT(pSrc) || !IS_WORD_ALIGNMENT(dwSize))
        {
            ERRMSG(("[WAV] pSrc(0x%X) or dwSize(0x%X) is not aligned\r\n", pSrc, dwSize));
            bSave = FALSE;
            break;
        }

        if(bCopy)
        {
            if(dwSize > LONG_DMA_BUF_SIZE)
            {
                ERRMSG(("[WAV] dwSize is larger than LONG_DMA_BUF_SIZE\r\n"));
                bSave = FALSE;
                break;
            }
            /*
            dwByteXferCnt = dwSize % 32; 
            dwBurstXferCnt = dwSize - dwByteXferCnt;
            dwByteXferCnt /= 4;
            */
            
            //BurstCopy((PDWORD)m_SavingBuffer, (PDWORD)pSrc, dwBurstXferCnt);
            BurstCopy((PDWORD)m_SavingBuffer, (PDWORD)pSrc, dwSize);
            /*
            pdwXferedDst = (PDWORD)(m_SavingBuffer + dwBurstXferCnt);
            pdwXferedSrc = (PDWORD)(pSrc + dwBurstXferCnt);
            for(DWORD i=0; i<dwByteXferCnt;)
            {
                pdwXferedDst[i] = pdwXferedSrc[i];
            }
            */
            
        m_pSBCurrPtr = &m_SavingBuffer[0];
            m_dwFillSize = dwSize;
        }
        else
        {
            m_pSBCurrPtr = pSrc;
            m_dwFillSize = dwSize;
        }
    } while(FALSE);

    //DBGMSG(WAVE_INFO,(L"[WAV] ---SavePCMBuffer()\r\n", pSrc, dwLength));
    
    return bSave;
}

PBYTE 
OutModeInterfaceLayer::TransferBufferFromSB(PBYTE pStart, PBYTE pEnd)
{
    DWORD dwSize = (pEnd - pStart);
    PBYTE pLast;

    do
    {
        if(!m_dwFillSize || !m_pSBCurrPtr)
    {
            pLast = pStart;
            break;
    }
        
        if(!IS_WORD_ALIGNMENT(pStart) || !IS_WORD_ALIGNMENT(pEnd))
    {
            ERRMSG(("[WAV] pStart(0x%X) or pEnd(0x%X) is not aligned\r\n", pStart, pEnd));
            pLast = pStart;
            break;
    }

        if(m_dwFillSize >= dwSize)
        {
            //DBGMSG(WAVE_INFO,(L"[WAV] +++TransferBufferFromSB1(%d, %d, 0x%X, 0x%X)\r\n",m_dwFillSize, dwSize, pStart, m_pSBCurrPtr));
            //DBGMSG(WAVE_INFO,(L"[WAV] ---TransferBufferFromSB()\r\n"));

            BurstCopy((PDWORD)pStart, (PDWORD)m_pSBCurrPtr, dwSize);  

            pLast = pStart + dwSize;
            m_dwFillSize -= dwSize;
            m_pSBCurrPtr += dwSize;
        }
        else
{
            //DBGMSG(WAVE_INFO,(L"[WAV] +++TransferBufferFromSB2(%d, %d, 0x%X, 0x%X)\r\n",m_dwFillSize, dwSize, pStart, m_pSBCurrPtr));
            //DBGMSG(WAVE_INFO,(L"[WAV] ---TransferBufferFromSB()\r\n"));
            
            BurstCopy((PDWORD)pStart, (PDWORD)m_pSBCurrPtr, m_dwFillSize);
                    
            pLast = pStart + m_dwFillSize;
            m_dwFillSize = 0;
            m_pSBCurrPtr = NULL;
        }
    } while(FALSE);

    return pLast;
}

DWORD 
OutModeInterfaceLayer::FillBuffer(PBYTE pStart, DWORD dwSize)
{
    DWORD dwXferedCnt1 = 0, dwXferedCnt2 = 0;
    PBYTE pBufferStart = pStart;
    PBYTE pBufferEnd = pBufferStart + dwSize;
    PBYTE pBufferLast;

    pBufferLast = TransferBufferFromSB(pBufferStart, pBufferEnd);
    dwXferedCnt1 = pBufferLast-pBufferStart;
    pBufferStart += dwXferedCnt1;
  
    if(pBufferStart < pBufferEnd)
    {
        //DBGMSG(WAVE_INFO,(L"[WAV] TransferBuffer(%d)\r\n", (pBufferEnd - pBufferStart)/1024));
        pBufferLast = m_pOutDevCtxt->TransferBuffer(pBufferStart, pBufferEnd, NULL);
        dwXferedCnt2 = (pBufferLast-pBufferStart);
        pBufferStart += dwXferedCnt2;
    }
    
    if(pBufferLast != pBufferEnd)
    {
    // Enable if you need to clear the rest of the DMA buffer
        DBGMSG(WAVE_INFO,(L"[WAV] Clear Buffer From 0x%X To 0x%X\r\n", pBufferLast, pBufferEnd));
    StreamContext::ClearBuffer(pBufferLast, pBufferEnd);
    }

    return (dwXferedCnt1+dwXferedCnt2);
}

DWORD 
OutModeInterfaceLayer::FillBuffer(DWORD dwBufNum)
{
    DWORD dwFilledCnt;

//    DBGMSG(1,(L"[WAV] +++FillBuffer(Num : %d, Size : %dKB)\r\n", dwBufNum, (m_dwDMABufSize/1024)));
//	 DBGMSG(1, (L"[WAV] LTransferBuffer         DMA_DONE0 and 1          \r\n"));  
    dwFilledCnt = FillBuffer(m_pDMABufVirPage[dwBufNum], m_dwDMABufSize);
    m_dwTransfered[dwBufNum] = dwFilledCnt;

    if(dwBufNum == DMA_BUFFER0)
    {
        m_dwDMAStatus &= ~DMA_DONE0;
    }
    else                  
    {
        m_dwDMAStatus &= ~DMA_DONE1;
    }

    //DBGMSG(WAVE_INFO,(L"[WAV] ---FillBuffer()\r\n"));

    return dwFilledCnt;
}

DWORD 
OutModeInterfaceLayer::TransferBuffer(VOID)
{
    DWORD dwXferedCnt = 0;
    DWORD dwXferedTot = 0;
	
 //   DBGMSG(1, (L"[WAV] LTransferBuffer\r\n"));  						

    switch (m_dwDMAStatus & (DMA_DONE0|DMA_DONE1))
    {
        case DMA_CLEAR:
            // No done bits set- must not be my interrupt
            return 0;
        case DMA_DONE0:
//		 DBGMSG(1, (L"[WAV] LTransferBuffer         DMA_DONE0           \r\n"));  	
            dwXferedCnt = FillBuffer(DMA_BUFFER0);
            break;
        case DMA_DONE1:
//		 DBGMSG(1, (L"[WAV] LTransferBuffer         DMA_DONE1           \r\n"));  			
            dwXferedCnt = FillBuffer(DMA_BUFFER1);
            break;
        case DMA_DONE0|DMA_DONE1:
//		 DBGMSG(1, (L"[WAV] LTransferBuffer         DMA_DONE0 and 1          \r\n"));  			
            dwXferedCnt = FillBuffer(DMA_BUFFER0);
            dwXferedCnt += FillBuffer(DMA_BUFFER1);
            break;
        default:
            ERRMSG(("[WAV] TransferBuffer(Unknown m_dwDMAStatus : 0x%X)\r\n", m_dwDMAStatus));
            break;
    }

    // If it was our interrupt, but we weren't able to transfer any bytes
    // (e.g. no full buffers ready to be emptied)
    // and all the output DMA buffers are now empty, then stop the output DMA
    
    dwXferedTot = m_dwTransfered[DMA_BUFFER0] + m_dwTransfered[DMA_BUFFER1];

    if (dwXferedTot == 0)
    {
        DBGMSG(WAVE_INFO,(L"[WAV] Request Stopping from TransferBuffer\r\n"));
        m_pStopPlayback();
    }
/*  else
    {
        m_pStartPlayback();        // for DMA resume when wake up
    }*/
    DBGMSG(0, (L"[WAV] ---dwXferedCnt==%d\r\n",dwXferedCnt));
    return dwXferedCnt;
}

VOID 
OutModeInterfaceLayer::DumpPCMData(PBYTE pBuffer, DWORD dwBytes, BOOL bNeedAlignment)
{
#ifdef DEBUG_MODE
    DWORD dwWritten;

    //DBGMSG(WAVE_INFO, (L"[WAV] DA : 0x%X, DL: %d\r\n", pBuffer, dwBytes));

    if(bNeedAlignment)
    {
        PBYTE pData = new BYTE[dwBytes];

        PDWORD  pdwSrc = (PDWORD)pBuffer;
        PDWORD  pdwDst = (PDWORD)pData;
        DWORD dwWSize = dwBytes>>2;
        
        for(DWORD i=0; i<dwWSize; ++i)
        {
            pdwDst[i] = pdwSrc[i];
        }       
        
        //BurstCopy((PDWORD)pData, (PDWORD)pBuffer, dwBytes);
        WriteFile(m_hDumpFile, pData, dwBytes, &dwWritten, NULL);
        
        delete pData;
    }
    else
    {
        WriteFile(m_hDumpFile, pBuffer, dwBytes, &dwWritten, NULL);
    }
#endif
}

InModeInterfaceLayer::InModeInterfaceLayer(
    InputDeviceContext *pDevCtxt, 
    OutModeInterfaceLayer** ppOutMode,
    PCB_MODEOP pStart, 
    PCB_MODEOP pStop)
    :ModeInterfaceLayer()
{
    m_Mode = IN_ANONYMOUSE_MODE;

    m_ppOutMode = ppOutMode;
    m_pInDevCtxt = pDevCtxt;
    m_pStartPlayback = pStart;
    m_pStopPlayback = pStop;
}

InModeInterfaceLayer::~InModeInterfaceLayer()
{
}

DWORD 
InModeInterfaceLayer::FillBuffer(DWORD dwBufNum)
{
    DWORD dwTransferred = 0;
    PBYTE pBufferStart = m_pDMABufVirPage[dwBufNum];
    PBYTE pBufferEnd = pBufferStart + m_dwDMABufSize;
    PBYTE pBufferLast;

    //DBGMSG(WAVE_INFO,(L"[WAV] +++FillBuffer(Num : %d, Size : %dKB)\r\n", dwBufNum, (m_dwDMABufSize/1024)));

    pBufferLast = m_pInDevCtxt->TransferBuffer(pBufferStart, pBufferEnd, NULL);
    dwTransferred = m_dwTransfered[dwBufNum] = pBufferLast-pBufferStart;

    if(dwBufNum == DMA_BUFFER0)
    {
        m_dwDMAStatus &= ~DMA_DONE0;
    }
    else
    {
        m_dwDMAStatus &= ~DMA_DONE1;
    }

    //DBGMSG(WAVE_INFO,(L"[WAV] ---FillBuffer()\r\n"));

    return dwTransferred;
}

DWORD 
InModeInterfaceLayer::TransferBuffer(VOID)
{
    DWORD dwXferedCnt = 0;
    DWORD dwXferedTot = 0;

    switch (m_dwDMAStatus & (DMA_DONE0|DMA_DONE1))
    {
        case DMA_CLEAR:
            // No done bits set- must not be my interrupt
            return 0;
        case DMA_DONE0:
            dwXferedCnt = FillBuffer(DMA_BUFFER0);
            break;
        case DMA_DONE1:
            dwXferedCnt = FillBuffer(DMA_BUFFER1);
            break;
        case DMA_DONE0|DMA_DONE1:
            dwXferedCnt = FillBuffer(DMA_BUFFER0);
            dwXferedCnt += FillBuffer(DMA_BUFFER1);
            break;
        default:
            ERRMSG(("[WAV] TransferBuffer(Unknown m_dwDMAStatus : 0x%X)\r\n", m_dwDMAStatus));
            break;
    }

    // If it was our interrupt, but we weren't able to transfer any bytes
    // (e.g. no full buffers ready to be emptied)
    // and all the output DMA buffers are now empty, then stop the output DMA
    
    dwXferedTot = m_dwTransfered[DMA_BUFFER0] + m_dwTransfered[DMA_BUFFER1];
    if (dwXferedTot == 0)
    {
        m_pStopPlayback();
    }
/*  else
    {
        m_pStartPlayback();        // for DMA resume when wake up
    }*/

    return dwXferedCnt;
}
