//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//
// Copyright (c) Samsung Electronics. Co. LTD.  All rights reserved.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

Module Name:    LocalPathAPI.c

Abstract:       Implementation of Video Driver
                This module handle Local Path control for each IP's IOCTLs

Functions:


Notes:


--*/

#include <bsp.h>
#include "SVEngine.h"
#include <CAMDriver.h>

#ifdef USE_LOCALPATH_EMUL_WITH_MEM2MEM
#include "CMMAPI.h"

#define LOCALPATH_FB_NUM 3
#define LPE_POST_THREAD_PRIORITY 100

static HANDLE g_hCmmFB = NULL;
static unsigned int g_uiFBVirAddr[LOCALPATH_FB_NUM];
static unsigned int g_uiFBPhyAddr[LOCALPATH_FB_NUM];
static HANDLE g_hPostReadyEvent = NULL;
static HANDLE g_hPostBusyEvent = NULL;
static HANDLE g_hPostTreadEnd = NULL;
static BOOL g_bPostThreadExit = FALSE;
static HANDLE g_hPostIST = NULL;
static unsigned int g_uiCurPostFB = 0;
static CAMARG_POST_PARAMETER g_tPostParam;

static BOOL SVE_LpeAllocCmmMemory(unsigned int uiSize, DWORD Loc,
                                unsigned int* puiPhy, unsigned int* puiVir);
static void SVE_LpeReleaseCmmMemory(PBYTE pbVir);
static BOOL SVE_LpeInitVariables(unsigned int uiSize);
static void SVE_LpeDeInitVariables(void);
static unsigned int SVE_LpeGetCurrentBuffer(void);
static void SVE_LpeChangeBuffer(void);
static BOOL SVE_LpePrepare(HANDLE hCamera, DWORD hOpenContext,
                                DISP_WINDOW eDispWin, DISP_WINDOW_MODE eWinMode);
static void SVE_LpePostThread(void);
#endif // USE_LOCALPATH_EMUL_WITH_MEM2MEM

//extern DBGPARAM dpCurSettings;

