/*
 * Copyright (c) 2012-2013, 2016 The Linux Foundation. All rights reserved.
 *
 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
 *
 *
 * Permission to use, copy, modify, and/or distribute this software for
 * any purpose with or without fee is hereby granted, provided that the
 * above copyright notice and this permission notice appear in all
 * copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * This file was originally distributed by Qualcomm Atheros, Inc.
 * under proprietary terms before Copyright ownership was assigned
 * to the Linux Foundation.
 */

/*===========================================================================
  @file VossWrapper.c

  @brief This source file contains the various function definitions for the
  RTOS abstraction layer, implemented for VOSS
===========================================================================*/

/*===========================================================================

                       EDIT HISTORY FOR FILE


  This section contains comments describing changes made to the module.
  Notice that changes are listed in reverse chronological order.


  $Header:$ $DateTime: $ $Author: $


  when        who    what, where, why
  --------    ---    --------------------------------------------------------
  03/31/09    sho    Remove the use of vosTimerIsActive flag as it is not
                     thread-safe
  02/17/08    sho    Fix the timer callback function to work when it is called
                     after the timer has stopped due to a race condition.
  02/10/08    sho    Refactor the TX timer to use VOS timer directly instead
                     of using VOS utility timer
  12/15/08    sho    Resolved errors and warnings from the AMSS compiler when
                     this is ported from WM
  11/20/08    sho    Renamed this to VosWrapper.c; remove all dependencies on
                     WM platform and allow this to work on all VOSS enabled
                     platform
  06/24/08    tbh    Modified the file to remove the dependecy on HDD files as
                     part of Gen6 bring up process.
  10/29/02 Neelay Das Created file.

===========================================================================*/

/*---------------------------------------------------------------------------
 * Include Files
 * ------------------------------------------------------------------------*/
#include "VossWrapper.h"

#ifdef WLAN_DEBUG
#define TIMER_NAME (timer_ptr->timerName)
#else
#define TIMER_NAME "N/A"
#endif

/**---------------------------------------------------------------------
 * tx_time_get()
 *
 * FUNCTION:
 *
 * LOGIC:
 *
 * ASSUMPTIONS:
 *
 * NOTE:
 *
 * @param
 *
 * @return current system time in units of miliseconds
 *
 */
v_ULONG_t tx_time_get( void )
{
   return(vos_timer_get_system_ticks());

} //* tx_time_get()


/**---------------------------------------------------------------------
 * tx_timer_activate()
 *
 * FUNCTION:
 *
 * LOGIC:
 *
 * ASSUMPTIONS:
 *
 * NOTE:
 *
 * @param
 *
 * @return TX_SUCCESS.
 *
 */
v_UINT_t tx_timer_activate(TX_TIMER *timer_ptr)
{
   VOS_STATUS status;

    // Uncomment the asserts, if the intention is to debug the occurence of the
    // following anomalous cnditions.

    // Assert that the timer structure pointer passed, is not NULL
    //dbgAssert(NULL != timer_ptr);

    // If the NIC is halting just spoof a successful timer activation, so that all
    // the timers can be cleaned up.

    if(NULL == timer_ptr)
        return TX_TIMER_ERROR;

    // Put a check for the free builds
    if (TX_AIRGO_TMR_SIGNATURE != timer_ptr->tmrSignature) {
        VOS_ASSERT( timer_ptr->tmrSignature == 0 );

        return TX_TIMER_ERROR;

    }

    // Check for an uninitialized timer
    VOS_ASSERT(0 != strlen(TIMER_NAME));

    status = vos_timer_start( &timer_ptr->vosTimer,
         timer_ptr->initScheduleTimeInMsecs );

   if (VOS_STATUS_SUCCESS == status)
   {
      return TX_SUCCESS;
   }
   else if (VOS_STATUS_E_ALREADY == status)
   {
      // starting timer fails because timer is already started; this is okay
      VOS_TRACE(VOS_MODULE_ID_SYS, VOS_TRACE_LEVEL_INFO,
            "Timer %s is already running\n", TIMER_NAME);
      return TX_SUCCESS;
   }
   else
   {
      VOS_TRACE(VOS_MODULE_ID_SYS, VOS_TRACE_LEVEL_ERROR,
            "Timer %s fails to activate\n", TIMER_NAME);
      return TX_TIMER_ERROR;
   }
} /*** tx_timer_activate() ***/


