/*****************************************************************************/
/* 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_UserMode.c
    @brief  Usermode access library for phKernelIfce.

@b  Component:  phKernelIfce

*//*

Rev Date       Author      Comments
--------------------------------------------------------------------------------
  1 20061013   batelaan    Initial
  2 20061020   batelaan    Crosscheck fixes
  3 20061020   batelaan    Crosscheck fixes
  4 20061109   G.Lawrance  Workaround DBG init problem
  5 20061110   batelaan    Enable DBG_REGISTER_MODULE again.
  6 20090120   batelaan    Update file copyright/license text
--------------------------------------------------------------------------------
    For consistency and standardisation retain the Section Separators.
*/

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

#include <tmNxTypes.h>
#include <phStbDbg.h>
#include <phKernelIfce.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>
#include <syslog.h>

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

/** Sleep time in usecs between attempt opening #PH_KERNELIFCE_DEVICE_PATH,
    to cope with delay caused by UDEV on startup.
    #PH_KERNELIFCE_ATTEMPTS attemps are made. */
#define PH_KERNELIFCE_USLEEP 50000U

/** Num attempts opening #PH_KERNELIFCE_DEVICE_PATH,
    to cope with delay caused by UDEV on startup.
    Time between attempts is #PH_KERNELIFCE_USLEEP. */
#define PH_KERNELIFCE_ATTEMPTS 60U

/******************************************************************
* LOCAL TYPEDEFS                                                  *
* recommendation only:                [p]phKernelIfce_<Word>+_t       *
*******************************************************************/

/******************************************************************
* STATIC FUNCTION PROTOTYPES                  <Module>_<Word>+    *
*******************************************************************/

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

DBG_UNIT(gphKernelIfce_DbgUnit);

static bool gKernelIfce_Initialised = false;

/** File descriptor to phKernelIfce interface device. */
static Int gKernelIfce_Fd = -1;

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

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

/** Initialise component. Automatically called by phKernelIfce_Call().
    However for debugging purposes this function is made global.
*/
tmErrorCode_t phKernelIfce_Init(void)
{
    uint32_t attempts = PH_KERNELIFCE_ATTEMPTS;
    gKernelIfce_Initialised = true;

    DBG_REGISTER_MODULE(gphKernelIfce_DbgUnit, "KernelIfce");
    DBG_ENABLE_FLAGS(gphKernelIfce_DbgUnit, DBG_WARNING);
    //DBG_ENABLE_FLAGS(gphKernelIfce_DbgUnit, DBG_ALL_FLAGS);

    DBG_PRINT1(gphKernelIfce_DbgUnit, DBG_LEVEL_2,
               "phKernelIfce_Init: opening \"%s\"",
               PH_KERNELIFCE_DEVICE_PATH);

    /* Since the device may be created uses UDEV at startup
       it may not yet exist, so retry sometime. */
    for (;;)
    {
        gKernelIfce_Fd = open(PH_KERNELIFCE_DEVICE_PATH, O_RDWR);
        if ((gKernelIfce_Fd < 0) && (attempts != 1))
        {
            attempts--;
            (void)usleep(PH_KERNELIFCE_USLEEP);
        }
        else
        {
            break;
        }
    }
    if (gKernelIfce_Fd < 0)
    {
#if TMDBG_ASSERTS_ARE_ENABLED
        DBG_ASSERT_ALWAYS(("Opening \"%s\" => errno=%s", PH_KERNELIFCE_DEVICE_PATH, strerror(errno)));
#else
        return PH_ERR_KERNELIFCE_DEVICE;
#endif
    }
    return TM_OK;
}

/******************************************************************************/
void phKernelIfce_Call(
    pphKernelIfce_CallData_t pCallData
)
{
    tmErrorCode_t err;
    Int st;

    if (!gKernelIfce_Initialised)
    {
        err = phKernelIfce_Init();
        if (err != TM_OK)
        {
            pCallData->err = err;
            return;
        }
    }

    pCallData->err = PH_ERR_KERNELIFCE_UNKNOWN;
    DBG_PRINT4(gphKernelIfce_DbgUnit, DBG_INTERFACE_ENTER,
               "phKernelIfce_Call: nameSpace=%s/%d func=%s/%d",
               pCallData->pFunc->pNameSpace->name,
               pCallData->pFunc->pNameSpace->id,
               pCallData->pFunc->name,
               pCallData->pFunc->id);
    st = ioctl(gKernelIfce_Fd, PH_KERNELIFCE_IOCTL_CALL, pCallData);
    if (st != 0)
    {
        perror(PH_KERNELIFCE_DEVICE_PATH ": ioctl");
        pCallData->err = PH_ERR_KERNELIFCE_IOCTL;
        return;
    }
    pCallData->err = TM_OK;

    DBG_PRINT5(gphKernelIfce_DbgUnit, DBG_INTERFACE_LEAVE,
               "phKernelIfce_Call: nameSpace=%s/%d func=%s/%d => 0x%x\n",
               pCallData->pFunc->pNameSpace->name,
               pCallData->pFunc->pNameSpace->id,
               pCallData->pFunc->name,
               pCallData->pFunc->id,
               pCallData->err);
}

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