#ifndef PHKERNELIFCE_KERNEL_H    /* Multi-include protection.   <FILENAME>_H */
#define PHKERNELIFCE_KERNEL_H


/*****************************************************************************/
/* Copyright (c) 2008 NXP B.V.                                               */
/*                                                                           */
/* This program is free software; you can redistribute it and/or modify      */
/* it under the terms of the GNU General Public License as published by      */
/* the Free Software Foundation, using version 2 of the License.             */
/*                                                                           */
/* This program is distributed in the hope that it will be useful,           */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the              */
/* GNU General Public License for more details.                              */
/*                                                                           */
/* You should have received a copy of the GNU General Public License         */
/* along with this program; if not, write to the Free Software               */
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307       */
/* USA.                                                                      */
/*                                                                           */
/*****************************************************************************/
/**
    @file   phKernelIfce_Kernel.h
    @brief  Generic usermode to kernelspace API framework.

@b  Component:  phKernelIfce

    Do not include directly. Please include phKernelIfce.h instead.

   Example of a kernel handler function follows.
   Various means of indicating the size of the marshalled area
   are used:
   - An explicit size field passed in the function call.
   - A constant in the form of a macro name
   - The size of the object pointed to by the pointer argument.
   Take special care when using multi-layered pointers. They require the use
   of additional #PH_KERNELIFCE_MARSHAL_PTR/#PH_KERNELIFCE_MARSHAL_PTR
   macro calls. See the example below.

   @code
static void myFunction_Handler(
    myFunction_CallData_t *KI_callDataPtr)
{
    W** ppW = NULL;
    W* pW = NULL;
    W* pLocalW = NULL;

    uint8_t *x = NULL;
    Y *y = NULL;
    Z *z = NULL;
    if (PH_KERNELIFCE_MARSHAL(PH_KERNELIFCE_INOUT, ppW, sizeof(*ppW))
    &&  PH_KERNELIFCE_MARSHAL_PTR(PH_KERNELIFCE_OUT, pW, sizeof(*pW))
    &&  PH_KERNELIFCE_MARSHAL(PH_KERNELIFCE_IN, x, KI_callDataPtr->xSize)
    &&  PH_KERNELIFCE_MARSHAL(PH_KERNELIFCE_INOUT, y, PH_MY_FUNCTION_Y_MAX_SIZE)
    &&  PH_KERNELIFCE_MARSHAL(PH_KERNELIFCE_OUT, z, sizeof(*z)))
    {
        KI_callDataPtr->returnValue = myFunction(&pLocalW, x, y, z);
        if ( TM_OK == KI_callDataPtr->returnValue )
            *pW = *pLocalW;
    }
    else
    {
        KI_callDataPtr->returnValue = PH_ERR_KERNELIFCE_FAULT;
    }
    PH_KERNELIFCE_UNMARSHAL_PTR(PH_KERNELIFCE_OUT, pW, sizeof(*pW));
    PH_KERNELIFCE_UNMARSHAL(PH_KERNELIFCE_INOUT, ppW, sizeof(*ppW));
    PH_KERNELIFCE_UNMARSHAL(PH_KERNELIFCE_IN, x, KI_callDataPtr->xSize);
    PH_KERNELIFCE_UNMARSHAL(PH_KERNELIFCE_INOUT, y, PH_MY_FUNCTION_Y_MAX_SIZE);
    PH_KERNELIFCE_UNMARSHAL(PH_KERNELIFCE_OUT, z, sizeof(*z));
}
   @endcode

*//*

Rev Date        Author      Comments
--------------------------------------------------------------------------------
  1 20061012    batelaan    Initial
  2 20061020    batelaan    Crosscheck fixes
  3 20070524    iwillis     Added "const" qualifiers to prevent warnings in
                           tmdlMsvd_KI.c
  4 20071002    batelaan    Portability enhancements
  5 20071024    batelaan    Add marshalling abstraction macros
  6 20071210    hutchinson  Merged in EB's changes for WinCe from 12/12/07 
  7 20080206    batelaan    Update file copyright/license text
  8 20080617    batelaan    Update file copyright/license text
--------------------------------------------------------------------------------
    For consistency and standardisation retain the Section Separators.
*/

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

#ifndef PHKERNELIFCE_H
  #error Please include phKernelIfce.h instead.
#endif

#if TMFL_OS_IS_LINUX
# include <linux/kernel.h>
#endif
#include <phKernelIfce_Common.h>

