view src/aci2/aci/psa_ccs.c @ 662:8cd8fd15a095

SIM speed enhancement re-enabled and made configurable TI's original code supported SIM speed enhancement, but Openmoko had it disabled, and OM's disabling of speed enhancement somehow caused certain SIM cards to start working which didn't work before (OM's bug #666). Because our FC community is much smaller in year 2020 than OM's community was in their day, we are not able to find one of those #666-affected SIMs, thus the real issue they had encountered remains elusive. Thus our solution is to re-enable SIM speed enhancement and simply wait for if and when someone runs into a #666-affected SIM once again. We provide a SIM_allow_speed_enhancement global variable that allows SIM speed enhancement to be enabled or disabled per session, and an /etc/SIM_spenh file in FFS that allows it to enabled or disabled on a non-volatile basis. SIM speed enhancement is now enabled by default.
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 24 May 2020 05:02:28 +0000
parents 93999a60b835
children
line wrap: on
line source

/* 
+----------------------------------------------------------------------------- 
|  Project :  GSM-PS (6147)
|  Modul   :  PSA_CCS
+----------------------------------------------------------------------------- 
|  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 module defines the signalling functions of the 
|             protocol stack adapter for call control.
+----------------------------------------------------------------------------- 
*/ 

#ifndef PSA_CCS_C
#define PSA_CCS_C
#endif

#include "aci_all.h"

/*==== INCLUDES ===================================================*/
#include "ccdapi.h"

#include "aci_cmh.h"
#include "ati_cmd.h"
#include "aci_cmd.h"
#include "aci.h"
#include "psa.h"
#include "psa_cc.h"
#include "psa_ss.h"
#include "aoc.h"
#include "l4_tim.h"

#if !defined (MFW)
#include "aci_io.h"
#endif

#include "aci_fd.h"
#include "cmh.h"

#include "cmh_cc.h"
#include "psa_cc.h"

#include "wap_aci.h"

/*==== CONSTANTS ==================================================*/

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

/*==== IMPORT =====================================================*/

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

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


/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : PSA_CCS                      |
|                            ROUTINE : psaCC_NewCall                |
+-------------------------------------------------------------------+

  PURPOSE : setup a new call

*/

