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

#define DEVICE_NAME_LEN     6
static TCHAR PostCandidate[3][DEVICE_NAME_LEN] = {_T("CAM1:"), _T("CAM2:"), _T("CAM3:")};

// Open specified Camera Driver
BOOL SVE_initialize_RAW_camera_driver()
{
    HKEY    hDevKey = NULL;
    SVEngineContext *pCtxt;
    DWORD dwType = 0;
    DWORD dwDataLen = 0;
    DWORD dwCameraNo = 0;
    TCHAR  szCamDriver[6]=_T("");
    LONG status;
    DWORD dwBytes;

    pCtxt = SVE_get_context();

    // Read LocalPath Camera Driver
    if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, PC_REG_DISPLAY_CONFIG, 0, 0, &hDevKey ) != ERROR_SUCCESS )
    {
        hDevKey = NULL;
        VDE_ERR((_T("[VDE:ERR] Cannot open device Key:%s\r\n"), PC_REG_DISPLAY_CONFIG));
        return ERROR_CANTOPEN;
    }

    dwDataLen = sizeof(CAMIF_DEFAULT_PORT)+1;
    status = RegQueryValueEx( hDevKey,
                                       PC_REG_LOCALPATHPORT,
                                       NULL,
                                       &dwType,
                                       (LPBYTE)dwCameraNo,
                                       &dwDataLen );
    RegCloseKey( hDevKey );

    if(status != ERROR_SUCCESS )
    {
        VDE_ERR((_T("[VDE:ERR] %s() : %s Cannot Read RegistryKey : %s%s\r\n"), _T(__FUNCTION__), PC_REG_DISPLAY_CONFIG, PC_REG_LOCALPATHPORT));
        _tcsncpy(szCamDriver, CAMIF_DEFAULT_PORT, DEVICE_NAME_LEN);
        VDE_ERR((_T("[VDE:ERR] %s() : Try to use Default Setting Driver %s, But it can not work\r\n"), _T(__FUNCTION__), szCamDriver));
    }
    else
    {
        _tcsncpy(szCamDriver, PostCandidate[dwCameraNo], DEVICE_NAME_LEN);
    }
    // Open Device RAW Camera Driver
    pCtxt->hCamera = CreateFile( CAMIF_DEFAULT_PORT, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
    if (pCtxt->hCamera == NULL)
    {
        VDE_ERR((_T("[VDE:ERR] %s() : %s Open Device Failed\r\n"), _T(__FUNCTION__), szCamDriver));
        goto CleanUp;
    }

    // Request for camera resource
    if ( !DeviceIoControl(pCtxt->hCamera, IOCTL_CAM_RSC_REQUEST, NULL, 0, NULL, 0, &dwBytes, NULL) )
    {
        VDE_ERR((_T("[VDE:ERR] %s() : %s IOCTL_CAM_RSC_REQUEST Failed\r\n"), _T(__FUNCTION__), szCamDriver));
        goto CleanUp;
    }


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

    return TRUE;

CleanUp:

    VDE_ERR((_T("[VDE:ERR] --%s() : Failed\r\n"), _T(__FUNCTION__)));

    return FALSE;
}

