view src/g23m-gprs/upm/upm_link_control.c @ 51:04aaa5622fa7

disable deep sleep when Iota LEDB is on TI's Iota chip docs say that CLK13M must be running in order for LEDB to work, and practical experience on Mot C139 which uses Iota LEDB for its keypad backlight concurs: if Calypso enters deep sleep while the keypad backlight is turned on, the light flickers visibly as the chipset goes into and out of deep sleep. TI's original L1 sleep manager code had logic to disable deep sleep when LT_Status() returns nonzero, but that function only works for B-Sample and C-Sample LT, always returns 0 on BOARD 41 - no check of Iota LEDB status anywhere. Change this code for our current hardware: disable deep sleep when Iota LEDB has been turned on through LLS.
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 19 Oct 2020 05:11:29 +0000
parents fa8dc04885d8
children
line wrap: on
line source

/*----------------------------------------------------------------------------
|  Project :  3G PS
|  Module  :  UPM
+-----------------------------------------------------------------------------
|             Copyright 2003 Texas Instruments.
|             All rights reserved. 
| 
|             This file is confidential and a trade secret of Texas 
|             Instruments .
|             The receipt of or possession of this file does not convey 
|             any rights to reproduce or disclose its contents or to 
|             manufacture, use, or sell anything it may describe, in 
|             whole, or in part, without the specific written consent of 
|             Texas Instruments. 
+-----------------------------------------------------------------------------
| Purpose:    Link Control state machine implementation in the UPM entity.
|             For design details, see:
|             8010.939 UPM Detailed Specification
+---------------------------------------------------------------------------*/

/*==== DECLARATION CONTROL =================================================*/


/*==== INCLUDES =============================================================*/

#include "upm.h"

#ifdef TI_UMTS
#include "upm_rab_control.h"
#endif /* TI_UMTS */

#ifdef TI_GPRS
#include "upm_sndcp_control.h"
#endif /* TI_GPRS */

#include "upm_sm_output_handler.h"

/*==== CONSTS ===============================================================*/

/*==== TYPES ================================================================*/

typedef void (*T_UPM_LINK_CONTROL_TRANSITION_FUNC)(struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data);

typedef struct {
#ifdef DEBUG
  T_UPM_LINK_CONTROL_EVENT            event;
#endif /* DEBUG */
  T_UPM_LINK_CONTROL_TRANSITION_FUNC  func;
} T_UPM_LINK_CONTROL_TRANSITION;

/*==== LOCALS ===============================================================*/

static void state_event_error                           (struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data);
static void ignored                                     (struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data);
static void handle_sm_activate_started_ind              (struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data);
static void handle_dti_closed                           (struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data);
#ifdef TI_UMTS
static void go_to_S2                                    (struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data);
static void handle_sm_activate_ind_in_umts              (struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data);
static void handle_sm_modify_ind_in_umts                (struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data);
static void handle_deactivate_in_umts                   (struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data);
static void handle_rab_released_abnormal                (struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data);
static void handle_rab_released_normal                  (struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data);
#endif /* TI_UMTS */
#ifdef TI_GPRS
static void handle_sm_activate_ind_in_gsm               (struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data);
static void handle_llc_link_established                 (struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data);
static void handle_sm_modify_ind_in_gsm                 (struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data);
static void handle_modify_response_in_gsm               (struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data);
static void handle_deactivate_in_gsm                    (struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data);
static void handle_deactivate_without_link_in_gsm       (struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data);
static void handle_llc_release_normal                   (struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data);
static void handle_llc_release_abnormal                 (struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data);
static void handle_gsm_qos_store(struct T_CONTEXT_DATA *ptr_context_data,
                                 U8 sapi, U8 radio_prio, U8 pkt_flow_id,
                                 T_PS_ctrl_qos ctrl_qos, T_PS_qos *qos);
#endif /* TI_GPRS */
#ifdef TI_DUAL_MODE
static void go_to_S8                                    (struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data);
static void handle_rat_change_to_gsm_without_context    (struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data);
static void handle_rat_change_to_gsm                    (struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data);
static void handle_rab_established_in_S6                (struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data);
static void handle_rat_change_to_umts_without_context   (struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data);
static void handle_rat_change_to_umts_while_establishing(struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data);
static void handle_rat_change_to_umts                   (struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data);
#else
#define handle_rat_change_to_gsm_without_context        state_event_error
#define handle_rat_change_to_gsm                        state_event_error
#define handle_rat_change_to_umts_without_context       state_event_error
#define handle_rat_change_to_umts_while_establishing    state_event_error
#define handle_rat_change_to_umts                       state_event_error
#endif /* TI_DUAL_MODE */
static void upm_link_mark_nsapi_deactivated(U8 nsapi);

/***********************************************************************
 * State/Transition Table
 */
static const T_UPM_LINK_CONTROL_TRANSITION
transition[UPM_LINK_CONTROL_NUMBER_OF_STATES]
          [UPM_LINK_CONTROL_NUMBER_OF_EVENTS] =
{
  { /* S0: UPM_LINK_RELEASED */
    M_TRANSITION(UPM_P_SM_ACTIVATE_STARTED_IND,    handle_sm_activate_started_ind),
    M_TRANSITION(UPM_P_SM_ACTIVATE_IND,            state_event_error),
    M_TRANSITION(UPM_P_SM_DEACTIVATE_IND,          state_event_error),
    M_TRANSITION(UPM_P_SM_MODIFY_IND,              state_event_error),
    M_TRANSITION(UPM_I_LINK_DTI_CLOSED,            state_event_error),
    M_TRANSITION(UPM_I_RAB_ESTABLISHED,            state_event_error),
    M_TRANSITION(UPM_I_RAB_RELEASED,               state_event_error),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_ESTABLISHED, state_event_error),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_MODIFIED,    state_event_error),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_RELEASED,    state_event_error),
    M_TRANSITION(UPM_I_LINK_RAT_CHANGED,           state_event_error)
  },