/**---------------------------------------------------------------------
 * tx_timer_change()
 *
 * FUNCTION:
 *
 * LOGIC:
 *
 * ASSUMPTIONS:
 *
 * NOTE:
 *
 * @param
 *
 * @return TX_SUCCESS.
 *
 */
v_UINT_t tx_timer_change(TX_TIMER *timer_ptr,
      v_ULONG_t initScheduleTimeInTicks, v_ULONG_t rescheduleTimeInTicks)
{
   // Put a check for the free builds
   if (TX_AIRGO_TMR_SIGNATURE != timer_ptr->tmrSignature) {
       VOS_ASSERT( timer_ptr->tmrSignature == 0 );

       return TX_TIMER_ERROR;
   }

    // changes cannot be applied until timer stops running
    if (VOS_TIMER_STATE_STOPPED == vos_timer_getCurrentState(&timer_ptr->vosTimer))
    {
       timer_ptr->initScheduleTimeInMsecs = TX_MSECS_IN_1_TICK * initScheduleTimeInTicks;
       timer_ptr->rescheduleTimeInMsecs = TX_MSECS_IN_1_TICK * rescheduleTimeInTicks;
       return TX_SUCCESS;
    }
    else
    {
       return TX_TIMER_ERROR;
    }
} /*** tx_timer_change() ***/

/**---------------------------------------------------------------------
 * tx_timer_change_context()
 *
 * FUNCTION:
 *
 * LOGIC:
 *
 * ASSUMPTIONS:
 *
 * NOTE:
 *
 * @param
 *
 * @return TX_SUCCESS.
 *
 */
v_UINT_t tx_timer_change_context(TX_TIMER *timer_ptr, tANI_U32 expiration_input)
{

    // Put a check for the free builds
    if (TX_AIRGO_TMR_SIGNATURE != timer_ptr->tmrSignature) {
       VOS_ASSERT( timer_ptr->tmrSignature == 0 );

       return TX_TIMER_ERROR;
    }

    // changes cannot be applied until timer stops running
    if (VOS_TIMER_STATE_STOPPED == vos_timer_getCurrentState(&timer_ptr->vosTimer))
    {
       timer_ptr->expireInput = expiration_input;
       return TX_SUCCESS;
    }
    else
    {
       return TX_TIMER_ERROR;
    }
} /*** tx_timer_change() ***/


/**---------------------------------------------------------------------
 * tx_main_timer_func()
 *
 * FUNCTION:
 *
 * LOGIC:
 *
 * ASSUMPTIONS:
 *
 * NOTE:
 *
 * @param
 *
 * @return None.
 *
 */
static v_VOID_t tx_main_timer_func( v_PVOID_t functionContext )
{
   TX_TIMER *timer_ptr = (TX_TIMER *)functionContext;


   if (NULL == timer_ptr)
   {
       VOS_ASSERT(0);
       return;
   }


   if (NULL == timer_ptr->pExpireFunc)
   {
       VOS_ASSERT(0);
       return;
   }

   VOS_TRACE(VOS_MODULE_ID_SYS, VOS_TRACE_LEVEL_INFO,
             "Timer %s triggered", TIMER_NAME);

   // Now call the actual timer function, taking the function pointer,
   // from the timer structure.
   (* timer_ptr->pExpireFunc)( timer_ptr->pMac, timer_ptr->expireInput );

   // check if this needs to be rescheduled
   if (0 != timer_ptr->rescheduleTimeInMsecs)
   {
      VOS_STATUS status;
      status = vos_timer_start( &timer_ptr->vosTimer,
                                timer_ptr->rescheduleTimeInMsecs );
      timer_ptr->rescheduleTimeInMsecs = 0;

      if (VOS_STATUS_SUCCESS != status)
      {
         VOS_TRACE(VOS_MODULE_ID_SYS, VOS_TRACE_LEVEL_WARN,
             "Unable to reschedule timer %s; status=%d", TIMER_NAME, status);
      }
   }
} /*** tx_timer_change() ***/