// Close Camera Driver
void SVE_deinitialize_RAW_camera_driver()
{
    SVEngineContext *pCtxt;
    TCHAR  szCamDriver[6]=_T("");
    DWORD dwBytes;

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

    pCtxt = SVE_get_context();

    // Release the camera resource
    if ( !DeviceIoControl(pCtxt->hCamera, IOCTL_CAM_RSC_RELEASE, NULL, 0, NULL, 0, &dwBytes, NULL) )
    {
        _tcsncpy(szCamDriver, CAMIF_DEFAULT_PORT, DEVICE_NAME_LEN);
        VDE_ERR((_T("[VDE:ERR] %s() : %s IOCTL_CAM_RSC_RELEASE Failed\r\n"), _T(__FUNCTION__), szCamDriver));
    }

    if (pCtxt->hCamera !=NULL)
    {
        CloseHandle(pCtxt->hCamera);
    }

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

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

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

    pCtxt = SVE_get_context();
#ifndef USE_LOCALPATH_EMUL_WITH_MEM2MEM
    pPMCtxt = SVE_get_power_context();
#endif

    //-------------------------------------------------------------
    // Check OpenContext of Caller have the right to access to H/W Resource
    //-------------------------------------------------------------
    switch(dwCode)
    {
    case SVE_POST_SET_PROCESSING_PARAM: // 12d
    case SVE_POST_SET_SOURCE_BUFFER: // 12e
    case SVE_POST_SET_NEXT_SOURCE_BUFFER: // 12f
    case SVE_POST_SET_DESTINATION_BUFFER: // 130
    case SVE_POST_SET_PROCESSING_START: // 131
    case SVE_POST_SET_PROCESSING_STOP: // 132
    case SVE_POST_WAIT_PROCESSING_DONE: // 133
    case SVE_POST_GET_PROCESSING_STATUS: // 134
        bRet = SVE_resource_compare_Post((DWORD)hOpenContext);
    if (!bRet)
    {
        VDE_ERR((_T("[VDE:ERR] SVE_Post_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 post Processor, Deligate to Camera Device Driver
    //--------------------------------
    switch(dwCode)
    {
        case SVE_POST_SET_PROCESSING_PARAM:
#ifdef USE_LOCALPATH_EMUL_WITH_MEM2MEM
            if(((CAMARG_POST_PARAMETER*)pBufIn)->dwOpMode == POST_FREE_RUN_MODE)
            {
                bRet = SVE_LpeSetPostParam((CAMARG_POST_PARAMETER*)pBufIn);
                if(!bRet)
                {
                    break;
                }
            }
#endif // USE_LOCALPATH_EMUL_WITH_MEM2MEM
            bRet = DeviceIoControl(pCtxt->hCamera, IOCTL_CAM_POST_SET_PROCESSING_PARAM, pBufIn, dwLenIn, pBufOut, dwLenOut, pdwActualOut, NULL);
            break;
        case SVE_POST_SET_SOURCE_BUFFER:
            bRet = DeviceIoControl(pCtxt->hCamera, IOCTL_CAM_POST_SET_SOURCE_BUFFER, pBufIn, dwLenIn, pBufOut, dwLenOut, pdwActualOut, NULL);
            break;
        case SVE_POST_SET_NEXT_SOURCE_BUFFER:
#ifdef USE_LOCALPATH_EMUL_WITH_MEM2MEM
            SVE_LpeUpdateFB(pBufIn, dwLenIn, \
                                pBufOut, dwLenOut, pdwActualOut);
#else // USE_LOCALPATH_EMUL_WITH_MEM2MEM
            // Check Waitfor VSYNC
        {
            CAMARG_POST_BUFFER *pArg;

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

            pArg = (CAMARG_POST_BUFFER *)pBufIn;

            // Actually, V210 has shadow register to set dma address, so this setting can be before WaitForVSync
            bRet = DeviceIoControl(pCtxt->hCamera, IOCTL_CAM_POST_SET_NEXT_SOURCE_BUFFER, pBufIn, dwLenIn, pBufOut, dwLenOut, pdwActualOut, NULL);
            if(!bRet)
            {
                return bRet;
            }

            // Wait for VSync, this will ensure the next frame is processed.
            // When in Power off or display off state. Display Interrupt will not occur
            // So does not wait for VSYNC
            if (pArg->bWaitForVSync && pPMCtxt->bPowerOn)
            {
                dwWaitCompletion = SVE_wait_disp_cmd_done();
                if (WAIT_TIMEOUT == dwWaitCompletion)
                {
                    VDE_ERR( (_T("[VDE:ERR] %s() : SVE_POST_SET_NEXT_SOURCE_BUFFER : SVE_wait_disp_cmd_done() TimeOut, \n"), _T(__FUNCTION__)));
                    VDE_ERR( (_T("[VDE:ERR] %s() : SVE_POST_SET_NEXT_SOURCE_BUFFER : Please check Interrupt Latency\n\r"), _T(__FUNCTION__)));
                    bRet = FALSE;
                }
                else if(WAIT_OBJECT_0 == dwWaitCompletion)
                {
                    bRet = TRUE;
                    break;
                }
            }
        }
#endif // USE_LOCALPATH_EMUL_WITH_MEM2MEM
        break;
        case SVE_POST_SET_DESTINATION_BUFFER:
            bRet = DeviceIoControl(pCtxt->hCamera, IOCTL_CAM_POST_SET_DESTINATION_BUFFER, pBufIn, dwLenIn, pBufOut, dwLenOut, pdwActualOut, NULL);
            break;
        case SVE_POST_SET_PROCESSING_START:
            bRet = DeviceIoControl(pCtxt->hCamera, IOCTL_CAM_POST_SET_PROCESSING_START, pBufIn, dwLenIn, pBufOut, dwLenOut, pdwActualOut, NULL);
            break;
        case SVE_POST_SET_PROCESSING_STOP:
            bRet = DeviceIoControl(pCtxt->hCamera, IOCTL_CAM_POST_SET_PROCESSING_STOP, pBufIn, dwLenIn, pBufOut, dwLenOut, pdwActualOut, NULL);
            break;
        case SVE_POST_WAIT_PROCESSING_DONE:
            bRet = DeviceIoControl(pCtxt->hCamera, IOCTL_CAM_POST_WAIT_PROCESSING_DONE, pBufIn, dwLenIn, pBufOut, dwLenOut, pdwActualOut, NULL);
            break;
        case SVE_POST_GET_PROCESSING_STATUS:
            bRet = DeviceIoControl(pCtxt->hCamera, IOCTL_CAM_POST_GET_PROCESSING_STATUS, pBufIn, dwLenIn, pBufOut, dwLenOut, pdwActualOut, NULL);
            break;
        default:    // This is filtered above switch statement
            bRet = FALSE;
            break;
    }

CleanUp:

    VDE_MSG((_T("[VDE] --SVE_Post_API_Proc(0x%x, 0x%x, ...)\n\r"), pCtxt->hCamera, dwCode));

    return bRet;
}


