/*****************************************************************************/
/* Copyright (c) 2009 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   phKernelIfce_ModuleTest.c
    @brief  Test Linux kernel module for phKernelIfce component.

@b  Component:  phKernelIfce.

*//*

Rev Date       Author      Comments
--------------------------------------------------------------------------------
  1 20061012   batelaan    Initial
  2 20061020   batelaan    Crosscheck fixes
  3 20061109   G.Lawrance  Fix after tmStbDbg.h changes
  4 20090121   batelaan    Update author/license.
  5 20090122   batelaan    Use MODULE_LICENSE("Dual BSD/GPL");
--------------------------------------------------------------------------------
    For consistency and standardisation retain the Section Separators.
*/

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>        /* kmalloc() */
#include <linux/errno.h>
#include <linux/fs.h>
#include <asm/semaphore.h>
#include <asm/uaccess.h>
#include <linux/delay.h>

#include <linux/device.h>
#include <linux/cdev.h>

#include <phKernelIfce.h>
#include <phStbDbg.h>

#include <phExample1_KI.c>

DBG_UNIT_EXTERN(gphKernelIfce_DbgUnit);

/***********************************************
* LOCAL MACROS                                 *
* recommendation only: <MODULE><_WORD>+        *
************************************************/

#define THIS_MODULE_DESCRIPTION "Test for phKernelIfce Kernel Module"
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION(THIS_MODULE_DESCRIPTION);
MODULE_AUTHOR("NXP B.V.");

