//
// 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:    Interrupt.c

Abstract:       Implementation of Video Driver.
                This module handle interrupt

Functions:


Notes:


--*/

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

BOOL SVE_initialize_interrupt(void)
{
    SVEngineContext *pCtxt;
    DWORD dwIRQ;

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

    pCtxt = SVE_get_context();

    // Interrupt for Display Controller (Vsync Interrupt)
    dwIRQ = IRQ_LCD1_FRAME;
    if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &dwIRQ, sizeof(DWORD), &(pCtxt->dwSysIntrDisp), sizeof(DWORD), NULL))
    {
        VDE_ERR((_T("[VDE:ERR] SVE_initialize_interrupt() : IOCTL_HAL_REQUEST_SYSINTR dwSysIntrDisp Failed\n\r")));
        pCtxt->dwSysIntrDisp = SYSINTR_UNDEFINED;
        goto CleanUp;
    }

    pCtxt->hInterruptDisp = CreateEvent(NULL, FALSE, FALSE, NULL);
    if(NULL == pCtxt->hInterruptDisp)
    {
        VDE_ERR((_T("[VDE:ERR] SVE_initialize_interrupt() : CreateEvent() hInterruptDisp Failed \n\r")));
        goto CleanUp;
    }

    if (!(InterruptInitialize(pCtxt->dwSysIntrDisp, pCtxt->hInterruptDisp, 0, 0)))
    {
        VDE_ERR((_T("[VDE:ERR] SVE_initialize_interrupt() : InterruptInitialize() hInterruptDisp Failed \n\r")));
        goto CleanUp;
    }

    // Interrupt for Rotator
    dwIRQ = IRQ_ROTATOR;
    if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &dwIRQ, sizeof(DWORD), &(pCtxt->dwSysIntrRotator), sizeof(DWORD), NULL))
    {
        VDE_ERR((_T("[VDE:ERR] SVE_initialize_interrupt() : IOCTL_HAL_REQUEST_SYSINTR dwSysIntrRotator Failed\n\r")));
        pCtxt->dwSysIntrRotator = SYSINTR_UNDEFINED;
        goto CleanUp;
    }

    pCtxt->hInterruptRotator = CreateEvent(NULL, FALSE, FALSE, NULL);
    if(NULL == pCtxt->hInterruptRotator)
    {
        VDE_ERR((_T("[VDE:ERR] SVE_initialize_interrupt() : CreateEvent() hInterruptRotator Failed \n\r")));
        goto CleanUp;
    }

    if (!(InterruptInitialize(pCtxt->dwSysIntrRotator, pCtxt->hInterruptRotator, 0, 0)))
    {
        VDE_ERR((_T("[VDE:ERR] SVE_initialize_interrupt() : InterruptInitialize() hInterruptRotator Failed \n\r")));
        goto CleanUp;
    }

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

    return TRUE;

CleanUp:

    VDE_ERR((_T("[VDE:ERR] --SVE_initialize_interrupt() : Failed\n\r")));

    return FALSE;
}