#ifdef TI_UMTS
  { /* S1: UPM_LINK_ESTABLISHING_RAB */
    M_TRANSITION(UPM_P_SM_ACTIVATE_STARTED_IND,    state_event_error),
    M_TRANSITION(UPM_P_SM_ACTIVATE_IND,            state_event_error),
    M_TRANSITION(UPM_P_SM_DEACTIVATE_IND,          handle_deactivate_in_umts),
    M_TRANSITION(UPM_P_SM_MODIFY_IND,              state_event_error),
    M_TRANSITION(UPM_I_LINK_DTI_CLOSED,            handle_dti_closed),
    M_TRANSITION(UPM_I_RAB_ESTABLISHED,            go_to_S2),
    M_TRANSITION(UPM_I_RAB_RELEASED,               state_event_error),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_ESTABLISHED, state_event_error),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_MODIFIED,    state_event_error),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_RELEASED,    state_event_error),
    M_TRANSITION(UPM_I_LINK_RAT_CHANGED,           handle_rat_change_to_gsm_without_context)
  },
  { /* S2: UPM_LINK_AWAITING_ACTIVATE_UMTS */
    M_TRANSITION(UPM_P_SM_ACTIVATE_STARTED_IND,    state_event_error),
    M_TRANSITION(UPM_P_SM_ACTIVATE_IND,            handle_sm_activate_ind_in_umts),
    M_TRANSITION(UPM_P_SM_DEACTIVATE_IND,          handle_deactivate_in_umts),
    M_TRANSITION(UPM_P_SM_MODIFY_IND,              state_event_error),
    M_TRANSITION(UPM_I_LINK_DTI_CLOSED,            handle_dti_closed),
    M_TRANSITION(UPM_I_RAB_ESTABLISHED,            state_event_error),
    M_TRANSITION(UPM_I_RAB_RELEASED,               handle_rab_released_abnormal),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_ESTABLISHED, state_event_error),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_MODIFIED,    state_event_error),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_RELEASED,    state_event_error),
    M_TRANSITION(UPM_I_LINK_RAT_CHANGED,           state_event_error)
  },
  { /* S3: UPM_LINK_RAB_ESTABLISHED */
    M_TRANSITION(UPM_P_SM_ACTIVATE_STARTED_IND,    state_event_error),
    M_TRANSITION(UPM_P_SM_ACTIVATE_IND,            state_event_error),
    M_TRANSITION(UPM_P_SM_DEACTIVATE_IND,          handle_deactivate_in_umts),
    M_TRANSITION(UPM_P_SM_MODIFY_IND,              handle_sm_modify_ind_in_umts),
    M_TRANSITION(UPM_I_LINK_DTI_CLOSED,            handle_dti_closed),
    M_TRANSITION(UPM_I_RAB_ESTABLISHED,            ignored),
    M_TRANSITION(UPM_I_RAB_RELEASED,               handle_rab_released_abnormal),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_ESTABLISHED, state_event_error),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_MODIFIED,    state_event_error),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_RELEASED,    ignored),
    M_TRANSITION(UPM_I_LINK_RAT_CHANGED,           handle_rat_change_to_gsm)
  },
  { /* S4: UPM_LINK_RELEASING_RAB */
    M_TRANSITION(UPM_P_SM_ACTIVATE_STARTED_IND,    state_event_error),
    M_TRANSITION(UPM_P_SM_ACTIVATE_IND,            state_event_error),
    M_TRANSITION(UPM_P_SM_DEACTIVATE_IND,          state_event_error),
    M_TRANSITION(UPM_P_SM_MODIFY_IND,              state_event_error),
    M_TRANSITION(UPM_I_LINK_DTI_CLOSED,            state_event_error),
    M_TRANSITION(UPM_I_RAB_ESTABLISHED,            state_event_error),
    M_TRANSITION(UPM_I_RAB_RELEASED,               handle_rab_released_normal),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_ESTABLISHED, state_event_error),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_MODIFIED,    state_event_error),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_RELEASED,    state_event_error),
    M_TRANSITION(UPM_I_LINK_RAT_CHANGED,           ignored)
  },
#endif /* TI_UMTS */
#ifdef TI_DUAL_MODE
  { /* S5: UPM_LINK_COMPLETING_RAT_CHANGE_TO_GSM */
    M_TRANSITION(UPM_P_SM_ACTIVATE_STARTED_IND,    state_event_error),
    M_TRANSITION(UPM_P_SM_ACTIVATE_IND,            state_event_error),
    M_TRANSITION(UPM_P_SM_DEACTIVATE_IND,          handle_deactivate_in_gsm),
    M_TRANSITION(UPM_P_SM_MODIFY_IND,              state_event_error),
    M_TRANSITION(UPM_I_LINK_DTI_CLOSED,            handle_dti_closed),
    M_TRANSITION(UPM_I_RAB_ESTABLISHED,            state_event_error),
    M_TRANSITION(UPM_I_RAB_RELEASED,               ignored),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_ESTABLISHED, go_to_S8),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_MODIFIED,    state_event_error),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_RELEASED,    handle_llc_release_abnormal),
    M_TRANSITION(UPM_I_LINK_RAT_CHANGED,           state_event_error)
  },
  { /* S6: UPM_LINK_COMPLETING_RAT_CHANGE_TO_UMTS_INITIAL */
    M_TRANSITION(UPM_P_SM_ACTIVATE_STARTED_IND,    state_event_error),
    M_TRANSITION(UPM_P_SM_ACTIVATE_IND,            state_event_error),
    M_TRANSITION(UPM_P_SM_DEACTIVATE_IND,          handle_deactivate_in_umts),
    M_TRANSITION(UPM_P_SM_MODIFY_IND,              state_event_error),
    M_TRANSITION(UPM_I_LINK_DTI_CLOSED,            handle_dti_closed),
    M_TRANSITION(UPM_I_RAB_ESTABLISHED,            handle_rab_established_in_S6),
    M_TRANSITION(UPM_I_RAB_RELEASED,               state_event_error),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_ESTABLISHED, state_event_error),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_MODIFIED,    state_event_error),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_RELEASED,    ignored),
    M_TRANSITION(UPM_I_LINK_RAT_CHANGED,           handle_rat_change_to_gsm)
  },
#endif /* TI_DUAL_MODE */
#ifdef TI_GPRS
  { /* S7: UPM_LINK_AWAITING_ACTIVATE_GSM */
    M_TRANSITION(UPM_P_SM_ACTIVATE_STARTED_IND,    state_event_error),
    M_TRANSITION(UPM_P_SM_ACTIVATE_IND,            handle_sm_activate_ind_in_gsm),
    M_TRANSITION(UPM_P_SM_DEACTIVATE_IND,          handle_deactivate_without_link_in_gsm),
    M_TRANSITION(UPM_P_SM_MODIFY_IND,              state_event_error),
    M_TRANSITION(UPM_I_LINK_DTI_CLOSED,            handle_dti_closed),
    M_TRANSITION(UPM_I_RAB_ESTABLISHED,            state_event_error),
    M_TRANSITION(UPM_I_RAB_RELEASED,               state_event_error),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_ESTABLISHED, state_event_error),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_MODIFIED,    state_event_error),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_RELEASED,    state_event_error),
    M_TRANSITION(UPM_I_LINK_RAT_CHANGED,           handle_rat_change_to_umts_without_context)
  },
  { /* S8: UPM_LINK_ESTABLISHING_LLC_LINK */
    M_TRANSITION(UPM_P_SM_ACTIVATE_STARTED_IND,    state_event_error),
    M_TRANSITION(UPM_P_SM_ACTIVATE_IND,            state_event_error),
    M_TRANSITION(UPM_P_SM_DEACTIVATE_IND,          handle_deactivate_in_gsm),
    M_TRANSITION(UPM_P_SM_MODIFY_IND,              state_event_error),
    M_TRANSITION(UPM_I_LINK_DTI_CLOSED,            handle_dti_closed),
    M_TRANSITION(UPM_I_RAB_ESTABLISHED,            ignored),
    M_TRANSITION(UPM_I_RAB_RELEASED,               state_event_error),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_ESTABLISHED, handle_llc_link_established),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_MODIFIED,    state_event_error),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_RELEASED,    handle_llc_release_abnormal),
    M_TRANSITION(UPM_I_LINK_RAT_CHANGED,           handle_rat_change_to_umts_while_establishing)
  },
  { /* S9: UPM_LINK_LLC_LINK_ESTABLISHED */
    M_TRANSITION(UPM_P_SM_ACTIVATE_STARTED_IND,    state_event_error),
    M_TRANSITION(UPM_P_SM_ACTIVATE_IND,            state_event_error),
    M_TRANSITION(UPM_P_SM_DEACTIVATE_IND,          handle_deactivate_in_gsm),
    M_TRANSITION(UPM_P_SM_MODIFY_IND,              handle_sm_modify_ind_in_gsm),
    M_TRANSITION(UPM_I_LINK_DTI_CLOSED,            handle_dti_closed),
    M_TRANSITION(UPM_I_RAB_ESTABLISHED,            state_event_error),
    M_TRANSITION(UPM_I_RAB_RELEASED,               state_event_error),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_ESTABLISHED, state_event_error),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_MODIFIED,    handle_modify_response_in_gsm),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_RELEASED,    handle_llc_release_abnormal),
    M_TRANSITION(UPM_I_LINK_RAT_CHANGED,           handle_rat_change_to_umts)
  },
  { /* S10: UPM_LINK_RELEASING_LLC_LINK */
    M_TRANSITION(UPM_P_SM_ACTIVATE_STARTED_IND,    state_event_error),
    M_TRANSITION(UPM_P_SM_ACTIVATE_IND,            state_event_error),
    M_TRANSITION(UPM_P_SM_DEACTIVATE_IND,          state_event_error),
    M_TRANSITION(UPM_P_SM_MODIFY_IND,              state_event_error),
    M_TRANSITION(UPM_I_LINK_DTI_CLOSED,            state_event_error),
    M_TRANSITION(UPM_I_RAB_ESTABLISHED,            state_event_error),
    M_TRANSITION(UPM_I_RAB_RELEASED,               state_event_error),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_ESTABLISHED, state_event_error),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_MODIFIED,    state_event_error),
    M_TRANSITION(UPM_I_SNDCP_LLC_LINK_RELEASED,    handle_llc_release_normal),
    M_TRANSITION(UPM_I_LINK_RAT_CHANGED,           ignored)
  }
