view src/g23m-gsm/cc/cc_rel.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 :  GSM-PS (6147)
|  Modul   :  CC_REL
+----------------------------------------------------------------------------- 
|  Copyright 2002 Texas Instruments Berlin, AG 
|                 All rights reserved. 
| 
|                 This file is confidential and a trade secret of Texas 
|                 Instruments Berlin, AG 
|                 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 Berlin, AG. 
+----------------------------------------------------------------------------- 
|  Purpose :  This Modul defines the functions for call release
|             of the component CC of the mobile station.
+----------------------------------------------------------------------------- 
*/ 

#ifndef CC_REL_C
#define CC_REL_C

#define ENTITY_CC
/*==== INCLUDES ===================================================*/

#include <string.h>
#include "typedefs.h"
#include "pcm.h"
#include "vsi.h"
#include "custom.h"
#include "gsm.h"
#include "message.h"
#include "ccdapi.h"
#include "prim.h"
#include "cnf_cc.h"
#include "mon_cc.h"
#include "pei.h"
#include "tok.h"
#include "cc.h"
#include "cc_em.h"

/*==== EXPORT =====================================================*/

/*==== PROTOTYPES =================================================*/
/* Implements Measure#  8 */
LOCAL void cc_mncc_release_ind  (T_PRIM * prim);
/* Implements Measure#  9 */
LOCAL void cc_mncc_release_cnf (T_PRIM * prim);
/* Implements Measure#  41 */
LOCAL void cc_mncc_sync_ind ( UBYTE ti, 
                              UBYTE new_state);
/*==== PRIVAT =====================================================*/

/*==== VARIABLES ==================================================*/

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

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_REL                     |
| STATE   : code                ROUTINE : cc_check_setup_reattempt   |
+--------------------------------------------------------------------+

  PURPOSE : This function checks whether a the mobile originated setup
            may be reattempted. This will be done for some certain
            reasons which may indicate network failure.
            This function is considered as a hack only
            for networks which tend to deliver a poor quality
            of service only (e.g. typically in China). 
            This behaviour or the algorithm is not specified / implied 
            by GSM but driven by customer requests and the desire
            to have a good, working product.
*/

