view src/g23m-gprs/llc/llc_txs.c @ 287:3dee79757ae4

UI fw: load handheld audio mode on boot We have now reached the point where use of audio mode config files should be considered mandatory. In ACI usage we can tell users that they need to perform an AT@AUL of some appropriate audio mode, but in UI-enabled fw we really need to have the firmware load audio modes on its own, so that correct audio config gets established when the handset or development board runs on its own, without a connected host computer. Once have FC Venus with both main and headset audio channels and headset plug insertion detection, our fw will need to automatically load the handheld mode or the headset mode depending on the plug insertion state. For now we load only the handheld mode, which has been tuned for FC-HDS4 on FC Luna.
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 13 Nov 2021 03:20:57 +0000
parents fa8dc04885d8
children
line wrap: on
line source

/* 
+----------------------------------------------------------------------------- 
|  Project :  
|  Modul   :  
+----------------------------------------------------------------------------- 
|  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 is part of the entity LLC and implements all 
|             functions to handles the incoming process internal signals as  
|             described in the SDL-documentation (TX-statemachine)
+----------------------------------------------------------------------------- 
*/ 

#ifndef LLC_TXS_C
#define LLC_TXS_C
#endif

#define ENTITY_LLC

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

#include "typedefs.h"   /* to get Condat data types */
#include "vsi.h"        /* to get a lot of macros */
#include "macdef.h"
#include "gprs.h"
#include "gsm.h"        /* to get a lot of macros */
#include "cnf_llc.h"    /* to get cnf-definitions */
#include "mon_llc.h"    /* to get mon-definitions */
#include "prim.h"       /* to get the definitions of used SAP and directions */
#include "llc.h"        /* to get the global entity definitions */
#include "llc_f.h"

#include "llc_txf.h"    /* to get local TX functions */
#include "llc_txl.h"    /* to get local TX labels */
#include "llc_uitxs.h"  /* to get signal interface to UITX */
#include "llc_itxs.h"   /* to get signal interface to ITX */

#ifdef REL99 
#include "llc_uf.h"     /* to get interface to U control frame */
#endif /* REL99 */

/*==== CONST ================================================================*/

/*==== LOCAL VARS ===========================================================*/

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

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


/*
+------------------------------------------------------------------------------
| Function    : sig_llme_tx_assign_req
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_LLME_TX_ASSIGN_REQ
|
| Parameters  : 
|
+------------------------------------------------------------------------------
*/
GLOBAL void sig_llme_tx_assign_req (void)
{
  T_SAPI sapi;


  TRACE_ISIG( "sig_llme_tx_assign_req" );

  switch( GET_STATE( TX ) )
  {
    case TX_TLLI_UNASSIGNED_NOT_READY:
      SET_STATE (TX, TX_TLLI_ASSIGNED_NOT_READY);

      /*
       * ATTENTION:
       * The following loops implies that all SAPIs are odd numbers beginning
       * with 1!
       */
      for (sapi = LL_SAPI_1; sapi <= LL_SAPI_11; sapi += 2)
      {
        SWITCH_SERVICE (llc, uitx, UIMAP(sapi));
        llc_data->current_sapi = sapi;

        sig_tx_uitx_ready_ind();
      }

      for (sapi = LL_SAPI_3; sapi <= LL_SAPI_11; sapi += 2)
      {
        SWITCH_SERVICE (llc, itx, IMAP(sapi));
        llc_data->current_sapi = sapi;

        if (sapi != LL_SAPI_7)
        {
          sig_tx_itx_ready_ind();
        }
      }
      break;
    case TX_TLLI_UNASSIGNED_READY:
      SET_STATE (TX, TX_TLLI_ASSIGNED_READY);

      /*
       * ATTENTION:
       * The following loops implies that all SAPIs are odd numbers beginning
       * with 1!
       */
      for (sapi = LL_SAPI_1; sapi <= LL_SAPI_11; sapi += 2)
      {
        SWITCH_SERVICE (llc, uitx, UIMAP(sapi));
        llc_data->current_sapi = sapi;

        sig_tx_uitx_ready_ind();
      }

      for (sapi = LL_SAPI_3; sapi <= LL_SAPI_11; sapi += 2)
      {
        SWITCH_SERVICE (llc, itx, IMAP(sapi));
        llc_data->current_sapi = sapi;

        if (sapi != LL_SAPI_7)
        {
          sig_tx_itx_ready_ind();
        }
      }
      break;

    default:
      TRACE_ERROR( "SIG_LLME_TX_ASSIGN_REQ unexpected" );
      break;
  }

  return;
} /* sig_llme_tx_assign_req() */