#endif /* TI_GPRS */
};

/*==== PRIVATE FUNCTIONS ====================================================*/

/*
+------------------------------------------------------------------------------
| Function    : link_control_goto_state
+------------------------------------------------------------------------------
| Description : Move to the state specified in the new_state parameter
|
| Parameters  : ptr_context_data - Context data
|               new_state        - New state
+------------------------------------------------------------------------------
*/
static void link_control_goto_state(struct T_CONTEXT_DATA *ptr_context_data,
                                    T_UPM_LINK_CONTROL_STATE new_state)
{
  ptr_context_data->link_control_state = new_state;
}

/*
+------------------------------------------------------------------------------
| Function    : link_control_state
+------------------------------------------------------------------------------
| Description : Return the state in which Link Control is in for this
|               context instanse.
|
| Parameters  : ptr_context_data - Context data
+------------------------------------------------------------------------------
*/
static T_UPM_LINK_CONTROL_STATE
link_control_state(struct T_CONTEXT_DATA *ptr_context_data)
{
  return ptr_context_data->link_control_state;
}

/*
+------------------------------------------------------------------------------
| Function    : state_event_error
+------------------------------------------------------------------------------
| Description : General function used to report state event errors.
|
| Parameters  : ptr_context_data - Not used
|               data             - Not used
+------------------------------------------------------------------------------
*/
static void state_event_error(/*@unused@*/ struct T_CONTEXT_DATA *ptr_context_data, /*@unused@*/ /*@null@*/ void *data)
{
  (void)TRACE_ERROR("UPM Link Control: STATE EVENT ERROR!");
}

/*
+------------------------------------------------------------------------------
| Function    : ignored
+------------------------------------------------------------------------------
| Description : General function used for transitions that shall be ignored
|
| Parameters  : ptr_context_data - Not used
|               data             - Not used
+------------------------------------------------------------------------------
*/
static void ignored(/*@unused@*/ struct T_CONTEXT_DATA *ptr_context_data, /*@unused@*/ /*@null@*/ void *data)
{
  (void)TRACE_FUNCTION("UPM Link Control: Event ignored.");
}

/*
+------------------------------------------------------------------------------
| Function    : go_to_S*
+------------------------------------------------------------------------------
| Description : General functions for simple state transitions
|
| Parameters  : ptr_context_data - Not used
|               data             - Not used
+------------------------------------------------------------------------------
*/
#ifdef TI_UMTS
static void go_to_S2(/*@unused@*/ struct T_CONTEXT_DATA *ptr_context_data, /*@unused@*/ /*@null@*/ void *data)
{
  /* (void)TRACE_FUNCTION("UPM Link Control: Transition to UPM LINK AWAITING ACTIVATE UMTS state"); */
  link_control_goto_state(ptr_context_data, UPM_LINK_AWAITING_ACTIVATE_UMTS);
}
#endif /* TI_UMTS */

#ifdef TI_DUAL_MODE
static void go_to_S8(/*@unused@*/ struct T_CONTEXT_DATA *ptr_context_data, /*@unused@*/ /*@null@*/ void *data)
{
  /* (void)TRACE_FUNCTION("UPM Link Control: Transition to UPM LINK LLC LINK ESTABLISHED state"); */
  link_control_goto_state(ptr_context_data, UPM_LINK_LLC_LINK_ESTABLISHED);
}
#endif /* TI_DUAL_MODE */

/*
+------------------------------------------------------------------------------
| Function    : handle_sm_activate_started_ind
+------------------------------------------------------------------------------
| Description : Handle SM_ACTIVATE_STARTED_IND primitive.  Examines RAT,
|               and moves to GSM or UTMS state. Starts RAB in UMTS.
|
| Parameters  : ptr_context_data - Context data
|               data             - SM_ACTIVATE_STARTED_IND primitive (unused)
+------------------------------------------------------------------------------
*/
static void handle_sm_activate_started_ind(struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ /*@unused@*/ void *data)
{
  (void)TRACE_FUNCTION("UPM Link Control: handle_sm_activate_started_ind");

#ifdef TI_DUAL_MODE
  /* Examine RAT: */
  if (upm_get_current_rat() == PS_RAT_GSM)
#endif /* TI_DUAL_MODE */
#ifdef TI_GPRS
  {
    /* GSM: Do nothing until SM_ACTIVATE_IND arrives.  Just change state. */
    link_control_goto_state(ptr_context_data, UPM_LINK_AWAITING_ACTIVATE_GSM);
  }
#endif /* TI_GPRS */
#ifdef TI_DUAL_MODE
  else if (upm_get_current_rat() == PS_RAT_UMTS_FDD)
#endif /* TI_DUAL_MODE */
#ifdef TI_UMTS
  {
    /* UMTS: Order RAB Control to await RAB establishment, and change state. */
    link_control_goto_state(ptr_context_data, UPM_LINK_ESTABLISHING_RAB);
    upm_rab_control(ptr_context_data, UPM_I_RAB_AWAIT_INITIAL_ESTABLISH, NULL);
  }
#endif /* TI_UMTS */
}

