/*
 * Copyright 2010 Trident Microsystems (Far East) Ltd. All rights reserved.
 * All prior copyright rights in this work and the accompanying software
 * products transferred to Trident Microsystems (Far East) Ltd. by written
 * agreement.
 */
/*****************************************************************************/
/* Copyright (c) 2010 NXP B.V.  All rights are reserved.                     */
/*                                                                           */
/* Redistribution and use in source and binary forms, with or without        */
/* modification, are permitted provided that the following conditions        */
/* are met:                                                                  */
/*                                                                           */
/* Redistributions of source code must retain the above copyright            */
/* notice, this list of conditions and the following disclaimer.             */
/*                                                                           */
/* Redistributions in binary form must reproduce the above copyright         */
/* notice, this list of conditions and the following disclaimer in the       */
/* documentation and/or other materials provided with the distribution.      */
/*                                                                           */
/* Neither the name of NXP nor the names of its                              */
/* contributors may be used to endorse or promote products derived from      */
/* this software without specific prior written permission.                  */
/*                                                                           */
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS       */
/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT         */
/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR     */
/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT      */
/* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,     */
/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT          */
/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,     */
/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY     */
/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT       */
/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE         */
/* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH          */
/* DAMAGE.                                                                   */
/*                                                                           */
/*****************************************************************************/
/**
    @file   phStbKBufMgr_KI.c
    @brief  Kernel Buffer Manager component

    Implementation of the Kernel Buffer Manager's Kernel Space to User Space interface

    Set your editor for 4 space indentation.
*//*

Rev Date       Author      Comments
--------------------------------------------------------------------------------
  1 20061129   burningh    Original
  2 20061129   burningh    Add further implementation
  3 20061205   steel       Add static allocation for hw buffers
  4 20071008   batelaan    Portability enhancements
  5 20071218   hutch       WinCE.
  6 20080910   batelaan    Rm phStbKBufMgr_KI_Deinit
  7 20081104   batelaan    Add phStbKBufMgr_LookupBuffer and phStbKBufMgr_BufferStats
  8 20090120   batelaan    Update file copyright/license text
--------------------------------------------------------------------------------
    For consistency and standardisation retain the Section Separators.
*/

/**************************************************************
* INCLUDE FILES                                               *
***************************************************************/

#include "tmNxTypes.h"
#include "phKernelIfce.h"
#include "phStbKBufMgr.h"
#include "phStbKBufMgr_Int.h"

#if TMFL_MODE_KERNEL
#  if TMFL_OS_IS_LINUX
#    include <asm/uaccess.h>
#  endif
#endif

/**************************************************************
* LOCAL MACROS                                                *
***************************************************************/

/** KernelIfce namespace for this set of functions */
#define PH_STBKBUFMGR_KIFCE_NAMESPACE "phStbKBufMgr"

/**************************************************************
* LOCAL TYPEDEFS                                              *
***************************************************************/

/** KernelIfce function call structure for phStbKBufMgr_GetBuffer */
typedef struct phStbKBufMgr_GetBuffer
{
    phKernelIfce_CallData_t KI_Header;
    /* Parameters */
    phStbKBufMgr_Buffer_t buf;
    uint32_t *pBufAddr;
    uint32_t *pSize;
    /* Return Value */
    tmErrorCode_t returnValue;
} phStbKBufMgr_GetBuffer_CallData_t;

/** KernelIfce function call structure for phStbKBufMgr_ReleaseBuffer */
typedef struct phStbKBufMgr_ReleaseBuffer
{
    phKernelIfce_CallData_t KI_Header;
    /* Parameters */
    phStbKBufMgr_Buffer_t buf;
    uint32_t bufAddr;
    /* Return Value */
    tmErrorCode_t returnValue;
} phStbKBufMgr_ReleaseBuffer_CallData_t;

typedef struct phStbKBufMgr_SwapStopBuffer
{
    phKernelIfce_CallData_t KI_Header;
    /* Parameters */
    phStbKBufMgr_Buffer_t buf;
    phStbKBufMgr_Buffer_t stop_buf;
    uint32_t bufAddr;
    /* Return Value */
    tmErrorCode_t returnValue;
} phStbKBufMgr_SwapStopBuffer_CallData_t;

/** KernelIfce function call structure for phStbKBufMgr_LookupBuffer */
typedef struct phStbKBufMgr_LookupBuffer
{
    phKernelIfce_CallData_t KI_Header;
    /* Parameters */
    phStbKBufMgr_Buffer_t buf;
    uint32_t bufferIndex;
    uint32_t *pBufAddr;
    uint32_t *pSize;
    /* Return Value */
    tmErrorCode_t returnValue;
} phStbKBufMgr_LookupBuffer_CallData_t;