/*
+------------------------------------------------------------------------------
| Function    : sig_llme_tx_unassign_req
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_LLME_TX_UNASSIGN_REQ
|
| Parameters  : 
|
+------------------------------------------------------------------------------
*/
GLOBAL void sig_llme_tx_unassign_req (void)
{
  TRACE_ISIG( "sig_llme_tx_unassign_req" );

  switch( GET_STATE( TX ) )
  {
    case TX_TLLI_ASSIGNED_NOT_READY:
      tx_clear_buffer();
      SET_STATE (TX, TX_TLLI_UNASSIGNED_NOT_READY);
      break;

    case TX_TLLI_ASSIGNED_READY:
      tx_clear_buffer();
      SET_STATE (TX, TX_TLLI_UNASSIGNED_READY);
      break;

    default:
      TRACE_ERROR( "SIG_LLME_TX_UNASSIGN_REQ unexpected" );
      break;
  }

  return;
} /* sig_llme_tx_unassign_req() */


/*
+------------------------------------------------------------------------------
| Function    : sig_llme_tx_reset_req
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_LLME_TX_RESET_REQ
|
| Parameters  : 
|
+------------------------------------------------------------------------------
*/
GLOBAL void sig_llme_tx_reset_req (void)
{
  TRACE_ISIG( "sig_llme_tx_reset_req" );

  switch( GET_STATE( TX ) )
  {
    case TX_TLLI_ASSIGNED_NOT_READY:
      /*
       * No break!
       */
    case TX_TLLI_ASSIGNED_READY:
      tx_clear_buffer();
      //sig_tx_uitx_ready_ind();
      break;

    default:
      TRACE_ERROR( "SIG_LLME_TX_RESET_REQ unexpected" );
      break;
  }

  return;
} /* sig_llme_tx_reset_req() */


/*
+------------------------------------------------------------------------------
| Function    : sig_llme_tx_ready_req
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_LLME_TX_READY_REQ
|
| Parameters  : 
|
+------------------------------------------------------------------------------
*/
GLOBAL void sig_llme_tx_ready_req (void)
{
  TRACE_ISIG( "sig_llme_tx_ready_req" );

  switch( GET_STATE( TX ) )
  {
    case TX_TLLI_ASSIGNED_NOT_READY:
      /*
       * No break!
       */
    case TX_TLLI_ASSIGNED_READY:
      sig_tx_uitx_ready_ind();
      break;

    default:
      TRACE_ERROR( "SIG_LLME_TX_READY_REQ unexpected" );
      break;
  }

  return;
} /* sig_llme_tx_ready_req() */