/*
+------------------------------------------------------------------------------
| Function    : handle_dti_closed
+------------------------------------------------------------------------------
| Description : Handle UPM_I_LINK_DTI_CLOSED
|
| Parameters  : ptr_context_data - Context data
|               data             - Not used
+------------------------------------------------------------------------------
*/
static void handle_dti_closed(struct T_CONTEXT_DATA *ptr_context_data, /*@unused@*/ /*@null@*/ void *data)
{
  T_PS_sapi  llc_sapi;

  (void)TRACE_FUNCTION("UPM Link Control: handle_dti_closed");

#ifdef TI_GPRS
  llc_sapi = (T_PS_sapi)ptr_context_data->gprs_data.sndcp_llc_sapi;
#else
  llc_sapi = PS_SAPI_0; /* SAPI not assigned [3G 24.008, 6.1.3.1.1] */
#endif /* TI_GPRS */

  /* Send SM_STATUS_REQ, and expect control plane to take action. */
  send_sm_status_req(upm_nsapi2nsapi_set(ptr_context_data->nsapi),
                     llc_sapi,
                     CAUSE_is_from_upm, (U16)CAUSE_UPM_DTI_DISCONNECT);
}

/*
+------------------------------------------------------------------------------
| Function    : handle_sm_activate_ind_in_utms
+------------------------------------------------------------------------------
| Description : Handle SM_ACTIVATE_IND primitive while in UMTS RAT.
|
| Parameters  : ptr_context_data - Context data
|               data             - SM_ACTIVATE_IND primitive
+------------------------------------------------------------------------------
*/
#ifdef TI_UMTS
static void handle_sm_activate_ind_in_umts(struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data)
{
  T_SM_ACTIVATE_IND *prim = (T_SM_ACTIVATE_IND *)data;

  (void)TRACE_FUNCTION("UPM Link Control: handle_sm_activate_ind_in_umts");

  TRACE_ASSERT( data != NULL );

#ifdef TI_DUAL_MODE
  /* Store GSM-RAT relevant QoS parameters in ptr_context_data fields. */
  handle_gsm_qos_store(ptr_context_data, prim->sapi, prim->radio_prio,
                       (U8)prim->pkt_flow_id, prim->ctrl_qos, &prim->qos);
#endif /* TI_DUAL_MODE */

  /* Send SM_ACTIVATE_RES */
  send_sm_activate_res(ptr_context_data, ((T_SN_ACTIVATE_CNF*)data));

  /* Go to state UPM LINK RAB ESTABLISHED */
  link_control_goto_state(ptr_context_data, UPM_LINK_RAB_ESTABLISHED);

  /* Store QoS parameter as needed in RAB Control */
  upm_rab_control(ptr_context_data, UPM_I_RAB_MODIFY, &(prim->qos.qos_r99));

  /* Inform Uplink and Downlink state machines of link up. */
  upm_uplink_data_control(ptr_context_data, UPM_I_UPLINK_DATA_LINK_UP, NULL);
  upm_downlink_data_control(ptr_context_data, UPM_I_DOWNLINK_DATA_LINK_UP, NULL);
}
#endif /* TI_UMTS */

/*
+------------------------------------------------------------------------------
| Function    : handle_sm_modify_ind_in_utms
+------------------------------------------------------------------------------
| Description : Handle SM_MODIFY_IND primitive while in UMTS RAT.
|
| Parameters  : ptr_context_data - Context data
|               data             - SM_MODIFY_IND primitive
+------------------------------------------------------------------------------
*/
#ifdef TI_UMTS
static void handle_sm_modify_ind_in_umts(struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data)
{
  T_SM_MODIFY_IND *prim = (T_SM_MODIFY_IND *)data;

  (void)TRACE_FUNCTION("UPM Link Control: handle_sm_modify_ind_in_umts");

  TRACE_ASSERT( data != NULL );

#ifdef TI_DUAL_MODE
  /* Store GSM-RAT relevant QoS parameters in ptr_context_data fields. */
  handle_gsm_qos_store(ptr_context_data, prim->sapi, prim->radio_prio,
                       (U8)prim->pkt_flow_id, prim->ctrl_qos, &prim->qos);
#endif

  /* Store QoS parameter as needed in RAB Control */
  upm_rab_control(ptr_context_data, UPM_I_RAB_MODIFY,
                  &(prim->qos.qos_r99));

  /* Send SM_MODIFY_RES */
  send_sm_modify_res(ptr_context_data);
}
#endif /* TI_UMTS */

/*
+------------------------------------------------------------------------------
| Function    : handle_deactivate_in_umts
+------------------------------------------------------------------------------
| Description : Handle SM_DEACTIVATE_IND primitive while in UMTS RAT.
|
| Parameters  : ptr_context_data - Context data
|               data             - Local release flag (Not used in UMTS)
+------------------------------------------------------------------------------
*/
#ifdef TI_UMTS
static void handle_deactivate_in_umts(struct T_CONTEXT_DATA *ptr_context_data, /*@unused@*/ /*@null@*/ void *data)
{
  (void)TRACE_FUNCTION("UPM Link Control: handle_deactivate_in_umts");

  /* Go to state UPM LINK RELEASING RAB */
  link_control_goto_state(ptr_context_data, UPM_LINK_RELEASING_RAB);

  /* Terminate Uplink and Downlink state machines. */
  upm_uplink_data_control(ptr_context_data, UPM_I_UPLINK_DATA_LINK_DOWN, NULL);
  upm_downlink_data_control(ptr_context_data, UPM_I_DOWNLINK_DATA_LINK_DOWN, NULL);

  /* Order RAB Control to await RAB release. */
  upm_rab_control(ptr_context_data, UPM_I_RAB_AWAIT_RAB_RELEASE, NULL);
}
#endif /* TI_UMTS */

/*
+------------------------------------------------------------------------------
| Function    : handle_rab_released_abnormal
+------------------------------------------------------------------------------
| Description : Handle UPM_I_RAB_RELEASED when not expected
|
| Parameters  : ptr_context_data - Context data
|               data             - Not used
+------------------------------------------------------------------------------
*/
#ifdef TI_UMTS
static void handle_rab_released_abnormal(struct T_CONTEXT_DATA *ptr_context_data, /*@unused@*/ /*@null@*/ void *data)
{
  (void)TRACE_FUNCTION("UPM Link Control: handle_rab_released_abnormal");

  /* Go to state UPM LINK RELEASED */
  link_control_goto_state(ptr_context_data, UPM_LINK_RELEASED);

  /* Terminate Uplink and Downlink state machines. */
  upm_uplink_data_control(ptr_context_data, UPM_I_UPLINK_DATA_LINK_DOWN, NULL);
  upm_downlink_data_control(ptr_context_data, UPM_I_DOWNLINK_DATA_LINK_DOWN, NULL);
}
#endif /* TI_UMTS */

