view src/aci2/aci/dti_cntrl_mng.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 :  ...
|  Modul   :  dti_cntrl_mng.c
+-----------------------------------------------------------------------------
|  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 ...
+-----------------------------------------------------------------------------
*/

#ifdef DTI

#ifndef DTI_CNTRL_MNG_C
#define DTI_CNTRL_MNG_C
#endif

#ifdef MFW
#define ENTITY_MFW
#else
#ifdef SMI
#define ENTITY_SMI
#else
#define ENTITY_ACI
#endif
#endif

#define ACI_MEMBER

#include "aci_all.h"

#include "dti.h"      /* functionality of the dti library */
#include "aci.h"
#include "aci_cmh.h"
#include "ati_cmd.h"
#include "aci_io.h"

#include "aci_cmh.h"
#include "aci_mem.h"
#include "aci_lst.h"

#include "dti_conn_mng.h"
#include "cmh_dti.h"

#ifdef FAX_AND_DATA
#include "aci_fd.h"
#include "psa.h"
#include "psa_l2r.h"
#include "cmh.h"
#include "cmh_ra.h"
#include "cmh_l2r.h"

#ifdef FF_FAX
#include "psa_t30.h"
#include "psa_tra.h"
#endif

#else

#include "psa.h"
#include "cmh.h"

#endif /* #ifdef FAX_AND_DATA */

#include "psa_aaa.h"

#if defined (GPRS) AND defined (UART)
#include "gaci.h"
#include "gaci_cmh.h"
#include "pcm.h"
#include "psa_gmm.h"
#include "cmh_gmm.h"
#include "psa_sm.h"
#include "cmh_sm.h"
#include "psa_gppp.h"
#include "cmh_gppp.h"
#ifdef FF_PKTIO
#include "psa_pktio.h"
#endif
#endif /* GPRS */

#if defined (FF_WAP) || defined (GPRS) || defined (FF_SAT_E)
#include "gaci.h"
#include "gaci_cmh.h"
#include "psa_sm.h"
#include "cmh_sm.h"
#endif

#if defined (FF_WAP) || defined (FF_TCP_IP) || defined (FF_GPF_TCPIP) || defined (FF_SAT_E)
#include "psa_ppp_w.h"
#include "wap_aci.h"
#endif /* WAP or FF_TCP_IP */

#ifdef UART
#include "dti_cntrl_mng.h"
#include "psa_uart.h"
#include "ati_src_uart.h"
#endif
#ifdef FF_PSI
#include "psa_psi.h"
#endif
#include "sap_dti.h"

#ifdef SIM_TOOLKIT
#include "psa.h"
#include "psa_sim.h"
#endif

 extern void psaTCPIP_Dti_Req(T_DTI_CONN_LINK_ID dti_id, 
                             UBYTE peer_to_connect_to, UBYTE dti_conn);
/*
 * list for devices maintained by DTI Control Manager
 */
LOCAL T_ACI_LIST *dti_cntrl_list = NULL;
/* static pointer to manage output of dti_cntrl_list  elements */
static const T_ACI_LIST  *dti_cntrl_dev_ptr = NULL;
/*
 * a customer can install up to 3 own entities involved in data transmission
 * every customer entity has its own call back function, noted in this array
 */
LOCAL T_DTI_CNTRL_REGISTERED_EXT_CB reg_ext_cb[DTI_MAX_EXT_CB] =
{
  {DTI_DTI_ID_NOTPRESENT, NULL},
  {DTI_DTI_ID_NOTPRESENT, NULL},
  {DTI_DTI_ID_NOTPRESENT, NULL}
};


/*
 * reuse of the global variable g_cur_cap due to the fact that the
 * function dti_cntrl_est_dpath_indirect() is (always) called with the
 * SPLIT mode, which means that there is the calling of
 * dti_cntrl_entity_disconnected() which causes to reset the current
 * capability and then there is the calling of dti_cntrl_entity_connected()
 * and here we need the capability given in dti_cntrl_est_dpath_indirect()
 */
UBYTE g_cur_cap;

/* bit set for DTI ID which should be reconnected to ACI */
ULONG dti_cntrl_reconnect_to_aci;

/*********************** LOCAL FUNCTIONS *****************************/

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : DTI_CNTRL               |
| STATE   : code                   ROUTINE : dti_cntrl_search_dev_id |
+--------------------------------------------------------------------+

  PURPOSE : help function for
            find_element_by_tupel (dti_cntrl_list, dev_id, dev_no, sub_no, dti_cntrl_search_dev_id);
*/
LOCAL BOOL dti_cntrl_search_dev_id (T_DTI_ENTITY_ID dev_id, UBYTE dev_no, UBYTE sub_no, void *elem)
{
  T_DTI_CNTRL *compared = (T_DTI_CNTRL *)elem;

  if (compared NEQ NULL)
    if (compared->dev_id EQ dev_id)
      if (compared->dev_no EQ dev_no)
        if (compared->sub_no EQ sub_no
#ifdef _SIMULATION_

OR 0 EQ sub_no AND 255 EQ compared->sub_no

#endif    
          )
          return (TRUE);
  return (FALSE);
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)           MODULE  : DTI_CNTRL             |
| STATE   : code                     ROUTINE : find_element_by_tupel |
+--------------------------------------------------------------------+

  PURPOSE : find element in dti_cntrl_list
*/
typedef BOOL  T_LIST_HELP_FCT (T_DTI_ENTITY_ID criterium1, UBYTE criterium2, UBYTE criterium3, void *elem);