/** KernelIfce function call structure for phStbKBufMgr_BufferStats */
typedef struct phStbKBufMgr_BufferStats
{
    phKernelIfce_CallData_t KI_Header;
    /* Parameters */
    phStbKBufMgr_Buffer_t buf;
    uint32_t *pSize;
    uint32_t *pNumTotal;
    uint32_t *pNumFree;
    /* Return Value */
    tmErrorCode_t returnValue;
} phStbKBufMgr_BufferStats_CallData_t;

/**************************************************************
* STATIC FUNCTION PROTOTYPES                                  *
***************************************************************/

#if TMFL_MODE_KERNEL

/******************************************************************************/
/** Kernel space KernelIfce handler functions

    @param  KI_callDataPtr        IN/OUT    KernelIfce function calldata structure

    @retval None
*/
static void phStbKBufMgr_GetBuffer_Handler(
    phStbKBufMgr_GetBuffer_CallData_t *KI_callDataPtr);

static void phStbKBufMgr_ReleaseBuffer_Handler(
    phStbKBufMgr_ReleaseBuffer_CallData_t *KI_callDataPtr);

static void phStbKBufMgr_SwapStopBuffer_Handler(
    phStbKBufMgr_SwapStopBuffer_CallData_t *KI_callDataPtr);

static void phStbKBufMgr_LookupBuffer_Handler(
    phStbKBufMgr_LookupBuffer_CallData_t *KI_callDataPtr);

static void phStbKBufMgr_BufferStats_Handler(
    phStbKBufMgr_BufferStats_CallData_t *KI_callDataPtr);

#endif

/**************************************************************
* STATIC DATA                                                 *
***************************************************************/

#if TMFL_MODE_KERNEL

/** Kernel Space KernelIfce table mapping function name to handler function */
static phKernelIfce_FuncSetup_t phStbKBufMgr_KI_Functions[] =
{
    {
        "phStbKBufMgr_GetBuffer",
        (pphKernelIfce_Handler_t) &phStbKBufMgr_GetBuffer_Handler
    },
    {
        "phStbKBufMgr_ReleaseBuffer",
        (pphKernelIfce_Handler_t) &phStbKBufMgr_ReleaseBuffer_Handler
    },
    {
        "phStbKBufMgr_LookupBuffer",
        (pphKernelIfce_Handler_t) &phStbKBufMgr_LookupBuffer_Handler
    },
    {
        "phStbKBufMgr_BufferStats",
        (pphKernelIfce_Handler_t) &phStbKBufMgr_BufferStats_Handler
    },
    {
        "phStbKBufMgr_SwapStopBuffer",
        (pphKernelIfce_Handler_t) &phStbKBufMgr_SwapStopBuffer_Handler
    }
};

#else /* #if TMFL_MODE_KERNEL */

/** KernelIfce namespace init data */
static phKernelIfce_NameSpace_t _KI_phStbKBufMgr_NameSpaceData =
{
    PH_STBKBUFMGR_KIFCE_NAMESPACE,
    PH_KERNELIFCE_UNINITIALISED
};

#endif /* #if TMFL_MODE_KERNEL */

/**************************************************************
* EXPORTED DATA                                               *
***************************************************************/

/**************************************************************
* FUNCTION IMPLEMENTATION                                     *
***************************************************************/

#if TMFL_MODE_KERNEL

/**************************************************************************
* Kernelspace handler functions - Resolve KernelIfce call
***************************************************************************/

/******************************************************************************/
static void phStbKBufMgr_GetBuffer_Handler(
    phStbKBufMgr_GetBuffer_CallData_t *KI_callDataPtr)
{
    uint32_t *pBufAddr = NULL;
    uint32_t *pSize = NULL;

    if ( PH_KERNELIFCE_MARSHAL(PH_KERNELIFCE_OUT, pBufAddr, sizeof(*pBufAddr))
      && PH_KERNELIFCE_MARSHAL(PH_KERNELIFCE_OUT, pSize, sizeof(*pSize)) )
    {
        KI_callDataPtr->returnValue = phStbKBufMgr_GetBuffer(
            KI_callDataPtr->buf,
            pBufAddr,
            pSize);
    }
    else
    {
        KI_callDataPtr->returnValue = PH_STBKBUFMGR_ERR_BAD_OUT_PARAM;
    }
    PH_KERNELIFCE_UNMARSHAL(PH_KERNELIFCE_OUT, pBufAddr, sizeof(*pBufAddr));
    PH_KERNELIFCE_UNMARSHAL(PH_KERNELIFCE_OUT, pSize, sizeof(*pSize));
}