BOOL SVE_LocalPath_API_Proc(
    DWORD hOpenContext,
    DWORD dwCode,
    PBYTE pBufIn,
    DWORD dwLenIn,
    PBYTE pBufOut,
    DWORD dwLenOut,
    PDWORD pdwActualOut
    )
{
    SVEngineContext *pCtxt;
    SVEnginePowerContext *pPMCtxt;
    BOOL bRet = TRUE;

    VDE_MSG((_T("[VDE] ++SVE_LocalPath_API_Proc()\n\r")));

    pCtxt = SVE_get_context();
    pPMCtxt = SVE_get_power_context();

    //-------------------------------------------------------------
    // Check OpenContext of Caller have the right to access to H/W Resource
    //-------------------------------------------------------------
    switch(dwCode)
    {
        case SVE_LOCALPATH_SET_WIN0_START:
        case SVE_LOCALPATH_SET_WIN0_STOP:
        {
            bRet = (SVE_resource_compare_FIMD_window(DISP_WIN0, hOpenContext)
                    && SVE_resource_compare_Post(hOpenContext));
            if (!bRet)
            {
                VDE_ERR((_T("[VDE:ERR] SVE_LocalPath_API_Proc(0x%08x) : No Right to Access to H/W Resource\r\n"), dwCode));
                goto CleanUp;
            }
            break;
        }
        case SVE_LOCALPATH_SET_WIN1_START:
        case SVE_LOCALPATH_SET_WIN1_STOP:
        {
            bRet = (SVE_resource_compare_FIMD_window(DISP_WIN1, hOpenContext)
                    && SVE_resource_compare_Post(hOpenContext));
            if (!bRet)
            {
                VDE_ERR((_T("[VDE:ERR] SVE_LocalPath_API_Proc(0x%08x) : No Right to Access to H/W Resource\r\n"), dwCode));
                goto CleanUp;
            }
            break;
        }

        case SVE_LOCALPATH_SET_WIN2_START:
        case SVE_LOCALPATH_SET_WIN2_STOP:
        {
            bRet = (SVE_resource_compare_FIMD_window(DISP_WIN2, hOpenContext)
                    && SVE_resource_compare_Post(hOpenContext));
            if (!bRet)
            {
                VDE_ERR((_T("[VDE:ERR] SVE_LocalPath_API_Proc(0x%08x) : No Right to Access to H/W Resource\r\n"), dwCode));
                goto CleanUp;
            }
            break;
        }
        default:
            VDE_ERR( (TEXT("[VDE:ERR] Invalid IOCTL code\n")));
            bRet = FALSE;
        goto CleanUp;
    }


    //---------------------------------------
    // Processing IOCTL for Local Path (FIMD+Post)
    //---------------------------------------
    switch(dwCode)
    {
        case SVE_LOCALPATH_SET_WIN0_START:
        {
            BOOL bRetry = TRUE;

            VDE_MSG((_T("[VDE] SVE_LocalPath_API_Proc() : SVE_LOCALPATH_SET_WIN0_START\n\r")));

            if (pPMCtxt->bPowerOn)
            {
                // Enable Post Interrupt
                Disp_set_framebuffer(DISP_WIN0, g_VideoMemoryPhysicalBase);    // Safe Frame Bufer Address for Local Path
                Disp_window_onfoff(DISP_WIN0, DISP_WINDOW_ON);

                pCtxt->bWindowEnable[DISP_WIN0] = TRUE;

                bRet = DeviceIoControl(pCtxt->hCamera, IOCTL_CAM_POST_SET_PROCESSING_START, pBufIn, dwLenIn, pBufOut, dwLenOut, pdwActualOut, NULL);
                if(!bRet)
                {
                    VDE_ERR( (_T("[VDE:ERR] %s() : Cannot Start Post Processor\n\r"), _T(__FUNCTION__)));
                    Disp_window_onfoff(DISP_WIN0, DISP_WINDOW_OFF);
                    break;
                }

                // Wait for Cmd context get free or Wait for Local Path enabled
                if (WAIT_TIMEOUT == SVE_wait_disp_cmd_done())
                {
                    VDE_ERR((_T("[VDE:ERR] SVE_LocalPath_API_Proc() : SVE_LOCALPATH_SET_WIN0_START : SVE_wait_disp_cmd_done() TimeOut\n\r")));
                    bRet = FALSE;
                }
            }

            // Backup for PM
            pPMCtxt->bLocalPathWin0Enable = TRUE;

            break;
        }

        case SVE_LOCALPATH_SET_WIN0_STOP:
        {
            BOOL bRetry = TRUE;

            VDE_MSG((_T("[VDE] SVE_LocalPath_API_Proc() : SVE_LOCALPATH_SET_WIN0_STOP\n\r")));

            if (pPMCtxt->bPowerOn)
            {
                Disp_window_onfoff(DISP_WIN0, DISP_WINDOW_OFF);

                while(bRetry)
                {

                    if (WAIT_TIMEOUT == SVE_wait_disp_cmd_done())
                    {
                        VDE_ERR((_T("[VDE:ERR] SVE_LocalPath_API_Proc() : SVE_LOCALPATH_SET_WIN0_STOP : SVE_wait_disp_cmd_done() TimeOut\n\r")));
                    }
                    else
                    {
                        pCtxt->bWindowEnable[DISP_WIN0] = FALSE;
                        bRetry = FALSE;
                    }
                }

                bRet = DeviceIoControl(pCtxt->hCamera, IOCTL_CAM_POST_SET_PROCESSING_STOP, (LPVOID)NULL, (DWORD)NULL, (LPVOID)NULL, (DWORD)NULL, (LPDWORD)NULL, NULL);
                if(!bRet)
                {
                    VDE_ERR( (_T("[VDE:ERR] %s() : Cannot Stop Post Processor\n\r"), _T(__FUNCTION__)));
                    break;
                }
            }

            // Backup for PM
            pPMCtxt->bLocalPathWin0Enable = FALSE;

            break;
        }
        case SVE_LOCALPATH_SET_WIN1_START:
        {
            BOOL bRetry = TRUE;

            VDE_MSG((_T("[VDE] SVE_LocalPath_API_Proc() : SVE_LOCALPATH_SET_WIN1_START\n\r")));

            if (pPMCtxt->bPowerOn)
            {
#ifdef USE_LOCALPATH_EMUL_WITH_MEM2MEM
                bRet = SVE_LpePrepare(pCtxt->hCamera, hOpenContext, \
                                        DISP_WIN1, DISP_WIN1_DMA);
                if(!bRet)
                {
                    VDE_ERR((_T("[VDE] %s() : Cannot Start Post Processor\n\r"), _T(__FUNCTION__)));
                    Disp_window_onfoff(DISP_WIN1, DISP_WINDOW_OFF);
                    break;
                }

                bRet = DeviceIoControl(pCtxt->hCamera, \
                                        IOCTL_CAM_POST_SET_PROCESSING_START, \
                                        pBufIn, dwLenIn, pBufOut, dwLenOut, \
                                        pdwActualOut, NULL);
                if(!bRet)
                {
                    VDE_ERR((_T("[VDE] %s() : Cannot Start Post Processor\n\r"), _T(__FUNCTION__)));
                    Disp_window_onfoff(DISP_WIN1, DISP_WINDOW_OFF);
                    break;
                }

                if ( !DeviceIoControl(pCtxt->hCamera, \
                                        IOCTL_CAM_POST_WAIT_PROCESSING_DONE, \
                                        NULL, 0, NULL, 0, pdwActualOut, NULL) )
                {
                    VDE_ERR((_T("[VDE:ERR] %s() : IOCTL_CAM_POST_WAIT_PROCESSING_DONE Failed\n\r"), _T(__FUNCTION__)));
                }

                pCtxt->bWindowEnable[DISP_WIN1] = TRUE;

                Disp_set_framebuffer(DISP_WIN1, SVE_LpeGetCurrentBuffer());
                Disp_window_onfoff(DISP_WIN1, DISP_WINDOW_ON);
#else // USE_LOCALPATH_EMUL_WITH_MEM2MEM
                // Enable Post Interrupt

                Disp_set_framebuffer(DISP_WIN1, g_VideoMemoryPhysicalBase);    // Safe Frame Bufer Address for Local Path
                Disp_window_onfoff(DISP_WIN1, DISP_WINDOW_ON);

                pCtxt->bWindowEnable[DISP_WIN1] = TRUE;

                bRet = DeviceIoControl(pCtxt->hCamera, IOCTL_CAM_POST_SET_PROCESSING_START, pBufIn, dwLenIn, pBufOut, dwLenOut, pdwActualOut, NULL);
                if(!bRet)
                {
                    VDE_ERR( (_T("[VDE] %s() : Cannot Start Post Processor\n\r"), _T(__FUNCTION__)));
                    Disp_window_onfoff(DISP_WIN1, DISP_WINDOW_OFF);
                    break;
                }

                // Wait for Cmd context get free or Wait for Local Path enabled
                if (WAIT_TIMEOUT == SVE_wait_disp_cmd_done())
                {
                    VDE_ERR((_T("[VDE:ERR] SVE_LocalPath_API_Proc() : SVE_LOCALPATH_SET_WIN1_START : SVE_wait_disp_cmd_done() TimeOut\n\r")));
                    bRet = FALSE;
                }
#endif // USE_LOCALPATH_EMUL_WITH_MEM2MEM
            }

            // Backup for PM
            pPMCtxt->bLocalPathWin1Enable = TRUE;

            break;
        }

        case SVE_LOCALPATH_SET_WIN1_STOP:
        {
            BOOL bRetry = TRUE;

            VDE_MSG((_T("[VDE] SVE_LocalPath_API_Proc() : SVE_LOCALPATH_SET_WIN1_STOP\n\r")));

            if (pPMCtxt->bPowerOn)
            {
                Disp_window_onfoff(DISP_WIN1, DISP_WINDOW_OFF);

#ifdef USE_LOCALPATH_EMUL_WITH_MEM2MEM
                pCtxt->bWindowEnable[DISP_WIN1] = FALSE;
                SVE_LpeDeInitVariables();
#else // USE_LOCALPATH_EMUL_WITH_MEM2MEM
                while(bRetry)
                {

                    if (WAIT_TIMEOUT == SVE_wait_disp_cmd_done())
                    {
                        VDE_ERR((_T("[VDE:ERR] SVE_LocalPath_API_Proc() : SVE_LOCALPATH_SET_WIN1_STOP : SVE_wait_disp_cmd_done() TimeOut\n\r")));
                    }
                    else
                    {
                        pCtxt->bWindowEnable[DISP_WIN1] = FALSE;
                        bRetry = FALSE;
                    }
                }

                bRet = DeviceIoControl(pCtxt->hCamera, IOCTL_CAM_POST_SET_PROCESSING_STOP, (LPVOID)NULL, (DWORD)NULL, (LPVOID)NULL, (DWORD)NULL, (LPDWORD)NULL, NULL);
                if(!bRet)
                {
                    VDE_ERR( (_T("[VDE:ERR] %s() : Cannot Stop Post Processor\n\r"), _T(__FUNCTION__)));
                    break;
                }
#endif // USE_LOCALPATH_EMUL_WITH_MEM2MEM
            }

            // Backup for PM
            pPMCtxt->bLocalPathWin1Enable = FALSE;

            break;
        }
        case SVE_LOCALPATH_SET_WIN2_START:
        {
            BOOL bRetry = TRUE;

            VDE_MSG((_T("[VDE] SVE_LocalPath_API_Proc() : SVE_LOCALPATH_SET_WIN2_START\n\r")));

            if (pPMCtxt->bPowerOn)
            {
                // Enable Post Interrupt

                Disp_set_framebuffer(DISP_WIN2, g_VideoMemoryPhysicalBase);    // Safe Frame Bufer Address for Local Path
                Disp_window_onfoff(DISP_WIN2, DISP_WINDOW_ON);

                pCtxt->bWindowEnable[DISP_WIN2] = TRUE;

                bRet = DeviceIoControl(pCtxt->hCamera, IOCTL_CAM_POST_SET_PROCESSING_START, pBufIn, dwLenIn, pBufOut, dwLenOut, pdwActualOut, NULL);
                if(!bRet)
                {
                    VDE_ERR( (_T("[VDE:ERR] %s() : Cannot Start Post Processor\n\r"), _T(__FUNCTION__)));
                    break;
                }

                // Wait for Cmd context get free or Wait for Local Path enabled
                if (WAIT_TIMEOUT == SVE_wait_disp_cmd_done())
                {
                    VDE_ERR((_T("[VDE:ERR] SVE_LocalPath_API_Proc() : SVE_LOCALPATH_SET_WIN2_START : SVE_wait_disp_cmd_done() TimeOut\n\r")));
                    bRet = FALSE;
                }
            }

            // Backup for PM
            pPMCtxt->bLocalPathWin2Enable = TRUE;

            break;
        }

        case SVE_LOCALPATH_SET_WIN2_STOP:
        {
            BOOL bRetry = TRUE;

            VDE_MSG((_T("[VDE] SVE_LocalPath_API_Proc() : SVE_LOCALPATH_SET_WIN2_STOP\n\r")));

            if (pPMCtxt->bPowerOn)
            {
                Disp_window_onfoff(DISP_WIN2, DISP_WINDOW_OFF);

                while(bRetry)
                {

                    if (WAIT_TIMEOUT == SVE_wait_disp_cmd_done())
                    {
                        VDE_ERR((_T("[VDE:ERR] SVE_LocalPath_API_Proc() : SVE_LOCALPATH_SET_WIN2_STOP : SVE_wait_disp_cmd_done() TimeOut\n\r")));
                    }
                    else
                    {
                        pCtxt->bWindowEnable[DISP_WIN2] = FALSE;
                        bRetry = FALSE;
                    }
                }

                bRet = DeviceIoControl(pCtxt->hCamera, IOCTL_CAM_POST_SET_PROCESSING_STOP, (LPVOID)NULL, (DWORD)NULL, (LPVOID)NULL, (DWORD)NULL, (LPDWORD)NULL, NULL);
                if(!bRet)
                {
                    VDE_ERR( (_T("[VDE:ERR] %s() : Cannot Stop Post Processor\n\r"), _T(__FUNCTION__)));
                    break;
                }
            }

            // Backup for PM
            pPMCtxt->bLocalPathWin2Enable = FALSE;

            break;
        }
        default:    // This is filtered above switch statement
            bRet = FALSE;
            break;
    }

CleanUp:

    VDE_MSG((_T("[VDE] --SVE_LocalPath_API_Proc()\n\r")));

    return bRet;
}