/** Check that an expression returns the right result. */
#define CHECK(expr, expected) { \
        tmErrorCode_t err; \
        printk(KERN_CRIT "\n  %s\n", #expr); \
        err = (expr); \
        if (err != (expected)) { \
            printk(KERN_CRIT "**ERROR (0x%x - expected 0x%x): %s\n", err, (unsigned int)(expected), #expr); \
            return(1); \
        } \
    }

/******************************************************************
* FUNCTION PROTOTYPES                    [p]ph<Module>_<Word>+    *
*******************************************************************/

static int __init KernelIfce_KmoduleTestInit(void);
static void __exit KernelIfce_KmoduleTestExit(void);
static int KernelIfce_KmoduleTestRun(void);

/******************************************************************
* LOCAL TYPEDEFS                                                  *
* recommendation only:                   [p]ph<Module>_<Word>+_t  *
*******************************************************************/

/*******************************************************************
* EXPORTED DATA                 g[k|p|kp|pk|kpk]ph<Module>_<Word>+ *
********************************************************************/

module_init(KernelIfce_KmoduleTestInit);
module_exit(KernelIfce_KmoduleTestExit);

/*******************************************************************
* LOCAL DATA                                                       *
********************************************************************/

/*******************************************************************************
* FUNCTION IMPLEMENTATION  <Module>[_<Word>+] for static functions             *
*                          tm[<layer>]<Module>[_<Word>+] for exported functions*
********************************************************************************/

/******************************************************************************/
/** Module Creation function.
    @retval int Always 0.
*/
static int __init KernelIfce_KmoduleTestInit(void)
{
    tmErrorCode_t err;

    // not exported: DBG_ENABLE_FLAGS(gphKernelIfce_DbgUnit, DBG_ALL_FLAGS);
    (void)KernelIfce_KmoduleTestRun();

    err = phKernelIfce_Register(
        "phExample1",
        phExample1_KI_Functions,
        sizeof(phExample1_KI_Functions) / sizeof(phExample1_KI_Functions[0]));
    DBG_ASSERT2(err == TM_OK, ("err=0x%x\n", err));

    return 0;
}

/******************************************************************************/
/** Stuff to run on module exit.
    @return 0 if OK, !0 on error.
*/
static int KernelIfce_KmoduleTestExitRun(void)
{
    tmErrorCode_t err;
    err = phKernelIfce_NameSpaceUnregister("phExample1");
    DBG_ASSERT2(err == TM_OK, ("err=0x%x\n", err));

    CHECK(phKernelIfce_NameSpaceUnregister("NameSpace0"),
          TM_OK);
    CHECK(phKernelIfce_NameSpaceUnregister("NameSpace1_0funcs"),
          TM_OK);
    return 0;
}

/******************************************************************************/
/** Module Exit function.
*/
static void __exit KernelIfce_KmoduleTestExit(void)
{
    (void)KernelIfce_KmoduleTestExitRun();
}

/******************************************************************************/
/** Defines a function to be called from userspace,
    and which will be registered with phKernelIfce_NameSpaceRegister().
    @param nameSpace @b IN Namespace number (e.g. 0, 1, etc)
    @param func @b IN Function number (e.g. 0, 1, etc)
*/
#define SETUP_HANDLER(nameSpace, func)                                       \
static void NameSpace##nameSpace##_Func##func##_handler(pphKernelIfce_CallData_t pCallData) \
{ \
    printk("NameSpace%u_Func%u_handler called;\n", nameSpace, func); \
    pCallData->err = TM_OK; \
}

SETUP_HANDLER(0, 0)
SETUP_HANDLER(0, 1)
SETUP_HANDLER(0, 2)
SETUP_HANDLER(1, 0)
SETUP_HANDLER(1, 1)
SETUP_HANDLER(1, 2)

/******************************************************************************/
static int KernelIfce_KmoduleTestRun(void)
{
    pphKernelIfce_KNameSpace_t pNameSpace;
    pphKernelIfce_KNameSpace_t pNameSpace0;
    pphKernelIfce_KNameSpace_t pNameSpace1;

    /* Unregistering unknown namespace. */
    CHECK(phKernelIfce_NameSpaceUnregister("NameSpace_NonExistant"),
          PH_ERR_KERNELIFCE_UNKNOWN_NAMESPACE);

    /* Registering and unregistering namespaces (before any namespaces
     * have been registered). */
    CHECK(phKernelIfce_NameSpaceRegister("NameSpaceA_Unregistered", 2, &pNameSpace),
          TM_OK);

    CHECK(phKernelIfce_NameSpaceUnregister("NameSpaceA_Unregistered"),
          TM_OK);
    CHECK(phKernelIfce_NameSpaceUnregister("NameSpaceA_Unregistered"),
          PH_ERR_KERNELIFCE_UNKNOWN_NAMESPACE);


    /* Registering namespace with known number of functions. */
    CHECK(phKernelIfce_NameSpaceRegister("NameSpace0", 2, &pNameSpace),
          TM_OK);
    pNameSpace0 = pNameSpace;

    CHECK(phKernelIfce_NameSpaceRegister("NameSpace0", 2, &pNameSpace),
          PH_ERR_KERNELIFCE_DUPL_NAMESPACE);
    
    CHECK(phKernelIfce_FuncRegister(pNameSpace, "NameSpace0_Func0", (pphKernelIfce_Handler_t)&NameSpace0_Func0_handler),
          TM_OK);
    CHECK(phKernelIfce_FuncRegister(pNameSpace, "NameSpace0_Func0", (pphKernelIfce_Handler_t)&NameSpace0_Func0_handler),
          PH_ERR_KERNELIFCE_DUPL_FUNC);
    CHECK(phKernelIfce_FuncRegister(pNameSpace, "NameSpace0_Func1", &NameSpace0_Func1_handler),
          TM_OK);
    CHECK(phKernelIfce_FuncRegister(pNameSpace, "NameSpace0_Func2", &NameSpace0_Func2_handler),
          TM_OK);
    CHECK(phKernelIfce_FuncRegister(pNameSpace, "NameSpace0_Func0", (pphKernelIfce_Handler_t)&NameSpace0_Func0_handler),
          PH_ERR_KERNELIFCE_DUPL_FUNC);
    CHECK(phKernelIfce_FuncRegister(pNameSpace, "NameSpace0_Func2", &NameSpace0_Func2_handler),
          PH_ERR_KERNELIFCE_DUPL_FUNC);


    /* Registering namespace with unknown number of functions. */
    CHECK(phKernelIfce_NameSpaceRegister("NameSpace1_0funcs", 0, &pNameSpace),
          TM_OK);
    pNameSpace1 = pNameSpace;

    CHECK(phKernelIfce_NameSpaceRegister("NameSpace1_0funcs", 0, &pNameSpace),
          PH_ERR_KERNELIFCE_DUPL_NAMESPACE);
    CHECK(phKernelIfce_FuncRegister(pNameSpace, "NameSpace1_Func0", &NameSpace1_Func0_handler),
          TM_OK);
    CHECK(phKernelIfce_FuncRegister(pNameSpace, "NameSpace1_Func0", &NameSpace1_Func0_handler),
          PH_ERR_KERNELIFCE_DUPL_FUNC);
    CHECK(phKernelIfce_FuncRegister(pNameSpace, "NameSpace1_Func1", &NameSpace1_Func1_handler),
          TM_OK);
    CHECK(phKernelIfce_FuncRegister(pNameSpace, "NameSpace1_Func2", &NameSpace1_Func2_handler),
          TM_OK);
    CHECK(phKernelIfce_FuncRegister(pNameSpace, "NameSpace1_Func0", &NameSpace1_Func0_handler),
          PH_ERR_KERNELIFCE_DUPL_FUNC);
    CHECK(phKernelIfce_FuncRegister(pNameSpace, "NameSpace1_Func2", &NameSpace1_Func2_handler),
          PH_ERR_KERNELIFCE_DUPL_FUNC);

    /* Check that NameSpace0 is still around: */
    CHECK(phKernelIfce_NameSpaceRegister("NameSpace0", 2, &pNameSpace),
          PH_ERR_KERNELIFCE_DUPL_NAMESPACE);
    CHECK(pNameSpace == pNameSpace0, !false);

    /* Registering and unregistering namespaces again (now that some
     * namespaces have been registered before). */
    CHECK(phKernelIfce_NameSpaceRegister("NameSpaceB_Unregistered", 2, &pNameSpace),
          TM_OK);

    CHECK(phKernelIfce_NameSpaceUnregister("NameSpaceB_Unregistered"),
          TM_OK);
    CHECK(phKernelIfce_NameSpaceUnregister("NameSpaceB_Unregistered"),
          PH_ERR_KERNELIFCE_UNKNOWN_NAMESPACE);
    return 0;
}

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