/*
+------------------------------------------------------------------------------
| Function    : sig_u_tx_data_req
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_U_TX_DATA_REQ
|
| Parameters  : ll_unitdata_req - a valid pointer to a GRLC-UNITDATA-REQ 
|                                 primitive
|               cause           - RLC/MAC cause
|
+------------------------------------------------------------------------------
*/
GLOBAL void sig_u_tx_data_req 
(
#ifdef LL_DESC
 T_LL_UNITDESC_REQ *ll_unitdesc_req,
#else
 T_LL_UNITDATA_REQ *ll_unitdesc_req,
#endif
 UBYTE cause
)
{
  ULONG             reservation_no;
  BOOL              buffer_available;   
  UBYTE             protected_mode;

  TRACE_ISIG( "sig_u_tx_data_req" );
  
  switch( GET_STATE( TX ) )
  {
    case TX_TLLI_ASSIGNED_NOT_READY:
      /* No break. */
    case TX_TLLI_ASSIGNED_READY:

      /*
       * U frames are always sent with default cause! except cell notification.
       */
#ifdef REL99 
      if (cause EQ GRLC_DTACS_CELL_NOTIFI_NULL_FRAME)
      {
        tx_reserve_buffer (ll_unitdesc_req, PRIM_DATA, cause, 
                          SERVICE_U, &reservation_no, &buffer_available);
      }
      else
#endif /* REL99 */
      {
        tx_reserve_buffer (ll_unitdesc_req, PRIM_DATA, GRLC_DTACS_DEF, 
                          SERVICE_U, &reservation_no, &buffer_available);
      }
      /*
       * U frames are always sent in LLC protected mode.
       */
      protected_mode = CCI_PM_PROTECTED;

      {
#ifdef LL_DESC 
        T_CCI_CIPHER_DESC_REQ *cci_cipher_desc_req;
        MALLOC(cci_cipher_desc_req, sizeof(T_CCI_CIPHER_DESC_REQ));
        cci_cipher_desc_req->desc_list3.first = ll_unitdesc_req->desc_list3.first;
        cci_cipher_desc_req->desc_list3.list_len = ll_unitdesc_req->desc_list3.list_len;
        cci_cipher_desc_req->attached_counter = ll_unitdesc_req->attached_counter;
        /*
         * decrease attached counter. If no one is still attached
         * free the primitive memory
         */
        if (ll_unitdesc_req->attached_counter == CCI_NO_ATTACHE)
        {
          PFREE(ll_unitdesc_req);
        } else {
          TRACE_0_INFO("LL_UNITDESC_REQ still attached");
        }
#else
        PPASS (ll_unitdesc_req, cci_cipher_desc_req, CCI_CIPHER_REQ);
#endif
        /*
         * Header size (offset of information) is reqired, if ciphering is used
         * or if the frame shall be send in unprotected mode. In this case both
         * is not true and so it can be ignored.
         */
        cci_cipher_desc_req->header_size = 0;

        /*
         * Associate reservation_no with the frame.
         */
        cci_cipher_desc_req->reference1 = reservation_no;

        /*
         * U frames are never sent ciphered, thus define LL_CIPHER_OFF and set
         * N(S) to 0 (it is not used).
         */
        tx_send_cipher_req (cci_cipher_desc_req, U_FRAME, protected_mode, 0,
          LL_CIPHER_OFF, 0);

      }
      break;

    default:
#ifdef LL_DESC
      llc_cl_desc3_free((T_desc3*)ll_unitdesc_req->desc_list3.first);
#endif /* LL_DESC */
      PFREE (ll_unitdesc_req);

      TRACE_ERROR( "SIG_U_TX_DATA_REQ unexpected" );
      break;
  }
} /* sig_u_tx_data_req() */


/*
+------------------------------------------------------------------------------
| Function    : sig_uitx_tx_data_req
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_UITX_TX_DATA_REQ
|
| Parameters  : ll_unitdata_req - a valid pointer to a GRLC-UNITDATA-REQ 
|                                 primitive
|               cipher - indicates if the frame shall be ciphered or not
|
+------------------------------------------------------------------------------
*/
GLOBAL void sig_uitx_tx_data_req 
  (
#ifdef LL_DESC
  T_LL_UNITDESC_REQ *ll_unitdesc_req,
#else
  T_LL_UNITDATA_REQ *ll_unitdesc_req,
#endif
  UBYTE             cipher,
  UBYTE             cause,
  T_FRAME_NUM       nu,
  ULONG             oc
  )
 