#ifdef USE_LOCALPATH_EMUL_WITH_MEM2MEM

BOOL
SVE_LpeSetPostParam
(CAMARG_POST_PARAMETER* ptPostParam)
{
    VDE_MSG((_T("[VDE] ++%s()\r\n"),_T(__FUNCTION__)));

    if(!ptPostParam)
    {
        return FALSE;
    }
    memcpy((void *)&g_tPostParam, (const void *)ptPostParam, \
        sizeof(CAMARG_POST_PARAMETER));
    return TRUE;
}

BOOL
SVE_LpeUpdateFB
(PBYTE pBufIn,
 DWORD dwLenIn,
 PBYTE pBufOut,
 DWORD dwLenOut,
 PDWORD pdwActualOut)
{
    DWORD dwBytes;
    CAMARG_POST_BUFFER tPostParam;
    HANDLE hCamera = SVE_get_context()->hCamera;

    VDE_MSG((_T("\r\n\r\n[VDE] ++%s()\r\n\r\n"),_T(__FUNCTION__)));

    if(g_tPostParam.dwOpMode == POST_FREE_RUN_MODE)
    {
        return TRUE; // ignore if function call at initaial time
    }

    //RETAIL_DISP_MSG(DISP_ZONE_TEMP,(_T("[DISPDRV] %s() : WaitForSingleObject(g_hPostReadyEvent) 0x%x\r\n"),_T(__FUNCTION__),g_hPostReadyEvent));
    WaitForSingleObject(g_hPostReadyEvent, INFINITE);

    if ( !DeviceIoControl(hCamera, \
                            IOCTL_CAM_POST_SET_SOURCE_BUFFER, \
                            pBufIn, dwLenIn, \
                            pBufOut, dwLenOut, pdwActualOut, NULL) )
    {
        VDE_ERR((_T("[VDE:ERR] %s() : IOCTL_CAM_POST_SET_SOURCE_BUFFER Failed at %d\n\r"), _T(__FUNCTION__), __LINE__));
        return FALSE;
    }

    SVE_LpeChangeBuffer();
    tPostParam.dwBufferRGBY = SVE_LpeGetCurrentBuffer();
    tPostParam.dwBufferCb = tPostParam.dwBufferRGBY;
    tPostParam.dwBufferCr = tPostParam.dwBufferRGBY;
    tPostParam.bWaitForVSync = FALSE;

    if ( !DeviceIoControl(hCamera, \
                            IOCTL_CAM_POST_SET_DESTINATION_BUFFER, \
                            &tPostParam, sizeof(CAMARG_POST_BUFFER), \
                            NULL, 0, &dwBytes, NULL) )
    {
        VDE_ERR((_T("[VDE:ERR] %s() : IOCTL_SVE_POST_SET_SOURCE_BUFFER Failed\n\r"),_T(__FUNCTION__)));
        return FALSE;
    }
    // This will be Per Frame Mode
    if ( !DeviceIoControl(hCamera, \
                            IOCTL_CAM_POST_SET_PROCESSING_START, NULL, \
                            0, NULL, 0, &dwBytes, NULL) )
    {
        VDE_ERR((_T("[VDE:ERR] %s() : IOCTL_SVE_POST_SET_PROCESSING_START Failed\n\r"), _T(__FUNCTION__)));
        if(!DeviceIoControl(hCamera, IOCTL_CAM_POST_SET_PROCESSING_STOP, NULL, \
                            0, NULL, 0, &dwBytes, NULL))
        {
            VDE_ERR((_T("[VDE:ERR] %s() : IOCTL_CAM_POST_SET_PROCESSING_STOP Failed\n\r"), _T(__FUNCTION__)));
        }
        return FALSE;
    }
    SetEvent(g_hPostBusyEvent);
    //VDE_ERR((_T("[DISPDRV] %s() : SetEvent(m_hPostBusyEvent)\r\n"),_T(__FUNCTION__)));
    return TRUE;
}