/*
+------------------------------------------------------------------------------
| Function    : handle_rab_released_normal
+------------------------------------------------------------------------------
| Description : Handle UPM_I_RAB_RELEASED during normal deactivation
|
| Parameters  : ptr_context_data - Context data
|               data             - Not used
+------------------------------------------------------------------------------
*/
#ifdef TI_UMTS
static void handle_rab_released_normal(struct T_CONTEXT_DATA *ptr_context_data, /*@unused@*/ /*@null@*/ void *data)
{
  (void)TRACE_FUNCTION("UPM Link Control: handle_rab_released_normal");

  /* SM_DEACTIVATE_RES sent from dispatcher; groups responses for all NSAPIs */
  /* send_sm_deactivate_res( ... ); */
  upm_link_mark_nsapi_deactivated(ptr_context_data->nsapi);

  /* Go to state UPM LINK RELEASED */
  link_control_goto_state(ptr_context_data, UPM_LINK_RELEASED);
}
#endif /* TI_UMTS */

/*
+------------------------------------------------------------------------------
| Function    : handle_sm_activate_ind_in_gsm
+------------------------------------------------------------------------------
| Description : Handle SM_ACTIVATE_IND in S7
|
| Parameters  : ptr_context_data - Context data
|               data             - Not used
+------------------------------------------------------------------------------
*/
#ifdef TI_GPRS
static void handle_sm_activate_ind_in_gsm(struct T_CONTEXT_DATA *ptr_context_data, /*@unused@*/ /*@null@*/ void *data)
{
  T_SM_ACTIVATE_IND *prim = (T_SM_ACTIVATE_IND *)data;

  (void)TRACE_FUNCTION("UPM Link Control: handle_sm_activate_ind_in_gsm");

  TRACE_ASSERT(prim != NULL);

  /*lint -e613 (Possible use of null pointer 'prim' in left argument to operator '->') */
  /* Store GSM-RAT relevant QoS parameters in ptr_context_data fields. */
  handle_gsm_qos_store(ptr_context_data, prim->sapi, prim->radio_prio,
                       (U8)prim->pkt_flow_id, prim->ctrl_qos, &prim->qos);

  /* Go to state UPM LINK ESTABLISHING LLC LINK */
  link_control_goto_state(ptr_context_data, UPM_LINK_ESTABLISHING_LLC_LINK);

  /* Order SNDCP Control to establish LLC link */

  /* Pass compression parameter fields only if they are present */
  if( (((T_SM_ACTIVATE_IND *)data)->v_comp_params == TRUE) )
  {
    upm_sndcp_control(ptr_context_data, UPM_I_SNDCP_ESTABLISH_LLC_LINK, 
      &((T_SM_ACTIVATE_IND *)data)->comp_params);
  } else {
    upm_sndcp_control(ptr_context_data, UPM_I_SNDCP_ESTABLISH_LLC_LINK, NULL);
  }
}
#endif /* TI_GPRS */

/*
+------------------------------------------------------------------------------
| Function    : handle_llc_link_established
+------------------------------------------------------------------------------
| Description : Handle UPM_I_LLC_LINK_ESTABLISHED in S8
|
| Parameters  : ptr_context_data - Context data
|               data             - Not used
+------------------------------------------------------------------------------
*/
#ifdef TI_GPRS
static void handle_llc_link_established(struct T_CONTEXT_DATA *ptr_context_data, /*@unused@*/ /*@null@*/ void *data)
{
  (void)TRACE_FUNCTION("UPM Link Control: handle_llc_link_established");

  send_sm_activate_res(ptr_context_data, ((T_SN_ACTIVATE_CNF*)data));

  /* Go to state UPM LINK LLC LINK ESTABLISHED */
  link_control_goto_state(ptr_context_data, UPM_LINK_LLC_LINK_ESTABLISHED);

#ifndef UPM_WITHOUT_USER_PLANE
  /* Report initial LINK UP to Uplink Data */
  upm_uplink_data_control(ptr_context_data, UPM_I_UPLINK_DATA_LINK_UP, NULL);

  /* Report link up to Downlink Data Control.  This triggers flow control
   * initialization towards SNDCP. */
  upm_downlink_data_control(ptr_context_data, UPM_I_DOWNLINK_DATA_LINK_UP, NULL);
#endif /* UPM_WITHOUT_USER_PLANE */
}
#endif /* TI_GPRS */

/*
+------------------------------------------------------------------------------
| Function    : handle_sm_modify_ind_in_gsm
+------------------------------------------------------------------------------
| Description : Handle SM_MODIFY_IND primitive while in GSM RAT.
|
| Parameters  : ptr_context_data - Context data
|               data             - SM_MODIFY_IND primitive
+------------------------------------------------------------------------------
*/
#ifdef TI_GPRS
static void handle_sm_modify_ind_in_gsm(struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data)
{
  T_SM_MODIFY_IND *prim = (T_SM_MODIFY_IND *)data;

  (void)TRACE_FUNCTION("UPM Link Control: handle_sm_modify_ind_in_gsm");

  TRACE_ASSERT( data != NULL );
  
  /*lint -e613 (Possible use of null pointer 'unknown-name' in left argument to operator '->') */
  /* Store GSM-RAT relevant QoS parameters in ptr_context_data fields. */
  handle_gsm_qos_store(ptr_context_data, prim->sapi, prim->radio_prio,
                       (U8)prim->pkt_flow_id, prim->ctrl_qos, &prim->qos);

  /* SNDCP Control constructs a modify primitive to SNDCP */
  upm_sndcp_control(ptr_context_data, UPM_I_SNDCP_MODIFY_LLC_LINK,
                    &((T_SM_MODIFY_IND *)data)->qos.qos_r99);
  /*lint +e613 (Possible use of null pointer 'unknown-name' in left argument to operator '->') */
  
}
#endif /* TI_GPRS */

/*
+------------------------------------------------------------------------------
| Function    : handle_modify_response_in_gsm
+------------------------------------------------------------------------------
| Description : Handle UPM_I_SNDCP_LLC_LINK_MODIFIED
|
| Parameters  : ptr_context_data - Context data
|               data             - Not used
+------------------------------------------------------------------------------
*/
#ifdef TI_GPRS
static void handle_modify_response_in_gsm(struct T_CONTEXT_DATA *ptr_context_data, /*@unused@*/ /*@null@*/ void *data)
{
  (void)TRACE_FUNCTION("UPM Link Control: handle_modify_response_in_gsm");

  /* Send SM_MODIFY_RES */
  send_sm_modify_res(ptr_context_data);
}
#endif /* TI_GPRS */

/*
+------------------------------------------------------------------------------
| Function    : handle_deactivate_in_gsm
+------------------------------------------------------------------------------
| Description : Handle SM_DEACTIVATE_IND while active in GSM RAT
|
| Parameters  : ptr_context_data - Context data
|               data             - Local flag (rel_ind)
+------------------------------------------------------------------------------
*/
#ifdef TI_GPRS
static void handle_deactivate_in_gsm(struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data)
{
  (void)TRACE_FUNCTION("UPM Link Control: handle_deactivate_in_gsm");

  /* Go to state UPM LINK RELEASING LLC LINK */
  link_control_goto_state(ptr_context_data, UPM_LINK_RELEASING_LLC_LINK);

#ifndef UPM_WITHOUT_USER_PLANE
  /* Terminate Uplink and Downlink state machines. */
  upm_uplink_data_control(ptr_context_data, UPM_I_UPLINK_DATA_LINK_DOWN, NULL);
  upm_downlink_data_control(ptr_context_data, UPM_I_DOWNLINK_DATA_LINK_DOWN, NULL);
#endif /* UPM_WITHOUT_USER_PLANE */

  /* SNDCP Control constructs a deactivate primitive for SNDCP */
  upm_sndcp_control(ptr_context_data, UPM_I_SNDCP_RELEASE_LLC_LINK, data);
}
#endif /* TI_GPRS */