#ifdef TIMER_MANAGER
v_UINT_t tx_timer_create_intern_debug( v_PVOID_t pMacGlobal, TX_TIMER *timer_ptr,
   char *name_ptr,
   v_VOID_t ( *expiration_function )( v_PVOID_t, tANI_U32 ),
   tANI_U32 expiration_input, v_ULONG_t initScheduleTimeInTicks,
   v_ULONG_t rescheduleTimeInTicks, v_ULONG_t auto_activate,
   char* fileName, v_U32_t lineNum)
{
    VOS_STATUS status;

    if (NULL == expiration_function)
    {
        VOS_TRACE(VOS_MODULE_ID_SYS, VOS_TRACE_LEVEL_ERROR,
                "NULL timer expiration");
        VOS_ASSERT(0);
        return TX_TIMER_ERROR;
    }

    if(NULL == name_ptr)
    {

        VOS_TRACE(VOS_MODULE_ID_SYS, VOS_TRACE_LEVEL_ERROR,
                "NULL name pointer for timer");
        VOS_ASSERT(0);
        return TX_TIMER_ERROR;
    }
    if (!initScheduleTimeInTicks)
        return TX_TICK_ERROR;

    if (!timer_ptr)
        return TX_TIMER_ERROR;

    // Initialize timer structure
    timer_ptr->pExpireFunc = expiration_function;
    timer_ptr->expireInput = expiration_input;
    timer_ptr->initScheduleTimeInMsecs =
        TX_MSECS_IN_1_TICK * initScheduleTimeInTicks;
    timer_ptr->rescheduleTimeInMsecs =
        TX_MSECS_IN_1_TICK * rescheduleTimeInTicks;
    timer_ptr->pMac = pMacGlobal;

    // Set the flag indicating that the timer was created
    timer_ptr->tmrSignature = TX_AIRGO_TMR_SIGNATURE;

#ifdef WLAN_DEBUG
    // Store the timer name
    strlcpy(timer_ptr->timerName, name_ptr, sizeof(timer_ptr->timerName));
#endif // Store the timer name, for Debug build only

    status = vos_timer_init_debug( &timer_ptr->vosTimer, VOS_TIMER_TYPE_SW,
          tx_main_timer_func, (v_PVOID_t)timer_ptr, fileName, lineNum);
    if (VOS_STATUS_SUCCESS != status)
    {
       VOS_TRACE(VOS_MODULE_ID_SYS, VOS_TRACE_LEVEL_ERROR,
             "Cannot create timer for %s\n", TIMER_NAME);
       return TX_TIMER_ERROR;
    }

    if(0 != rescheduleTimeInTicks)
    {
        VOS_TRACE(VOS_MODULE_ID_SYS, VOS_TRACE_LEVEL_INFO,
                  "Creating periodic timer for %s\n", TIMER_NAME);
    }

    // Activate this timer if required
    if (auto_activate)
    {
        tx_timer_activate(timer_ptr);
    }

    return TX_SUCCESS;

} //** tx_timer_create() ***/
#else
v_UINT_t tx_timer_create_intern( v_PVOID_t pMacGlobal, TX_TIMER *timer_ptr,
   char *name_ptr,
   v_VOID_t ( *expiration_function )( v_PVOID_t, tANI_U32 ),
   tANI_U32 expiration_input, v_ULONG_t initScheduleTimeInTicks,
   v_ULONG_t rescheduleTimeInTicks, v_ULONG_t auto_activate )
{
    VOS_STATUS status;

    if((NULL == name_ptr) || (NULL == expiration_function))
        return TX_TIMER_ERROR;

    if (!initScheduleTimeInTicks)
        return TX_TICK_ERROR;

    if (!timer_ptr)
        return TX_TIMER_ERROR;

    // Initialize timer structure
    timer_ptr->pExpireFunc = expiration_function;
    timer_ptr->expireInput = expiration_input;
    timer_ptr->initScheduleTimeInMsecs =
        TX_MSECS_IN_1_TICK * initScheduleTimeInTicks;
    timer_ptr->rescheduleTimeInMsecs =
        TX_MSECS_IN_1_TICK * rescheduleTimeInTicks;
    timer_ptr->pMac = pMacGlobal;

    // Set the flag indicating that the timer was created
    timer_ptr->tmrSignature = TX_AIRGO_TMR_SIGNATURE;

#ifdef WLAN_DEBUG
    // Store the timer name
    strlcpy(timer_ptr->timerName, name_ptr, sizeof(timer_ptr->timerName));
#endif // Store the timer name, for Debug build only

    status = vos_timer_init( &timer_ptr->vosTimer, VOS_TIMER_TYPE_SW,
          tx_main_timer_func, (v_PVOID_t)timer_ptr );
    if (VOS_STATUS_SUCCESS != status)
    {
       VOS_TRACE(VOS_MODULE_ID_SYS, VOS_TRACE_LEVEL_ERROR,
             "Cannot create timer for %s\n", TIMER_NAME);
       return TX_TIMER_ERROR;
    }

    if(0 != rescheduleTimeInTicks)
    {
        VOS_TRACE(VOS_MODULE_ID_SYS, VOS_TRACE_LEVEL_INFO,
                  "Creating periodic timer for %s\n", TIMER_NAME);
    }

    // Activate this timer if required
    if (auto_activate)
    {
        tx_timer_activate(timer_ptr);
    }

    return TX_SUCCESS;

} //** tx_timer_create() ***/
#endif