BOOL
SVE_LpeInitialize
(void)
{
    int i = 0;
    VDE_MSG((_T("[VDE] ++%s()\n\r"),_T(__FUNCTION__)));

    //CMM init
    g_hCmmFB = CreateFile(CODEC_MEM_DRIVER_NAME,
                       GENERIC_READ|GENERIC_WRITE,
                       0,
                       NULL,
                       OPEN_EXISTING,
                       FILE_ATTRIBUTE_NORMAL,
                       NULL);

    if (g_hCmmFB == NULL)
    {
        VDE_ERR((_T("[VDE:ERR] %s() : CMM Open failure\n"),_T(__FUNCTION__)));
        return FALSE;
    }

    for(i=0;i<LOCALPATH_FB_NUM;i++)
    {
        g_uiFBVirAddr[i] = 0;
        g_uiFBPhyAddr[i] = 0;
    }
    g_hPostReadyEvent = NULL;
    g_hPostBusyEvent = NULL;
    g_hPostTreadEnd = NULL;
    g_bPostThreadExit = FALSE;
    g_hPostIST = NULL;
    g_uiCurPostFB = 0;

    VDE_MSG((_T("[VDE] --%s()\n\r"),_T(__FUNCTION__)));

    return TRUE;
}

void
SVE_LpeDeinitialize
(void)
{
    VDE_MSG((_T("[VDE] ++%s()\n\r"),_T(__FUNCTION__)));

    if(g_hCmmFB != NULL)
    {
        CloseHandle(g_hCmmFB);
    }

    SVE_LpeDeInitVariables();

    VDE_MSG((_T("[VDE] --%s()\n\r"),_T(__FUNCTION__)));
}