/*
+------------------------------------------------------------------------------
| Function    : handle_deactivate_without_link_in_gsm
+------------------------------------------------------------------------------
| Description : Handle SM_DEACTIVATE_IND in GSM, when no link exists (S5)
|
| Parameters  : ptr_context_data - Context data
|               data             - Not used
+------------------------------------------------------------------------------
*/
#ifdef TI_GPRS
static void handle_deactivate_without_link_in_gsm(struct T_CONTEXT_DATA *ptr_context_data, /*@unused@*/ /*@null@*/ void *data)
{
  (void)TRACE_FUNCTION("UPM Link Control: handle_deactivate_without_link_in_gsm");

  /* SM_DEACTIVATE_RES sent in dispatcher. One primitive for all NSAPIs. */
  /* send_sm_deactivate_res( ... ); */
  upm_link_mark_nsapi_deactivated(ptr_context_data->nsapi);

  /* Go to state UPM LINK RELEASED */
  link_control_goto_state(ptr_context_data, UPM_LINK_RELEASED);
}
#endif /* TI_GPRS */

/*
+------------------------------------------------------------------------------
| Function    : handle_llc_release_normal
+------------------------------------------------------------------------------
| Description : Handle UPM_I_SNDCP_LLC_LINK_RELEASED in S10
|
| Parameters  : ptr_context_data - Context data
|               data             - Not used
+------------------------------------------------------------------------------
*/
#ifdef TI_GPRS
static void handle_llc_release_normal(struct T_CONTEXT_DATA *ptr_context_data, /*@unused@*/ /*@null@*/ void *data)
{
  (void)TRACE_FUNCTION("UPM Link Control: handle_llc_release_normal");

  /* SM_DEACTIVATE_RES sent in dispatcher. One primitive for all NSAPIs. */
  /* send_sm_deactivate_res( ... ); */
  upm_link_mark_nsapi_deactivated(ptr_context_data->nsapi);

  /* Go to state UPM LINK RELEASED */
  link_control_goto_state(ptr_context_data, UPM_LINK_RELEASED);
}
#endif /* TI_GPRS */

/*
+------------------------------------------------------------------------------
| Function    : handle_llc_release_abnormal
+------------------------------------------------------------------------------
| Description : Handle UPM_I_SNDCP_LLC_LINK_RELEASED in state other than S10
|
| Parameters  : ptr_context_data - Context data
|               data             - SN_STATUS_IND primitive (unused)
+------------------------------------------------------------------------------
*/
#ifdef TI_GPRS
static void handle_llc_release_abnormal(struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ /*@unused@*/ void *data)
{
  (void)TRACE_FUNCTION("UPM Link Control: handle_llc_release_abnormal");

  /* SM_STATUS_REQ sent once for all affected NSAPIs in sndcp_control. */
  /* send_sm_status_req(...) */

  /* Go to state UPM LINK RELEASED */
  link_control_goto_state(ptr_context_data, UPM_LINK_RELEASED);

#ifndef UPM_WITHOUT_USER_PLANE
  /* Terminate Uplink and Downlink state machines. */
  upm_uplink_data_control(ptr_context_data, UPM_I_UPLINK_DATA_LINK_DOWN, NULL);
  upm_downlink_data_control(ptr_context_data, UPM_I_DOWNLINK_DATA_LINK_DOWN, NULL);
#endif /* UPM_WITHOUT_USER_PLANE */
}
#endif /* TI_GPRS */

/*
+------------------------------------------------------------------------------
| Function    : handle_rat_change_to_gsm_without_context
+------------------------------------------------------------------------------
| Description : Handle UPM_I_LINK_RAT_CHANGED(GSM) in S1 or S2
|
| Parameters  : ptr_context_data - Context Data
|               data             - GSM/UMTS
+------------------------------------------------------------------------------
*/
#ifdef TI_DUAL_MODE
static void handle_rat_change_to_gsm_without_context(struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data)
{
  (void)TRACE_FUNCTION("UPM Link Control: handle_rat_change_to_gsm_without_context");
  TRACE_ASSERT( (T_PS_rat)data == PS_RAT_GSM );

  /* Go to state UPM LINK AWAITING ACTIVATE GSM */
  link_control_goto_state(ptr_context_data, UPM_LINK_AWAITING_ACTIVATE_GSM);

  /* Order RAB Control to await RAB release,
   * or to stop awaiting RAB establish */
  upm_rab_control(ptr_context_data, UPM_I_RAB_AWAIT_RAB_RELEASE, NULL);
}
#endif /* TI_DUAL_MODE */

/*
+------------------------------------------------------------------------------
| Function    : handle_rat_change_to_gsm
+------------------------------------------------------------------------------
| Description : Handle UPM_I_LINK_RAT_CHANGED(GSM) in S3
|
| Parameters  : ptr_context_data - Context data
|               data             - GSM/UMTS
+------------------------------------------------------------------------------
*/
#ifdef TI_DUAL_MODE
static void handle_rat_change_to_gsm(struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data)
{
  (void)TRACE_FUNCTION("UPM Link Control: handle_rat_change_to_gsm");

  TRACE_ASSERT( (T_PS_rat)data == PS_RAT_GSM );

  /* Go to state UPM LINK COMPLETING RAT CHANGE TO GSM */
  link_control_goto_state(ptr_context_data, UPM_LINK_COMPLETING_RAT_CHANGE_TO_GSM);

  /* Order RAB Control to await RAB release */
  upm_rab_control(ptr_context_data, UPM_I_RAB_AWAIT_RAB_RELEASE, NULL);

  /* Order SNDCP Control to await LLC link establishment */
  upm_sndcp_control(ptr_context_data, UPM_I_SNDCP_AWAIT_ESTABLISH, NULL);
}
#endif /* TI_DUAL_MODE */

/*
+------------------------------------------------------------------------------
| Function    : handle_rab_established_in_S6
+------------------------------------------------------------------------------
| Description : Handle UPM_I_RAB_ESTABLISHED in S7
|
| Parameters  : ptr_context_data - Context data
|               data             - Not used
+------------------------------------------------------------------------------
*/
#ifdef TI_DUAL_MODE
static void handle_rab_established_in_S6(struct T_CONTEXT_DATA *ptr_context_data, /*@unused@*/ /*@null@*/ void *data)
{
  (void)TRACE_FUNCTION("UPM Link Control: handle_rab_established_in_S6");

  /* Go to state UPM LINK RAB ESTABLISHED */
  link_control_goto_state(ptr_context_data, UPM_LINK_RAB_ESTABLISHED);

  /* Send SM_ACTIVATE_RES */
  send_sm_activate_res(ptr_context_data, ((T_SN_ACTIVATE_CNF*)data));

  /* Inform Uplink and Downlink state machines. */
  upm_uplink_data_control(ptr_context_data, UPM_I_UPLINK_DATA_LINK_UP, NULL);
  upm_downlink_data_control(ptr_context_data, UPM_I_DOWNLINK_DATA_LINK_UP, NULL);
}
#endif /* TI_DUAL_MODE */