{
  ULONG             reservation_no;
  BOOL              buffer_available;
  UBYTE             protected_mode;


  TRACE_ISIG( "sig_uitx_tx_data_req" );
  
  switch( GET_STATE( TX ) )
  {
    case TX_TLLI_ASSIGNED_NOT_READY:
      /* No break. */
    case TX_TLLI_ASSIGNED_READY:

      tx_reserve_buffer (ll_unitdesc_req, PRIM_DATA, cause, SERVICE_UITX,
        &reservation_no, &buffer_available);

      if (ll_unitdesc_req->ll_qos.relclass EQ LL_NO_REL)
      {
        protected_mode = CCI_PM_UNPROTECTED;
      }
      else /* reliability classes 4 - 1 */
      {
        protected_mode = CCI_PM_PROTECTED;
      }

      {
#ifdef LL_DESC        
        T_CCI_CIPHER_DESC_REQ *cci_cipher_desc_req;
        MALLOC(cci_cipher_desc_req, sizeof(T_CCI_CIPHER_DESC_REQ));
        cci_cipher_desc_req->desc_list3.first = ll_unitdesc_req->desc_list3.first;
        cci_cipher_desc_req->desc_list3.list_len = ll_unitdesc_req->desc_list3.list_len;
        cci_cipher_desc_req->attached_counter = ll_unitdesc_req->attached_counter;
        /*
         * decrease attached counter. If no one is still attached
         * free the primitive memory
         */
        if (ll_unitdesc_req->attached_counter == CCI_NO_ATTACHE)
        {
          PFREE(ll_unitdesc_req);
        } else {
          TRACE_0_INFO("LL_UNITDESC_REQ still attached");
        }
#else
        PPASS (ll_unitdesc_req, cci_cipher_desc_req, CCI_CIPHER_REQ);
#endif
        /*
         * Header size (offset of information) is reqired, if ciphering is used
         * or if the frame shall be send in unprotected mode. 
         */
        cci_cipher_desc_req->header_size = UI_CTRL_MIN_OCTETS;

        /*
         * Associate reservation_no with the frame.
         */
        cci_cipher_desc_req->reference1 = reservation_no;

        tx_send_cipher_req (cci_cipher_desc_req, UI_FRAME, protected_mode, nu, 
          cipher, oc);

        if (buffer_available)
        {
          /*
           * Buffer is still available for current SAPI.
           */
          sig_tx_uitx_ready_ind();
        }

      }
      break;

    default:
#ifdef LL_DESC
      llc_cl_desc3_free((T_desc3*)ll_unitdesc_req->desc_list3.first);
#endif /* LL_DESC */
      PFREE (ll_unitdesc_req);

      TRACE_ERROR( "SIG_UITX_TX_DATA_REQ unexpected" );
      break;
  }
} /* sig_uitx_tx_data_req() */


/*
+------------------------------------------------------------------------------
| Function    : sig_uitx_tx_unitdata_req
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_UITX_TX_UNITDATA_REQ
|
| Parameters  : ll_unitdata_req - a valid pointer to a GRLC-UNITDATA-REQ 
|                                 primitive
|               cipher - indicates if the frame shall be ciphered or not
|
+------------------------------------------------------------------------------
*/
GLOBAL void sig_uitx_tx_unitdata_req
(
#ifdef LL_DESC
  T_LL_UNITDESC_REQ *ll_unitdesc_req, 
#else
  T_LL_UNITDATA_REQ *ll_unitdesc_req,
#endif  
  UBYTE             cipher,
  T_FRAME_NUM       nu,
  ULONG             oc
) 
  