static BOOL
SVE_LpeAllocCmmMemory
(unsigned int uiSize,
 DWORD Loc,
 unsigned int* puiPhy,
 unsigned int* puiVir)
{
    BOOL bResult = TRUE;

    CMM_ALLOC_PRAM_T CMMParam;
    char *virBuf = NULL;
    unsigned int phyBuf = 0;

    VDE_MSG((_T("[VDE] ++%s()\r\n"),_T(__FUNCTION__)));

    CMMParam.size = uiSize;
    CMMParam.dramLocation = (CMM_DRAM_LOCATION)Loc;       // DRAM 0 or DRAM 1 = 0;
    //VDE_MSG((_T("\r\n\r\n[VDE] %s() : CMM dwSize = %d\r\n"), _T(__FUNCTION__),uiSize));

    bResult = DeviceIoControl(g_hCmmFB, IOCTL_DISPLAY_MEM_ALLOC, (PBYTE)&CMMParam,
                        sizeof(CMM_ALLOC_PRAM_T *), &virBuf, sizeof(virBuf),
                        NULL, NULL);
    if(bResult == FALSE)
    {
        VDE_ERR((_T("[VDE:ERR] %s() : CMM IOCTL_DISPLAY_MEM_ALLOC failure\n"), _T(__FUNCTION__)));
        //DeviceIoControl(g_hCmmFB, IOCTL_CODEC_MEM_FREE, (PBYTE)virBuf,
        //                        sizeof(virBuf), NULL, 0, NULL, NULL);
        return bResult;
    }
    //VDE_MSG((_T("[VDE] %s() : CMM virBuf = 0x%x\r\n"), _T(__FUNCTION__),virBuf));

    bResult = DeviceIoControl(g_hCmmFB, IOCTL_CODEC_GET_PHY_ADDR, (PBYTE)virBuf,
                        sizeof(virBuf), &phyBuf, sizeof(phyBuf),
                        NULL, NULL);
    if(bResult == FALSE)
    {
        VDE_ERR((_T("[VDE:ERR] %s() : CMM IOCTL_CODEC_GET_PHY_ADDR failure\n"), _T(__FUNCTION__)));
        SVE_LpeReleaseCmmMemory((PBYTE)virBuf);
        return bResult;
    }

    *puiPhy = (DWORD)phyBuf;
    *puiVir = (DWORD)virBuf;

    //VDE_MSG((_T("[VDE] %s() : CMM phyBuf = 0x%x\r\n"), _T(__FUNCTION__),phyBuf));

    //VDE_MSG((_T("[VDE] %s() : CMM *puiVir = 0x%x\r\n"), _T(__FUNCTION__),*puiVir));
    //VDE_MSG((_T("[VDE] %s() : CMM *puiPhy = 0x%x\r\n\r\n\r\n"), _T(__FUNCTION__),*puiPhy));

    return bResult;
}