GLOBAL SHORT psaCC_NewCall ( SHORT cId )
{
  T_CC_CALL_TBL *pCtbNtry = ccShrdPrm.ctb[cId];

  TRACE_FUNCTION ("psaCC_NewCall()");

  if (pCtbNtry EQ NULL)
    return -1;

  /* get a valid ti for a MOC, otherwise return */
  if (psaCC_ctb(cId)->calType NEQ CT_NI_MOC )
  {
    if( psaCC_getMOCTi( cId ) < 0 ) return ( -1 );
  }

#if defined (FF_WAP) || defined (FF_GPF_TCPIP) || defined (FF_SAT_E)
  /* if this call is a WAP call then set wapId to the current Call Id */
  if (Wap_Call EQ TRUE)
  {
    wapId = cId;
  }
#endif /* defined(WAP) OR defined(FF_GPF_TCPIP) */

/*
 *-------------------------------------------------------------------
 * create and send primitive
 *-------------------------------------------------------------------
 */
  {
    PALLOC (mncc_setup_req, MNCC_SETUP_REQ);

    /*
     * fill in primitive parameter: setup request
     */
    mncc_setup_req -> ti               = pCtbNtry -> ti;
    mncc_setup_req -> prio             = pCtbNtry -> prio;
    mncc_setup_req -> ri               = pCtbNtry -> rptInd;

    mncc_setup_req->called_party.ton          = pCtbNtry->cldPty.ton;
    mncc_setup_req->called_party.npi          = pCtbNtry->cldPty.npi;
    mncc_setup_req->called_party.c_called_num = pCtbNtry->cldPty.c_called_num;
    memcpy (mncc_setup_req->called_party.called_num, 
            pCtbNtry->cldPty.called_num,
            pCtbNtry->cldPty.c_called_num);

    mncc_setup_req -> called_party_sub = pCtbNtry -> cldPtySub;
    mncc_setup_req -> clir_sup         = pCtbNtry -> CLIRsup;
    memcpy( &(mncc_setup_req->bcpara),&(pCtbNtry->BC[0]), 
          sizeof( T_bcpara) ); 
    memcpy( &(mncc_setup_req->bcpara2),&(pCtbNtry->BC[1]), 
          sizeof( T_bcpara) ); 

    /*
     * fill in CUG info facility
     */
    if( !(pCtbNtry -> CUGidx EQ NOT_PRESENT_8BIT AND
          pCtbNtry -> CUGprf EQ FALSE AND
          pCtbNtry -> OAsup  EQ FALSE    ))
    {
      CCD_START;
      psaCC_asmCUGInfo( cId );

      {
        UBYTE ccdRet;

        MCAST( com, COMPONENT );

        memset( com, 0, sizeof( T_COMPONENT ));

        com -> v_inv_comp = TRUE;
        com -> inv_comp.v_inv_id  = TRUE;
        com -> inv_comp.inv_id    = pCtbNtry -> iId 
                                  = ccShrdPrm.iIdNxt++;
        com -> inv_comp.v_op_code = TRUE;
        com -> inv_comp.op_code   = pCtbNtry -> opCode
                                  = ssFIECodeBuf.buf[0];
        com -> inv_comp.v_params  = TRUE;
        com -> inv_comp.params.l_params = ssFIECodeBuf.l_buf-8;
        com -> inv_comp.params.o_params = 8;
        memcpy( com -> inv_comp.params.b_params, 
                ssFIECodeBuf.buf, ssFIECodeBuf.l_buf );

        mncc_setup_req -> fac_inf.l_fac = FACILITY_LEN<<3;
        mncc_setup_req -> fac_inf.o_fac = 0;
        ccdRet = ccd_codeMsg (CCDENT_FAC,
                              UPLINK,
                              (T_MSGBUF *) &mncc_setup_req -> fac_inf,
                              (UBYTE    *) _decodedMsg,
                              COMPONENT);

        if( ccdRet NEQ ccdOK )
        {
          TRACE_EVENT_P1("CCD Coding Error: %d",ccdRet ); 
          memset( &mncc_setup_req -> fac_inf, 0, sizeof( T_fac_inf));
        }
      }
      CCD_END;
    }
    else
    {
      memset( &mncc_setup_req -> fac_inf, 0, sizeof( T_fac_inf));
    }

    if(pCtbNtry -> calType NEQ CT_MOC_RDL)
    {
      pCtbNtry -> calType = CT_MOC;
    }
    pCtbNtry -> curBC   = 0;

    PSENDX (CC, mncc_setup_req);

    /*
     * update call status
     */
    pCtbNtry -> calStat = CS_ACT_REQ;
  }
#ifdef FF_TTY
  /* TTY notification */
  cmhCC_notifyTTY (((pCtbNtry->BC[0].bearer_serv EQ BEARER_SERV_SPEECH_CTM OR
                     pCtbNtry->BC[0].bearer_serv EQ BEARER_SERV_AUX_SPEECH_CTM)?
                    CTTY_NEG_Request: CTTY_NEG_None),
                   CTTY_TRX_Unknown);
#endif /* FF_TTY */
  if(cmhCC_atdsendok ( cId ))
  {
    R_AT( RAT_OK, pCtbNtry->curSrc ) ( pCtbNtry->curCmd );
  }

  /* start call time measurement */
  aoc_info (cId, AOC_START_TIME);

  /* Disable voice path in case this is first call */
  psaCC_setSpeechMode ();

  return 0;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_AcceptCall        |
+-------------------------------------------------------------------+
  PURPOSE : In addition to sending the setup response for an MT call
            this function enables the vocoder if the call is a voice
            call
*/

GLOBAL void psaCC_AcceptCall ( SHORT cId )
{
  T_CC_CALL_TBL * pCtbNtry;     /* holds pointer to call table entry */

  TRACE_FUNCTION ("psaCC_AcceptCall()");

  /* update call status and attach the user if not done previously */
  pCtbNtry = ccShrdPrm.ctb[cId];
  pCtbNtry -> calStat = CS_CPL_REQ;
  psaCC_setSpeechMode();
  
  /* create and send primitive */
  {
    PALLOC (mncc_setup_res, MNCC_SETUP_RES);
    mncc_setup_res -> ti = pCtbNtry -> ti;
    PSENDX (CC, mncc_setup_res);
    psaCC_send_satevent( EVENT_CALL_CONN, cId, NEAR_END, FALSE );
  }

  /* start call time measurement */
  aoc_info (cId, AOC_START_TIME);
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_ClearCall         |
+-------------------------------------------------------------------+

  PURPOSE : clear a call
*/

GLOBAL void psaCC_ClearCall ( SHORT cId )
{
  T_CC_CALL_TBL *pCtbNtry = ccShrdPrm.ctb[cId];

  TRACE_FUNCTION ("psaCC_ClearCall()");

  if (!psaCC_ctbIsValid (cId))
    return; /* Ensure we are not dereferencing NULL */

  psaCC_StopDTMF ( cId );

  /* inform advice of charge module */
  aoc_info (cId, AOC_STOP_TIME);

  /*
   *-----------------------------------------------------------------
   * relase call if in disconnect request state
   *-----------------------------------------------------------------
   */
  if( pCtbNtry -> calStat EQ CS_DSC_REQ )
  {
    PALLOC (mncc_release_req, MNCC_RELEASE_REQ);

    /* fill in primitive parameter: release request */
    mncc_release_req -> ti    = pCtbNtry -> ti;
    mncc_release_req -> cause = pCtbNtry -> nrmCs;
      
    /* fill in CCBS request facility */
    if( pCtbNtry -> CCBSstat EQ CCBSS_REQ )
    {
      CCD_START;
      {
        psaCC_asmCCBSReq( cId );
        psaCC_asmComponent( cId );
      }
      CCD_END;
      
      mncc_release_req -> fac_inf.l_fac = ssFIECodeBuf.l_buf;
      mncc_release_req -> fac_inf.o_fac = 0;
      memcpy (mncc_release_req->fac_inf.fac, 
              ssFIECodeBuf.buf + (ssFIECodeBuf.o_buf >> 3),
              ssFIECodeBuf.l_buf >> 3);

      mncc_release_req -> ss_version = SS_VERSION_3;
    }
    else
    {
      memset( &mncc_release_req -> fac_inf, 0, sizeof( T_fac_inf));
      mncc_release_req -> ss_version = SS_VER_NOT_PRES;
    }

    PSENDX (CC, mncc_release_req);

    psaCC_send_satevent( EVENT_CALL_DISC, cId, NEAR_END, TRUE );
  }

  /*
   *-----------------------------------------------------------------
   * relase call if in activate request state, network initiated
   *-----------------------------------------------------------------
   */
  else if( pCtbNtry -> calStat EQ CS_ACT_REQ AND
           pCtbNtry -> calType EQ CT_NI_MOC      )
  {
    PALLOC (mncc_reject_req, MNCC_REJECT_REQ);

    /* fill in primitive parameter: release request */
    mncc_reject_req -> ti    = pCtbNtry -> ti;
    mncc_reject_req -> cause = pCtbNtry -> nrmCs;

    PSENDX (CC, mncc_reject_req);

    /* free call table entry */
    psaCC_retMOCTi( pCtbNtry -> ti );

    psaCC_FreeCtbNtry (cId);
  }
      
  /*
   *-----------------------------------------------------------------
   * disconnect all other calls
   *-----------------------------------------------------------------
   */
  else
  {
    PALLOC (disc_req, MNCC_DISCONNECT_REQ); /* T_MNCC_DISCONNECT_REQ */
    disc_req -> ti    = pCtbNtry -> ti;
    disc_req -> cause = pCtbNtry -> nrmCs;
    if (pCtbNtry -> curCmd EQ AT_CMD_CTFR)
    {
      /* We expect here an already built facility in ssFIECodeBuf */
      disc_req -> fac_inf.l_fac = ssFIECodeBuf.l_buf;
      disc_req -> fac_inf.o_fac = 0;
      memcpy (disc_req->fac_inf.fac, 
              ssFIECodeBuf.buf, 
              ssFIECodeBuf.l_buf >> 3);
      disc_req -> ss_version = SS_VERSION_2;
    }
    else
    {
      disc_req -> fac_inf.l_fac = 0;
      disc_req -> ss_version    = SS_VER_NOT_PRES;
    }
    PSENDX (CC, disc_req);

    /* update call status */
    pCtbNtry -> calStat = CS_DSC_REQ;

    /* monitoring for SAT */
    psaCC_send_satevent( EVENT_CALL_DISC, cId , NEAR_END, TRUE );
  }

  /* Switch off audio path after user action (e.g. hangup) */
/* clb this breaks ACI056 (among others..) necessary ??  pCtbNtry -> inBndTns = FALSE; */
  psaCC_setSpeechMode ();
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_HoldCall          |
+-------------------------------------------------------------------+

  PURPOSE : put a call into hold state

*/

GLOBAL void psaCC_HoldCall ( SHORT cId )
{
  T_CC_CALL_TBL *pCtbNtry = ccShrdPrm.ctb[cId];

  TRACE_FUNCTION ("psaCC_HoldCall()");

  if (pCtbNtry EQ NULL)
    return; /* Ensure not to dereference NULL */

/*
 *-------------------------------------------------------------------
 * create and send primitive
 *-------------------------------------------------------------------
 */
  psaCC_StopDTMF ( cId );

  {
    PALLOC (mncc_hold_req, MNCC_HOLD_REQ);

    /*
     * fill in primitive parameter: hold request
     */

    mncc_hold_req -> ti = pCtbNtry -> ti;
      
    PSENDX (CC, mncc_hold_req);

    /* update call status */
    pCtbNtry -> calStat = CS_HLD_REQ;

  }
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_RetrieveCall      |
+-------------------------------------------------------------------+

  PURPOSE : retrieve a held call

*/

GLOBAL void psaCC_RetrieveCall ( SHORT cId )
{
  T_CC_CALL_TBL *pCtbNtry = ccShrdPrm.ctb[cId];

  TRACE_FUNCTION ("psaCC_RetrieveCall()");

/*
 *-------------------------------------------------------------------
 * create and send primitive
 *-------------------------------------------------------------------
 */
  {
    PALLOC (mncc_retrieve_req, MNCC_RETRIEVE_REQ);

    /*
     * fill in primitive parameter: retrieve request
     */

    mncc_retrieve_req -> ti = pCtbNtry -> ti;
      
    PSENDX (CC, mncc_retrieve_req);

    /*
     * update call status   ???
     */
  }
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_ModifyCall        |
+-------------------------------------------------------------------+

  PURPOSE : modify an active call 

*/

GLOBAL SHORT psaCC_ModifyCall ( SHORT cId )
{
  T_CC_CALL_TBL *pCtbNtry = ccShrdPrm.ctb[cId];
  UBYTE nomBC;                  /* holds nominal bearer capabilities */

  TRACE_FUNCTION ("psaCC_ModifyCall()");

  if (pCtbNtry EQ NULL)
    return -1;

/*
 *-------------------------------------------------------------------
 * check if call is in a active state
 *-------------------------------------------------------------------
 */
 if(
     (pCtbNtry -> calStat NEQ CS_ACT)     AND
     (pCtbNtry -> calStat NEQ CS_ACT_REQ)
   )
   return( -1 );
/*
 *-------------------------------------------------------------------
 * create and send primitive
 *-------------------------------------------------------------------
 */
  psaCC_StopDTMF ( cId );
  {
    PALLOC (mncc_modify_req, MNCC_MODIFY_REQ);

    /*
     * fill in primitive parameter: modify request
     */
    nomBC = (pCtbNtry -> curBC)?0:1;

    switch( pCtbNtry -> BC[nomBC].bearer_serv )
    {
    case( BEARER_SERV_AUX_SPEECH    ):
    case( BEARER_SERV_SPEECH        ):
    case( BEARER_SERV_AUX_SPEECH_CTM):
    case( BEARER_SERV_SPEECH_CTM    ):
      mncc_modify_req -> serv = SERV_SPEECH;
      break;

    case( BEARER_SERV_FAX           ):
    case( BEARER_SERV_ASYNC         ):
    case( BEARER_SERV_SYNC          ):
    case( BEARER_SERV_PAD_ACCESS    ):
    case( BEARER_SERV_PACKET_ACCESS ):
      mncc_modify_req -> serv = SERV_DATA;

      /* check for TTY service */
      cmhCC_TTY_Control ( cId, TTY_PAUSE );
      break;

    default:
      mncc_modify_req -> serv = SERV_NOT_PRES;
    }
    mncc_modify_req ->   ti = pCtbNtry -> ti;

    PSENDX (CC, mncc_modify_req);

    /*
     * update call status
     */
    pCtbNtry -> calStat = CS_MDF_REQ;
  }
  return 0;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_SendDTMF          |
+-------------------------------------------------------------------+

  PURPOSE : send DTMF tones

*/

GLOBAL SHORT psaCC_SendDTMF ( SHORT cId,
                              UBYTE digit,
                              UBYTE mode )
{

  TRACE_FUNCTION ("psaCC_SendDTMF()");

  if (ccShrdPrm.ctb[cId] EQ NULL)
    return -1; /* Ensure not to dereference NULL */

/*
 *-------------------------------------------------------------------
 * create and send primitive
 *-------------------------------------------------------------------
 */
  {
    PALLOC (mncc_start_dtmf_req, MNCC_START_DTMF_REQ);

    /*
     * fill in primitive parameter: DTMF tone request
     */

    mncc_start_dtmf_req -> ti       = psaCC_ctb(cId)->ti;
    mncc_start_dtmf_req -> key      = digit;
    mncc_start_dtmf_req -> dtmf_mod = mode;
      
    PSENDX (CC, mncc_start_dtmf_req);
  }

  return 0;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_Config            |
+-------------------------------------------------------------------+
  PURPOSE : configure CC entity
*/

GLOBAL void psaCC_Config ( void )
{
  T_bcpara *mtcBC;

  TRACE_FUNCTION ("psaCC_Config()");

  /* create and send primitive */
  {
    PALLOC (mncc_configure_req, MNCC_CONFIGURE_REQ);

    /* fill in primitive parameter: configure request */
    memset(&(mncc_configure_req -> called_party_sub), 0,
            sizeof(T_called_party_sub));

    /* MTC bearer caps */
    mtcBC = &mncc_configure_req -> bcpara;
    mtcBC->rate = cmhCC_SelRate( ccShrdPrm.CBSTspeed );

    if( ccShrdPrm.snsMode EQ CSNS_MOD_Fax      OR
        ccShrdPrm.snsMode EQ CSNS_MOD_VAFVoice OR
        ccShrdPrm.snsMode EQ CSNS_MOD_VAFFax )
    {
      mtcBC->bearer_serv = BEARER_SERV_FAX;
      mtcBC->modem_type  = MT_NONE;
      mtcBC->conn_elem   = CONN_ELEM_TRANS;
    }
    else
    {
      mtcBC->bearer_serv = cmhCC_SelServ( ccShrdPrm.CBSTname );
      mtcBC->modem_type  = cmhCC_SelMT  ( ccShrdPrm.CBSTspeed );
      mtcBC->conn_elem   = cmhCC_SelCE  ( ccShrdPrm.CBSTce );
    }

    /* not sure whether this is taken into account by CC */
    mtcBC->stop_bits   = DEF_BC1_SB; /*cmhCC_SelStopBit( srcId );*/
    mtcBC->data_bits   = DEF_BC1_DB; /*cmhCC_SelDataBit( srcId );*/
    mtcBC->parity      = DEF_BC1_PR; /*cmhCC_SelParity ( srcId );*/
    mtcBC->flow_control = DEF_BC1_FC;
    /*****************************************************/

/*    mncc_configure_req -> bcpara   = *mtcBC; superfluous */
    mncc_configure_req -> sns_mode = ccShrdPrm.snsMode;
#ifdef FF_TTY
    mncc_configure_req -> ctm_ena = ccShrdPrm.ctmReq;
#else
    mncc_configure_req -> ctm_ena = CTM_DISABLED;
#endif /* FF_TTY */
    PSENDX (CC, mncc_configure_req);
  }
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_SendSS            |
+-------------------------------------------------------------------+

  PURPOSE : send SS facility

*/

LOCAL SHORT psaCC_SendSS ( SHORT cId )
{
  T_CC_CALL_TBL *pCtbNtry = ccShrdPrm.ctb[cId];
  UBYTE           ccdRet;       /* holds CCD return value */

  TRACE_FUNCTION ("psaCC_SendSS()");

  if (pCtbNtry EQ NULL)
    return -1; /* Ensure not to dereference NULL */

/*
 *-------------------------------------------------------------------
 * create and send primitive
 *-------------------------------------------------------------------
 */
  {
    PALLOC (mncc_facility_req, MNCC_FACILITY_REQ);

    /*
     * fill in primitive parameter: facility request
     */

    mncc_facility_req -> ti          = pCtbNtry -> ti;
    mncc_facility_req -> ss_version  = pCtbNtry -> SSver;

    CCD_START;
    {
      MCAST( com, COMPONENT );

      memset( com, 0, sizeof( T_COMPONENT ));
      switch( ccShrdPrm.cmpType )
      {
        case( CT_INV ):
          com -> v_inv_comp = TRUE;
          com -> inv_comp.v_inv_id  = TRUE;
          com -> inv_comp.inv_id    = pCtbNtry -> iId 
                                    = ccShrdPrm.iIdNxt++;
          com -> inv_comp.v_op_code = TRUE;
          com -> inv_comp.op_code   = pCtbNtry -> opCode
                                    = ssFIECodeBuf.buf[0];
          com -> inv_comp.v_params  = TRUE;
          com -> inv_comp.params.l_params = ssFIECodeBuf.l_buf-8;
          com -> inv_comp.params.o_params = 8;
          memcpy( com -> inv_comp.params.b_params, 
                  ssFIECodeBuf.buf, ssFIECodeBuf.l_buf );
          break;
        case( CT_RET_RSLT ):
          break;
        case( CT_RET_ERR ):
          break;
        case( CT_RET_REJ ):
          break;
      }
      mncc_facility_req -> fac_inf.l_fac = FACILITY_LEN<<3;
      mncc_facility_req -> fac_inf.o_fac = 0;
      ccdRet = ccd_codeMsg (CCDENT_FAC,
                            UPLINK,
                            (T_MSGBUF *) &mncc_facility_req -> fac_inf,
                            (UBYTE    *) _decodedMsg,
                            COMPONENT);

      if( ccdRet NEQ ccdOK )
      {
        TRACE_EVENT_P1( "CCD Coding Error: %d",ccdRet ); 
        PFREE( mncc_facility_req );
        CCD_END;
        return( -1 );
      }
    }
    CCD_END;

    pCtbNtry -> srvType = ST_MOS;

    psaCC_DumpFIE ( &mncc_facility_req -> fac_inf );
    cmhCC_sendFie ( CSCN_FACILITY_DIRECTION_OUT,
                    cId,
                    &mncc_facility_req -> fac_inf );
    
    PSENDX (CC, mncc_facility_req);
  }

  return 0;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_BuildMPTY         |
+-------------------------------------------------------------------+

  PURPOSE : build multiparty

*/

GLOBAL void psaCC_BuildMPTY ( SHORT cId )
{
  SHORT ctbIdx;     /* holds call table index */

  TRACE_FUNCTION ("psaCC_BuildMPTY()");

/*
 *-------------------------------------------------------------------
 * set multiparty status for held calls
 *-------------------------------------------------------------------
 */
  for( ctbIdx = 0; ctbIdx < MAX_CALL_NR; ctbIdx++ )
  {
    if (ccShrdPrm.ctb[ctbIdx] NEQ NULL AND
        psaCC_ctb(ctbIdx)->calStat EQ CS_HLD )
    {
      if( psaCC_ctb(ctbIdx)->mptyStat NEQ CS_ACT )
      
        psaCC_ctb(ctbIdx)->mptyStat = CS_ACT_REQ;
    }
  }

  /* set multiparty status for active call */
  if( psaCC_ctb(cId)->mptyStat NEQ CS_ACT )
    psaCC_ctb(cId)->mptyStat = CS_ACT_REQ;

/*
 *-------------------------------------------------------------------
 * send facility information element
 *-------------------------------------------------------------------
 */
  psaCC_asmBuildMPTY();

  if( psaCC_SendSS(cId) EQ 0 )
  {
    ccShrdPrm.cIdMPTY = cId;
    TIMERSTART( TMPTY_VALUE, ACI_TMPTY );
  }
    
  psaCC_MPTY (cId, MPTY_BUILD_SENT);
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_HoldMPTY          |
+-------------------------------------------------------------------+

  PURPOSE : hold multiparty

*/

GLOBAL void psaCC_HoldMPTY ( SHORT cId )
{
  SHORT ctbIdx;     /* holds call table index */

  TRACE_FUNCTION ("psaCC_HoldMPTY()");

/*
 *-------------------------------------------------------------------
 * set call status for multiparty members
 *-------------------------------------------------------------------
 */
  for( ctbIdx = 0; ctbIdx < MAX_CALL_NR; ctbIdx++ )
  {
    if (ccShrdPrm.ctb[ctbIdx] NEQ NULL AND
        psaCC_ctb(ctbIdx)->calStat  EQ CS_ACT AND 
        psaCC_ctb(ctbIdx)->mptyStat EQ CS_ACT)
    {
      psaCC_ctb(ctbIdx)->calStat = CS_HLD_REQ;
    }
  }

  /* set multiparty status for active call */
  psaCC_ctb(cId)->calStat = CS_HLD_REQ;

/*
 *-------------------------------------------------------------------
 * send facility information element
 *-------------------------------------------------------------------
 */
  psaCC_asmHoldMPTY();

  if( psaCC_SendSS(cId) EQ 0 )
  {
    ccShrdPrm.cIdMPTY = cId;
    TIMERSTART( TMPTY_VALUE, ACI_TMPTY );
  }

  psaCC_MPTY (cId, MPTY_HOLD_SENT);
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_RetrieveMPTY      |
+-------------------------------------------------------------------+

  PURPOSE : retrieve multiparty

*/

GLOBAL void psaCC_RetrieveMPTY ( SHORT cId )
{
  SHORT ctbIdx;     /* holds call table index */

  TRACE_FUNCTION ("psaCC_RetrieveMPTY()");

/*
 *-------------------------------------------------------------------
 * set call status for multiparty members
 *-------------------------------------------------------------------
 */
  for( ctbIdx = 0; ctbIdx < MAX_CALL_NR; ctbIdx++ )
  {
    if (ccShrdPrm.ctb[ctbIdx] NEQ NULL AND
        psaCC_ctb(ctbIdx)->calStat  EQ CS_HLD AND 
        psaCC_ctb(ctbIdx)->mptyStat EQ CS_ACT)
    {
      psaCC_ctb(ctbIdx)->calStat = CS_ACT_REQ;
    }
  }

  /* set multiparty status for active call */
  psaCC_ctb(cId)->calStat = CS_ACT_REQ;

/*
 *-------------------------------------------------------------------
 * send facility information element
 *-------------------------------------------------------------------
 */
  psaCC_asmRetrieveMPTY();

  if( psaCC_SendSS(cId) EQ 0 )
  {
    ccShrdPrm.cIdMPTY = cId;
    TIMERSTART( TMPTY_VALUE, ACI_TMPTY );
  }

  psaCC_MPTY (cId, MPTY_RETRIEVE_SENT);

  return;
}



/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_CountMPTY         |
+-------------------------------------------------------------------+

  PURPOSE : counts the number of parties in a MPTY

*/

GLOBAL int psaCC_CountMPTY ( void )
{
  int i = 0;
  SHORT cId;
  TRACE_FUNCTION ("psaCC_CountMPTY()");
  
  for( cId = 0; cId < MAX_CALL_NR; cId++ )
  {
    if (ccShrdPrm.ctb[cId] NEQ NULL AND
        psaCC_ctb(cId)->mptyStat EQ CS_ACT)
    {
      i++;
    }
  }
  return i;
}



/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_SplitMPTY         |
+-------------------------------------------------------------------+

  PURPOSE : split multiparty

*/

GLOBAL void psaCC_SplitMPTY ( SHORT cId )
{
  TRACE_FUNCTION ("psaCC_SplitMPTY()");

  /* set multiparty status for active call */
  psaCC_ctb(cId)->mptyStat = CS_DSC_REQ;

/*
 *-------------------------------------------------------------------
 * send facility information element
 *-------------------------------------------------------------------
 */
  psaCC_asmSplitMPTY();

  if( psaCC_SendSS(cId) EQ 0 )
  {
    ccShrdPrm.cIdMPTY = cId;
    TIMERSTART( TMPTY_VALUE, ACI_TMPTY );
  }

  psaCC_MPTY (cId, MPTY_SPLIT_SENT);
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_ECT               |
+-------------------------------------------------------------------+

  PURPOSE : explicit call transfer

*/

GLOBAL SHORT psaCC_ECT ( SHORT cId )
{
  SHORT psa_ret;
  
  TRACE_FUNCTION ("psaCC_ECT()");

/*
 *-------------------------------------------------------------------
 * send facility information element
 *-------------------------------------------------------------------
 */
  psaCC_asmECT();

  psa_ret = psaCC_SendSS(cId);
    
  if( psa_ret EQ 0 )
  {
    TIMERSTART( TECT_VALUE, ACI_TECT );
  }
 
  return(psa_ret);
}

#if 0 /* HM 3-May-2005: This function is not used, but it's still planned for some day */
/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_BCapCode          |
+-------------------------------------------------------------------+

  PURPOSE : code bearer capabilites according GSM 04.08

*/

GLOBAL SHORT psaCC_BCapCode ( UBYTE reqId, SHORT cId, UBYTE bc )
{
  TRACE_FUNCTION ("psaCC_BCapCode()");

/*
 *-------------------------------------------------------------------
 * create and send primitive
 *-------------------------------------------------------------------
 */
  {
    PALLOC (mncc_bearer_cap_req, MNCC_BEARER_CAP_REQ);

    /*
     * fill in primitive parameter: bearer capability coding request
     */
    mncc_bearer_cap_req -> req_id = reqId;
    mncc_bearer_cap_req -> bc_mod = BC_MOD_CODE;
    mncc_bearer_cap_req -> bcpara = psaCC_ctb(cId)->BC[bc];

    PSENDX (CC, mncc_bearer_cap_req);
  }

  return 0;
}
#endif /* #if 0 */

#if 0 /* HM 3-May-2005: This function is not used, but it's still planned for some day */
/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_BCapDecode        |
+-------------------------------------------------------------------+

  PURPOSE : decode bearer cpabilities according GSM 04.08 into struct
            bcpara.

*/

GLOBAL SHORT psaCC_BCapDecode ( UBYTE reqId, UBYTE bcLen, UBYTE *bc )
{
  TRACE_FUNCTION ("psaCC_BCapDecode()");

/*
 *-------------------------------------------------------------------
 * create and send primitive
 *-------------------------------------------------------------------
 */
  if( bcLen > MAX_BC_LEN ) return -1;

  {
    PALLOC (mncc_bearer_cap_req, MNCC_BEARER_CAP_REQ);

    /*
     * fill in primitive parameter: bearer capability decoding request
     */
    mncc_bearer_cap_req -> req_id        = reqId;
    mncc_bearer_cap_req -> bc_mod        = BC_MOD_DECODE;
    mncc_bearer_cap_req -> bcconf.bc_len = bcLen;

    memcpy( mncc_bearer_cap_req -> bcconf.bc, bc, bcLen );

    PSENDX (CC, mncc_bearer_cap_req);
  }

  return 0;
}
#endif /* #if 0 */


/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : PSA_CCS                 |
|                                 ROUTINE : psaCC_MPTY              |
+-------------------------------------------------------------------+

  PURPOSE : Inform CC about an event related to a multiparty call
            which may change the auxiliary state hold or mpty in CC.

*/

GLOBAL SHORT psaCC_MPTY ( SHORT cId, UBYTE mpty_event )
{
  TRACE_FUNCTION ("psaCC_MPTY()");
  
  /* Send the synchronization request to CC */
  {
    PALLOC (mncc_sync_req, MNCC_SYNC_REQ); /* T_MNCC_SYNC_REQ */
    mncc_sync_req->synccs     = SYNCCS_MPTY_EVENT;
    mncc_sync_req->ti         = psaCC_ctb(cId)->ti;
    mncc_sync_req->mpty_event = mpty_event;
    PSENDX (CC, mncc_sync_req);
  }
  return 0;
}

/*==== EOF ========================================================*/