#ifdef __cplusplus
extern "C"
{
#endif

/**************************************************************************
* EXPORTED MACROS                          PH_KERNELIFCE_<_WORD>+             *
***************************************************************************/

/** @def PH_KERNELIFCE_IN
    Direction in which an argument must be marshalled.
    IN means from userspace to kernelspace. */
/** @def PH_KERNELIFCE_INOUT
    Direction in which an argument must be marshalled.
    INOUT means from userspace to kernelspace and back again. */
/** @def PH_KERNELIFCE_OUT
    Direction in which an argument must be marshalled.
    OUT means to userspace from kernelspace. */

/** @def PH_KERNELIFCE_MARSHAL
    Marshal data from userspace to kernelspace.
    This means making data originating in userspace
    accessible in kernelspace, as well as preparing
    for kernelspace to write to userspace.
    Actions taken are dependent on OS and other issues,
    such as whether kernelspace has transparent access to usermode addresses.
    @param @b IN direction Direction of marshalling.
    One of #PH_KERNELIFCE_IN #PH_KERNELIFCE_INOUT #PH_KERNELIFCE_OUT.
    @param @b IN varName Name of the function argument variable to marshal.
    A local variable must exist with this name, as well as a field
    in the structure pointed to by KI_callDataPtr.
    @param @b IN varSize Number of bytes to marshal.
    @return A true value for success, a false value for failure.
*/

/** @def PH_KERNELIFCE_UNMARSHAL
    Marshal data to userspace from kernelspace.
    This means cleaning up any actions performed by #PH_KERNELIFCE_MARSHAL.
    Actions taken are dependent on OS and other issues,
    such as whether kernelspace has transparent access to usermode addresses.
    @param @b IN direction Direction of unmarshalling.
    One of #PH_KERNELIFCE_IN #PH_KERNELIFCE_INOUT #PH_KERNELIFCE_OUT.
    @param @b IN varName Name of the function argument variable to unmarshal.
    A local variable must exist with this name, as well as a field
    in the structure pointed to by KI_callDataPtr.
    @param @b IN varSize Number of bytes to unmarshal.
    @return Has no return value.
*/

/** @def PH_KERNELIFCE_MARSHAL_PTR
    Marshal embedded data from userspace to kernelspace.
    This means marshalling data pointed to by a pointer which was previously
    marshalled by #PH_KERNELIFCE_MARSHAL or #PH_KERNELIFCE_MARSHAL_PTR.
    @param @b IN direction Direction of marshalling.
    One of #PH_KERNELIFCE_IN #PH_KERNELIFCE_INOUT #PH_KERNELIFCE_OUT.
    @param @b IN varName Name of the function argument to marshal.
    A local variable must exist with this name, as well as a variable with a
    prepended 'p', such that varName = marshal(pvarName).
    @param @b IN varSize Number of bytes to marshal.
    @return A true value for success, a false value for failure.
*/

/** @def PH_KERNELIFCE_UNMARSHAL_PTR
    Marshal embedded data to userspace from kernelspace.
    This is the inverse of #PH_KERNELIFCE_MARSHAL_PTR.
    @param @b IN direction Direction of unmarshalling.
    One of #PH_KERNELIFCE_IN #PH_KERNELIFCE_INOUT #PH_KERNELIFCE_OUT.
    @param @b IN varName Name of the function argument to unmarshal.
    A local variable must exist with this name, as well as a variable with a
    prepended 'p', such that pvarName = unmarshal(varName).
    @param @b IN varSize Number of bytes to unmarshal.
    @return Has no return value.
*/

#define PH_KERNELIFCE_MARSHAL(direction, varName, varSize) \
    PH_KERNELIFCE_MARSHAL_IMPL(direction, varName, KI_callDataPtr->varName, varSize)

#define PH_KERNELIFCE_UNMARSHAL(direction, varName, varSize)  \
    PH_KERNELIFCE_UNMARSHAL_IMPL(direction, varName, KI_callDataPtr->varName, varSize)

#define PH_KERNELIFCE_MARSHAL_PTR(direction, varName, varSize) \
    PH_KERNELIFCE_MARSHAL_IMPL(direction, varName, *p ## varName, varSize)

#define PH_KERNELIFCE_UNMARSHAL_PTR(direction, varName, varSize)  \
    PH_KERNELIFCE_UNMARSHAL_IMPL(direction, varName, *p ## varName, varSize)


#if TMFL_OS_IS_LINUX

#define PH_KERNELIFCE_IN    (-1)
#define PH_KERNELIFCE_INOUT (0)
#define PH_KERNELIFCE_OUT   (1)

/** Verify that address/size is correctly accessible. */
#define PH_KERNELIFCE_ACCESS_OK(direction, address, argSize) \
    access_ok((((direction) == PH_KERNELIFCE_IN) \
               ? VERIFY_READ \
               : VERIFY_WRITE), \
              (address), (argSize))

#define PH_KERNELIFCE_MARSHAL_IMPL(direction, varName, ptrName, varSize) \
    (PH_KERNELIFCE_ACCESS_OK((direction), ptrName, (varSize))   \
    ? (((varName) = (ptrName)), 1)                              \
    : 0)

#define PH_KERNELIFCE_UNMARSHAL_IMPL(direction, varName, ptrName, varSize) \
   do { (ptrName) = (varName); } while (0)

#elif TMFL_OS_IS_CE

#define PH_KERNELIFCE_IN    ARG_I_PTR
#define PH_KERNELIFCE_INOUT ARG_IO_PTR
#define PH_KERNELIFCE_OUT   ARG_O_PTR

#define PH_KERNELIFCE_MARSHAL_IMPL(direction, varName, ptrName, varSize) \
    (ptrName                                \
        ? SUCCEEDED( CeOpenCallerBuffer(    \
          (PVOID*) &(varName),              \
          (PVOID) (ptrName),                \
          (varSize),                        \
          (direction),                      \
          FALSE) )                          \
        : 1)

#define PH_KERNELIFCE_UNMARSHAL_IMPL(direction, varName, ptrName, varSize) \
    if ( varName ) CeCloseCallerBuffer( \
        (PVOID) (varName),              \
        (PVOID) (ptrName),              \
        (varSize),                      \
        (direction) )


#else
   #error Unsupported OS
#endif

/*********************************************************************
* EXPORTED TYPEDEFS                      [p]phKernelIfce_<Word>+_t       *
**********************************************************************/

/** Type of a handler function. Instances of this will be C functions
    that de-marshal arguments, and call the 'real' function. */
typedef void phKernelIfce_Handler_t(pphKernelIfce_CallData_t);

/** Pointer to a ::phKernelIfce_Handler_t. */
typedef phKernelIfce_Handler_t *pphKernelIfce_Handler_t;

/** Stores information about a registered namespace. Opaque. */
typedef struct phKernelIfce_KNameSpace *pphKernelIfce_KNameSpace_t;

/** Declares information for registering a handler function.
 */
typedef struct phKernelIfce_FuncSetup {
    /** Name of the function that the handler function will call. */
    const char *name;
    /** Handler function address. */
    phKernelIfce_Handler_t *handler;
} phKernelIfce_FuncSetup_t;
    
/**************************************************************************
* EXPORTED DATA                     g[k|p|kp|pk|kpk]phKernelIfce_<Word>+      *
***************************************************************************/

/****************************************************************************
* EXPORTED FUNCTION PROTOTYPES                    phKernelIfce[_<Word>+]        *
*****************************************************************************/

/** Registers the namespace and associated functions with phKernelIfce.
    @param nameSpace @b IN Name of the namespace.
    @param functions @b IN Array of functions information.
    @param numFunctions @b IN Number of entries in functions array.
    @return TM_OK if successful, otherwise error code.
*/
tmErrorCode_t phKernelIfce_Register(
    const char *nameSpace,
    const phKernelIfce_FuncSetup_t functions[],
    uint numFunctions
);

/** Registers functions with phKernelIfce.
    @param pNameSpace @b IN Namespace registered via phKernelIfce_NameSpaceRegister().
    @param functions @b IN Array of functions information.
    @param numFunctions @b IN Number of entries in functions array.
    @return TM_OK if successful, otherwise error code.
*/
tmErrorCode_t phKernelIfce_RegisterFunctions(
    pphKernelIfce_KNameSpace_t pNameSpace,
    const phKernelIfce_FuncSetup_t functions[],
    uint numFunctions
);

/** Register a namespace.
    @param name @b IN Namespace name. The address of this string is retained.
    @param funcsCountMax @b IN Number of functions, if known. Otherwise set it to 0.
    @param ppNameSpace @b OUT Allocated namespace structure.
    @return Error code, or TM_OK if successful. If the namespace is already registered,
    then *ppNameSpace is set, and #PH_ERR_KERNELIFCE_DUPL_NAMESPACE is returned.
 */
tmErrorCode_t phKernelIfce_NameSpaceRegister(
    const char *name,
    uint funcsCountMax,
    pphKernelIfce_KNameSpace_t *ppNameSpace
);

/** Unregister a namespace.
    @param name @b IN Namespace name.
    @return Error code, or TM_OK if successful.
 */
tmErrorCode_t phKernelIfce_NameSpaceUnregister(
    const char *name
);

/** Register a function.
    @param name @b IN Function name. The address of this string is retained.
    @param pNameSpace @b IN Namespace, returned from phKernelIfce_NameSpaceRegister().
    @param pHandler @b IN Address of C handler function.
    @return Error code, or TM_OK if successful.
 */
tmErrorCode_t phKernelIfce_FuncRegister(
    pphKernelIfce_KNameSpace_t pNameSpace,
    const char *name,
    phKernelIfce_Handler_t *pHandler
);

/******************************************************************************/

#ifdef __cplusplus
}
#endif

#endif /* PHKERNELIFCE_KERNEL_H      Do not add any thing below this line */