{
  ULONG             reservation_no;
  BOOL              buffer_available;
  UBYTE             protected_mode;


  TRACE_ISIG( "sig_uitx_tx_unitdata_req" ); 
  
  switch( GET_STATE( TX ) )
  {
    case TX_TLLI_ASSIGNED_NOT_READY:
      /* No break. */
    case TX_TLLI_ASSIGNED_READY:

      /*
       * Parameter cause will be ignored for RLC/MAC unacknowledged frames,
       * so set it to 0.
       */
      tx_reserve_buffer (ll_unitdesc_req, PRIM_UNITDATA, 0, SERVICE_UITX,
        &reservation_no, &buffer_available);

      if (ll_unitdesc_req->ll_qos.relclass EQ LL_NO_REL)
      {
        protected_mode = CCI_PM_UNPROTECTED;
      }
      else /* reliability classes 4 - 1 */
      {
        protected_mode = CCI_PM_PROTECTED;
      }

      {
#ifdef LL_DESC
        T_CCI_CIPHER_DESC_REQ *cci_cipher_desc_req;
        MALLOC(cci_cipher_desc_req, sizeof(T_CCI_CIPHER_DESC_REQ));
        cci_cipher_desc_req->desc_list3.first = ll_unitdesc_req->desc_list3.first;
        cci_cipher_desc_req->desc_list3.list_len = ll_unitdesc_req->desc_list3.list_len;
        cci_cipher_desc_req->attached_counter = ll_unitdesc_req->attached_counter;
        /*
         * decrease attached counter. If no one is still attached
         * free the primitive memory
         */
        if (ll_unitdesc_req->attached_counter == CCI_NO_ATTACHE)
        {
          PFREE(ll_unitdesc_req); 
        } else {
          TRACE_0_INFO("LL_UNITDESC_REQ still attached");
        }
#else
        PPASS (ll_unitdesc_req, cci_cipher_desc_req, CCI_CIPHER_REQ);
#endif
        /*
         * Header size (offset of information) is reqired, if ciphering is used
         * or if the frame shall be send in unprotected mode. 
         */
        cci_cipher_desc_req->header_size = UI_CTRL_MIN_OCTETS;

        /*
         * Associate reservation_no with the frame.
         */
        cci_cipher_desc_req->reference1 = reservation_no;

        tx_send_cipher_req (cci_cipher_desc_req, UI_FRAME, protected_mode, nu, 
          cipher, oc);

        if (buffer_available)
        {
          /*
           * Buffer is still available for current SAPI.
           */
          sig_tx_uitx_ready_ind();
        }

      }
      break;

    default:
#ifdef LL_DESC
      llc_cl_desc3_free((T_desc3*)ll_unitdesc_req->desc_list3.first);
#endif /* LL_DESC */
      PFREE (ll_unitdesc_req);

      TRACE_ERROR( "SIG_UITX_TX_UNITDATA_REQ unexpected" );
      break;
  }
} /* sig_uitx_tx_unitdata_req() */


/*
+------------------------------------------------------------------------------
| Function    : sig_itx_tx_data_req
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_ITX_TX_DATA_REQ
|
| Parameters  : ll_data_req - a valid pointer to a GRLC-DATA-REQ primitive
|               cause       - 
|
+------------------------------------------------------------------------------
*/
GLOBAL void sig_itx_tx_data_req
(
#ifdef LL_DESC
  T_LL_UNITDESC_REQ *ll_unitdesc_req, 
#else
  T_LL_UNITDATA_REQ *ll_unitdesc_req, 
#endif
  T_PDU_TYPE        frame_type,
  T_FRAME_NUM       ns,
  UBYTE             cause,
  USHORT            header_size,
  ULONG             oc
)
{
  ULONG             reservation_no;
  BOOL              buffer_available;
  UBYTE             protected_mode;

  TRACE_ISIG( "sig_itx_tx_data_req" );
  
  switch( GET_STATE( TX ) )
  {
    case TX_TLLI_ASSIGNED_NOT_READY:
      /* No break. */
    case TX_TLLI_ASSIGNED_READY:

      tx_reserve_buffer (ll_unitdesc_req, PRIM_DATA, cause, SERVICE_ITX,
        &reservation_no, &buffer_available);

      /*
       * I/S + S frames always send in protected mode
       */
      protected_mode = CCI_PM_PROTECTED;

      {
#ifdef LL_DESC
        T_CCI_CIPHER_DESC_REQ *cci_cipher_desc_req;
        MALLOC(cci_cipher_desc_req, sizeof(T_CCI_CIPHER_DESC_REQ));
        cci_cipher_desc_req->desc_list3.first = ll_unitdesc_req->desc_list3.first;
        cci_cipher_desc_req->desc_list3.list_len = ll_unitdesc_req->desc_list3.list_len;
        cci_cipher_desc_req->attached_counter = ll_unitdesc_req->attached_counter;
        /*
         * free the primitive memory
         */
        PFREE(ll_unitdesc_req); 
#else
        PPASS (ll_unitdesc_req, cci_cipher_desc_req, CCI_CIPHER_REQ);
#endif
        /*
         * Header size (offset of information) is reqired, if ciphering is used
         * or if the frame shall be send in unprotected mode. 
         */
        cci_cipher_desc_req->header_size = header_size;

        /*
         * Associate reservation_no with the frame.
         */
        cci_cipher_desc_req->reference1 = reservation_no;

        if (frame_type == S_FRAME)
        {
          /*
           * Do not try to cipher an S frame (there is no information ;-)
           */
          tx_send_cipher_req (cci_cipher_desc_req, frame_type, protected_mode, ns, 
            LL_CIPHER_OFF, oc);
        }
        else
        {
          /*
           * I frames shall always send ciphered
           */
          tx_send_cipher_req (cci_cipher_desc_req, frame_type, protected_mode, ns, 
            LL_CIPHER_ON, oc);
        }

        if (buffer_available)
        {
          /*
           * Buffer is still available for current SAPI.
           */
          sig_tx_itx_ready_ind();
        }

      }
      break;

    default:
      if (ll_unitdesc_req->attached_counter == CCI_NO_ATTACHE)
      {
#ifdef LL_DESC
        llc_cl_desc3_free((T_desc3*)ll_unitdesc_req->desc_list3.first);
#endif /* LL_DESC */
        PFREE (ll_unitdesc_req);
      }
      TRACE_ERROR( "SIG_ITX_TX_DATA_REQ unexpected" );
      break;
  }
} /* sig_itx_tx_data_req() */