static void
SVE_LpeReleaseCmmMemory
(PBYTE pbVir)
{
    VDE_MSG((_T("[VDE] %s() : CMM pbVir = 0x%x\r\n"), _T(__FUNCTION__),pbVir));

    if(!DeviceIoControl(g_hCmmFB, IOCTL_DISPLAY_MEM_FREE, pbVir,
                            sizeof(pbVir), NULL, 0, NULL, NULL))
    {
        VDE_ERR((_T("[VDE:ERR] %s() : IOCTL_DISPLAY_MEM_FREE Failed \n\r"),_T(__FUNCTION__)));        
    }
}

static BOOL
SVE_LpeInitVariables
(unsigned int uiSize)
{
    int i=0;

    VDE_MSG((_T("[VDE] ++%s()\r\n"),_T(__FUNCTION__)));

    for(i=0;i<LOCALPATH_FB_NUM;i++)
    {
        if(g_uiFBVirAddr[i] != 0)
        {
            SVE_LpeReleaseCmmMemory((PBYTE)g_uiFBVirAddr[i]);
            g_uiFBVirAddr[i] = 0;
            g_uiFBPhyAddr[i] = 0;
        }
        if(!SVE_LpeAllocCmmMemory(uiSize, CMM_MEMAREA_FOR_LPE, \
                            &(g_uiFBPhyAddr[i]), &(g_uiFBVirAddr[i])))
        {
            VDE_ERR((TEXT("g_uiFBPhyAddr[%d] Surface Allocation is failed. %d\n"),i,__LINE__));
            VDE_ERR((TEXT("Maybe There's no sufficient video memory. please increase video memory\r\n")));
            return FALSE;
        }
    }

    g_hPostReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    if(NULL == g_hPostReadyEvent)
    {
        VDE_ERR((_T("[VDE:ERR] %s() : CreateEvent() g_hPostReadyEvent Failed \n\r"),_T(__FUNCTION__)));
        return FALSE;
    }
    SetEvent(g_hPostReadyEvent);
    //VDE_MSG((_T("[VDE] %s() : SetEvent(g_hPostReadyEvent)\r\n"),_T(__FUNCTION__)));

    g_hPostBusyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    if(NULL == g_hPostBusyEvent)
    {
        VDE_ERR((_T("[VDE:ERR] %s() : CreateEvent() g_hPostBusyEvent Failed \n\r"),_T(__FUNCTION__)));
        return FALSE;
    }

    g_hPostTreadEnd = CreateEvent(NULL, FALSE, FALSE, NULL);
    if(NULL == g_hPostTreadEnd)
    {
        VDE_ERR((_T("[VDE:ERR] %s() : CreateEvent() g_hPostTreadEnd Failed \n\r"),_T(__FUNCTION__)));
        return FALSE;
    }

    g_bPostThreadExit = FALSE;
    g_hPostIST = CreateThread(NULL, 0, \
            (LPTHREAD_START_ROUTINE)SVE_LpePostThread, NULL, 0, NULL);
    if (g_hPostIST == NULL)
    {
        VDE_ERR((_T("[VDE:ERR] %s() : g_hPostIST CreateThread() Fail\n\r"),_T(__FUNCTION__)));
        return FALSE;
    }

    return TRUE;
}