/*
+------------------------------------------------------------------------------
| Function    : handle_rat_change_to_umts_without_context
+------------------------------------------------------------------------------
| Description : Handle UPM_I_LINK_RAT_CHANGED(UMTS) in S7
|
| Parameters  : ptr_context_data - Context data
|               data             - GSM/UMTS
+------------------------------------------------------------------------------
*/
#ifdef TI_DUAL_MODE
static void handle_rat_change_to_umts_without_context(struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data)
{
  (void)TRACE_FUNCTION("UPM Link Control: handle_rat_change_to_umts_without_context");

  TRACE_ASSERT( (T_PS_rat)data == PS_RAT_UMTS_FDD );

  /* Go to state UPM LINK ESTABLISHING RAB */
  link_control_goto_state(ptr_context_data, UPM_LINK_ESTABLISHING_RAB);

  /* Order RAB Control to await RAB establishment */
  upm_rab_control(ptr_context_data, UPM_I_RAB_AWAIT_INITIAL_ESTABLISH, NULL);
}
#endif /* TI_DUAL_MODE */

/*
+------------------------------------------------------------------------------
| Function    : handle_rat_change_to_umts_without_context
+------------------------------------------------------------------------------
| Description : Handle UPM_I_LINK_RAT_CHANGED(UMTS) in S8
|
| Parameters  : ptr_context_data - Context data
|               data             - GSM/UMTS
+------------------------------------------------------------------------------
*/
#ifdef TI_DUAL_MODE
static void handle_rat_change_to_umts_while_establishing(struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data)
{
  (void)TRACE_FUNCTION("UPM Link Control: handle_rat_change_to_umts_while_establishing");

  TRACE_ASSERT( (T_PS_rat)data == PS_RAT_UMTS_FDD );

  /* Go to state UPM LINK COMPLETING RAT CHANGE TO UMTS INITIAL */
  link_control_goto_state(ptr_context_data, UPM_LINK_COMPLETING_RAT_CHANGE_TO_UMTS_INITIAL);

  /* Order RAB Control to await RAB establishment */
  upm_rab_control(ptr_context_data, UPM_I_RAB_AWAIT_INITIAL_ESTABLISH, NULL);
}
#endif /* TI_DUAL_MODE */

/*
+------------------------------------------------------------------------------
| Function    : handle_rat_change_to_umts
+------------------------------------------------------------------------------
| Description : Handle UPM_I_LINK_RAT_CHANGED(UMTS) in S9
|
| Parameters  : ptr_context_data - Context data
|               data             - GSM/UMTS
+------------------------------------------------------------------------------
*/
#ifdef TI_DUAL_MODE
static void handle_rat_change_to_umts(struct T_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data)
{
  (void)TRACE_FUNCTION("UPM Link Control: handle_rat_change_to_umts");

  TRACE_ASSERT( (T_PS_rat)data == PS_RAT_UMTS_FDD );

  /* Go to state UPM LINK RAB ESTABLISHED*/
  link_control_goto_state(ptr_context_data, UPM_LINK_RAB_ESTABLISHED);

  /* Order RAB Control to await RAB establishment */
  upm_rab_control(ptr_context_data, UPM_I_RAB_AWAIT_RAB_ESTABLISH, NULL);
}
#endif /* TI_DUAL_MODE */

/*
+------------------------------------------------------------------------------
| Function    : handle_gsm_qos_store
+------------------------------------------------------------------------------
| Description : Store GSM-RAT relevant QoS parameters for the NSAPI
|
| Parameters  : ptr_context_data - Context data
|               qos              - R99 format QoS data
+------------------------------------------------------------------------------
*/
#ifdef TI_GPRS
static void handle_gsm_qos_store(struct T_CONTEXT_DATA *ptr_context_data,
                                 U8 sapi, U8 radio_prio, U8 pkt_flow_id,
                                 T_PS_ctrl_qos ctrl_qos, T_PS_qos *qos)
{
  struct T_UPM_CONTEXT_DATA_GPRS *gprs_data = &ptr_context_data->gprs_data;

  (void)TRACE_FUNCTION("UPM Link Control: handle_gsm_qos_store");

  gprs_data->sndcp_llc_sapi   = sapi;
  gprs_data->sndcp_radio_prio = radio_prio;

  /* [3G 24.008] version 6 says to keep PFI if omitted. */
  if (pkt_flow_id != (U8)PS_PKT_FLOW_ID_NOT_PRES) {
    gprs_data->pkt_flow_id      = pkt_flow_id;
  }

  if (ctrl_qos == PS_is_R97)
  {
    gprs_data->sndcp_delay        = qos->qos_r97.delay;
    gprs_data->sndcp_relclass     = qos->qos_r97.relclass;
    gprs_data->sndcp_peak_bitrate = qos->qos_r97.peak;
    gprs_data->sndcp_preced       = qos->qos_r97.preced;
    gprs_data->sndcp_mean         = qos->qos_r97.mean;
  } else if (ctrl_qos == PS_is_R99) {
    T_PS_qos_r97 temp_qos_r97;

    cl_qos_convert_r99_to_r97(&qos->qos_r99, &temp_qos_r97);

    gprs_data->sndcp_delay        = temp_qos_r97.delay;
    gprs_data->sndcp_relclass     = temp_qos_r97.relclass;
    gprs_data->sndcp_peak_bitrate = temp_qos_r97.peak;
    gprs_data->sndcp_preced       = temp_qos_r97.preced;
    gprs_data->sndcp_mean         = temp_qos_r97.mean;
  } else {
    (void)TRACE_ERROR("Link Control (handle_gsm_qos_store): Invalid QoS union controller!");
  }
}
#endif /* TI_GPRS */
/*
+------------------------------------------------------------------------------
| Function    : upm_link_mark_nsapi_deactivated
+------------------------------------------------------------------------------
| Description : Helper function to group nsapis in SM_DEACTIVATE_RES
|
| Parameters  : nsapi            - NSAPI        
+------------------------------------------------------------------------------
*/
static U16 nsapis_to_deactivate = 0, nsapis_currently_deactivated = 0;

static void upm_link_mark_nsapi_deactivated(U8 nsapi)
{
  (void)TRACE_FUNCTION("UPM Link Control: upm_link_mark_nsapi_deactivated");

  nsapis_currently_deactivated |= upm_nsapi2nsapi_set(nsapi);

  if (nsapis_currently_deactivated == nsapis_to_deactivate)
  {
    send_sm_deactivate_res(nsapis_to_deactivate);
    /* All context requested deactivated have been deactivated */
    /* Zero out store */
    nsapis_to_deactivate = 0;
    nsapis_currently_deactivated = 0;
  }
}

/*==== PUBLIC FUNCTIONS =====================================================*/