static void phStbKBufMgr_ReleaseBuffer_Handler(
    phStbKBufMgr_ReleaseBuffer_CallData_t *KI_callDataPtr)
{
    KI_callDataPtr->returnValue = phStbKBufMgr_ReleaseBuffer(
        KI_callDataPtr->buf,
        KI_callDataPtr->bufAddr);
}

static void phStbKBufMgr_SwapStopBuffer_Handler(
    phStbKBufMgr_SwapStopBuffer_CallData_t *KI_callDataPtr)
{
    KI_callDataPtr->returnValue = phStbKBufMgr_SwapStopBuffer(
        KI_callDataPtr->buf,
        KI_callDataPtr->stop_buf,
        KI_callDataPtr->bufAddr);
}

static void phStbKBufMgr_LookupBuffer_Handler(
    phStbKBufMgr_LookupBuffer_CallData_t *KI_callDataPtr)
{
    uint32_t *pBufAddr = NULL;
    uint32_t *pSize = NULL;

    if ( PH_KERNELIFCE_MARSHAL(PH_KERNELIFCE_OUT, pBufAddr, sizeof(*pBufAddr))
      && PH_KERNELIFCE_MARSHAL(PH_KERNELIFCE_OUT, pSize, sizeof(*pSize)) )
    {
        KI_callDataPtr->returnValue = phStbKBufMgr_LookupBuffer(
            KI_callDataPtr->buf,
            KI_callDataPtr->bufferIndex,
            pBufAddr,
            pSize);
    }
    else
    {
        KI_callDataPtr->returnValue = PH_STBKBUFMGR_ERR_BAD_OUT_PARAM;
    }
    PH_KERNELIFCE_UNMARSHAL(PH_KERNELIFCE_OUT, pBufAddr, sizeof(*pBufAddr));
    PH_KERNELIFCE_UNMARSHAL(PH_KERNELIFCE_OUT, pSize, sizeof(*pSize));
}

static void phStbKBufMgr_BufferStats_Handler(
    phStbKBufMgr_BufferStats_CallData_t *KI_callDataPtr)
{
    uint32_t *pSize = NULL;
    uint32_t *pNumTotal = NULL;
    uint32_t *pNumFree = NULL;

    if ( PH_KERNELIFCE_MARSHAL(PH_KERNELIFCE_OUT, pSize, sizeof(*pSize))
      && PH_KERNELIFCE_MARSHAL(PH_KERNELIFCE_OUT, pNumTotal, sizeof(*pNumTotal))
      && PH_KERNELIFCE_MARSHAL(PH_KERNELIFCE_OUT, pNumFree, sizeof(*pNumFree)) )
    {
        KI_callDataPtr->returnValue = phStbKBufMgr_BufferStats(
            KI_callDataPtr->buf,
            pSize,
            pNumTotal,
            pNumFree);
    }
    else
    {
        KI_callDataPtr->returnValue = PH_STBKBUFMGR_ERR_BAD_OUT_PARAM;
    }
    PH_KERNELIFCE_UNMARSHAL(PH_KERNELIFCE_OUT, pSize, sizeof(*pSize));
    PH_KERNELIFCE_UNMARSHAL(PH_KERNELIFCE_OUT, pNumTotal, sizeof(*pNumTotal));
    PH_KERNELIFCE_UNMARSHAL(PH_KERNELIFCE_OUT, pNumFree, sizeof(*pNumFree));
}

/** Register functions with KernelIfce. */
tmErrorCode_t phStbKBufMgr_KI_Init(void)
{
    tmErrorCode_t status;

    status = phKernelIfce_Register(
        PH_STBKBUFMGR_KIFCE_NAMESPACE,
        phStbKBufMgr_KI_Functions,
        sizeof(phStbKBufMgr_KI_Functions)/sizeof(*phStbKBufMgr_KI_Functions));

    return status;
}


#else /* #if TMFL_MODE_KERNEL */

/*****************************************************************************
* Userspace stub functions - Map function calls to kernelspace using KernelIfce
******************************************************************************/

/******************************************************************************/
tmErrorCode_t phStbKBufMgr_GetBuffer(
    phStbKBufMgr_Buffer_t buf,
    uint32_t *pBufAddr,
    uint32_t *pSize)
{
    /* KernelIfce function data */
    static phKernelIfce_Func_t KI_FuncData = {
        &_KI_phStbKBufMgr_NameSpaceData,
        "phStbKBufMgr_GetBuffer",
        PH_KERNELIFCE_UNINITIALISED
    };

    phStbKBufMgr_GetBuffer_CallData_t KI_CallData;

    KI_CallData.KI_Header.len = sizeof(KI_CallData);
    KI_CallData.KI_Header.pFunc = &KI_FuncData;
    /* Parameters */
    KI_CallData.buf = buf;
    KI_CallData.pBufAddr = pBufAddr;
    KI_CallData.pSize = pSize;
    phKernelIfce_Call(&KI_CallData.KI_Header);
    /* Return Value */
    return KI_CallData.returnValue;
}