static void
SVE_LpeDeInitVariables
(void)
{
    int i=0;

    VDE_MSG((_T("[VDE] ++%s()\r\n"),_T(__FUNCTION__)));

    for(i=0;i<LOCALPATH_FB_NUM;i++)
    {
        if(g_uiFBVirAddr[i] != 0)
        {
            SVE_LpeReleaseCmmMemory((PBYTE)g_uiFBVirAddr[i]);
            g_uiFBVirAddr[i] = 0;
            g_uiFBPhyAddr[i] = 0;
        }
    }

    if (g_hPostIST != NULL)
    {
        g_bPostThreadExit = TRUE;
        SetEvent(g_hPostBusyEvent);
        //VDE_MSG((_T("[DISPDRV] %s() : SetEvent(g_hPostBusyEvent)\r\n"),_T(__FUNCTION__)));
        //VDE_MSG((_T("[DISPDRV] %s() : WaitForSingleObject(g_hPostTreadEnd)\r\n"),_T(__FUNCTION__)));
        WaitForSingleObject(g_hPostTreadEnd, INFINITE);
    }

    if (g_hPostBusyEvent != NULL)
    {
        CloseHandle(g_hPostBusyEvent);
        g_hPostBusyEvent = NULL;
    }

    if (g_hPostReadyEvent != NULL)
    {
        CloseHandle(g_hPostReadyEvent);
        g_hPostReadyEvent = NULL;
    }

    if (g_hPostTreadEnd != NULL)
    {
        CloseHandle(g_hPostTreadEnd);
        g_hPostTreadEnd = NULL;
    }

    g_uiCurPostFB = 0;
    g_hPostIST = NULL;
}

static unsigned int
SVE_LpeGetCurrentBuffer
(void)
{
    VDE_MSG((_T("[VDE] ++%s()\r\n"),_T(__FUNCTION__)));

    return g_uiFBPhyAddr[g_uiCurPostFB];
}

static void
SVE_LpeChangeBuffer
(void)
{
    VDE_MSG((_T("[VDE] ++%s()\r\n"),_T(__FUNCTION__)));

    g_uiCurPostFB = (g_uiCurPostFB+1)%LOCALPATH_FB_NUM;
}