LOCAL void *find_element_by_tupel (T_ACI_LIST         *search_list,
                                   T_DTI_ENTITY_ID     criterium1,
                                   UBYTE               criterium2,
                                   UBYTE               criterium3,
                                   T_LIST_HELP_FCT     test_criterium)
{
  T_ACI_LIST *current = NULL;

  if ((search_list EQ NULL) OR (search_list->msg EQ NULL))
  {
    return (NULL);
  }

  current = search_list;

  do
  {
    if (current->msg NEQ NULL)
    {
      if (test_criterium (criterium1, criterium2, criterium3, current->msg))
      {
        return (current->msg);
      }
      else
      {
        current = current->next;
      }
    }
  }while (current NEQ NULL);

  return (NULL);
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : DTI_CNTRL               |
| STATE   : code                   ROUTINE : dti_cntrl_call_reg_fct  |
+--------------------------------------------------------------------+

  PURPOSE : this function is called by dti_cntrl_maintain_entity(),
            which is a call back function used by the DTI Connection
            Manager, in such a case, where a customer installed its
            own entity involved during data transmission
*/
LOCAL BOOL dti_cntrl_call_reg_fct( T_DTI_ENTITY_ID    entity_id,
                                   T_DTI_CONN_LINK_ID link_id,
                                   T_DTI_ENTITY_ID    peer_entity_id,
                                   UBYTE              dti_conn )
{
  UBYTE i = 0;

  TRACE_FUNCTION("dti_cntrl_call_reg_fct()");

  for (i=0; i<DTI_MAX_EXT_CB; ++i)
  {
    if (reg_ext_cb[i].ent_id EQ entity_id)
    {
      if (reg_ext_cb[i].fct)
      {
        return (reg_ext_cb[i].fct(link_id, peer_entity_id, dti_conn));
      }
    }
  }
  return (FALSE);
}

/*
+------------------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : DTI_CNTRL                         |
| STATE   : code                   ROUTINE : dti_cntrl_set_redirection         |
+------------------------------------------------------------------------------+

  PURPOSE : sub function of dti_cntrl_set_redirect_from_src and
                            dti_cntrl_set_redirect_from_device
*/
LOCAL BOOL dti_cntrl_set_redirection (T_DTI_CNTRL *dti_cntrl_dev,
                                      T_DTI_CNTRL *indirect_dev,
                                      UBYTE        mode,
                                      UBYTE        capability,
                                      UBYTE        cid)
{
  TRACE_FUNCTION("dti_cntrl_set_redirection()");

  switch (capability)
  {
    case (DTI_CPBLTY_PKT):
    {
      if (mode EQ DTI_MODE_DELETE)
      {
        dti_cntrl_dev->redirect_info.tbl->pkt_redirect[cid].mode        = DTI_MODE_NIL;
        dti_cntrl_dev->redirect_info.tbl->pkt_redirect[cid].redirection = NULL;
      }
      else
      {
        dti_cntrl_dev->redirect_info.tbl->pkt_redirect[cid].mode        = mode;
        dti_cntrl_dev->redirect_info.tbl->pkt_redirect[cid].redirection = indirect_dev;
      }
      break;
    }
    case (DTI_CPBLTY_SER):
    {
      if (mode EQ DTI_MODE_DELETE)
      {
        dti_cntrl_dev->redirect_info.tbl->ser_redirect[cid].mode        = DTI_MODE_NIL;
        dti_cntrl_dev->redirect_info.tbl->ser_redirect[cid].redirection = NULL;
      }
      else
      {
        dti_cntrl_dev->redirect_info.tbl->ser_redirect[cid].mode        = mode;
        dti_cntrl_dev->redirect_info.tbl->ser_redirect[cid].redirection = indirect_dev;
      }
      break;
    }
    default:
    {
      TRACE_EVENT("given capability is not SER or PKT");
      return (FALSE);
    }
  }
  return (TRUE);
}

/*
+------------------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : DTI_CNTRL                         |
| STATE   : code                   ROUTINE : dti_cntrl_get_redirection         |
+------------------------------------------------------------------------------+

  PURPOSE : sub function of dti_cntrl_get_first_redirection and
                            dti_cntrl_get_next_redirection
*/
LOCAL BOOL dti_cntrl_get_redirection (T_DTI_CNTRL *dti_cntrl_dev,
                                      T_DTI_CNTRL *indirection,  /* out parameter */
                                      UBYTE        cid,
                                      UBYTE        capability)
{
  UBYTE mode = DTI_MODE_NIL; /* remember temporary */

  TRACE_FUNCTION("dti_cntrl_get_redirection()");

  switch (capability)
  {
    case (DTI_CPBLTY_PKT):
    {
      for (cid += 1; cid<DTI_MAX_REDIRECTIONS; cid++) /* watch the start value */
      {
        if (dti_cntrl_dev->redirect_info.tbl->pkt_redirect[cid].redirection)
        {
          mode = dti_cntrl_dev->redirect_info.tbl->pkt_redirect[cid].mode;
          /*
           * set the pointer to the redirected device for packet data transmission
           */
          dti_cntrl_dev = dti_cntrl_dev->redirect_info.tbl->pkt_redirect[cid].redirection;
          break; 
        }
      }
      break;
    }
    case (DTI_CPBLTY_SER):
    {
      for (cid += 1; cid<DTI_MAX_REDIRECTIONS; cid++) /* watch the start value */
      {
        if (dti_cntrl_dev->redirect_info.tbl->ser_redirect[cid].redirection)
        {
          mode = dti_cntrl_dev->redirect_info.tbl->ser_redirect[cid].mode;
          /*
           * set the pointer to the redirected device for serial data transmission
           */
          dti_cntrl_dev = dti_cntrl_dev->redirect_info.tbl->ser_redirect[cid].redirection;
          break;
        }
      }
      break;
    }
    default:
    {
      TRACE_EVENT("given capability is not SER or PKT");
      indirection = NULL; /* make it invalid */
      return (FALSE);
    }
  }

  if (cid >= DTI_MAX_REDIRECTIONS)
  {
    indirection = NULL; /* there is no further redirection */
  }
  else
  {
    /*
     * fill the out parameter
     */
    indirection->dev_id        = dti_cntrl_dev->dev_id;
    indirection->dev_no        = dti_cntrl_dev->dev_no;
    indirection->sub_no        = dti_cntrl_dev->sub_no;
    indirection->capability    = dti_cntrl_dev->capability;
    indirection->src_id        = dti_cntrl_dev->src_id;
    indirection->dti_id        = dti_cntrl_dev->dti_id;
    indirection->port_number   = dti_cntrl_dev->port_number;
    indirection->cur_cap       = dti_cntrl_dev->cur_cap;
    /*
     * ! important ! with >>DTI_DEV_I_AM_THE_ONE<< we indicate that the
     * redirect_info is now _actually_ the info about this device
     */
    indirection->redirect_info.info.cid        = cid;
    indirection->redirect_info.info.mode       = mode;
    indirection->redirect_info.info.capability = capability;
    indirection->redirect_info.info.direction  = DTI_DEV_I_AM_THE_ONE;
  }
  return (TRUE);
}

/*
+------------------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : DTI_CNTRL                         |
| STATE   : code                   ROUTINE : dti_cntrl_get_info                |
+------------------------------------------------------------------------------+

  PURPOSE : sub function of the three functions
            dti_cntrl_get_info_from_src_id
            dti_cntrl_get_info_from_dti_id
            dti_cntrl_get_info_from_dev_id
*/
LOCAL BOOL dti_cntrl_get_info (T_DTI_CNTRL  *info, /* out parameter */
                               T_DTI_CNTRL  *dti_cntrl_dev)
{
  UBYTE  i  = 0;

  TRACE_FUNCTION("dti_cntrl_get_info()");

  info->dev_id        = dti_cntrl_dev->dev_id;
  info->dev_no        = dti_cntrl_dev->dev_no;
  info->sub_no        = dti_cntrl_dev->sub_no;
  info->capability    = dti_cntrl_dev->capability;
  info->src_id        = dti_cntrl_dev->src_id;
  info->dti_id        = dti_cntrl_dev->dti_id;
  info->port_number   = dti_cntrl_dev->port_number;
  info->cur_cap       = dti_cntrl_dev->cur_cap;
  info->driver_id     = dti_cntrl_dev->driver_id;
  info->dio_ctrl_id   = dti_cntrl_dev->dio_ctrl_id;
  /*
   * init a possible indirection info with default values ( all 0xFF )
   */
  info->redirect_info.info.cid        = DTI_CID_NOTPRESENT;
  info->redirect_info.info.mode       = DTI_MODE_NIL;
  info->redirect_info.info.capability = DTI_CPBLTY_NO;
  info->redirect_info.info.direction  = DTI_DIRECTION_NOTPRESENT;
  /*
   * search, whether there is a redirection, start with packet device
   */
  for (i=0; i<DTI_MAX_REDIRECTIONS; i++)
  {
    if (dti_cntrl_dev->redirect_info.tbl->pkt_redirect[i].redirection)
    {
      break;
    }
  }
  if (i < DTI_MAX_REDIRECTIONS)
  {
    info->redirect_info.info.cid        = i;
    info->redirect_info.info.mode       = dti_cntrl_dev->redirect_info.tbl->pkt_redirect[i].mode;
    info->redirect_info.info.capability = DTI_CPBLTY_PKT;
    info->redirect_info.info.direction  = DTI_DEV_IS_REDIRECTED;
  }
  /*
   * there is no redirection to a packet device, so search for redirection to a serial device
   */
  for (i=0; i<DTI_MAX_REDIRECTIONS; i++)
  {
    if (dti_cntrl_dev->redirect_info.tbl->ser_redirect[i].redirection)
    {
      break;
    }
  }
  if (i < DTI_MAX_REDIRECTIONS)
  {
    info->redirect_info.info.cid        = i;
    info->redirect_info.info.mode       = dti_cntrl_dev->redirect_info.tbl->ser_redirect[i].mode;
    info->redirect_info.info.capability = DTI_CPBLTY_SER;
    info->redirect_info.info.direction  = DTI_DEV_IS_REDIRECTED;
  }
  return (TRUE);
}


/*
+------------------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : DTI_CNTRL                         |
| STATE   : code                   ROUTINE : dti_cntrl_maintain_entity_connect |
+------------------------------------------------------------------------------+

  PURPOSE : sub function of dti_cntrl_maintain_entity, called when the DTI
            Connection Manager wants to connect entites for data transmission

*/
LOCAL BOOL dti_cntrl_maintain_entity_connect ( T_DTI_CONN_LINK_ID  link_id,
                                               T_DTI_ENTITY_ID     cur_ent_id,
                                               T_DTI_ENTITY_ID     peer_ent_id,
                                               UBYTE               dti_conn)
{
  TRACE_FUNCTION("dti_cntrl_maintain_entity_connect()");

#ifdef FF_TCP_IP
  /* If the peer entity is AAA, delay the connect request until AAA has
   * responded to the AAA_DTI_IND. ati_src_riv_dti_rsp() calls
   * dti_cntrl_connect_after_aaa_dti_rsp(), which in turn calls this function,
   * on receiving the response. */
  {
    if (peer_ent_id EQ DTI_ENTITY_AAA)
    {
      T_DTI_CNTRL *dti_cntrl_dev; /* Information about DTI link. */
      UBYTE dti_id ;              /* DTI id of this connection. */

      dti_id = EXTRACT_DTI_ID(link_id) ;
      dti_cntrl_dev = (T_DTI_CNTRL *) find_element (dti_cntrl_list, dti_id,
                                                    dti_cntrl_search_dti_id) ;
      if (!dti_cntrl_dev->had_aaa_dti_rsp)
      {
        dti_cntrl_dev->save_link_id = link_id ;
        dti_cntrl_dev->save_cur_ent_id = cur_ent_id ;
        dti_cntrl_dev->save_dti_conn = dti_conn ;
        return TRUE ;
      }
      dti_cntrl_dev->had_aaa_dti_rsp = FALSE;

    }
  }
#endif /* FF_TCP_IP */

  switch ( cur_ent_id )
  {
  case DTI_ENTITY_ACI: /* entity ACI */
    /* handle ACI as independent entity */
    psaACI_Dti_Req(link_id, peer_ent_id, ACI_CONNECT_DTI);
    break;

  case DTI_ENTITY_UART: /* entity UART */
    psaUART_SetDTIReq (link_id, peer_ent_id);
    break;

#ifdef FF_TRACE_OVER_MTST
  case DTI_ENTITY_MTST: /* for traces */
    psaMTST_Switch_Trace (link_id, peer_ent_id, TRUE);
    break;
#endif

#ifdef FAX_AND_DATA
  case DTI_ENTITY_TRA:
    psaTRA_Dti_Req( link_id, TRA_CONNECT_DTI, (UBYTE)peer_ent_id );
    break;

  case DTI_ENTITY_L2R:
    psaL2R_Enable (link_id, (UBYTE)peer_ent_id);
    break;

#ifdef FF_FAX
  case DTI_ENTITY_T30:
    psaT30_Dti_Req( link_id, T30_CONNECT_DTI );
    break;
#endif

#ifdef BT_ADAPTER
  case DTI_ENTITY_BLUETOOTH:
    psaBTI_Dti_Req( link_id, peer_ent_id, BTI_CONNECT_DTI );
    break;
#endif /* BT_ADAPTER */

#endif /* FAX_AND_DATA */

#ifdef GPRS
  case DTI_ENTITY_PPPS:
    psaGPPPS_Dti_Req(link_id, (UBYTE) peer_ent_id); /* rather use dti_id instead of link_id ???? */
    break;
#ifdef FF_PKTIO
  case DTI_ENTITY_PKTIO:
    psaPKT_Dti_Req((ULONG)link_id, (UBYTE)peer_ent_id, PKT_CONNECT_DTI);
    break;
#endif /* FF_PKTIO */
  case DTI_ENTITY_SNDCP:
    psaSNDCP_Dti_Req( link_id, (UBYTE) peer_ent_id ); /* rather use dti_id instead of link_id ???? */
    break;
#endif /* GPRS */
#ifdef FF_PSI
  case DTI_ENTITY_PSI:
    psaPSI_Dti_Req((ULONG)link_id, (UBYTE)peer_ent_id, PSI_CONNECT_DTI);
    break;
#endif /*FF_PSI*/
  case DTI_ENTITY_NULL:
    dti_cntrl_entity_connected (link_id, DTI_ENTITY_NULL, DTI_OK);
    break;

#if defined (FF_WAP) || defined (FF_TCP_IP) || defined (FF_GPF_TCPIP) || defined (FF_SAT_E) 
  case DTI_ENTITY_PPPC:
    psaPPP_Establish(link_id, (UBYTE) peer_ent_id);
    break;
#endif /* WAP or FF_TCP_IP or SAT E */
#ifdef CO_UDP_IP 
  case DTI_ENTITY_IP:
    psaIPA_Dti_Req(link_id, (UBYTE) peer_ent_id, IPA_CONNECT_DTI);
    break;

  case DTI_ENTITY_UDP:
    psaUDPA_Dti_Req(link_id, (UBYTE) peer_ent_id, UDPA_CONNECT_DTI);
    break;

#ifdef FF_WAP 
  case DTI_ENTITY_WAP:
    psaWAP_Dti_Req(link_id, (UBYTE) peer_ent_id, WAP_CONNECT_DTI);
    break;
#endif /* WAP */

#endif /* WAP || SAT E */

#ifdef FF_GPF_TCPIP
  case DTI_ENTITY_TCPIP:
    psaTCPIP_Dti_Req(link_id, (UBYTE) peer_ent_id, TCPIP_CONNECT_DTI);
    break;
#endif

#ifdef FF_TCP_IP
  case DTI_ENTITY_AAA: /* entity AAA */
    psaAAA_dti_ind (link_id, peer_ent_id);
    break;
#endif

#ifdef FF_SAT_E
    /* SAT class e */
  case DTI_ENTITY_SIM:
    /* init connection SIM--PEER */ 
    /* open DTI connection */
    psaSIM_Dti_Req(link_id);
    break;
#endif

  default:
    /* search for registered connect function */
    return dti_cntrl_call_reg_fct(cur_ent_id, link_id, peer_ent_id, dti_conn);
  }
  return (TRUE);
}

#ifdef FF_TCP_IP
EXTERN void dti_cntrl_connect_after_aaa_dti_rsp(UBYTE dti_id)
{
  /* If the peer entity is AAA, the connect request has been delayed, until
   * AAA has responded to the AAA_DTI_IND. ati_src_riv_dti_rsp() calls this
   * function on receiving this response. */

  T_DTI_CNTRL *dti_cntrl_dev ;  /* Information about DTI link. */

  TRACE_FUNCTION("dti_cntrl_connect_after_aaa_dti_rsp()");
  dti_cntrl_dev = (T_DTI_CNTRL *) find_element (dti_cntrl_list, dti_id,
                                                dti_cntrl_search_dti_id) ;
  dti_cntrl_dev->had_aaa_dti_rsp = TRUE ;
  dti_cntrl_maintain_entity_connect(dti_cntrl_dev->save_link_id,
                                    dti_cntrl_dev->save_cur_ent_id,
                                    DTI_ENTITY_AAA,
                                    dti_cntrl_dev->save_dti_conn) ;
}
#endif /* FF_TCP_IP */

/*
+---------------------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : DTI_CNTRL                            |
| STATE   : code                   ROUTINE : dti_cntrl_maintain_entity_disconnect |
+---------------------------------------------------------------------------------+

  PURPOSE : sub function of dti_cntrl_maintain_entity, called when the DTI
            Connection Manager wants to disconnect entites after data transmission
*/
LOCAL BOOL dti_cntrl_maintain_entity_disconnect ( T_DTI_CONN_LINK_ID  link_id,
                                                  T_DTI_ENTITY_ID     cur_ent_id,
                                                  T_DTI_ENTITY_ID     peer_ent_id,
                                                  UBYTE               dti_conn)
{
  TRACE_FUNCTION("dti_cntrl_maintain_entity_disconnect()");
  switch( cur_ent_id )
  {
  case DTI_ENTITY_ACI:
    psaACI_Dti_Req (link_id, peer_ent_id, ACI_DISCONNECT_DTI);
    break;

  case DTI_ENTITY_UART:
    /* for UART, we have to wait for UART_DTI_IND
     * sent when UART recognizes it's dti connection has been
     * closed down.
     * It would be nice to just send UART_DTI_REQ
     * here in order to make handling of the UART entity
     * more similar to the other entities..
     */
    break;

#ifdef FF_TRACE_OVER_MTST
  case DTI_ENTITY_MTST: /* for traces */
    if (psaMTST_Switch_Trace (link_id, peer_ent_id, FALSE) EQ PEI_ERROR)
    {
      return (FALSE);
    }
    break;
#endif

#ifdef FAX_AND_DATA
  case DTI_ENTITY_TRA:
    psaTRA_Dti_Req (link_id, TRA_DISCONNECT_DTI, (UBYTE)peer_ent_id);
    break;

#ifdef FF_FAX
  case DTI_ENTITY_T30:
    psaT30_Dti_Req (link_id, T30_DISCONNECT_DTI);
    break;
#endif

  case DTI_ENTITY_L2R:
    /* in the case of disconnecting L2R,
    it has to be DEACTIVATED */
    psaL2R_Deactivate();
    break;

#ifdef BT_ADAPTER
  case DTI_ENTITY_BLUETOOTH:
    psaBTI_Dti_Req(link_id, peer_ent_id, BTI_DISCONNECT_DTI);
    break;
#endif /* BT_ADAPTER */

#endif  /* FAX_AND_DATA */

#ifdef GPRS
  case DTI_ENTITY_PPPS:
    cmhGPPPS_Disable( link_id );
    break;

  case DTI_ENTITY_SNDCP:
    cmhSNDCP_Disable( link_id );
    break;
#ifdef FF_PKTIO
   case DTI_ENTITY_PKTIO:
     psaPKT_Dti_Req((ULONG)link_id, (UBYTE)peer_ent_id, PKT_DISCONNECT_DTI);
   	break;
#endif /* FF_PKTIO */
#endif /* GPRS */

#ifdef FF_PSI
   case DTI_ENTITY_PSI:
     psaPSI_Dti_Req((ULONG)link_id, (UBYTE)peer_ent_id, PSI_DISCONNECT_DTI);
     break;
#endif /*FF_PSI*/

#ifdef CO_UDP_IP
  case DTI_ENTITY_IP:
    psaIPA_Dti_Req(link_id, (UBYTE)peer_ent_id, IPA_DISCONNECT_DTI);
    break;

  case DTI_ENTITY_UDP:
    /* for UDP, we have to wait for UDPA_DTI_IND(DISCONNECT) which is
     * sent when UDP recognizes it's dti connection has been
     * closed down
     */
    break;
#endif /* CO_UDP_IP */

#ifdef FF_WAP
  case DTI_ENTITY_WAP:
    psaWAP_Dti_Req(link_id, (UBYTE) peer_ent_id, WAP_DISCONNECT_DTI);
    break;
#endif /* WAP */

#ifdef FF_GPF_TCPIP
  case DTI_ENTITY_TCPIP:
    /* for TCP/IP, we have to wait for TCPIP_DTI_IND(DISCONNECT) which is
     * sent when TCP/IP recognizes its DTI connection has been closed down */
    psaTCPIP_Dti_Req(link_id, (UBYTE) peer_ent_id, TCPIP_DISCONNECT_DTI);
    break;
#endif /* FF_GPF_TCPIP */

#ifdef FF_TCP_IP
  case DTI_ENTITY_AAA: /* entity AAA */
    psaAAA_disconnect_ind (link_id);
    break;
  case DTI_ENTITY_PPPC:
    psaPPP_Terminate(UP);
    break;
#endif

#ifdef FF_SAT_E
    /* SAT class e */
  case DTI_ENTITY_SIM:
    psaSIM_Dti_Req(link_id);
    break;
#endif

  default:
    /* search for registered connect function */
    return dti_cntrl_call_reg_fct(cur_ent_id, link_id, peer_ent_id, dti_conn);
  }

  return (TRUE);
}

/*
+----------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : DTI_CNTRL                 |
| STATE   : code                   ROUTINE : dti_cntrl_maintain_entity |
+----------------------------------------------------------------------+

  PURPOSE : this function is used by the DTI Connection Manager as a
            call back function for connecting/disconnecting.
            The registeration of dti_cntrl_maintain_entity in the
            DTI Connection Manager takes place with:
              dti_conn_init (dti_cntrl_maintain_entity);
*/
LOCAL BOOL dti_cntrl_maintain_entity ( T_DTI_CONN_LINK_ID  link_id,
                                       T_DTI_ENTITY_ID     cur_ent_id,
                                       T_DTI_ENTITY_ID     peer_ent_id,
                                       UBYTE               dti_conn)
{
  TRACE_FUNCTION("dti_cntrl_maintain_entity()");

  if (dti_conn EQ DTI_CONNECT)
  {
    return (dti_cntrl_maintain_entity_connect (link_id, cur_ent_id, peer_ent_id, dti_conn));
  }
  else /* DTI_DISCONNECT */
  {
    return (dti_cntrl_maintain_entity_disconnect (link_id, cur_ent_id, peer_ent_id, dti_conn));
  }
}
/********************** GLOBAL FUNCTIONS *****************************/

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : DTI_CNTRL               |
| STATE   : code                   ROUTINE : dti_cntrl_search_src_id |
+--------------------------------------------------------------------+

  PURPOSE : help function for
            find_element (dti_cntrl_list, dti_id, dti_cntrl_search_src_id);
*/
GLOBAL BOOL dti_cntrl_search_src_id (UBYTE src_id, void *elem)
{
  T_DTI_CNTRL *compared = (T_DTI_CNTRL *)elem;

  if (compared NEQ NULL)
    if (compared->src_id EQ src_id)
      return (TRUE);
  return (FALSE);
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : DTI_CNTRL               |
| STATE   : code                   ROUTINE : dti_cntrl_search_dti_id |
+--------------------------------------------------------------------+

  PURPOSE : help function for
            find_element (dti_cntrl_list, dti_id, dti_cntrl_search_dti_id);
*/
GLOBAL BOOL dti_cntrl_search_dti_id (UBYTE dti_id, void *elem)
{
  T_DTI_CNTRL *compared = (T_DTI_CNTRL *)elem;

  if (compared NEQ NULL)
    if (compared->dti_id EQ dti_id)
      return (TRUE);
  return (FALSE);
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : DTI_CNTRL               |
| STATE   : code                   ROUTINE : dti_cntrl_init          |
+--------------------------------------------------------------------+

  PURPOSE : create the global defined dti_cntrl_list and
            register dti_cntrl_maintain_entity as call back
*/
GLOBAL void dti_cntrl_init (void)
{
  UBYTE i;

  TRACE_FUNCTION("dti_cntrl_init()");

  for (i=0; i<MAX_DTI_CONN_LINK_IDS; i++)
  {
    dti_aci_data_base[i].link_id  = DTI_LINK_ID_NOTPRESENT;
    dti_aci_data_base[i].dev_no1  = DTI_DEV_NO_NOTPRESENT;
    dti_aci_data_base[i].dev_no2  = DTI_DEV_NO_NOTPRESENT;
    dti_aci_data_base[i].ent_id1  = DTI_ENTITY_INVALID;
    dti_aci_data_base[i].ent_id2  = DTI_ENTITY_INVALID;
    dti_aci_data_base[i].sub_no1  = DTI_SUB_NO_NOTPRESENT;
    dti_aci_data_base[i].sub_no2  = DTI_SUB_NO_NOTPRESENT;
  }

  dti_cntrl_reconnect_to_aci = 0;

  dti_cntrl_list = new_list ();

  dti_conn_init (dti_cntrl_maintain_entity);
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : DTI_CNTRL               |
| STATE   : code                   ROUTINE : dti_cntrl_new_dti       |
+--------------------------------------------------------------------+

  PURPOSE :

*/
GLOBAL UBYTE  dti_cntrl_new_dti (UBYTE  dti_id)
{

  TRACE_FUNCTION("dti_cntrl_new_dti()");

  /* call DTI connection manager function to get a DTI ID */
  if ((dti_id = dti_conn_new(dti_id)) EQ DTI_DTI_ID_NOTPRESENT)
  {
    TRACE_EVENT("couldn't create new dti_id");
    return (FALSE);
  }

  return (dti_id);
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : DTI_CNTRL               |
| STATE   : code                   ROUTINE : dti_cntrl_new_device    |
+--------------------------------------------------------------------+

  PURPOSE : a PSA wants to set up a device.
            in case of ATI_RIV called this function, then port_num
            is meaningful number, else port_num = NO_PORT_NUMBER.
            we keep the port number here to frees ATI-RIV from
            maintaining its own redundant list.
*/
GLOBAL BOOL   dti_cntrl_new_device (UBYTE  src_id,
                                    UBYTE  dev_id,
                                    UBYTE  dev_no,
                                    UBYTE  sub_no,
                                    UBYTE  port_num,
                                    UBYTE  capability,
                                    UBYTE  driver_id,
                                    UBYTE  dio_ctrl_id)
{
  UBYTE         dti_id         = DTI_DTI_ID_NOTPRESENT;
  T_DTI_CNTRL  *dti_cntrl_dev  = NULL;
  USHORT        i              = 0;

  TRACE_FUNCTION("dti_cntrl_new_device()");

  /* call DTI connection manager function to get a DTI ID */
  if ((dti_id = dti_conn_new(DTI_DTI_ID_NOTPRESENT)) EQ DTI_DTI_ID_NOTPRESENT)
  {
    TRACE_EVENT("couldn't create new dti_id");
    return (FALSE);
  }

  ACI_MALLOC (dti_cntrl_dev, sizeof (T_DTI_CNTRL));
  ACI_MALLOC (dti_cntrl_dev->redirect_info.tbl, sizeof (T_DTI_CNTRL_REDIRECT_INTERN));

  dti_cntrl_dev->dev_id      = dev_id;
  dti_cntrl_dev->dev_no      = dev_no;
  dti_cntrl_dev->sub_no      = sub_no;        /* multiplexed sub channels          */
  dti_cntrl_dev->capability  = capability;    /* what the device is capable to     */
  dti_cntrl_dev->src_id      = src_id;
  dti_cntrl_dev->dti_id      = dti_id;
  dti_cntrl_dev->port_number = port_num;
  dti_cntrl_dev->driver_id   = driver_id;
  dti_cntrl_dev->dio_ctrl_id = dio_ctrl_id;

  #ifdef FF_TCP_IP
  dti_cntrl_dev->had_aaa_dti_rsp = FALSE ;
  dti_cntrl_dev->save_link_id    = 0 ;
  dti_cntrl_dev->save_cur_ent_id = 0 ;
  dti_cntrl_dev->save_dti_conn   = 0 ;
  #endif /* FF_TCP_IP */
  
  if ((src_id NEQ DTI_SRC_ID_NOTPRESENT) AND (src_id <= CMD_SRC_MAX))
  {
    dti_cntrl_dev->cur_cap   = DTI_CPBLTY_CMD; /* has been called by an AT src, so at least CMD capability */
  }
  else
  {
    dti_cntrl_dev->cur_cap   = DTI_CPBLTY_NO;  /* has not been called by an AT src and there is no connection yet */
  }

  for (i=0; i<DTI_MAX_REDIRECTIONS; ++i)
  {
    dti_cntrl_dev->redirect_info.tbl->ser_redirect[i].mode        = DTI_MODE_PERM;
    dti_cntrl_dev->redirect_info.tbl->ser_redirect[i].redirection = NULL;
    dti_cntrl_dev->redirect_info.tbl->pkt_redirect[i].mode        = DTI_MODE_PERM;
    dti_cntrl_dev->redirect_info.tbl->pkt_redirect[i].redirection = NULL;
  }

  return (insert_list (dti_cntrl_list, dti_cntrl_dev));
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : DTI_CNTRL               |
| STATE   : code                   ROUTINE : dti_cntrl_new_device    |
+--------------------------------------------------------------------+

  PURPOSE : change the sub channel number (for multiplexer)
*/
GLOBAL void dti_cntrl_change_sub_no (UBYTE  src_id,
                                     UBYTE  sub_no)
{
  T_DTI_CNTRL  *dti_cntrl_dev  = (T_DTI_CNTRL *)find_element (dti_cntrl_list, src_id, dti_cntrl_search_src_id);

  TRACE_FUNCTION("dti_cntrl_change_sub_no()");

  if (dti_cntrl_dev NEQ NULL)
  {
    dti_cntrl_dev->sub_no = sub_no; /* multiplexed sub channels */
  }
  else
  {
    TRACE_EVENT_P1("no registered device found for src_id=%u", src_id);
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : DTI_CNTRL               |
| STATE   : code                   ROUTINE : dti_cntrl_est_dpath     |
+--------------------------------------------------------------------+

  PURPOSE : establish a data connection path directly

*/
GLOBAL BOOL dti_cntrl_est_dpath ( UBYTE               dti_id,
                                  T_DTI_ENTITY_ID    *entity_list,
                                  UBYTE               num_entities,
                                  T_DTI_CONN_MODE     mode,         /* split/append */
                                  T_DTI_CONN_CB      *cb)
{
  TRACE_FUNCTION("dti_cntrl_est_dpath()");

  return (dti_conn_est_dpath (dti_id, entity_list, num_entities, mode, cb));
}

/*
+-------------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : DTI_CNTRL                    |
| STATE   : code                   ROUTINE : dti_cntrl_est_dpath_indirect |
+-------------------------------------------------------------------------+

  PURPOSE : establish a data connection path, for which a redirection has been set up.
            a redirection relates to a serial or packet device indicated by capability.
            with the cid we find in ser_redirect[cid] respectively pkt_redirect[cid]
            the pointer to the redirected device maintenance in dti_cntrl_list, from
            which we get the dti_id to pass it to the DTI Connection Manager.
*/
GLOBAL BOOL   dti_cntrl_est_dpath_indirect (UBYTE               src_id,
                                            T_DTI_ENTITY_ID    *entity_list,
                                            UBYTE               num_entities,
                                            T_DTI_CONN_MODE     mode,         /* split/append */
                                            T_DTI_CONN_CB      *cb,
                                            UBYTE               capability,
                                            UBYTE               cid)
{
  T_DTI_CNTRL  *dti_cntrl_dev  = (T_DTI_CNTRL *)find_element (dti_cntrl_list, src_id, dti_cntrl_search_src_id);
  T_DTI_CNTRL  *indirect_dev   = NULL; /* the pointer to the redirected device maintenance */
  UBYTE         dti_id         = DTI_DTI_ID_NOTPRESENT;
  UBYTE         mode_once_perm = DTI_MODE_NIL;
  T_DTI_ENTITY_ID  *new_entity_list;
  BOOL ret_value;

/* for tracing of establishing of CMD channels for dual port version */
#ifdef RMV_15_04_03
  extern CHAR gob_tst_buf[];
#endif

  TRACE_FUNCTION("dti_cntrl_est_dpath_indirect()");

  if (dti_cntrl_dev EQ NULL)
  {
    TRACE_EVENT_P1("[ERR]Device with src_id=%d was not registered", src_id);
    return FALSE;
  }

  ACI_MALLOC(new_entity_list, sizeof(T_DTI_ENTITY_ID)*(num_entities+1) );
  memcpy(&new_entity_list[1], entity_list, sizeof(T_DTI_ENTITY_ID)*num_entities);

  if (cid EQ DTI_CID_NOTPRESENT)
  {
    cid = 0;
  }

  /*
   * requested capability for data transmission can be SER ,PKT or CMD
   */
  switch (capability)
  {
    case (DTI_CPBLTY_PKT):
    {
      mode_once_perm        = dti_cntrl_dev->redirect_info.tbl->pkt_redirect[cid].mode;
      indirect_dev          = dti_cntrl_dev->redirect_info.tbl->pkt_redirect[cid].redirection;

      /*
       * if there is no redirection for the given cid (so it is a GPRS call)
       * then look in the "redirection for all cids" entry
       */
      if ((indirect_dev EQ NULL) AND (cid NEQ 0))
      {
        mode_once_perm        = dti_cntrl_dev->redirect_info.tbl->pkt_redirect[0].mode;
        indirect_dev          = dti_cntrl_dev->redirect_info.tbl->pkt_redirect[0].redirection;
      }

      if(indirect_dev NEQ NULL)
      {
        indirect_dev->cur_cap = DTI_CPBLTY_PKT;
      }
      break;
    }
    case (DTI_CPBLTY_SER):
    {
      mode_once_perm        = dti_cntrl_dev->redirect_info.tbl->ser_redirect[cid].mode;
      indirect_dev          = dti_cntrl_dev->redirect_info.tbl->ser_redirect[cid].redirection;

      /*
       * if there is no redirection for the given cid (so it is a GPRS call)
       * then look in the "redirection for all cids" entry
       */
      if ((indirect_dev EQ NULL) AND (cid NEQ 0))
      {
        mode_once_perm        = dti_cntrl_dev->redirect_info.tbl->ser_redirect[0].mode;
        indirect_dev          = dti_cntrl_dev->redirect_info.tbl->ser_redirect[0].redirection;
#ifdef RMV_15_04_03
        TRACE_EVENT("redirection used");
        TRACE_EVENT_P1("cid: %d", cid);
#endif
      }

      if(indirect_dev NEQ NULL)
      {
      	indirect_dev->cur_cap = DTI_CPBLTY_SER;
      }
      break;
    }
    case (DTI_CPBLTY_CMD):
      dti_cntrl_dev->cur_cap = DTI_CPBLTY_CMD;
      break;
    default:
    {
      return (FALSE);
    }
  }

  if (indirect_dev EQ NULL)
  {
    /* verify that the device is able to work in the requested capability */
    if ((BITFIELD_CHECK (capability, dti_cntrl_dev->capability)) EQ FALSE)
    {
      return (FALSE);
    }

    dti_id = dti_cntrl_dev->dti_id;
    new_entity_list[0] = dti_cntrl_dev->dev_id;
  }
  else
  {
    /* verify that the device is able to work in the requested capability */
    if ((BITFIELD_CHECK (capability, indirect_dev->capability)) EQ FALSE)
    {
      return (FALSE);
    }

    dti_id = indirect_dev->dti_id;
    new_entity_list[0] = indirect_dev->dev_id;
    if (mode_once_perm EQ DTI_MODE_ONCE)
    {
      /* the redirected data transmission connection is not permanent,
       * so remove the pointer to the redirected device maintenance */
      indirect_dev = NULL;
    }
  }

  num_entities++;
  /*
   * remember capability, we need it again in dti_cntrl_entity_connected()
   */
  g_cur_cap = capability;

/* for tracing of establishing of CMD channels for dual port version */
#ifdef RMV_15_04_03
  TRACE_EVENT_P1("num_entities: %d", num_entities);
  TRACE_EVENT_P1("g_cur_cap: %d", g_cur_cap);
  TRACE_EVENT_P1("new_entity_list[0]: %d", new_entity_list[0]);
  TRACE_EVENT_P1("new_entity_list[1]: %d", new_entity_list[1]);
  TRACE_EVENT_P1("new_entity_list[2]: %d", new_entity_list[2]);
  TRACE_EVENT_P1("dti_cntrl_dev->dti_id: %d", dti_cntrl_dev->dti_id);
  if (indirect_dev)
  {
    TRACE_EVENT_P1("indirect_dev->dti_id: %d", indirect_dev->dti_id);
  }

  TRACE_EVENT(gob_tst_buf);
#endif

  /* clear reconnect flag for the new connction */
  dti_cntrl_clear_dti_id_to_reconnect(dti_id);

  ret_value = dti_conn_est_dpath (dti_id, new_entity_list, num_entities, mode, cb);

  ACI_MFREE(new_entity_list);
  return ret_value;
}

/*
+------------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411) MODULE  : DTI_CNTRL                           |
| STATE   : code           ROUTINE : dti_cntrl_is_dti_channel_connected  |
+------------------------------------------------------------------------+

  PURPOSE :

*/
GLOBAL BOOL dti_cntrl_is_dti_channel_connected (T_DTI_ENTITY_ID ent_id, UBYTE dti_id)
{
  TRACE_FUNCTION("dti_cntrl_is_dti_channel_connected()");

  return (dti_conn_is_dti_channel_connected (ent_id, dti_id));
}

/*
+--------------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411) MODULE  : DTI_CNTRL                             |
| STATE   : code           ROUTINE : dti_cntrl_is_dti_channel_disconnected |
+--------------------------------------------------------------------------+

  PURPOSE :

*/
GLOBAL BOOL dti_cntrl_is_dti_channel_disconnected (UBYTE dti_id)
{
  TRACE_FUNCTION("dti_cntrl_is_dti_channel_disconnected()");

  return (dti_conn_is_dti_channel_disconnected (dti_id));
}
/*
+------------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411) MODULE  : DTI_CNTRL                           |
| STATE   : code           ROUTINE : dti_cntrl_close_dpath_from_src_id   |
+------------------------------------------------------------------------+

  PURPOSE :

*/
GLOBAL BOOL dti_cntrl_close_dpath_from_src_id (UBYTE  src_id)
{
  T_DTI_CNTRL  *dti_cntrl_dev  = (T_DTI_CNTRL *)find_element (dti_cntrl_list, src_id, dti_cntrl_search_src_id);

  TRACE_FUNCTION("dti_cntrl_close_dpath_from_src_id()");

  return (dti_conn_close_dpath (dti_cntrl_dev->dti_id));
}

/*
+------------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411) MODULE  : DTI_CNTRL                           |
| STATE   : code           ROUTINE : dti_cntrl_close_dpath_from_dti_id   |
+------------------------------------------------------------------------+

  PURPOSE :

*/
GLOBAL BOOL   dti_cntrl_close_dpath_from_dti_id (UBYTE  dti_id)
{
  TRACE_FUNCTION("dti_cntrl_close_dpath_from_dti_id()");

  return (dti_conn_close_dpath (dti_id));
}

/*
+----------------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : DTI_CNTRL                       |
| STATE   : code                   ROUTINE : dti_cntrl_get_info_from_src_id  |
+----------------------------------------------------------------------------+

  PURPOSE :

*/
GLOBAL BOOL   dti_cntrl_get_info_from_src_id (UBYTE         src_id,
                                              T_DTI_CNTRL  *info) /* out parameter */
{
  T_DTI_CNTRL  *dti_cntrl_dev  = (T_DTI_CNTRL *)find_element (dti_cntrl_list, src_id, dti_cntrl_search_src_id);

  TRACE_FUNCTION("dti_cntrl_get_info_from_src_id()");

  if (dti_cntrl_dev)
  {
    return (dti_cntrl_get_info (info, dti_cntrl_dev));
  }
  return (FALSE);
}
/*
+----------------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : DTI_CNTRL                       |
| STATE   : code                   ROUTINE : dti_cntrl_get_info_from_dti_id  |
+----------------------------------------------------------------------------+

  PURPOSE :

*/
GLOBAL BOOL   dti_cntrl_get_info_from_dti_id (UBYTE         dti_id,
                                              T_DTI_CNTRL  *info) /* out parameter */
{
  T_DTI_CNTRL  *dti_cntrl_dev = (T_DTI_CNTRL *)find_element (dti_cntrl_list, dti_id, dti_cntrl_search_dti_id);

  TRACE_FUNCTION("dti_cntrl_get_info_from_dti_id()");

  if (dti_cntrl_dev)
  {
    return (dti_cntrl_get_info (info, dti_cntrl_dev));
  }
  return (FALSE);
}

/*
+----------------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : DTI_CNTRL                       |
| STATE   : code                   ROUTINE : dti_cntrl_get_info_from_dev_id  |
+----------------------------------------------------------------------------+

  PURPOSE :

*/
GLOBAL BOOL   dti_cntrl_get_info_from_dev_id (T_DTI_ENTITY_ID      dev_id,
                                              UBYTE                dev_no,
                                              UBYTE                sub_no,
                                              T_DTI_CNTRL         *info) /* out parameter */
{
  T_DTI_CNTRL  *dti_cntrl_dev = (T_DTI_CNTRL *)find_element_by_tupel (dti_cntrl_list,
                                                                      dev_id,
                                                                      dev_no,
                                                                      sub_no,
                                                                      dti_cntrl_search_dev_id);
  TRACE_FUNCTION("dti_cntrl_info_from_dev_id()");

  if (dti_cntrl_dev)
  {
    return (dti_cntrl_get_info (info, dti_cntrl_dev));
  }
  return (FALSE);
}

/*
+-----------------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : DTI_CNTRL                        |
| STATE   : code                   ROUTINE : dti_cntrl_set_redirect_from_src  |
+-----------------------------------------------------------------------------+

  PURPOSE :

*/
GLOBAL BOOL   dti_cntrl_set_redirect_from_src    (UBYTE               src_id,
                                                  UBYTE               mode,
                                                  T_DTI_ENTITY_ID     dst_dev_id,
                                                  UBYTE               dst_dev_no,
                                                  UBYTE               dst_sub_no,
                                                  UBYTE               capability,
                                                  UBYTE               cid)
{
  T_DTI_CNTRL  *dti_cntrl_dev = (T_DTI_CNTRL *)find_element (dti_cntrl_list, src_id, dti_cntrl_search_src_id);
  T_DTI_CNTRL  *indirect_dev  = (T_DTI_CNTRL *)find_element_by_tupel (dti_cntrl_list,
                                                                      dst_dev_id,
                                                                      dst_dev_no,
                                                                      dst_sub_no,
                                                                      dti_cntrl_search_dev_id);

  TRACE_FUNCTION("dti_cntrl_set_redirect_from_src()");

  if (dti_cntrl_dev AND indirect_dev)
  {
    return (dti_cntrl_set_redirection (dti_cntrl_dev, indirect_dev, mode, capability, cid));
  }

  if (dti_cntrl_dev EQ 0)
  {
    TRACE_EVENT_P1("dti_cntrl_set_redirect_from_src():[ERR] no list element for src_id=%d", src_id);
  }
  if (indirect_dev EQ 0)
  {
    TRACE_EVENT_P3("dti_cntrl_set_redirect_from_src():[ERR] no list element for dev_id=%d, dev_no=%d, sub_no=%d", dst_dev_id,
                                                                                                                  dst_dev_no,
                                                                                                                  dst_sub_no);
  }
  return (FALSE);
}

/*
+--------------------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : DTI_CNTRL                           |
| STATE   : code                   ROUTINE : dti_cntrl_set_redirect_from_device  |
+--------------------------------------------------------------------------------+

  PURPOSE :

*/
GLOBAL BOOL   dti_cntrl_set_redirect_from_device (UBYTE               mode,
                                                  T_DTI_ENTITY_ID     dst_dev_id,
                                                  UBYTE               dst_dev_no,
                                                  UBYTE               dst_sub_no,
                                                  T_DTI_ENTITY_ID     src_dev_id,
                                                  UBYTE               src_dev_no,
                                                  UBYTE               src_sub_no,
                                                  UBYTE               capability,
                                                  UBYTE               cid)
{
  T_DTI_CNTRL  *source_dev = (T_DTI_CNTRL *)find_element_by_tupel (dti_cntrl_list,
                                                                      src_dev_id,
                                                                      src_dev_no,
                                                                      src_sub_no,
                                                                      dti_cntrl_search_dev_id);
  T_DTI_CNTRL  *destination_dev = (T_DTI_CNTRL *)find_element_by_tupel (dti_cntrl_list,
                                                                        dst_dev_id,
                                                                        dst_dev_no,
                                                                        dst_sub_no,
                                                                        dti_cntrl_search_dev_id);

  TRACE_FUNCTION("dti_cntrl_set_redirect_from_device()");

  if (source_dev AND destination_dev)
  {
    if ((BITFIELD_CHECK (source_dev->capability, DTI_CPBLTY_CMD)) EQ FALSE)
    {
      TRACE_EVENT("source device has no command capability !");
      return (FALSE);
    }

    return (dti_cntrl_set_redirection (source_dev, destination_dev, mode, capability, cid));
  }
  return (FALSE);
}

/*
+-----------------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)           MODULE  : DTI_CNTRL                      |
| STATE   : code                     ROUTINE : dti_cntrl_get_first_device     |
+-----------------------------------------------------------------------------+

  PURPOSE :   this function is used in conjunction with
                     1:AT%DATA where all devices
                       and their possible redirections for data transmission have to
                       be listed. so start with the first element of dti_cntrl_list
                     2.AT%DINF where all devices have to be listed, start with first element
*/
GLOBAL BOOL   dti_cntrl_get_first_device (T_DTI_CNTRL  *info) /* out parameter */
{
  T_DTI_CNTRL  *dti_cntrl_dev;

  TRACE_FUNCTION("dti_cntrl_get_first_device()");

  dti_cntrl_dev_ptr = dti_cntrl_list;
  dti_cntrl_dev  = (T_DTI_CNTRL *)(dti_cntrl_dev_ptr->msg);

  if (dti_cntrl_dev)
  {
    return (dti_cntrl_get_info (info, dti_cntrl_dev));
  }
  return (FALSE);
}

/*
+-----------------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : DTI_CNTRL                   |
| STATE   : code                        ROUTINE : dti_cntrl_get_next_device   |
+-----------------------------------------------------------------------------+

  PURPOSE :   this function is used in conjunction with AT%DINF where all devices have
              to be listed, give next element
*/
GLOBAL BOOL   dti_cntrl_get_next_device (T_DTI_CNTRL  *info) /* out parameter */
{
  T_DTI_CNTRL  *dti_cntrl_dev;

  TRACE_FUNCTION("dti_cntrl_get_next_device()");

  if(dti_cntrl_dev_ptr->next NEQ NULL)
  {
     dti_cntrl_dev_ptr = 	dti_cntrl_dev_ptr->next;
     dti_cntrl_dev  = (T_DTI_CNTRL *)(dti_cntrl_dev_ptr->msg);

     if (dti_cntrl_dev)
     {
       return (dti_cntrl_get_info (info, dti_cntrl_dev));
     }
  }
  else
  	dti_cntrl_dev_ptr = NULL;
  return (FALSE);
}

/*
+-----------------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : DTI_CNTRL                        |
| STATE   : code                   ROUTINE : dti_cntrl_get_first_redirection  |
+-----------------------------------------------------------------------------+

  PURPOSE :   to the given src_id and capability (SER/PKT) find the first
              redirection.
*/
GLOBAL BOOL   dti_cntrl_get_first_redirection (UBYTE         src_id,
                                               UBYTE         capability,
                                               T_DTI_CNTRL  *redirection) /* out parameter */
{
  T_DTI_CNTRL  *dti_cntrl_dev  = (T_DTI_CNTRL *)find_element (dti_cntrl_list, src_id, dti_cntrl_search_src_id);

  TRACE_FUNCTION("dti_cntrl_get_first_redirection()");

  /*
   * for the cid we set here -1, because the sub function will first increase it by one
   * so we access ser_redirect[0] respectively pkt_redirect[0]
   */
  return (dti_cntrl_get_redirection (dti_cntrl_dev, redirection, -1, capability));
}

/*
+----------------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : DTI_CNTRL                       |
| STATE   : code                   ROUTINE : dti_cntrl_get_next_redirection  |
+----------------------------------------------------------------------------+

  PURPOSE :   to the given src_id and capability (SER/PKT) find the next
              redirection >>after<< the given cid.
*/
GLOBAL BOOL   dti_cntrl_get_next_redirection (UBYTE         src_id,
                                              UBYTE         cid,
                                              UBYTE         capability,
                                              T_DTI_CNTRL  *redirection) /* out parameter */
{
  T_DTI_CNTRL  *dti_cntrl_dev  = (T_DTI_CNTRL *)find_element (dti_cntrl_list, src_id, dti_cntrl_search_src_id);

  TRACE_FUNCTION("dti_cntrl_get_next_redirection()");

  return (dti_cntrl_get_redirection (dti_cntrl_dev, redirection, cid, capability));
}

/*
+-------------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : DTI_CNTRL                    |
| STATE   : code                   ROUTINE : dti_cntrl_entity_connected   |
+-------------------------------------------------------------------------+

  PURPOSE :

*/
GLOBAL void   dti_cntrl_entity_connected (ULONG             link_id,
                                          T_DTI_ENTITY_ID   entity_id,
                                          T_DTI_CONN_RESULT result)
{
  UBYTE         dti_id        = EXTRACT_DTI_ID(link_id);
  T_DTI_CNTRL  *dti_cntrl_dev = (T_DTI_CNTRL *)find_element (dti_cntrl_list, dti_id, dti_cntrl_search_dti_id);

  TRACE_FUNCTION("dti_cntrl_entity_connected()");

  if (dti_cntrl_dev AND (result EQ DTI_ERROR))
  {
    dti_cntrl_dev->cur_cap = DTI_CPBLTY_NO; /* reset current capability */
  }

  /* call DTI Connection Mng function */
  dti_conn_entity_connected (link_id, entity_id, result);

  /* set current capability if DTI channel is connected */
  if (dti_cntrl_dev AND (dti_conn_is_dti_channel_connected(entity_id, dti_id) EQ TRUE))
  {
    dti_cntrl_dev->cur_cap = g_cur_cap;
  }
}
/*
+----------------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : DTI_CNTRL                       |
| STATE   : code                   ROUTINE : dti_cntrl_entity_disconnected   |
+----------------------------------------------------------------------------+

  PURPOSE :

*/
GLOBAL void   dti_cntrl_entity_disconnected (ULONG             link_id,
                                             T_DTI_ENTITY_ID   entity_id)
{
  UBYTE         dti_id        = EXTRACT_DTI_ID(link_id);
  T_DTI_CNTRL  *dti_cntrl_dev = (T_DTI_CNTRL *)find_element (dti_cntrl_list, dti_id, dti_cntrl_search_dti_id);

  TRACE_FUNCTION("dti_cntrl_entity_disconnected()");

  if (dti_cntrl_dev)
  {
    dti_cntrl_dev->cur_cap = DTI_CPBLTY_NO; /* reset current capability */
  }

  /* call DTI Connection Mng function */
  dti_conn_entity_disconnected( link_id, entity_id );
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : DTI_CNTRL               |
| STATE   : code                   ROUTINE : dti_cntrl_erase_entry   |
+--------------------------------------------------------------------+

  PURPOSE : This function removes a registered device from
            DTI Cntrl Mng list and removes its DTI ID from the list of
            DTI Conn Mng.

*/
GLOBAL void dti_cntrl_erase_entry (UBYTE dti_id)
{
  T_DTI_CNTRL  *dti_cntrl_dev = NULL;

  TRACE_FUNCTION("dti_cntrl_erase_entry()");

  dti_cntrl_dev = remove_element (dti_cntrl_list, dti_id, dti_cntrl_search_dti_id);

  if (dti_cntrl_dev EQ NULL)
  {
    TRACE_EVENT_P1("Device with DTI ID %d was not registered", dti_id);
  }
  else
  {
    /*
     * redirect_info is a union, where we use the union element tbl,
     * which is a pointer to an allocated structure
     * of type T_DTI_CNTRL_REDIRECT_INTERN
     */
    if (dti_cntrl_dev->redirect_info.tbl NEQ NULL)
    {
      ACI_MFREE (dti_cntrl_dev->redirect_info.tbl);
      dti_cntrl_dev->redirect_info.tbl = NULL;
    }
    ACI_MFREE (dti_cntrl_dev);
  }

  /* call DTI connection manager function */
  dti_conn_erase_entry(dti_id);

}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)         MODULE  : DTI_CNTRL               |
| STATE   : code                   ROUTINE : dti_cntrl_reg_new_fct   |
+--------------------------------------------------------------------+

  PURPOSE : register an call back function, which is used when a
            customer/external has its own entity involved during
            a data transmission.
            The registered function is called by dti_cntrl_maintain_entity()
            only, where dti_cntrl_maintain_entity() itself is a
            call back function used by the DTI Connection Manager
*/
GLOBAL BOOL  dti_cntrl_reg_new_fct  (T_DTI_ENTITY_ID   entity_id,
                                     T_DTI_EXT_CB     *fct)
{
  UBYTE i = 0;

  TRACE_FUNCTION("dti_cntrl_reg_new_fct()");

  if (entity_id <= DTI_ENTITY_MAX)
  {
    TRACE_EVENT("ENTITY ID already in use");
    return (FALSE);
  }

  for (i=0; i<DTI_MAX_EXT_CB; i++)
  {
    if (reg_ext_cb[i].ent_id EQ DTI_ENTITY_INVALID)
    {
      reg_ext_cb[i].ent_id = entity_id;
      reg_ext_cb[i].fct    = fct;
      return (TRUE);
    }
  }
  return (FALSE);
}

/*
 * special temporary stuff
 */

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)        MODULE  : DTI_CNTRL                |
| STATE   : code                  ROUTINE : dti_cntrl_get_link_id()  |
+--------------------------------------------------------------------+

  PURPOSE :

*/
GLOBAL T_DTI_CONN_LINK_ID dti_cntrl_get_link_id( T_DTI_ENTITY_ID ent_id,
                                                 UBYTE           dev_no,
                                                 UBYTE           sub_no)
{
  UBYTE i;

  TRACE_FUNCTION("dti_cntrl_get_link_id()");

  for (i=0; i<MAX_DTI_CONN_LINK_IDS; i++)
  {
    if ( ((dti_aci_data_base[i].ent_id1 EQ ent_id)
           AND (dti_aci_data_base[i].dev_no1 EQ dev_no)
           AND (dti_aci_data_base[i].sub_no1 EQ sub_no))
         OR
         ((dti_aci_data_base[i].ent_id2 EQ ent_id)
           AND (dti_aci_data_base[i].dev_no2 EQ dev_no)
           AND (dti_aci_data_base[i].sub_no2 EQ sub_no)) )
      return (dti_aci_data_base[i].link_id);
  }

  TRACE_EVENT("link_id not found");
  return DTI_LINK_ID_NOTPRESENT;
}


/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)        MODULE  : DTI_CNTRL                |
| STATE   : code                  ROUTINE : dti_cntrl_get_peer_()    |
+--------------------------------------------------------------------+

  PURPOSE :

*/
GLOBAL T_DTI_ENTITY_ID dti_cntrl_get_peer( T_DTI_ENTITY_ID ent_id,
                                           UBYTE           dev_no,
                                           UBYTE           sub_no)
{
  UBYTE i;

  TRACE_FUNCTION("dti_cntrl_get_peer()");

  for (i=0; i<MAX_DTI_CONN_LINK_IDS; i++)
  {
    if  ((dti_aci_data_base[i].ent_id1 EQ ent_id)
          AND (dti_aci_data_base[i].dev_no1 EQ dev_no)
          AND (dti_aci_data_base[i].sub_no1 EQ sub_no))
    {
      return dti_aci_data_base[i].ent_id2;
    }
    if  ((dti_aci_data_base[i].ent_id2 EQ ent_id)
          AND (dti_aci_data_base[i].dev_no2 EQ dev_no)
          AND (dti_aci_data_base[i].sub_no2 EQ sub_no))
    {
      return dti_aci_data_base[i].ent_id1;
    }
  }

  TRACE_EVENT("peer entity not found");
  return DTI_ENTITY_INVALID;
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)      MODULE  : DTI_CNTRL                  |
| STATE   : code                ROUTINE : dti_cntrl_set_conn_parms() |
+--------------------------------------------------------------------+

  PURPOSE :

*/
GLOBAL BOOL dti_cntrl_set_conn_parms( T_DTI_CONN_LINK_ID link_id,
                                      T_DTI_ENTITY_ID    ent_id,
                                      UBYTE              dev_no,
                                      UBYTE              sub_no )
{
  UBYTE i;

  TRACE_FUNCTION("dti_cntrl_set_conn_parms()");

  for (i=0; i<MAX_DTI_CONN_LINK_IDS; i++)
  {
    if (dti_aci_data_base[i].link_id EQ DTI_LINK_ID_NOTPRESENT)
    {
      dti_aci_data_base[i].link_id  = link_id;

      dti_aci_data_base[i].ent_id1 = ent_id;
      dti_aci_data_base[i].dev_no1 = dev_no;
      dti_aci_data_base[i].sub_no1 = sub_no;

      return TRUE;
    }
    else if (dti_aci_data_base[i].link_id EQ link_id)
    {
      dti_aci_data_base[i].ent_id2 = ent_id;
      dti_aci_data_base[i].dev_no2 = dev_no;
      dti_aci_data_base[i].sub_no2 = sub_no;

      return TRUE;
    }
  }

  return FALSE;
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)      MODULE  : DTI_CNTRL                  |
| STATE   : code                ROUTINE : dti_cntrl_clear_conn_parms |
+--------------------------------------------------------------------+

  PURPOSE :

*/
GLOBAL void dti_cntrl_clear_conn_parms( UBYTE dti_id )
{
  UBYTE i;

  TRACE_FUNCTION("dti_cntrl_clear_conn_parms()");

  for (i=0; i<MAX_DTI_CONN_LINK_IDS; i++)
  {
    if (EXTRACT_DTI_ID(dti_aci_data_base[i].link_id) EQ dti_id)
    {
      dti_aci_data_base[i].link_id  = DTI_LINK_ID_NOTPRESENT;
      dti_aci_data_base[i].dev_no1  = DTI_DEV_NO_NOTPRESENT;
      dti_aci_data_base[i].dev_no2  = DTI_DEV_NO_NOTPRESENT;
      dti_aci_data_base[i].ent_id1  = DTI_ENTITY_INVALID;
      dti_aci_data_base[i].ent_id2  = DTI_ENTITY_INVALID;
      dti_aci_data_base[i].sub_no1  = DTI_SUB_NO_NOTPRESENT;
      dti_aci_data_base[i].sub_no2  = DTI_SUB_NO_NOTPRESENT;
    }
  }
}

/*
+---------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)  MODULE  : DTI_CNTRL                       |
| STATE   : code            ROUTINE : dti_cntrl_close_all_connections |
+---------------------------------------------------------------------+

  PURPOSE :

*/
GLOBAL void dti_cntrl_close_all_connections()
{
  T_DTI_CNTRL  *dti_cntrl_dev;
  USHORT        dti_cntrl_list_num = 0;
  USHORT        i                  = 0;
  USHORT        k                  = 0;

  TRACE_FUNCTION("dti_cntrl_close_all_connections()");

  dti_cntrl_list_num = get_list_count (dti_cntrl_list);
  /*
   * we clear the list from head to tail
   */
  while (i <= dti_cntrl_list_num)
  {
    dti_cntrl_dev = (T_DTI_CNTRL *)remove_first_element (dti_cntrl_list);

    if (dti_cntrl_dev)
    {
      for (k=0; k<DTI_MAX_REDIRECTIONS; ++k)
      {
        dti_cntrl_dev->redirect_info.tbl->ser_redirect[k].redirection = NULL;
        dti_cntrl_dev->redirect_info.tbl->pkt_redirect[k].redirection = NULL;
      }

      ACI_MFREE (dti_cntrl_dev->redirect_info.tbl);
      ACI_MFREE (dti_cntrl_dev);
    }
    ++i;
  }

  dti_conn_close_all_connections();
}

/*
+----------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)  MODULE  : DTI_CNTRL                        |
| STATE   : code            ROUTINE : dti_cntrl_set_dti_id_to_reconnect|
+----------------------------------------------------------------------+

  PURPOSE : This function sets a flag that means that if this DTI 
            connection is completely disconnected then reconnect the 
            registered device to ACI.
*/
GLOBAL void dti_cntrl_set_dti_id_to_reconnect(UBYTE dti_id)
{
  ULONG tmp_bit_field = 0x01 << (dti_id);

  TRACE_FUNCTION("dti_cntrl_set_dti_id_to_reconnect()");

  BITFIELD_SET(dti_cntrl_reconnect_to_aci, tmp_bit_field);
}

/*
+------------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)  MODULE  : DTI_CNTRL                          |
| STATE   : code            ROUTINE : dti_cntrl_clear_dti_id_to_reconnect|
+------------------------------------------------------------------------+

  PURPOSE : Clears the 'Reconnect-to-ACI' flag.

*/
GLOBAL void dti_cntrl_clear_dti_id_to_reconnect(UBYTE dti_id)
{
  ULONG tmp_bit_field = 0x01 << (dti_id);

  TRACE_FUNCTION("dti_cntrl_clear_dti_id_to_reconnect()");

  BITFIELD_CLEAR(dti_cntrl_reconnect_to_aci, tmp_bit_field);
}

/*
+------------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)  MODULE  : DTI_CNTRL                          |
| STATE   : code            ROUTINE : dti_cntrl_is_dti_id_to_reconnect   |
+------------------------------------------------------------------------+

  PURPOSE : Queries the 'Reconnect-to-ACI' flag.

*/
GLOBAL BOOL dti_cntrl_is_dti_id_to_reconnect(UBYTE dti_id)
{
  ULONG tmp_bit_field = 0x01 << (dti_id);

  TRACE_FUNCTION("dti_cntrl_is_dti_id_to_reconnect()");

  if (BITFIELD_CHECK(dti_cntrl_reconnect_to_aci, tmp_bit_field))
  {
    TRACE_EVENT_P1("dti_id=%d must be reconnected", dti_id);
    return TRUE;
  }
  else
  {
    return FALSE;
  }
}

#endif /* DTI */