void SVE_deinitialize_interrupt(void)
{
    SVEngineContext *pCtxt;

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

    pCtxt = SVE_get_context();

    if (pCtxt->dwSysIntrDisp != SYSINTR_UNDEFINED)
    {
        InterruptDisable(pCtxt->dwSysIntrDisp);
    }

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

    if (pCtxt->dwSysIntrDisp != SYSINTR_UNDEFINED)
    {
        KernelIoControl(IOCTL_HAL_RELEASE_SYSINTR, &(pCtxt->dwSysIntrDisp), sizeof(DWORD), NULL, 0, NULL);
        pCtxt->dwSysIntrDisp = SYSINTR_UNDEFINED;
    }

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

    if (pCtxt->dwSysIntrRotator != SYSINTR_UNDEFINED)
    {
        InterruptDisable(pCtxt->dwSysIntrRotator);
    }

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

    if (pCtxt->dwSysIntrRotator != SYSINTR_UNDEFINED)
    {
        KernelIoControl(IOCTL_HAL_RELEASE_SYSINTR, &(pCtxt->dwSysIntrRotator), sizeof(DWORD), NULL, 0, NULL);
        pCtxt->dwSysIntrRotator = SYSINTR_UNDEFINED;
    }

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

BOOL SVE_initialize_thread(void)
{
    SVEngineContext *pCtxt;

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

    pCtxt = SVE_get_context();

    pCtxt->bDispThrdExit = FALSE;
    pCtxt->hDisplayIST = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)SVE_DisplayIntrThread, NULL, 0, NULL);
    if (pCtxt->hDisplayIST == NULL)
    {
        VDE_ERR((_T("[VDE:ERR] SVE_initialize_thread() : DisplayIST CreateThread() Fail\n\r")));
        goto CleanUp;
    }

    pCtxt->bRotatorThrdExit = FALSE;
    pCtxt->hRotatorIST = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)SVE_RotatorIntrThread, NULL, 0, NULL);
    if (pCtxt->hRotatorIST == NULL)
    {
        VDE_ERR((_T("[VDE:ERR] SVE_initialize_thread() : hRotatorIST CreateThread() Fail\n\r")));
        goto CleanUp;
    }

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

    return TRUE;

CleanUp:

    VDE_ERR((_T("[VDE:ERR] --SVE_initialize_thread() : Failed\n\r")));

    return FALSE;
}

void SVE_deinitialize_thread(void)
{
    SVEngineContext *pCtxt;

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

    pCtxt = SVE_get_context();

    if (pCtxt->hDisplayIST != NULL)
    {
        pCtxt->bDispThrdExit = TRUE;
    }

    if (pCtxt->hRotatorIST != NULL)
    {
        pCtxt->bRotatorThrdExit = TRUE;
    }
}

DWORD SVE_DisplayIntrThread(void)
{
    SVEngineContext *pCtxt;

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

    pCtxt = SVE_get_context();

    CeSetThreadPriority(pCtxt->hDisplayIST, SVE_IST_PRIORITY);

    while(!pCtxt->bDispThrdExit)
    {
        WaitForSingleObject(pCtxt->hInterruptDisp, INFINITE);

        Disp_clear_interrupt_pending();

        InterruptDone(pCtxt->dwSysIntrDisp);

        PulseEvent(pCtxt->hDispCmdDone);
    }

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

    return 0;
}

DWORD SVE_RotatorIntrThread(void)
{
    SVEngineContext *pCtxt;
    BOOL bIntPending;

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

    pCtxt = SVE_get_context();

    CeSetThreadPriority(pCtxt->hRotatorIST, SVE_IST_PRIORITY);

    while(!pCtxt->bRotatorThrdExit)
    {
        WaitForSingleObject(pCtxt->hInterruptRotator, INFINITE);

        // Clear Interrupt Pending
        bIntPending = Rotator_clear_interrupt_pending();
        if (!bIntPending)
        {
            VDE_ERR((_T("[VDE:ERR] SVE_RotatorIntrThread() : Interrupt Occurs, But Pending Bit was not Set\n\r")));
        }

        // Image Rotator Operation Finished
        pCtxt->bRotatorBusy = FALSE;

        InterruptDone(pCtxt->dwSysIntrRotator);

        PulseEvent(pCtxt->hRotatorFinish);
    }

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

    return 0;
}

DWORD SVE_wait_disp_cmd_done(void)
{
    return WaitForSingleObject(SVE_get_context()->hDispCmdDone, SVE_DISP_CMD_TIMEOUT);
}
/*
DWORD SVE_wait_post_cmd_done(void)
{
    return WaitForSingleObject(SVE_get_context()->hPostCmdDone, SVE_POST_CMD_TIMEOUT);
}
*/
DWORD SVE_wait_rotator_finish(void)
{
    return WaitForSingleObject(SVE_get_context()->hRotatorFinish, SVE_ROTATOR_FINISH_TIMEOUT);
}