/*
+------------------------------------------------------------------------------
| Function    : sig_llme_tx_trigger_req
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_LLME_TX_TRIGGER_REQ
|
| Parameters  : cause - trigger cause
|
+------------------------------------------------------------------------------
*/
GLOBAL void sig_llme_tx_trigger_req (UBYTE cause)
{
  T_TX_QUEUE                  *elem;


  TRACE_ISIG( "sig_llme_tx_trigger_req" );
  
  TRACE_1_PARA("cause:%d", cause);

  switch( GET_STATE( TX ) )
  {
    case TX_TLLI_ASSIGNED_NOT_READY:
      /* no break! */
    case TX_TLLI_ASSIGNED_READY:
      tx_get_first_data_frame (&elem);

      if (elem EQ NULL)
      {
#ifdef REL99 
        if (cause EQ LLGMM_TRICS_CELL_UPDATE_NULL_FRAME)
        {
          cause = GRLC_DTACS_CELL_NOTIFI_NULL_FRAME;
          sig_tx_u_send_null(cause);
        }
        else 
#endif /* REL99 */      
        if (cause EQ LLGMM_TRICS_CELL_UPDATE)
        {
           cause = GRLC_DTACS_EMPTY_FRAME;
           sig_tx_uitx_trigger_ind (cause);
        }
        else
        {
           sig_tx_uitx_trigger_ind (cause);
        }
      }
      else /* elem is valid */
      {
        /*
         * NOTE: Possible cause values are DEFAULT, MOBILITY_MANAGEMENT, 
         * PAGE_RESPONSE, CELL_UPDATE and CELL NOTIFICATION.
         * Overwriting DEFAULT, MOBILITY_MANAGEMENT, and the same cause 
         * (which is already set) is ok. This leaves two relevant (and 
         * mutually exclusive) trigger causes to be considered. A problem may 
         * occur if the primitive contained the one remaining trigger cause 
         * and the other is requested. But according to ANS this should not 
         * happen.
         */
        
        if ((cause EQ LLGMM_TRICS_CELL_UPDATE)
#ifdef REL99 
               OR
            (cause EQ LLGMM_TRICS_CELL_UPDATE_NULL_FRAME)
#endif /*REL99*/
            )
        {
          cause = GRLC_DTACS_DEF;
        }

        if (elem->primitive EQ NULL)
        {
          /*
           * Primitive is not yet ready-to-send. Modify cause in primitve 
           * header variable.
           */
          elem->ph_cause = cause;
        }
        else /* elem->primitive is valid */
        {
          /*
           * Primitive is ready-to-send. Modifiy cause in primitive.
           */
          ((T_GRLC_DATA_REQ *)(elem->primitive))->cause = cause;
        }
      }
      break;

    default:
      TRACE_ERROR( "SIG_LLME_TX_TRIGGER_REQ unexpected" );
      break;
  }
} /* sig_llme_tx_trigger_req() */