LOCAL void cc_check_setup_reattempt ( const T_M_CC_cc_cause *cc_cause)
{
  GET_INSTANCE_DATA;
  EXTERN BOOL poor_quality_network;

  TRACE_FUNCTION ("cc_check_setup_reattempt()");

#ifdef  WIN32
  /*
   * Set poor_quality_network for test, pei_config() is the appropriate place,
   * but this seems not to be working for some strange reasons
   */
  poor_quality_network = TRUE;
#endif

  /* reattempt already "running", see cc_setup_reattempt for further reasoning */
  if (cc_data->setup_reattempt_ti NEQ NOT_PRESENT_8BIT)
    return;

  switch (cc_data->state[cc_data->index_ti])
  {
    case M_CC_CS_1:  /* call initiated                     */
    case M_CC_CS_3:  /* mobile originating call proceeding */
      cc_data->setup_attempts++;
      if (poor_quality_network AND
          (cc_data->setup_attempts < MAX_SETUP_ATTEMPTS) AND
          (cc_cause->v_cause))
      {
        /*
         * Mobile originated call got disconnect,
         * max. number of setup attempts not reached.
         * New dial attempt for certain disconnect reasons
         */
        switch (cc_cause->cause)
        {
          case M_CC_CAUSE_NO_CHAN_AVAIL:       /* #34  */
          case M_CC_CAUSE_NETWORK_ORDER:       /* #38  */
          case M_CC_CAUSE_TEMP_FAIL:           /* #41  */
          case M_CC_CAUSE_SWITCH_CONGEST:      /* #42  */
          case M_CC_CAUSE_INFO_DISCARD:        /* #43  */
          case M_CC_CAUSE_REQ_CHAN_UNAVAIL:    /* #44  */
          case M_CC_CAUSE_RESOURCE_UNAVAIL:    /* #47  */
          case M_CC_CAUSE_QOS_UNAVAIL:         /* #49  */
          case M_CC_CAUSE_BEARER_CAP_UNAVAIL:  /* #58  */
          case M_CC_CAUSE_TIMER:               /* #102 */
          case M_CC_CAUSE_INTERWORKING:        /* #127 */
            /*
             * Maybe some more causes to added here
             * which indicate network failure
             */

            /* try setup reattempt, remember this by setting setup_reattempt_ti */
            cc_data->setup_reattempt_ti = cc_data->ti;
            break;

          default: /* Don't try setup reattempt, no appropriate cause */
            srv_free_stored_setup ();
            break;
        }
      }
      break;

    default: /* Don't try setup reattempt in other states */
      break;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_REL                     |
| STATE   : code                ROUTINE : cc_setup_reattempt         |
+--------------------------------------------------------------------+

  PURPOSE : This function reattempts the mobile originated setup
            for some certain reasons which may indicate network
            failure. This function is considered as a hack only
            for networks which tend to deliver a poor quality
            of service only.

*/

LOCAL void cc_setup_reattempt (void)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION ("cc_setup_reattempt()");

  if (cc_data->ti EQ cc_data->setup_reattempt_ti)
  {
    PALLOC (est, MMCM_ESTABLISH_REQ); /* T_MMCM_ESTABLISH_REQ */
    est->ti    = cc_data->ti;
    est->estcs = cc_data->estcs;
    for_est_req (est);

    cc_data->setup_reattempt_ti = NOT_PRESENT_8BIT;
    cc_data->progress_desc[cc_data->index_ti] = NOT_PRESENT_8BIT;
    cc_set_state (M_CC_CS_01);
    TIMERSTART (T303, T303_VALUE);
  }
}

/*==== VARIABLES ==================================================*/

/*==== FUNCTIONS ==================================================*/
/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_REL                     |
| STATE   : code                ROUTINE : cc_mncc_disconnect_req     |
+--------------------------------------------------------------------+

  PURPOSE : Disconnection of call by the mobile side.

*/

GLOBAL void cc_mncc_disconnect_req (T_MNCC_DISCONNECT_REQ * disc)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION ("cc_mncc_disconnect_req()");

  if ((cc_data->index_ti = srv_convert_ti (disc->ti))
       EQ NOT_PRESENT_8BIT)
  {
    PFREE (disc);
    return;
  }
  if (cc_data->ti EQ cc_data->setup_reattempt_ti)
  {
    srv_free_stored_setup ();  
  }
  switch (cc_data->state[cc_data->index_ti])
  {
    case M_CC_CS_03: /* WAIT FOR NW. INFO */
    case M_CC_CS_05: /* CC ESTABLISHMENT CONFIRMED */
    case M_CC_CS_06: /* RECALL PRESENT */
      /* Forget stored CCBS setup */
      if (cc_data->stored_ccbs_setup NEQ NULL)
      {
        PFREE (cc_data->stored_ccbs_setup);
        cc_data->stored_ccbs_setup = NULL;
      }

      /* Send a (faked) MNCC_RELEASE_IND to MMI */
      {
        PALLOC (rel, MNCC_RELEASE_IND);
        rel->ti    = disc->ti;
        rel->cause = disc->cause;
        rel->c_raw_cause = 0;
        PSENDX (MMI, rel);
      }

      /* Send RELEASE COMPLETE to network */
      CCD_START;
      {
        MCAST (rel_com, U_RELEASE_COMP);
        cc_build_release_complete (rel_com, disc->cause);
        for_release_complete (rel_com);
      }
      CCD_END;

      /* Release MM connection */
      for_rel_req ();

      PFREE (disc);

      /* Stop all running timers */
      TIMERSTOP (TIMER_CC);

      /* Next state is NULL */
      cc_set_state (M_CC_CS_0);
      break;

    case M_CC_CS_01:
    case CS_101:
    case CS_261:
      {
        TIMERSTOP (TIMER_CC);

        cc_reset_dtmf ();

        {
          PALLOC (rel, MNCC_RELEASE_IND);
          rel->ti    = disc->ti;
          rel->cause = disc->cause;
          rel->c_raw_cause = 0;
          PSENDX (MMI, rel);
        }

        for_rel_req ();
        cc_set_state (M_CC_CS_0);
        srv_use_stored_prim ();
        PFREE (disc);
      }
      break;

    case M_CC_CS_1:      
    case M_CC_CS_3:
    case M_CC_CS_4:
    case M_CC_CS_7:
    case M_CC_CS_8:
    case M_CC_CS_9:
    case M_CC_CS_10:
    case M_CC_CS_26:
      TIMERSTOP (TIMER_CC);

      CCD_START;
      {
        MCAST (disconnect, U_DISCONNECT);
        
        cc_build_disconnect (disconnect, disc->cause,
                             &disc->fac_inf, disc->ss_version);
        cc_set_state (M_CC_CS_11);
        for_disconnect (disconnect);
      }
      CCD_END;
      TIMERSTART (T305, T305_VALUE);
      PFREE (disc);
      break;

    case M_CC_CS_12: /* DISCONNECT INDICATION, this is clear collision here */
      CCD_START;
      {
        MCAST (release, U_RELEASE);

        cc_build_release (release, disc->cause,
                          NULL, MNCC_SS_VER_NOT_PRES);
        cc_set_state (M_CC_CS_19);
        for_release (release);

      }
      CCD_END;
      TIMERSTART (T308, T308_VALUE);
      PFREE (disc);
      break;

    default:
      PFREE (disc);
      break;

  }
}
/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_REL                     |
| STATE   : code                ROUTINE : cc_mncc_reject_req         |
+--------------------------------------------------------------------+

  PURPOSE : Release of call by the mobile side by sending
            a RELEASE COMPLETE message.

*/