/**---------------------------------------------------------------------
 * tx_timer_deactivate()
 *
 * FUNCTION:
 *
 * LOGIC:
 *
 * ASSUMPTIONS:
 *
 * NOTE:
 *
 * @param
 *
 * @return TX_SUCCESS.
 *
 */
v_UINT_t tx_timer_deactivate(TX_TIMER *timer_ptr)
{
   VOS_STATUS vStatus;

   // Put a check for the free builds
   if (TX_AIRGO_TMR_SIGNATURE != timer_ptr->tmrSignature)
   {
      return TX_TIMER_ERROR;
   }

   // if the timer is not running then we do not need to do anything here
   vStatus = vos_timer_stop( &timer_ptr->vosTimer );
   if (VOS_STATUS_SUCCESS != vStatus)
   {
      VOS_TRACE(VOS_MODULE_ID_SYS, VOS_TRACE_LEVEL_INFO_HIGH,
                "Unable to stop timer %s; status =%d\n",
                TIMER_NAME, vStatus);
   }

   return TX_SUCCESS;

} /*** tx_timer_deactivate() ***/

v_UINT_t tx_timer_delete( TX_TIMER *timer_ptr )
{
   // Put a check for the free builds
   if (TX_AIRGO_TMR_SIGNATURE != timer_ptr->tmrSignature)
   {
      return TX_TIMER_ERROR;
   }

   vos_timer_destroy( &timer_ptr->vosTimer );
   return TX_SUCCESS;
} /*** tx_timer_delete() ***/



/**---------------------------------------------------------------------
 * tx_timer_running()
 *
 * FUNCTION:
 *
 * LOGIC:
 *
 * ASSUMPTIONS:
 *
 * NOTE:
 *
 * @param
 *
 * @return TX_SUCCESS.
 *
 */
v_BOOL_t tx_timer_running(TX_TIMER *timer_ptr)
{
   // Put a check for the free builds
   if (TX_AIRGO_TMR_SIGNATURE != timer_ptr->tmrSignature)
      return VOS_FALSE;

   if (VOS_TIMER_STATE_RUNNING ==
       vos_timer_getCurrentState( &timer_ptr->vosTimer ))
   {
       return VOS_TRUE;
   }
   return VOS_FALSE;

} /*** tx_timer_running() ***/