/*
+------------------------------------------------------------------------------
| Function    : sig_llme_tx_suspend_req
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_LLME_TX_SUSPEND_REQ
|
| Parameters  : 
|
+------------------------------------------------------------------------------
*/
GLOBAL void sig_llme_tx_suspend_req (void)
{
  TRACE_ISIG( "sig_llme_tx_suspend_req" );
  
  switch( GET_STATE( TX ) )
  {
    case TX_TLLI_UNASSIGNED_NOT_READY:
    case TX_TLLI_ASSIGNED_NOT_READY:
      /*
       * Nothing to do
       */
      break;

    case TX_TLLI_ASSIGNED_READY:
      /*
       * Flow Control has to be re-started by GRLC
       */
      SET_STATE (TX, TX_TLLI_ASSIGNED_NOT_READY);
      break;

    case TX_TLLI_UNASSIGNED_READY:
      /*
       * Flow Control has to be re-started by GRLC
       */
      SET_STATE (TX, TX_TLLI_UNASSIGNED_NOT_READY);
      break;

    default:
      TRACE_ERROR( "SIG_LLME_TX_SUSPEND_REQ unexpected" );
      break;
  }
} /* sig_llme_tx_suspend_req() */

/*
+------------------------------------------------------------------------------
| Function    : sig_llme_tx_resume_req
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_LLME_TX_RESUME_REQ
|
| Parameters  : 
|
+------------------------------------------------------------------------------
*/
GLOBAL void sig_llme_tx_resume_req (BOOL grlc_was_suspened)
{
  T_GRLC_DATA_REQ              *grlc_data_req;
  T_GRLC_UNITDATA_REQ          *grlc_unitdata_req;
  T_PRIM_TYPE                 prim_type;
  T_SERVICE                   rx_service;
  UBYTE                       sapi;

  TRACE_ISIG( "sig_llme_tx_resume_req" );
  
  switch( GET_STATE( TX ) )
  {
    case TX_TLLI_UNASSIGNED_NOT_READY:
    case TX_TLLI_ASSIGNED_NOT_READY:
      /*
       * Nothing to do
       */
      break;

    case TX_TLLI_ASSIGNED_READY:
      if (grlc_was_suspened == FALSE)
      {
        /*
         * LLME indicates that any data may now be sent again.
         */
        do {
          tx_get_next_frame (&grlc_data_req, &grlc_unitdata_req, &prim_type, 
            &rx_service, &sapi);

          switch (prim_type)
          {
            case PRIM_DATA:
              /*
               * Label S_DATA
               */
              tx_label_s_data (rx_service, grlc_data_req);
              break;
            case PRIM_UNITDATA:
              /*
               * Label S_UNITDATA
               */
              tx_label_s_unitdata (rx_service, grlc_unitdata_req);
              break;
            case PRIM_REMOVED:
              /*
               * Label S_REMOVED
               */
              tx_label_s_removed (rx_service, sapi);
              break;
            default: /* NO_PRIM */
              break;
          }
        } while (prim_type == PRIM_REMOVED);
      }
      else
      {
        /*
         * Flow Control has to be re-started by GRLC
         */
        SET_STATE (TX, TX_TLLI_ASSIGNED_NOT_READY);
      }
      break;

    case TX_TLLI_UNASSIGNED_READY:
      /*
       * Flow Control has to be re-started by GRLC
       */
      SET_STATE (TX, TX_TLLI_UNASSIGNED_NOT_READY);
      break;

    default:
      TRACE_ERROR( "SIG_LLME_TX_RESUME_REQ unexpected" );
      break;
  }
} /* sig_llme_tx_resume_req() */



/*
+------------------------------------------------------------------------------
| Function    : sig_llme_tx_flush_req
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_LLME_TX_FLUSH_REQ
|
| Parameters  : 
|
+------------------------------------------------------------------------------
*/
GLOBAL void sig_llme_tx_flush_req (T_SERVICE service)
{
  TRACE_ISIG( "sig_llme_tx_flush_req" );
  
  switch( GET_STATE( TX ) )
  {
    case TX_TLLI_ASSIGNED_READY:
    case TX_TLLI_ASSIGNED_NOT_READY:
      tx_remove_data_frames (service, llc_data->current_sapi);
      break;

    default:
      TRACE_ERROR( "SIG_LLME_TX_FLUSH_REQ unexpected" );
      break;
  }
} /* sig_llme_tx_flush_req() */