GLOBAL void cc_mncc_reject_req (T_MNCC_REJECT_REQ * rej)
{
  GET_INSTANCE_DATA;

  TRACE_FUNCTION ("cc_mncc_reject_req");

  if ((cc_data->index_ti = srv_convert_ti (rej->ti))
      EQ NOT_PRESENT_8BIT)
  {
    PFREE (rej);
    return;
  }

  if (cc_data->ti EQ cc_data->setup_reattempt_ti)
  {
    srv_free_stored_setup ();
  }

  switch (cc_data->state[cc_data->index_ti])
  {
    case M_CC_CS_03: /* WAIT FOR NW. INFO */
    case M_CC_CS_05: /* CC ESTABLISHMENT CONFIRMED */
    case M_CC_CS_06: /* RECALL PRESENT */
      /* Forget stored CCBS setup */
      if (cc_data->stored_ccbs_setup NEQ NULL)
      {
        PFREE (cc_data->stored_ccbs_setup);
        cc_data->stored_ccbs_setup = NULL;
      }

      /* Send RELEASE COMPLETE */
      CCD_START;
      {
        MCAST (rel_com, U_RELEASE_COMP);
        cc_build_release_complete (rel_com, rej->cause);
        for_release_complete (rel_com);
      }
      CCD_END;

      /* Release MM connection */
      for_rel_req ();

      PFREE (rej);

      /* Stop all running timers */
      TIMERSTOP (TIMER_CC);

      /* Next state is NULL */
      cc_set_state (M_CC_CS_0);
      break;
    default:
      PFREE (rej);
      break;
  }
}


/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_REL                     |
| STATE   : code                ROUTINE : cc_mncc_release_req        |
+--------------------------------------------------------------------+

  PURPOSE : Release of call by the mobile side.