tmErrorCode_t phStbKBufMgr_ReleaseBuffer(
    phStbKBufMgr_Buffer_t buf,
    uint32_t bufAddr)
{
    /* KernelIfce function data */
    static phKernelIfce_Func_t KI_FuncData = {
        &_KI_phStbKBufMgr_NameSpaceData,
        "phStbKBufMgr_ReleaseBuffer",
        PH_KERNELIFCE_UNINITIALISED
    };

    phStbKBufMgr_ReleaseBuffer_CallData_t KI_CallData;

    KI_CallData.KI_Header.len = sizeof(KI_CallData);
    KI_CallData.KI_Header.pFunc = &KI_FuncData;
    /* Parameters */
    KI_CallData.buf = buf;
    KI_CallData.bufAddr = bufAddr;
    phKernelIfce_Call(&KI_CallData.KI_Header);
    /* Return Value */
    return KI_CallData.returnValue;
}

tmErrorCode_t phStbKBufMgr_SwapStopBuffer(
    phStbKBufMgr_Buffer_t buf,
    phStbKBufMgr_Buffer_t stop_buf,
    uint32_t bufAddr)
{
    /* KernelIfce function data */
    static phKernelIfce_Func_t KI_FuncData = {
        &_KI_phStbKBufMgr_NameSpaceData,
        "phStbKBufMgr_SwapStopBuffer",
        PH_KERNELIFCE_UNINITIALISED
    };

    phStbKBufMgr_SwapStopBuffer_CallData_t KI_CallData;

    KI_CallData.KI_Header.len = sizeof(KI_CallData);
    KI_CallData.KI_Header.pFunc = &KI_FuncData;
    /* Parameters */
    KI_CallData.buf = buf;
    KI_CallData.stop_buf = stop_buf;
    KI_CallData.bufAddr = bufAddr;
    phKernelIfce_Call(&KI_CallData.KI_Header);
    /* Return Value */
    return KI_CallData.returnValue;
}

tmErrorCode_t phStbKBufMgr_LookupBuffer(
    phStbKBufMgr_Buffer_t buf,
    uint32_t bufferIndex,
    uint32_t *pBufAddr,
    uint32_t *pSize)
{
    /* KernelIfce function data */
    static phKernelIfce_Func_t KI_FuncData = {
        &_KI_phStbKBufMgr_NameSpaceData,
        "phStbKBufMgr_LookupBuffer",
        PH_KERNELIFCE_UNINITIALISED
    };

    phStbKBufMgr_LookupBuffer_CallData_t KI_CallData;

    KI_CallData.KI_Header.len = sizeof(KI_CallData);
    KI_CallData.KI_Header.pFunc = &KI_FuncData;
    /* Parameters */
    KI_CallData.buf = buf;
    KI_CallData.bufferIndex = bufferIndex;
    KI_CallData.pBufAddr = pBufAddr;
    KI_CallData.pSize = pSize;
    phKernelIfce_Call(&KI_CallData.KI_Header);
    /* Return Value */
    return KI_CallData.returnValue;
}

tmErrorCode_t phStbKBufMgr_BufferStats(
    phStbKBufMgr_Buffer_t buf,
    uint32_t *pSize,
    uint32_t *pNumTotal,
    uint32_t *pNumFree)
{
    /* KernelIfce function data */
    static phKernelIfce_Func_t KI_FuncData = {
        &_KI_phStbKBufMgr_NameSpaceData,
        "phStbKBufMgr_BufferStats",
        PH_KERNELIFCE_UNINITIALISED
    };

    phStbKBufMgr_BufferStats_CallData_t KI_CallData;

    KI_CallData.KI_Header.len = sizeof(KI_CallData);
    KI_CallData.KI_Header.pFunc = &KI_FuncData;
    /* Parameters */
    KI_CallData.buf = buf;
    KI_CallData.pSize = pSize;
    KI_CallData.pNumTotal = pNumTotal;
    KI_CallData.pNumFree = pNumFree;
    phKernelIfce_Call(&KI_CallData.KI_Header);
    /* Return Value */
    return KI_CallData.returnValue;
}

#endif /* #if TMFL_MODE_KERNEL */