static BOOL
SVE_LpePrepare
(HANDLE hCamera,
 DWORD hOpenContext,
 DISP_WINDOW eDispWin,
 DISP_WINDOW_MODE eWinMode)
{
    DWORD dwBytes;
    CAMARG_POST_PARAMETER* ptParamPost = (CAMARG_POST_PARAMETER*)&g_tPostParam;
    CAMARG_POST_BUFFER tPostBuffer;

    VDE_MSG((_T("[VDE] ++%s()\r\n"),_T(__FUNCTION__)));

    if(!SVE_LpeInitVariables(ptParamPost->dwDstWidth * \
                            ptParamPost->dwDstHeight * 4)) // RGB24
    {
        SVE_LpeDeInitVariables();
        return FALSE;
    }

    ptParamPost->dwOpMode = POST_PER_FRAME_MODE;
    ptParamPost->dwDstType = POST_DST_RGB24;
    tPostBuffer.dwBufferCb = tPostBuffer.dwBufferCr = \
        tPostBuffer.dwBufferRGBY = SVE_LpeGetCurrentBuffer();
    tPostBuffer.bWaitForVSync = FALSE;
    if(!DeviceIoControl(hCamera, \
                        IOCTL_CAM_POST_SET_DESTINATION_BUFFER, \
                        (void*)(&tPostBuffer), \
                        sizeof(CAMARG_POST_BUFFER), NULL, \
                        0, &dwBytes, NULL))
    {
        SVE_LpeDeInitVariables();
        return FALSE;
    }

    if(!DeviceIoControl(hCamera, IOCTL_CAM_POST_SET_PROCESSING_PARAM, \
                        ptParamPost, sizeof(CAMARG_POST_PARAMETER), NULL, 0, \
                        &dwBytes, NULL))
    {
        SVE_LpeDeInitVariables();
        return FALSE;
    }

    SVE_get_power_context()->tFIMDWinMode[eDispWin].dwWinMode = eWinMode;
    if(!SVE_DispCon_API_Proc(hOpenContext, SVE_FIMD_SET_WINDOW_MODE, \
                (PBYTE)&(SVE_get_power_context()->tFIMDWinMode[eDispWin]), \
                sizeof(SVEARG_FIMD_WIN_MODE), NULL, 0, &dwBytes))
    {
        SVE_LpeDeInitVariables();
        return FALSE;
    }

    return TRUE;
}

static void
SVE_LpePostThread
(void)
{
    DWORD dwBytes;
    HANDLE hCamera = SVE_get_context()->hCamera;

    VDE_MSG((_T("\r\n\r\n[VDE] ++%s()\r\n\r\n"),_T(__FUNCTION__)));

    CeSetThreadPriority(g_hPostIST, LPE_POST_THREAD_PRIORITY);

    while(!g_bPostThreadExit)
    {
        //VDE_MSG((_T("[VDE] %s() : g_hPostBusyEvent(g_hPostBusyEvent)\r\n"),_T(__FUNCTION__)));
        WaitForSingleObject(g_hPostBusyEvent, INFINITE);

        if(g_bPostThreadExit)
        {
            break;
        }

        if ( !DeviceIoControl(hCamera, IOCTL_CAM_POST_WAIT_PROCESSING_DONE, \
                                NULL, 0, NULL, 0, &dwBytes, NULL) )
        {
            VDE_ERR((_T("[VDE:ERR] %s() : IOCTL_CAM_POST_WAIT_PROCESSING_DONE Failed\n\r"), _T(__FUNCTION__)));
        }

        //RETAIL_DISP_MSG(DISP_ZONE_TEMP,(_T("[VDE] %s() : g_uiCurPostFB = %d\r\n"),_T(__FUNCTION__),g_uiCurPostFB));

        Disp_set_framebuffer(DISP_WIN1, SVE_LpeGetCurrentBuffer());

        SetEvent(g_hPostReadyEvent);
        //RETAIL_DISP_MSG(DISP_ZONE_TEMP,(_T("[VDE] %s() : SetEvent(g_hPostReadyEvent) 0x%x\r\n"),_T(__FUNCTION__),g_hPostReadyEvent));
    }

    VDE_MSG((_T("\r\n\r\n[VDE] --%s()\r\n\r\n"),_T(__FUNCTION__)));

    SetEvent(g_hPostTreadEnd);
}

#endif // USE_LOCALPATH_EMUL_WITH_MEM2MEM