*/
GLOBAL void cc_mncc_release_req (T_MNCC_RELEASE_REQ * rel)
{
  GET_INSTANCE_DATA;

  TRACE_FUNCTION ("cc_mncc_release_req()");

  if ((cc_data->index_ti = srv_convert_ti (rel->ti))
      EQ NOT_PRESENT_8BIT)
  {
    PFREE (rel);
    return;
  }

  if (cc_data->ti EQ cc_data->setup_reattempt_ti)
  {
    srv_free_stored_setup ();
  }

  switch (cc_data->state[cc_data->index_ti])
  {
    case M_CC_CS_12: /* DISCONNECT INDICATION */

      CCD_START;
      {
        MCAST (release, U_RELEASE);

        cc_build_release (release, rel->cause, 
                          &rel->fac_inf, rel->ss_version);
        cc_set_state (M_CC_CS_19);
        for_release (release);

      }
      CCD_END;
      TIMERSTART (T308, T308_VALUE);
      PFREE (rel);
      break;

    default:
      PFREE (rel);
      break;

  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_REL                     |
| STATE   : code                ROUTINE : cc_disconnect              |
+--------------------------------------------------------------------+

  PURPOSE : Processing an incoming disconnect message.

*/

GLOBAL void cc_disconnect (T_D_DISCONNECT * disconnect)
{
  GET_INSTANCE_DATA;

  TRACE_FUNCTION ("cc_disconnect()");

  /* The cause is in DISCONNECT a mandatory IE (given intact message) */
  TRACE_EVENT_P1 ("DISCONNECT cause: %02x", disconnect->cc_cause.cause);

  EM_CC_DISCONNECT_RECEIVED;

  switch (cc_data->state[cc_data->index_ti])
  {
    case M_CC_CS_11: /* DISCONNECT REQUEST, this is clear collision here */
      CCD_END;
      CCD_START;
      {
        MCAST (release, U_RELEASE);

        TIMERSTOP (TIMER_CC);
        /* PATCH LE 10.04.00
         * set disconnect collision flag
         */ 
        cc_data->disc_coll [cc_data->index_ti]    = TRUE;
        /* END PATCH LE 10.04.00 */

        switch (cc_data->error)
        {
          case M_CC_CAUSE_INVALID_MAND_INFO:
          case M_CC_CAUSE_COND_INFO_ELEM:
            cc_build_release (release, CAUSE_MAKE(DEFBY_STD, 
                                                  ORIGSIDE_MS, 
                                                  MNCC_CC_ORIGINATING_ENTITY,
                                                  cc_data->error),
                              NULL, MNCC_SS_VER_NOT_PRES);
            cc_set_state (M_CC_CS_19);
            for_release (release);
            TIMERSTART (T308, T308_VALUE);
            break;

          default:
            if (disconnect->v_progress) 
            {
              cc_data->progress_desc[cc_data->index_ti] = 
                disconnect->progress.progress_desc;
            }
            cc_build_release (release, CAUSE_MAKE(DEFBY_CONDAT, 
                                                  ORIGSIDE_MS, 
                                                  MNCC_CC_ORIGINATING_ENTITY,
                                                  NOT_PRESENT_8BIT),
                              NULL, MNCC_SS_VER_NOT_PRES);
            cc_set_state (M_CC_CS_19);
            for_release (release);
            TIMERSTART (T308, T308_VALUE);
            break;
        }
      }
      CCD_END;
      break;

    case M_CC_CS_12: /* DISCONNECT INDICATION */
    case M_CC_CS_19: /* RELEASE REQUEST */
      /* NULL (M_CC_CS_0) is handled by the formatter */
      CCD_END;
/* Implements Measure#  3 and streamline encoding */
      cc_send_status (M_CC_CAUSE_MESSAGE_TYPE_INCOMPAT);
      break;

    default:
      /* any "normal" state */
      TIMERSTOP (TIMER_CC);

      switch (cc_data->error)
      {
        case M_CC_CAUSE_INVALID_MAND_INFO:
        case M_CC_CAUSE_COND_INFO_ELEM:
          CCD_END;
          CCD_START;
          {
            USHORT curr_cause; /* local variable to avoid repeated CAUSE_MAKEs for the same cause */

            MCAST (release, U_RELEASE);
            PALLOC (disc_ind, MNCC_DISCONNECT_IND);

            disc_ind->ti    = cc_data->ti;
            curr_cause = CAUSE_MAKE(DEFBY_STD, 
                                    ORIGSIDE_MS, 
                                    MNCC_CC_ORIGINATING_ENTITY,
                                    cc_data->error);
            disc_ind->cause = curr_cause; 
            /* Setting raw_cause to empty as this is a local release
             * of MM connection,CC is not receiving any cause value
             * from Network
             */
            disc_ind->c_raw_cause = 0;

            disc_ind->diagnostic = NOT_PRESENT_8BIT;
            disc_ind->progress_desc = MNCC_PROG_NOT_PRES;
            /* CQ 23619: get the ss diagnostic >> */
            disc_ind->ss_diag = MNCC_SS_DIAG_NOT_PROVIDED;
            /* CQ 23619 << */
            PSENDX (MMI, disc_ind);
            
            /* Patch HM 29-Jan-02 >>> */
            cc_build_facility_ind (MNCC_FAC_IN_DISCONNECT,
                                   disconnect->v_facility, &disconnect->facility);
            /* Patch HM 29-Jan-02 <<< */
            cc_build_release (release, cc_data->error,
                              NULL, MNCC_SS_VER_NOT_PRES);
            cc_set_state (M_CC_CS_19);
            for_release (release);
            TIMERSTART (T308, T308_VALUE);
          }
          CCD_END;
        break;

        default:
          if (disconnect->v_progress) 
          {
            cc_data->progress_desc[cc_data->index_ti] = 
              disconnect->progress.progress_desc;
          }
          cc_check_setup_reattempt (&disconnect->cc_cause);

          if (cc_data->ti NEQ cc_data->setup_reattempt_ti)
          {
            /*
             * We don't perform setup reattempt, so send disconnect to MMI
             */
            USHORT curr_cause; /* local variable to avoid repeated CAUSE_MAKEs for the same cause */             
            PALLOC (disc_ind, MNCC_DISCONNECT_IND); /* T_MNCC_DISCONNECT_IND */
            disc_ind->ti    = cc_data->ti;
            disc_ind->cause = curr_cause = CAUSE_MAKE(DEFBY_STD, 
                                                      ORIGSIDE_NET, 
                                                      MNCC_CC_ORIGINATING_ENTITY,
                                                      disconnect->cc_cause.cause);
            disc_ind->c_raw_cause = cc_build_cause (&disconnect->cc_cause,
                                                     disc_ind->raw_cause);
            disc_ind->diagnostic = NOT_PRESENT_8BIT;

            if (disconnect->v_progress)
              disc_ind->progress_desc = disconnect->progress.progress_desc;
            else
              disc_ind->progress_desc = MNCC_PROG_NOT_PRES;

            /* Handle CCBS possible flag */
            if ((cc_data->call_ctrl_cap.pcp NEQ 0) AND
                (disconnect->v_allowed_actions NEQ 0) AND
                (disconnect->allowed_actions.ccbs_act EQ M_CC_CCBS_YES))
            {
              /* CCBS indicated as possible by the network */
              disc_ind->diagnostic = MNCC_DIAG_CCBS_POSSIBLE;
            }
            /* CQ 23619: get the ss diagnostic */
            disc_ind->ss_diag = cc_get_ss_diag(curr_cause, disconnect);
            /* CQ 23619 << */
            PSENDX (MMI, disc_ind);
            /* Patch HM 29-Jan-02 >>> */
            cc_build_facility_ind (MNCC_FAC_IN_DISCONNECT,
                                   disconnect->v_facility, &disconnect->facility);            
            /* Patch HM 29-Jan-02 <<< */
          }
          if ((cc_data->ti NEQ cc_data->setup_reattempt_ti) AND
              (((disconnect->v_progress AND
                (disconnect->progress.progress_desc EQ M_CC_PROG_INBAND_AVAIL) AND
                (cc_data->channel_mode != NAS_CHM_SIG_ONLY)))
              OR
              ((cc_data->call_ctrl_cap.pcp NEQ 0) AND
               (disconnect->v_allowed_actions NEQ 0) AND
               (disconnect->allowed_actions.ccbs_act EQ M_CC_CCBS_YES))))
          {
            /*
             * Hook on tone is generated by the
             * infrastructure and signalled via TCH OR CCBS is possible
             */
            CCD_END;
            cc_set_state (M_CC_CS_12);
          }
          else
          {
            CCD_END;
            CCD_START;
            {
              MCAST (release, U_RELEASE);

              /*
               * Hook on tone is generated internally by the mobile station
               * and no CCBS possible, the connection is released
               */
              cc_build_release (release, CAUSE_MAKE(DEFBY_CONDAT, 
                                                    ORIGSIDE_MS, 
                                                    MNCC_CC_ORIGINATING_ENTITY,
                                                    NOT_PRESENT_8BIT),
                                NULL, MNCC_SS_VER_NOT_PRES);
              cc_set_state (M_CC_CS_19);
              for_release (release);
              TIMERSTART (T308, T308_VALUE);
            }
            CCD_END;
          }
          break;
      }
      break;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_REL                     |
| STATE   : code                ROUTINE : cc_release                 |
+--------------------------------------------------------------------+

  PURPOSE : Processing an incoming release message.

*/

GLOBAL void cc_release (T_D_RELEASE * release)
{
  GET_INSTANCE_DATA;

  TRACE_FUNCTION ("cc_release()");
 
  if (release->cc_cause.v_cause)
  {
    /* The cause is in RELEASE an optional IE */
    TRACE_EVENT_P1 ("RELEASE cause: %02x", release->cc_cause.cause);
  }
  else
  {
    TRACE_EVENT ("RELEASE cause: --");
  }

  switch (cc_data->state[cc_data->index_ti])
  {
    /*
     * M_CC_CS_0 is handled by the formatter
     */
    case M_CC_CS_19: /* Release Request */
    {
      cc_reset_dtmf ();
      /* PATCH LE 10.04.00
       * in disconnect collision case send
       * MNCC_RELEASE_IND instead of MNCC_RELEASE_CNF
....   */
      TIMERSTOP (TIMER_CC);
      if (cc_data->disc_coll [cc_data->index_ti])
      {
/* Implements Measure#  8 */
        cc_mncc_release_ind ((T_PRIM *)D2P(release));
      }
      else
      {
/* Implements Measure#  9 */
        cc_mncc_release_cnf ((T_PRIM *)D2P(release));
      }
      // END PATCH LE 10.04.00     

      for_rel_req ();
      cc_set_state (M_CC_CS_0);
      /* END PATCH LE 10.04.00 */
      CCD_END;
      break;
    }

    case M_CC_CS_1:  /* call initiated                     */
    case M_CC_CS_3:  /* mobile originating call proceeding */ 
      cc_check_setup_reattempt (&release->cc_cause);
      /*FALLTHROUGH*/ /*lint -fallthrough*/
    default:
      cc_reset_dtmf (); /* China change HM 11.07.00 */
      CCD_END;
      CCD_START;
      {
        MCAST (rel_com, U_RELEASE_COMP);
        
        TIMERSTOP (TIMER_CC);
        switch (cc_data->error)
        {
          case M_CC_CAUSE_INVALID_MAND_INFO:
          case M_CC_CAUSE_COND_INFO_ELEM:
            {
              USHORT curr_cause; /* local variable to avoid repeated CAUSE_MAKEs for the same cause */
              curr_cause = CAUSE_MAKE(DEFBY_STD, 
                                      ORIGSIDE_MS, 
                                      MNCC_CC_ORIGINATING_ENTITY,
                                      cc_data->error);

              if (cc_data->ti NEQ cc_data->setup_reattempt_ti)
              {
                PALLOC (rel_ind, MNCC_RELEASE_IND);
                rel_ind->ti = cc_data->ti;
                rel_ind->cause = curr_cause;
                rel_ind->c_raw_cause = 0;
                PSENDX (MMI, rel_ind);
              }
              cc_build_release_complete (rel_com, curr_cause);
            }
            break;

          default:
            if (cc_data->ti NEQ cc_data->setup_reattempt_ti)
            {
/* Implements Measure#  8 */
              cc_mncc_release_ind ((T_PRIM *)D2P(release));
            }       
            cc_build_release_complete (rel_com, CAUSE_MAKE(DEFBY_CONDAT, 
                                                           ORIGSIDE_MS, 
                                                           MNCC_CC_ORIGINATING_ENTITY,
                                                           NOT_PRESENT_8BIT));
            break;
        }

        for_release_complete (rel_com);
      }
      CCD_END;
      for_rel_req ();
      cc_set_state (M_CC_CS_0);
      cc_setup_reattempt ();
      break;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_REL                     |
| STATE   : code                ROUTINE : cc_release_complete        |
+--------------------------------------------------------------------+

  PURPOSE : Processing an incoming release complete message.

*/

GLOBAL void cc_release_complete (T_D_RELEASE_COMP * rel_com)
{
  GET_INSTANCE_DATA;

  TRACE_FUNCTION ("cc_release_complete()");

  if (rel_com->cc_cause.v_cause)
  {
    /* The cause is in RELEASE COMPLETE an optional IE */
    TRACE_EVENT_P1 ("RELEASE COMPLETE cause: %02x", rel_com->cc_cause.cause);
  }
  else
  {
    TRACE_EVENT ("RELEASE COMPLETE cause: --");
  }

  EM_CC_RELEASE_COMPLETE_RECEIVED;

  switch (cc_data->state[cc_data->index_ti])
  {
    case M_CC_CS_0: /* NULL */
      CCD_END;
      for_rel_req ();
      break;

    case M_CC_CS_03: /* WAIT FOR NETWORK INFO*/
      /* Stop all running CC timers */
      TIMERSTOP (TIMER_CC);

      /* Inform MMI */
      {
        PALLOC (release, MNCC_RELEASE_IND);
        release->ti  = cc_data->ti;
        if (rel_com->v_cc_cause AND rel_com->cc_cause.v_cause)
        {
          release->cause = CAUSE_MAKE(DEFBY_STD, 
                                      ORIGSIDE_NET, 
                                      MNCC_CC_ORIGINATING_ENTITY,
                                      rel_com->cc_cause.cause);
          release->c_raw_cause = cc_build_cause (&rel_com->cc_cause,
                                                  release->raw_cause);
        }
        else
        {
          release->cause = CAUSE_MAKE(DEFBY_CONDAT, 
                                      ORIGSIDE_NET, 
                                      MNCC_CC_ORIGINATING_ENTITY,
                                      NOT_PRESENT_8BIT);
          release->c_raw_cause = 0;
        }
        PSENDX (MMI, release);
      }

      CCD_END;

      /* Release MM connection */
      for_rel_req ();

      /* Next state is NULL */
      cc_set_state (M_CC_CS_0);
      break;

    case M_CC_CS_05: /* CC ESTABLISHMENT CONFIRMED */
    case M_CC_CS_06: /* RECALL PRESENT */
      /* Forget stored CCBS setup */
      PFREE (cc_data->stored_ccbs_setup);
      cc_data->stored_ccbs_setup = NULL;

      /* Stop all running CC timers */
      TIMERSTOP (TIMER_CC);

      /* Inform MMI */
      {
        PALLOC (release, MNCC_RELEASE_IND);
        release->ti  = cc_data->ti;
        if (rel_com->v_cc_cause AND rel_com->cc_cause.v_cause)
        {
          release->cause = CAUSE_MAKE(DEFBY_STD, 
                                      ORIGSIDE_NET, 
                                      MNCC_CC_ORIGINATING_ENTITY,
                                      rel_com->cc_cause.cause);
          release->c_raw_cause = cc_build_cause (&rel_com->cc_cause,
                                                  release->raw_cause);
        }
        else
        {
          release->cause = CAUSE_MAKE(DEFBY_CONDAT, 
                                      ORIGSIDE_NET, 
                                      MNCC_CC_ORIGINATING_ENTITY,
                                      NOT_PRESENT_8BIT);
          release->c_raw_cause = 0;
        }
        PSENDX (MMI, release);
      }

      CCD_END;

      /* Release MM connection */
      for_rel_req ();

      /* Next state is NULL */
      cc_set_state (M_CC_CS_0);
      break;

    case M_CC_CS_19: /* RELEASE REQUEST */
      cc_reset_dtmf ();
      /* PATCH LE 10.04.00
       * in disconnect collision case send
       * MNCC_RELEASE_IND instead of MNCC_RELEASE_CNF
       */
      TIMERSTOP (TIMER_CC);

      if (cc_data->ti NEQ cc_data->setup_reattempt_ti) 
      {
        /* Inform MMI only if no setup reattempt for this ti */
        if (cc_data->disc_coll [cc_data->index_ti])
        {
/* Implements Measure#  9 */
          cc_mncc_release_ind ((T_PRIM *)D2P(rel_com));
        }
        else
        {
/* Implements Measure#  9 */
          cc_mncc_release_cnf ((T_PRIM *)D2P(rel_com));
        }
        /* END PATCH LE 10.04.00 */

      }

      for_rel_req ();
      cc_set_state (M_CC_CS_0);
      CCD_END;
      cc_setup_reattempt ();
      break;

    case M_CC_CS_1:  /* call initiated                     */
    case M_CC_CS_3:  /* mobile originating call proceeding */
      cc_check_setup_reattempt (&rel_com->cc_cause);
      /*FALLTHROUGH*/ /*lint -fallthrough*/
    default:
      cc_reset_dtmf (); /* China change HM 11.07.00 */
      if (cc_data->ti NEQ cc_data->setup_reattempt_ti)
      {
        /* Implements Measure#  10 */
        cc_mncc_release_ind ((T_PRIM *)D2P(rel_com));
      }
      for_rel_req ();
      CCD_END;
      cc_set_state (M_CC_CS_0);
      cc_setup_reattempt ();
      break;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_REL                     |
| STATE   : code                ROUTINE : cc_rel_ind                 |
+--------------------------------------------------------------------+

  PURPOSE : Processing of an incoming release indication from
            mobility management.

*/

GLOBAL void cc_rel_ind (USHORT cause)
{
  GET_INSTANCE_DATA;

  TRACE_FUNCTION ("cc_rel_ind()");

  switch (cc_data->state[cc_data->index_ti])
  {
    case M_CC_CS_0:
      break;

    case M_CC_CS_05: /* CC ESTABLISHMENT CONFIRMED */
    case M_CC_CS_06: /* RECALL PRESENT */
      /* Stop all timers */
      TIMERSTOP (TIMER_CC);

      /* Forget stored CCBS setup message */
      PFREE (cc_data->stored_ccbs_setup);
      cc_data->stored_ccbs_setup = NULL;

      /* Inform MMI */
      {
        PALLOC (release, MNCC_RELEASE_IND);
        release->ti    = cc_data->ti;
        release->cause = cause; /* provide cause from lower layers transparently to higher layers */
        release->c_raw_cause = 0;
        PSENDX (MMI, release);
      }

      cc_set_state (M_CC_CS_0);
      srv_use_stored_prim ();
      break;

    case CS_101: /* Re-establishment request in state M_CC_CS_10 */\
    case CS_261: /* Re-establishment request in state CS_26 */\
      EM_CC_REESTABLISHED_FAILED;
      /*FALLTHROUGH*/ /*lint -fallthrough*/

    default:
      cc_reset_dtmf (); /* China change HM 11.07.00 */
      if (cc_data->ti NEQ cc_data->setup_reattempt_ti)
      {
        PALLOC (rej_ind, MNCC_REJECT_IND);
        rej_ind->ti  = cc_data->ti;
        rej_ind->cause = cause;
        PSENDX (MMI, rej_ind);
      }

      cc_set_state (M_CC_CS_0);
      if (cc_data->ti EQ cc_data->setup_reattempt_ti)
      {
        cc_setup_reattempt();
      }
      else
      {
        srv_use_stored_prim ();
      }
      break;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_REL                     |
| STATE   : code                ROUTINE : cc_err_ind                 |
+--------------------------------------------------------------------+

  PURPOSE : Processing of an incoming error indication from
            mobility management.

*/

GLOBAL void cc_err_ind (T_MMCM_ERROR_IND * err_ind)
{
  GET_INSTANCE_DATA;

  TRACE_FUNCTION ("cc_err_ind()");

  switch (cc_data->state[cc_data->index_ti])
  {
    case M_CC_CS_0:
      break;

    case M_CC_CS_10:
      {
/* Implements Measure#  41 */
        cc_mncc_sync_ind(err_ind->ti, CS_101);

        EM_CC_REESTABLISHED_STARTED;

      }
      break;

    case M_CC_CS_26:
      {
/* Implements Measure#  41 */
        cc_mncc_sync_ind(err_ind->ti, CS_261);

        EM_CC_REESTABLISHED_STARTED;

      }
      break;

    default:
      cc_reset_dtmf ();
      if (cc_data->ti NEQ cc_data->setup_reattempt_ti)
      {
        PALLOC (rel_ind, MNCC_RELEASE_IND);
        rel_ind->cause = err_ind->cause;
        rel_ind->ti    = cc_data->ti;
        rel_ind->c_raw_cause = 0;
        PSENDX (MMI, rel_ind);
      }
      cc_set_state (M_CC_CS_0);
      for_rel_req ();
      cc_setup_reattempt ();
      break;
  }
  PFREE (err_ind);
}
/* Implements Measure#  8 */
/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_REL                     |
| STATE   : code                ROUTINE : cc_mncc_release_ind        |
+--------------------------------------------------------------------+

  PURPOSE : send mncc_release_ind

*/

LOCAL void cc_mncc_release_ind (T_PRIM * prim)
{
  GET_INSTANCE_DATA;
  UBYTE                     v_cc_cause;
  T_M_CC_cc_cause                *cc_cause;                             
  
  TRACE_FUNCTION ("cc_mncc_release_ind()");
  
  if (prim->custom.opc EQ D_RELEASE)
  {
    v_cc_cause = ((T_D_RELEASE *)P2D(prim))->v_cc_cause;
    cc_cause   = &((T_D_RELEASE *)P2D(prim))->cc_cause;
    cc_build_facility_ind (MNCC_FAC_IN_RELEASE, 
                           ((T_D_RELEASE *)P2D(prim))->v_facility,
                           &((T_D_RELEASE *)P2D(prim))->facility);
  }
  else
  {
    v_cc_cause = ((T_D_RELEASE_COMP *)P2D(prim))->v_cc_cause;
    cc_cause   = &((T_D_RELEASE_COMP *)P2D(prim))->cc_cause;
    cc_build_facility_ind (MNCC_FAC_IN_RELEASE_COMP,
                           ((T_D_RELEASE_COMP *)P2D(prim))->v_facility, 
                           &((T_D_RELEASE_COMP *)P2D(prim))->facility);
  }

  /* Patch HM 29-Jan-02 <<< */
  {
    PALLOC (rel_ind, MNCC_RELEASE_IND);
    rel_ind->ti    = cc_data->ti;
    if (v_cc_cause)
    {
      rel_ind->cause = CAUSE_MAKE(DEFBY_STD, 
                                   ORIGSIDE_NET, 
                                   MNCC_CC_ORIGINATING_ENTITY,
                                   cc_cause->cause);
      rel_ind->c_raw_cause = cc_build_cause (cc_cause,
                                             rel_ind->raw_cause);
    }
    else
    {
      rel_ind->cause = CAUSE_MAKE(DEFBY_CONDAT, 
                                   ORIGSIDE_NET, 
                                   MNCC_CC_ORIGINATING_ENTITY,
                                   NOT_PRESENT_8BIT);
      /* Setting raw_cause to empty as this is a local release
       * of MM connection,CC is not receiving any cause value
       * from Network
       */
       rel_ind->c_raw_cause = 0;
    }
    PSENDX (MMI, rel_ind);
  }
}

/* Implements Measure#  9 */
/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_REL                     |
| STATE   : code                ROUTINE : cc_mncc_release_cnf        |
+--------------------------------------------------------------------+

  PURPOSE : send mncc_release_cnf

*/

LOCAL void cc_mncc_release_cnf (T_PRIM * prim)
{
  GET_INSTANCE_DATA;
  UBYTE                     v_cc_cause;
  T_M_CC_cc_cause                *cc_cause;                             

  TRACE_FUNCTION ("cc_mncc_release_cnf()");
  
  if (prim->custom.opc EQ D_RELEASE)
  {
    v_cc_cause = ((T_D_RELEASE *)P2D(prim))->v_cc_cause;
    cc_cause   = &((T_D_RELEASE *)P2D(prim))->cc_cause;
    cc_build_facility_ind (MNCC_FAC_IN_RELEASE_COMP, /* A little bit dirty */
                           ((T_D_RELEASE *)P2D(prim))->v_facility,
                           &((T_D_RELEASE *)P2D(prim))->facility);
  }
  else
  {
    v_cc_cause = ((T_D_RELEASE_COMP *)P2D(prim))->v_cc_cause;
    cc_cause   = &((T_D_RELEASE_COMP *)P2D(prim))->cc_cause;
    cc_build_facility_ind (MNCC_FAC_IN_RELEASE_COMP,
                           ((T_D_RELEASE_COMP *)P2D(prim))->v_facility, 
                           &((T_D_RELEASE_COMP *)P2D(prim))->facility);
  }

  /* Patch HM 29-Jan-02  <<< */
  {
    PALLOC (rel_cnf, MNCC_RELEASE_CNF);
    rel_cnf->ti    = cc_data->ti;
    if (v_cc_cause)
    {
      rel_cnf->cause = CAUSE_MAKE(DEFBY_STD, 
                                  ORIGSIDE_NET, 
                                  MNCC_CC_ORIGINATING_ENTITY,
                                  cc_cause->cause);
      rel_cnf->c_raw_cause = cc_build_cause (cc_cause,
                                             rel_cnf->raw_cause);
    }
    else
    {
      rel_cnf->cause = CAUSE_MAKE(DEFBY_CONDAT, 
                                  ORIGSIDE_NET, 
                                  MNCC_CC_ORIGINATING_ENTITY,
                                  NOT_PRESENT_8BIT);
      /* Setting raw_cause to empty as this is a local release
       * of MM connection,CC is not receiving any cause value
       * from Network
       */
       rel_cnf->c_raw_cause = 0;
    }
    PSENDX (MMI, rel_cnf);
  }
}


/* Implements Measure#  41 */
/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_REL                     |
| STATE   : code                ROUTINE : cc_mncc_sync_ind           |
+--------------------------------------------------------------------+

  PURPOSE : send cc_mncc_sync_ind

*/

LOCAL void cc_mncc_sync_ind (UBYTE ti, UBYTE new_state)
{
  TRACE_FUNCTION ("cc_mncc_sync_ind()");
  {
    PALLOC (sync_ind, MNCC_SYNC_IND); /* T_MNCC_SYNC_IND */

    sync_ind->ti    = ti;
    sync_ind->cause = MNCC_CAUSE_REEST_STARTED;
    sync_ind->ch_info.ch_mode=NOT_PRESENT_8BIT;
    sync_ind->ch_info.ch_type=NOT_PRESENT_8BIT;
    
    PSENDX (MMI, sync_ind);
    
    for_reest_req ();
    cc_set_state (new_state);
  }

}
#endif