/*
+------------------------------------------------------------------------------
| Function    : upm_is_link_released
+------------------------------------------------------------------------------
| Description : Link Control state query function. Return TRUE if Link Control
|               is in state UPM LINK RELEASED; returns FALSE otherwise.
|
| Parameters  : ptr_context_data - Pointer to context data
+------------------------------------------------------------------------------
*/
BOOL upm_is_link_released(struct T_CONTEXT_DATA *ptr_context_data)
{
  TRACE_ASSERT(ptr_context_data != NULL);

  if (link_control_state(ptr_context_data) == UPM_LINK_RELEASED)
  {
    (void)TRACE_FUNCTION("UPM Link Control: upm_is_link_released (TRUE)");
    return TRUE;
  } else {
    (void)TRACE_FUNCTION("UPM Link Control: upm_is_link_released (FALSE)");
    return FALSE;
  }
}

/*
+------------------------------------------------------------------------------
| Function    : upm_link_dispatch_sm_deactivate_ind
+------------------------------------------------------------------------------
| Description : Dispatch SM_DEACTIVATE_IND
|
| Parameters  : sm_deactivate_ind          - received primitive
+------------------------------------------------------------------------------
*/
void upm_link_dispatch_sm_deactivate_ind(T_SM_DEACTIVATE_IND *sm_deactivate_ind)
{
  int                    nsapi;
  struct T_CONTEXT_DATA *ptr_context_data;

  (void)TRACE_FUNCTION("UPM Link Control: upm_link_dispatch_sm_deactivate_ind");

  /* Add NSAPI to nsapi_set to deactivate */
  nsapis_to_deactivate         |= sm_deactivate_ind->nsapi_set;

  for (nsapi = (int)NAS_NSAPI_5; nsapi < NAS_SIZE_NSAPI; nsapi++)
  {
    if ( (sm_deactivate_ind->nsapi_set & upm_nsapi2nsapi_set(nsapi)) != 0)
    {
      ptr_context_data = upm_get_context_data_from_nsapi(nsapi);
      if (ptr_context_data != NULL)
      {
        if (upm_is_link_released(ptr_context_data))
        {
          nsapis_currently_deactivated |= upm_nsapi2nsapi_set(nsapi);
        } else {
          upm_link_control(ptr_context_data, UPM_P_SM_DEACTIVATE_IND,
                           (void *)sm_deactivate_ind->rel_ind);
        }

        upm_check_for_released_context_and_release(ptr_context_data);
      } else {
        (void)TRACE_ERROR("Tried to deactivate non-existent context!");
      }
    }
  } /* for */
}

/*
+------------------------------------------------------------------------------
| Function    : upm_link_control_init
+------------------------------------------------------------------------------
| Description : Link Control state machine initialization function
|
| Parameters  : ptr_context_data - Pointer to context data
+------------------------------------------------------------------------------
*/
void upm_link_control_init(struct T_CONTEXT_DATA *ptr_context_data)
{
  (void)TRACE_FUNCTION("UPM Link Control: upm_link_control_init");

  TRACE_ASSERT(ptr_context_data != NULL);

  link_control_goto_state(ptr_context_data, UPM_LINK_RELEASED);

  /* Zero out store for deactivation synchronization */
  nsapis_to_deactivate                 = 0;
  nsapis_currently_deactivated         = 0;
}

/*
+------------------------------------------------------------------------------
| Function    : upm_link_control_exit
+------------------------------------------------------------------------------
| Description : Link Control state machine exit function
|
| Parameters  : ptr_context_data - Pointer to context data
+------------------------------------------------------------------------------
*/
void upm_link_control_exit(struct T_CONTEXT_DATA *ptr_context_data)
{
  (void)TRACE_FUNCTION("UPM Link Control: upm_link_control_exit");

  TRACE_ASSERT(ptr_context_data != NULL);

  link_control_goto_state(ptr_context_data, UPM_LINK_RELEASED);
}

/*
+------------------------------------------------------------------------------
| Function    : upm_link_control
+------------------------------------------------------------------------------
| Description : Link Control state machine
|
| Parameters  : ptr_context_data - Pointer to context data
|               event            - Internal event (see upm_link_control.h)
|               data             - Event dependent parameter
+------------------------------------------------------------------------------
*/
void upm_link_control (struct T_CONTEXT_DATA *ptr_context_data,
                      T_UPM_LINK_CONTROL_EVENT event,
                      /*@null@*/ void *data)
{
#ifdef DEBUG
  T_UPM_LINK_CONTROL_STATE old_state;
  /*@observer@*/ /*@notnull@*/
  static const char *state_name[UPM_LINK_CONTROL_NUMBER_OF_STATES] = {
    "S0_UPM_LINK_RELEASED",
#ifdef TI_UMTS
    "S1_UPM_LINK_ESTABLISHING_RAB",
    "S2_UPM_LINK_AWAITING_ACTIVATE_UMTS",
    "S3_UPM_LINK_RAB_ESTABLISHED",
    "S4_UPM_LINK_RELEASING_RAB",
#endif /* TI_UMTS */
#ifdef TI_DUAL_MODE
    "S5_UPM_LINK_COMPLETING_RAT_CHANGE_TO_GSM",
    "S6_UPM_LINK_COMPLETING_RAT_CHANGE_TO_UMTS_INITIAL",
#endif /* TI_DUAL_MODE */
#ifdef TI_GPRS
    "S7_UPM_LINK_AWAITING_ACTIVATE_GSM",
    "S8_UPM_LINK_ESTABLISHING_LLC_LINK",
    "S9_UPM_LINK_LLC_LINK_ESTABLISHED",
    "S10_UPM_LINK_RELEASING_LLC_LINK"
#endif /* TI_GPRS */
  };
  /*@observer@*/ /*@notnull@*/
  static const char *event_name[UPM_LINK_CONTROL_NUMBER_OF_EVENTS] = {
    "UPM_P_SM_ACTIVATE_STARTED_IND",
    "UPM_P_SM_ACTIVATE_IND",
    "UPM_P_SM_DEACTIVATE_IND",
    "UPM_P_SM_MODIFY_IND",
    "UPM_I_LINK_DTI_CLOSED",
    "UPM_I_RAB_ESTABLISHED",
    "UPM_I_RAB_RELEASED",
    "UPM_I_SNDCP_LLC_LINK_ESTABLISHED",
    "UPM_I_SNDCP_LLC_LINK_MODIFIED",
    "UPM_I_SNDCP_LLC_LINK_RELEASED",
    "UPM_I_LINK_RAT_CHANGED"
  };

  TRACE_ASSERT(ptr_context_data != NULL);
  TRACE_ASSERT(event < UPM_LINK_CONTROL_NUMBER_OF_EVENTS);

  old_state = link_control_state(ptr_context_data);
  TRACE_ASSERT(old_state < UPM_LINK_CONTROL_NUMBER_OF_STATES);

  if (transition[(U16)old_state][(U16)event].event != event)
  {
    (void)TRACE_ERROR("Event table error in upm_link_control!");
  }
#endif /* DEBUG */

  transition[(U16)link_control_state(ptr_context_data)][(U16)event].func(ptr_context_data, data);

#ifdef DEBUG
  (void)TRACE_EVENT_P4("LINK  #%d: %s => %s to %s",
                       ptr_context_data->nsapi,
                       event_name[(U16)event],
                       state_name[(U16)old_state],
                       state_name[(U16)link_control_state(ptr_context_data)]);
#endif /* DEBUG */
}

/*==== END OF FILE ==========================================================*/