view src/g23m-gprs/grlc/grlc_tmp.c @ 276:4221c724c664

R2D: preparations for adding LCD hardware suspend handling
author Mychaela Falconia <falcon@freecalypso.org>
date Tue, 07 Sep 2021 21:05:38 +0000
parents fa8dc04885d8
children
line wrap: on
line source

/* 
+----------------------------------------------------------------------------- 
|  Project :  GPRS (8441)
|  Modul   :  GRLC
+----------------------------------------------------------------------------- 
|  Copyright 2002 Texas Instruments Berlin, AG 
|                 All rights reserved. 
| 
|                 This file is confidential and a trade secret of Texas 
|                 Instruments Berlin, AG 
|                 The receipt of or possession of this file does not convey 
|                 any rights to reproduce or disclose its contents or to 
|                 manufacture, use, or sell anything it may describe, in 
|                 whole, or in part, without the specific written consent of 
|                 Texas Instruments Berlin, AG. 
+----------------------------------------------------------------------------- 
|  Purpose :  This module implements primitive handler functions for service
|             TM of entity GRLC.
+----------------------------------------------------------------------------- 
*/ 

#ifndef GRLC_TMP_C
#define GRLC_TMP_C
#endif

#define ENTITY_GRLC

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

#include "typedefs.h"   /* to get Condat data types */
#include "vsi.h"        /* to get a lot of macros */
#include <string.h>
#include "macdef.h"
#include "gprs.h"
#include "gsm.h"        /* to get a lot of macros */
#include "ccdapi.h"     /* to get CCD API */
#include "cnf_grlc.h"    /* to get cnf-definitions */
#include "mon_grlc.h"    /* to get mon-definitions */
#include "prim.h"       /* to get the definitions of used SAP and directions */
#include "message.h"    /* to get air message definitions */
#include "grlc.h"        /* to get the global entity definitions */
#include "grlc_f.h"      /* to get the grlc global function definitions */
#include "grlc_rus.h"    /* to get the service RU signal definitions */
#include "grlc_rds.h"    /* to get the service RD signal definitions */
#include "grlc_tmf.h"    /* to get the service TM functions definitions */
#include "grlc_meass.h"  /* to get the service MEAS signal definitions */
#include "grlc_tpcs.h"
#if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH
#include "grlc_tms.h"
#endif

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

/*==== DIAGNOSTICS ==========================================================*/

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

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

LOCAL void tm_uplink_data_req ( T_PRIM_TYPE  prim_type,
                                void        *llc_data_req );

/*==== PRIVATE FUNCTIONS ====================================================*/
/*
+------------------------------------------------------------------------------
| Function    : tm_uplink_data_req 
+------------------------------------------------------------------------------
| Description : Handles the primitives GRLC_DATA_REQ and GRLC_UNITDATA_REQ
|
| Parameters  : *llc_data_req  - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
LOCAL void tm_uplink_data_req ( T_PRIM_TYPE  prim_type,
                                void        *llc_data_req )
{ 
  UBYTE state = GET_STATE( TM );
  BOOL  use_data_req;

  T_GRLC_DATA_REQ     *grlc_data_req     = ( T_GRLC_DATA_REQ*     )llc_data_req;
  T_GRLC_UNITDATA_REQ *grlc_unitdata_req = ( T_GRLC_UNITDATA_REQ* )llc_data_req;

  TRACE_FUNCTION( "tm_uplink_data_req" );

  PACCESS( llc_data_req );

#ifdef FLOW_TRACE

  sndcp_trace_flow_control
                      ( FLOW_TRACE_GRLC, FLOW_TRACE_UP, FLOW_TRACE_TOP, FALSE );

#endif
  
  if( 
      (
        grlc_test_mode_active( )
      )
      AND 
      ( 
        ( prim_type              EQ  CGRLC_LLC_PRIM_TYPE_DATA_REQ     AND 
          grlc_data_req->sapi     NEQ GRLC_SAPI_TEST_MODE         )
        OR
        ( prim_type              EQ  CGRLC_LLC_PRIM_TYPE_UNITDATA_REQ AND 
          grlc_unitdata_req->sapi NEQ GRLC_SAPI_TEST_MODE         )
      )
    )
  {
    /*
     * all LLC data requests are ignored during GPRS test mode
     */      
    TRACE_EVENT( "tm_uplink_data_req: GPRS test mode active" );
    PFREE( llc_data_req );

    return;
  }


  if(   prim_type                  EQ CGRLC_LLC_PRIM_TYPE_DATA_REQ           AND 
        grlc_data->prim_start_tbf  <  PRIM_QUEUE_SIZE                        AND  
      ( grlc_data_req->cause       EQ GRLC_DTACS_EMPTY_FRAME            OR
        grlc_data_req->cause       EQ GRLC_DTACS_CELL_NOTIFI_NULL_FRAME    )     )
  {
    TRACE_EVENT_P1("EMPTY FRAME RECEIVED, LLLC FRAME AVAILABLE, delete empty frame: sdu_len=%d", grlc_data_req->sdu.l_buf / 8);    
    grlc_data->tm.send_grlc_ready_ind = SEND_A_GRLC_READY_IND;
    tm_handle_grlc_ready_ind( );
    PFREE( llc_data_req );
    return;
  }

  

/*

  if( prim_type EQ PRIM_TYPE_DATA_REQ )
  {
    TRACE_EVENT_P2( "tm_uplink_data_req: sdu_len=%ld data_req_cnt=%d",
                    grlc_data_req->sdu.l_buf / 8,
                    grlc_data->grlc_data_req_cnt );

    TRACE_EVENT_P9( "tm_uplink_data_req: sapi=%d tlli=%lx delay=%d relc=%d peak=%d prec=%d mean=%d r_pri=%d cause=%d",
                    grlc_data_req->sapi,
                    grlc_data_req->tlli,
                    grlc_data_req->qos.delay,
                    grlc_data_req->qos.relclass,
                    grlc_data_req->qos.peak,
                    grlc_data_req->qos.preced,
                    grlc_data_req->qos.mean,
                    grlc_data_req->radio_prio,
                    grlc_data_req->cause );
  }

*/

  grlc_data->tm.send_grlc_ready_ind = SEND_A_GRLC_READY_IND;

  switch( state )
  {
    case TM_ACCESS_DISABLED:
    case TM_ACCESS_PREPARED:
      use_data_req = 
        (
          grlc_data->tm.disable_class EQ CGRLC_DISABLE_CLASS_CR
        )
        AND
        (
          ( prim_type           EQ CGRLC_LLC_PRIM_TYPE_DATA_REQ     AND
            grlc_data_req->cause EQ GRLC_DTACS_DEF              )
          OR
          ( prim_type           EQ CGRLC_LLC_PRIM_TYPE_UNITDATA_REQ     )
        );
      break;
     
    default:
      use_data_req = tm_access_allowed (  grlc_data_req->radio_prio  );
      break;
  }

  if( use_data_req )
  {
    tm_data_req( prim_type, ( T_GRLC_DATA_REQ* )llc_data_req );
    grlc_data->grlc_data_req_cnt++;

    switch( state )
    {
      case TM_PIM:
        tm_ul_tbf_ind();
        break;

      case TM_PTM:
        tm_ul_tbf_ind();
        
        if( grlc_data->tbf_type NEQ TBF_TYPE_DL )
        {
          /* uplink is active*/
          sig_tm_ru_queue_status( );
        }
        break;

      default:
        /* do nothing */
        break;
    }
  }
  else
  {
    tm_cgrlc_status_ind( CGRLC_ACCESS_2_NETWORK_NOT_ALLOWED );
    PFREE( llc_data_req );
  }

  tm_handle_grlc_ready_ind( );

} /* tm_uplink_data_req () */

/*==== PUBLIC FUNCTIONS =====================================================*/
/*
+------------------------------------------------------------------------------
| Function    : tm_grlc_data_req 
+------------------------------------------------------------------------------
| Description : Handles the primitive GRLC_DATA_REQ 
|
| Parameters  : *grlc_data_req  - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_grlc_data_req  ( T_GRLC_DATA_REQ  *grlc_data_req  )
{ 
  TRACE_FUNCTION( "tm_grlc_data_req " );

  tm_uplink_data_req( CGRLC_LLC_PRIM_TYPE_DATA_REQ, ( void* )grlc_data_req );
   
} /* tm_grlc_data_req () */

/*
+------------------------------------------------------------------------------
| Function    : tm_grlc_unitdata_req
+------------------------------------------------------------------------------
| Description : Handles the primitive GRLC_UNITDATA_REQ
|
| Parameters  : *grlc_unitdata_req - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_grlc_unitdata_req ( T_GRLC_UNITDATA_REQ *grlc_unitdata_req )
{ 
  TRACE_FUNCTION( "tm_grlc_unitdata_req" );
  
  tm_uplink_data_req( CGRLC_LLC_PRIM_TYPE_UNITDATA_REQ, ( void* )grlc_unitdata_req );

} /* tm_grlc_unitdata_req() */



/*
+------------------------------------------------------------------------------
| Function    : tm_t3168
+------------------------------------------------------------------------------
| Description : Handles the primitive T3168
|               This timer is involved in 3 Procedures
|               1) Two Phase Access Procedure
|               2) Uplink TBF Setup on existing Downlink TBF
|               3) Uplink Realloaction Procedure on existing Uplink TBF
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_t3168 ( void )
{ 
  TRACE_FUNCTION( "tm_t3168" );
  TRACE_EVENT_P1("T3168 expired: n_acc=%d",grlc_data->tm.n_res_req);

  /* 
   * The expiry of this timer may occure in 3 cases:
   * 
   * a) uplink allocation during running downlink TBF  --> GRLC
   * b) two phase access procedure                    --> GRLC
   * c) uplink reallocation procedure on uplink TBF or on concurent TBF(UL&DL)  -->GRLC
   *
   */
  
  switch( GET_STATE( TM ) )
  {
    case TM_PTM:
      switch(grlc_data->tbf_type)
      {
#if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH
        case TBF_TYPE_TP_ACCESS:
          grlc_data->uplink_tbf.ti=1;
          tm_handle_error_ra(); 
          break;
#endif
        case TBF_TYPE_DL:
          /*
           *  cse a)
           */
        if(grlc_data->tm.n_res_req < 4) /* Is resource re-allocation is running? */  
        {
          grlc_data->tm.n_res_req++;
          tm_build_chan_req_des(&grlc_data->chan_req_des, 
                              &grlc_data->prim_queue[grlc_data->prim_start_tbf]);
          sig_tm_rd_ul_req();     
        }
        else
        { /* grlc_data->tm.n_res_req EQ 4 
                      -> last Channel Request Description has been sent */
          tm_handle_error_ra(); 
        }
        break;

        case TBF_TYPE_UL:
        case TBF_TYPE_CONC:
          /*
           * case c)
           */
        if(grlc_data->tm.n_res_req < 4) /* Is resource re-allocation is running? */  
        { 
          T_U_GRLC_RESOURCE_REQ resource_req;/*lint !e813*/

          tm_build_res_req(&resource_req,
                           R_RE_ALLOC); 
          tm_store_ctrl_blk( CGRLC_BLK_OWNER_TM, ( void* )&resource_req );
        }
        else
        { /* 
           * grlc_data->tm.n_res_req EQ 4 -> last resource request has been sent 
           * return to packet idle and indicate packet access failure to upper layers
           */
          while(grlc_data->prim_start_tbf < PRIM_QUEUE_SIZE_TOTAL)
          {
            grlc_delete_prim();
          }
          tm_cgrlc_status_ind(CGRLC_PACKET_ACCESS_FAILURE);
          tm_abort_tbf(grlc_data->tbf_type);
          grlc_data->tm.n_res_req = 0;
          TRACE_EVENT("4x p. resource req. failed");
          SET_STATE(TM,TM_WAIT_4_PIM);
        }
        break;
        default:
          /*
           *  Should never occure
           */
          TRACE_ERROR("T3168 expired, no task should not appear");
          break;
      }
      
      break;

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

} /* tm_t3168() */


/*
+------------------------------------------------------------------------------
| Function    : tm_t3188
+------------------------------------------------------------------------------
| Description : Handles the primitive T3188
|
| Parameters  :   
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_t3188 ( void )
{ 
  TRACE_FUNCTION( "tm_t3188" );
  

  switch( GET_STATE( TM ) )
  {
    case TM_PTM:
      /*
       * perform abnormal release with random access
       */
      tm_handle_error_ra();
      break;
    default:
      TRACE_ERROR( "tm_t3188 unexpected" );
      break;
  }

} /* tm_t3188() */


/*
+------------------------------------------------------------------------------
| Function    : tm_grlc_activate_gmm_queue_req
+------------------------------------------------------------------------------
| Description : Handles the primitive GRLC_ACTIVATE_GMM_QUEUE_REQ
|
| Parameters  :   
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_grlc_activate_gmm_queue_req  ( T_GRLC_ACTIVATE_GMM_QUEUE_REQ *grlc_activate_gmm_queue_req  )
{ 
  TRACE_FUNCTION( "tm_grlc_activate_gmm_queue_req" );
  

  switch( GET_STATE( TM ) )
  {
    case TM_ACCESS_DISABLED:
      tm_get_gmm_prim_queue( );      
      break;

    case TM_ACCESS_PREPARED:
      SET_STATE( TM, TM_PIM );
      sig_tm_ru_reset_poll_array();	  
      tm_get_gmm_prim_queue( );      
      tm_handle_grlc_ready_ind( );
      break;

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

  PFREE( grlc_activate_gmm_queue_req );

} /* tm_grlc_activate_gmm_queue_req() */

/*
+------------------------------------------------------------------------------
| Function    : tm_grlc_flush_data_req
+------------------------------------------------------------------------------
| Description : When LLC receives XID RESET during Inter-SGSN RAU procedure,
|               LLC sends this primitive GRLC_FLUSH_DATA_REQ to GRLC to flush out LLC 
|               user data maintained in GRLC
|
| Parameters  : void               
|               
+------------------------------------------------------------------------------
*/

GLOBAL void tm_grlc_flush_data_req (T_GRLC_FLUSH_DATA_REQ *grlc_flush_data_req)
{
  
  UBYTE i;
  UBYTE temp_start_tbf;
  UBYTE temp_start_free;   

  TRACE_FUNCTION( "tm_grlc_flush_data_req" );

  TRACE_EVENT_P4(" ps=%d, pf=%d,sps=%d,spf=%d",
                                       grlc_data->prim_start_tbf,
                                       grlc_data->prim_start_free,
                                       grlc_data->save_prim_start_tbf,
                                       grlc_data->save_prim_start_free);


  if(!grlc_data->gmm_procedure_is_running OR 
     !(grlc_data->prim_start_tbf >= PRIM_QUEUE_SIZE))
  /* Check for the condition grlc_data->prim_start_tbf EQ 0xFF is not required since
   * grlc_data->prim_start_tbf=0xFF implies there are no primitives in queue to flush out.
   * LLC PDUs are flushed only when GMM queue is active dring Inter-SGSN RAU procedure */
  {
    TRACE_ERROR( "GRLC_FLUSH_DATA_REQ unexpected" );
    PFREE(grlc_flush_data_req);
    return;
  }  

 /* Remember GMM primitives when gmm procedure is running*/
  temp_start_tbf = grlc_data->prim_start_tbf;
  temp_start_free = grlc_data->prim_start_free;

 /* Retrieve the saved primitive values when LLC was suspended by GMM */
  grlc_data->prim_start_tbf = grlc_data->save_prim_start_tbf;
  grlc_data->prim_start_free = grlc_data->save_prim_start_free;

  i = grlc_data->prim_start_tbf;

  grlc_data->prim_user_data = 0;
  while(i NEQ 0xFF)
  {
    grlc_data->prim_user_data += BYTELEN(grlc_data->prim_queue[i].prim_ptr->sdu.l_buf);
    i = grlc_data->prim_queue[i].next;
  }
  grlc_data->tm.send_grlc_ready_ind = SEND_A_GRLC_READY_IND;

 /* Delete all LLC primitives (user data) irrespective of going in same or new tbf */

  do
  {
    grlc_delete_prim();
  } while( (grlc_data->prim_start_tbf < PRIM_QUEUE_SIZE_TOTAL));


  grlc_data->save_prim_start_tbf = grlc_data->prim_start_tbf;
  if(grlc_data->prim_start_tbf NEQ 0xff)
  {
    TRACE_ASSERT(grlc_data->prim_start_tbf NEQ 0xff);
  }

  tm_handle_grlc_ready_ind();

 /* The GMM primitive values are put back */
  grlc_data->prim_start_tbf = temp_start_tbf;
  grlc_data->prim_start_free = temp_start_free;


  TRACE_EVENT_P4(" ps=%d, pf=%d,sps=%d,spf=%d",
                                       grlc_data->prim_start_tbf,
                                       grlc_data->prim_start_free,
                                       grlc_data->save_prim_start_tbf,
                                       grlc_data->save_prim_start_free);


  PFREE(grlc_flush_data_req);
  
}


/*
+------------------------------------------------------------------------------
| Function    : tm_cgrlc_enable_req
+------------------------------------------------------------------------------
| Description : Handles the primitive cgrlc_enable_req
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_cgrlc_enable_req ( T_CGRLC_ENABLE_REQ *cgrlc_enable_req )
{ 
  TRACE_FUNCTION( "tm_cgrlc_enable_req" );


  switch( GET_STATE( TM ) )
  {
    case TM_ACCESS_DISABLED:
    case TM_ACCESS_PREPARED:
      if( cgrlc_enable_req->enable_cause EQ  
                                   CGRLC_ENAC_ABNORM_RELEASE_CRESELECT_FAILED )
      {
        SET_STATE( TM, TM_PIM );
        sig_tm_ru_reset_poll_array();		
        tm_cgrlc_status_ind( CGRLC_RLC_MAC_ERROR );
        tm_delete_prim_queue( );
      }
      else if(cgrlc_enable_req->queue_mode EQ CGRLC_QUEUE_MODE_GMM)
      {
        if(grlc_data->gmm_procedure_is_running )       
        {
          SET_STATE(TM, TM_PIM);
          tm_delete_prim_queue();
          sig_tm_ru_reset_poll_array();		  		  
          TRACE_EVENT_P2("LLC QUEUE IS DISABLED, DELETE GMM PRIM QUEUE ps=%d pf=%d",
                                  grlc_data->prim_start_tbf,
                                  grlc_data->prim_start_free);
        }
        else
        {
          SET_STATE( TM, TM_ACCESS_PREPARED );
        }
      }

      /*lint -fallthrough*/

    case TM_PIM:
    case TM_PAM:
    case TM_PTM:
    case TM_WAIT_4_PIM: 

      grlc_data->tm.max_grlc_user_data = MAX_GRLC_USER_DATA ;

      if(cgrlc_enable_req->queue_mode EQ CGRLC_QUEUE_MODE_LLC)
      {
        UBYTE state = GET_STATE( TM );

        if( state EQ TM_ACCESS_DISABLED OR
            state EQ TM_ACCESS_PREPARED    )
        {
          SET_STATE( TM, TM_PIM );
          sig_tm_ru_reset_poll_array();		  		  
        }
        if(grlc_data->gmm_procedure_is_running)
        {
          tm_get_llc_prim_queue();
          if ( (tm_prim_queue_get_free_count() > 0)            AND
             (grlc_data->prim_user_data <= grlc_data->tm.max_grlc_user_data))
          {
            grlc_data->tm.send_grlc_ready_ind = SEND_A_GRLC_READY_IND;
          }
          else
          {
            grlc_data->tm.send_grlc_ready_ind = PRIM_QUEUE_FULL;
          }
        }
        else
        {
          TRACE_EVENT("RESUME IS DONE");
        }
        /*
         * check if cell update is required
         */
        if(cgrlc_enable_req->cu_cause EQ CGRLC_RA_CU)
        {
          TRACE_EVENT("CU REQ from GRR");
          /*
           * Delete Empty frames
           */
          if(   grlc_data->prim_start_tbf                                        <  PRIM_QUEUE_SIZE                        AND
              ( grlc_data->prim_queue[grlc_data->prim_start_tbf].prim_ptr->cause EQ GRLC_DTACS_EMPTY_FRAME            OR 
                grlc_data->prim_queue[grlc_data->prim_start_tbf].prim_ptr->cause EQ GRLC_DTACS_CELL_NOTIFI_NULL_FRAME    )     )
          {
            grlc_delete_prim();
            TRACE_EVENT("CEll_res: delete prim");
          }
          grlc_data->uplink_tbf.access_type = CGRLC_AT_CELL_UPDATE;
        }
        tm_ul_tbf_ind();
        tm_handle_grlc_ready_ind();

      }

      grlc_data->burst_type             = cgrlc_enable_req->burst_type;
      grlc_data->ab_type                = cgrlc_enable_req->ab_type;
      grlc_data->t3168_val              = cgrlc_enable_req->t3168_val;
      grlc_data->uplink_tbf.tlli        = cgrlc_enable_req->ul_tlli;
      grlc_data->uplink_tbf.ac_class    = cgrlc_enable_req->ac_class;
      grlc_data->downlink_tbf.tlli      = cgrlc_enable_req->dl_tlli;
      grlc_data->tm.change_mark         = cgrlc_enable_req->change_mark;

#ifdef REL99
      grlc_data->pfi_support            = cgrlc_enable_req->pfi_support;
      grlc_data->nw_rel                 = cgrlc_enable_req->nw_rel;	  
#endif
      /* 
       * set N3102 to maximum value after cell reselction
       */
      if(cgrlc_enable_req->v_pan_struct)
      {
        if(cgrlc_enable_req->pan_struct.pmax NEQ CGRLC_NO_UPDATE_N3102)
        {
          grlc_data->pan_struct = cgrlc_enable_req->pan_struct;
          grlc_data->N3102      = cgrlc_enable_req->pan_struct.pmax;
        }
      }
      else
      {
        grlc_data->pan_struct = cgrlc_enable_req->pan_struct;
        grlc_data->N3102      = 0xFF;
      }
      if( grlc_data->uplink_tbf.tlli EQ (0xffffffff))
      {
        TRACE_EVENT("GMM HAS UNASSIGNED GRR/GRLC, DELETE DATA QUEUE");        
        /*
         * delete prim queue
         */
        while(grlc_data->prim_start_tbf < PRIM_QUEUE_SIZE_TOTAL)
        {
          grlc_delete_prim();
        }
      }
      break;
    default:
      TRACE_ERROR( "CGRLC_ENABLE_REQ unexpected" );
      break;
  }
  PFREE(cgrlc_enable_req);

} /* tm_cgrlc_enable_req() */



/*
+------------------------------------------------------------------------------
| Function    : tm_cgrlc_disable_req
+------------------------------------------------------------------------------
| Description : Handles the primitive cgrlc_disable_req
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_cgrlc_disable_req ( T_CGRLC_DISABLE_REQ        *cgrlc_disable_req )
{ 
  UBYTE state = GET_STATE( TM );

  TRACE_FUNCTION( "tm_cgrlc_disable_req" );

  grlc_data->tm.disable_class = cgrlc_disable_req->disable_class; 

  switch( state )
  {
    case TM_ACCESS_PREPARED:
      SET_STATE(TM, TM_ACCESS_DISABLED);
      break;

    case TM_ACCESS_DISABLED:
      /* nothing to do */
      break;

    case TM_PIM:
    case TM_WAIT_4_PIM:
      SET_STATE(TM, TM_ACCESS_DISABLED);

      tm_handle_test_mode_cnf( grlc_test_mode_active( ) );

      grlc_data->rel_type = REL_TYPE_NULL;
      break;

    case TM_PTM:
      tm_abort_tbf(grlc_data->tbf_type);
       /*
        * delete all poll positions
        */
      sig_tm_ru_reset_poll_array();  

      /*lint -fallthrough*/

    case TM_PAM:
      SET_STATE(TM, TM_ACCESS_DISABLED);

      tm_handle_test_mode_cnf( grlc_test_mode_active( ) );

      grlc_data->rel_type = REL_TYPE_NULL;

      if( state EQ TM_PAM AND cgrlc_disable_req->disable_class EQ CGRLC_DISABLE_CLASS_CR )
      {
        tm_cgrlc_status_ind( CGRLC_TBF_ESTABLISHMENT_FAILURE );
      }
      break;

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

  if(cgrlc_disable_req->prim_status EQ CGRLC_PRIM_STATUS_ONE)
  {
    grlc_delete_prim();
    tm_handle_grlc_ready_ind();
  }
  else if(cgrlc_disable_req->prim_status EQ CGRLC_PRIM_STATUS_ALL)
  {
    tm_delete_prim_queue();
  /* Reinitialize GRLC context 
   * 1. Delete Primitives
   * 2. Abort TBF - (This is already done by GMMRR_SUSPEND_REQ)   
   *    We reach this disable req only after releasing all TBFs
   * 3. Reinitialize GRLC context */
  
    TRACE_EVENT("Reinit GRLC");
    grlc_init();
  }


  PFREE(cgrlc_disable_req);

} /* tm_cgrlc_disable_req() */


/*
+------------------------------------------------------------------------------
| Function    : tm_cgrlc_ul_tbf_res
+------------------------------------------------------------------------------
| Description : Handles the primitive cgrlc_ul_tbf_res
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_cgrlc_ul_tbf_res ( T_CGRLC_UL_TBF_RES *cgrlc_ul_tbf_res )
{ 
  TRACE_FUNCTION( "tm_cgrlc_ul_tbf_res" );

  tm_prcs_pwr_ctrl( &cgrlc_ul_tbf_res->pwr_ctrl );
  
  /*
   * Ignore the request for or modification of an UL TBF in case an UL TBF 
   * release request is currently sent to the data queue of GRR, it is just 
   * not yet processed, but TBF will be released anyway as one of the next
   * steps.
   */
  if( ( grlc_data->rel_type & REL_TYPE_UL ) EQ REL_TYPE_UL )
  {
    TRACE_EVENT( "tm_cgrlc_ul_tbf_res: release of UL TBF requested in parallel" );

    PFREE( cgrlc_ul_tbf_res );

    return;
  }

  vsi_t_stop(GRLC_handle,T3168);
  grlc_data->tm.n_res_req = 0;

  switch( GET_STATE( TM ) )
  {
    case TM_PAM:
      switch(cgrlc_ul_tbf_res->tbf_mode)
      {
        case CGRLC_TBF_MODE_ESTABLISHMENT_FAILURE:  /* establishment failure */
          SET_STATE(TM,TM_PIM);
          grlc_delete_prim();
          sig_tm_ru_reset_poll_array();		  
          tm_cgrlc_status_ind(CGRLC_TBF_ESTABLISHMENT_FAILURE);
          tm_handle_grlc_ready_ind();
          tm_ul_tbf_ind();
          break;
        case CGRLC_TBF_MODE_ACCESS_FAILED:
          if(cgrlc_ul_tbf_res->prim_status EQ CGRLC_PRIM_STATUS_ONE)
          {
            SET_STATE(TM,TM_PIM);
            grlc_delete_prim();
            sig_tm_ru_reset_poll_array();
            tm_cgrlc_status_ind(CGRLC_PACKET_ACCESS_FAILURE);
            tm_handle_grlc_ready_ind();
            tm_ul_tbf_ind();
          }
          else if(cgrlc_ul_tbf_res->prim_status EQ CGRLC_PRIM_STATUS_ALL)
          {
            SET_STATE(TM,TM_PIM);
            tm_delete_prim_queue();
            sig_tm_ru_reset_poll_array();
            tm_cgrlc_status_ind(CGRLC_PACKET_ACCESS_FAILURE);
            tm_handle_grlc_ready_ind();
            tm_ul_tbf_ind();
          }
          else if(cgrlc_ul_tbf_res->prim_status EQ CGRLC_PRIM_STATUS_TBF)
          {
            SET_STATE(TM,TM_PIM);
            sig_tm_ru_reset_poll_array();
            tm_cgrlc_status_ind(CGRLC_PACKET_ACCESS_FAILURE);
            tm_delete_prim_queue();
            tm_handle_grlc_ready_ind();
            tm_ul_tbf_ind();
          }
          else
          {
            tm_handle_error_ra();
            tm_ul_tbf_ind();
          }
          /*
           * what happens to the existing tbfs
           */
          break;
        case CGRLC_TBF_MODE_UL:
        case CGRLC_TBF_MODE_TMA:
        case CGRLC_TBF_MODE_TMB:
          SET_STATE(TM,TM_PTM);  
          if((grlc_data->testmode.mode EQ CGRLC_TEST_RANDOM) OR
             (grlc_data->testmode.mode EQ CGRLC_LOOP))
          {
            PALLOC(cgrlc_test_mode_ind,CGRLC_TEST_MODE_IND); /*T_CGRLC_TEST_MODE_IND*/
            cgrlc_test_mode_ind->test_mode_flag = grlc_data->testmode.mode;
            PSEND(hCommGRR,cgrlc_test_mode_ind);
          }
          grlc_data->uplink_tbf.cs_type      = (T_CODING_SCHEME)cgrlc_ul_tbf_res->cs_mode;
          grlc_data->uplink_tbf.mac_mode     = cgrlc_ul_tbf_res->mac_mode;
          grlc_data->uplink_tbf.nts          = cgrlc_ul_tbf_res->nts_max;
          grlc_data->uplink_tbf.ts_mask      = cgrlc_ul_tbf_res->tn_mask;
          grlc_data->uplink_tbf.ti           = cgrlc_ul_tbf_res->ti;
          grlc_data->uplink_tbf.tlli_cs_type = cgrlc_ul_tbf_res->tlli_cs_mode;
          grlc_data->uplink_tbf.bs_cv_max    = cgrlc_ul_tbf_res->bs_cv_max;
          grlc_data->r_bit                   = cgrlc_ul_tbf_res->r_bit;

          grlc_data->ul_tbf_start_time       = cgrlc_ul_tbf_res->starting_time;
          sig_tm_rd_ul_req_stop();
          sig_tm_meas_ptm();

          tm_activate_tbf ( TBF_TYPE_UL );

          if(cgrlc_ul_tbf_res->mac_mode)
          {
            grlc_data->uplink_tbf.fa_manag.fa_type = FA_NO_CURRENT;
            tm_store_fa_bitmap(&cgrlc_ul_tbf_res->fix_alloc_struct);
          }

          
          if(!grlc_data->uplink_tbf.ti)
            grlc_data->tm.n_acc_req_procedures = 0;

          grlc_data->tm.n_res_req = 0;

          grlc_data->uplink_tbf.rlc_db_granted = cgrlc_ul_tbf_res->rlc_db_granted;
          
          tm_tfi_handling  (cgrlc_ul_tbf_res->starting_time,CGRLC_TBF_MODE_UL, cgrlc_ul_tbf_res->tfi, 0xFF);
          sig_tm_ru_assign();
          if(cgrlc_ul_tbf_res->polling_bit NEQ 0xFF)
            tm_handle_polling_bit(cgrlc_ul_tbf_res->starting_time,cgrlc_ul_tbf_res->polling_bit);
          break;
        default:
          TRACE_ERROR("unexpected tbf mode in ul_tbf_res");
          break;
      }
      break;
    case TM_PTM:      
      switch(cgrlc_ul_tbf_res->tbf_mode)
      {
        case CGRLC_TBF_MODE_ACCESS_FAILED:
          if(cgrlc_ul_tbf_res->prim_status EQ CGRLC_PRIM_STATUS_ONE)
          {
            grlc_delete_prim();
            tm_cgrlc_status_ind(CGRLC_PACKET_ACCESS_FAILURE);
            tm_handle_grlc_ready_ind();
            tm_ul_tbf_ind();
          }
          else if(cgrlc_ul_tbf_res->prim_status EQ CGRLC_PRIM_STATUS_ALL)
          {
            tm_delete_prim_queue();
            tm_cgrlc_status_ind(CGRLC_PACKET_ACCESS_FAILURE);
            tm_handle_grlc_ready_ind();
            tm_ul_tbf_ind();
          }
          else if(cgrlc_ul_tbf_res->prim_status EQ CGRLC_PRIM_STATUS_TBF)
          {
            tm_cgrlc_status_ind(CGRLC_PACKET_ACCESS_FAILURE);
            tm_delete_prim_queue();
            tm_handle_grlc_ready_ind();
            tm_ul_tbf_ind();
          }
          else
          {
			tm_cgrlc_status_ind(CGRLC_PACKET_ACCESS_FAILURE);
            tm_handle_error_ra();
          }
          break;
        case CGRLC_TBF_MODE_UL:
        case CGRLC_TBF_MODE_TMA:
        case CGRLC_TBF_MODE_TMB:
          if((grlc_data->testmode.mode EQ CGRLC_TEST_RANDOM) OR
             (grlc_data->testmode.mode EQ CGRLC_LOOP))
          {
            PALLOC(cgrlc_test_mode_ind,CGRLC_TEST_MODE_IND); /*T_CGRLC_TEST_MODE_IND*/
            cgrlc_test_mode_ind->test_mode_flag = grlc_data->testmode.mode;
            PSEND(hCommGRR,cgrlc_test_mode_ind);
          }

          grlc_data->uplink_tbf.cs_type      = (T_CODING_SCHEME)cgrlc_ul_tbf_res->cs_mode;
          grlc_data->uplink_tbf.mac_mode     = cgrlc_ul_tbf_res->mac_mode;
          grlc_data->uplink_tbf.nts          = cgrlc_ul_tbf_res->nts_max;
          grlc_data->uplink_tbf.ts_mask      = cgrlc_ul_tbf_res->tn_mask;
          grlc_data->uplink_tbf.ti           = cgrlc_ul_tbf_res->ti;
          grlc_data->uplink_tbf.tlli_cs_type = cgrlc_ul_tbf_res->tlli_cs_mode;
          grlc_data->uplink_tbf.bs_cv_max    = cgrlc_ul_tbf_res->bs_cv_max;

#if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH
          if(grlc_data->tbf_type EQ TBF_TYPE_TP_ACCESS)
          {
            grlc_data->uplink_tbf.rlc_db_granted = cgrlc_ul_tbf_res->rlc_db_granted;
           
            if((grlc_data->testmode.mode EQ CGRLC_TEST_RANDOM) OR
               (grlc_data->testmode.mode EQ CGRLC_LOOP))
            {
              PALLOC(cgrlc_test_mode_ind,CGRLC_TEST_MODE_IND); /*T_CGRLC_TEST_MODE_IND*/
              cgrlc_test_mode_ind->test_mode_flag = grlc_data->testmode.mode;
              PSEND(hCommGRR,cgrlc_test_mode_ind);
            }
          }
          else
#endif
          {
            grlc_data->uplink_tbf.rlc_db_granted  = 0;
          }


          grlc_data->tm.n_res_req = 0;

          grlc_data->ul_tbf_start_time       = cgrlc_ul_tbf_res->starting_time;
          sig_tm_rd_ul_req_stop();

          tm_activate_tbf ( TBF_TYPE_UL );

          if(cgrlc_ul_tbf_res->mac_mode)
          {
            tm_store_fa_bitmap(&cgrlc_ul_tbf_res->fix_alloc_struct);
          }

          if(!grlc_data->uplink_tbf.ti)
            grlc_data->tm.n_acc_req_procedures = 0;

          tm_tfi_handling  (cgrlc_ul_tbf_res->starting_time,CGRLC_TBF_MODE_UL, cgrlc_ul_tbf_res->tfi, 0xFF);

          sig_tm_ru_assign();
          break;
#if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH
        case CGRLC_TBF_MODE_2PA: 
          {
            /*tbf establishment on PACCH*/
            grlc_data->ul_tbf_start_time       = cgrlc_ul_tbf_res->starting_time;
            tm_send_prr_2p_ptm();              
            grlc_data->tm.pacch_prr_pca_sent = FALSE ; /* For Release of TBF , as two phase */
          }
          break;
#endif
        default:
          TRACE_ERROR("unexpected tbf mode in ul_tbf_res");
          break;
      }
      break;
    default:
      TRACE_ERROR( "CGRLC_UL_TBF_RES unexpected" );
      break;
  }
  PFREE(cgrlc_ul_tbf_res);

} /* tm_cgrlc_ul_tbf_res() */

/*
+------------------------------------------------------------------------------
| Function    : tm_cgrlc_dl_tbf_req
+------------------------------------------------------------------------------
| Description : Handles the primitive cgrlc_dl_tbf_req
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_cgrlc_dl_tbf_req ( T_CGRLC_DL_TBF_REQ *cgrlc_dl_tbf_req )
{ 
  UBYTE rd_state=GET_STATE( RD );
  TRACE_FUNCTION( "tm_cgrlc_dl_tbf_req" );

  tm_prcs_pwr_ctrl( &cgrlc_dl_tbf_req->pwr_ctrl );
  grlc_data->downlink_tbf.trans_id++;

  /*
   * Ignore the request for or modification of an DL TBF in case an DL TBF 
   * release request is currently sent to the data queue of GRR, it is just 
   * not yet processed, but TBF will be released anyway as one of the next
   * steps.
   */
  if( ( grlc_data->rel_type & REL_TYPE_DL ) EQ REL_TYPE_DL )
  {
    /* The scenario T3192 expires before packet DL assignment message has been received
    is handled.*/

    TRACE_EVENT( "tm_cgrlc_dl_tbf_req: release of DL TBF requested in parallel" );
    
    TRACE_EVENT( "Exception: T3192 expiry before PDA race condition, verify this" );
    grlc_data->rel_type &= ( ~ ( REL_TYPE_DL ) );

  }

  switch( GET_STATE( TM ) )
  {
    case TM_PAM:     
    case TM_PIM:
    case TM_WAIT_4_PIM:
      SET_STATE(TM,TM_PTM);
      grlc_data->r_bit = 0; 

      sig_tm_meas_ptm();

      /*lint -fallthrough*/

    case TM_PTM:
      
    if(cgrlc_dl_tbf_req->ctrl_ack_bit)
    {
      TRACE_EVENT("GRLC ctrl ack bit set");
      if((grlc_data->tbf_type EQ TBF_TYPE_UL) OR 
         (grlc_data->tbf_type EQ TBF_TYPE_NULL))
      {
        TRACE_EVENT("DL ass will not be discarded in GRLC");
      }
      {
        sig_tm_rd_nor_rel();
        tm_deactivate_tbf(TBF_TYPE_DL);
        grlc_data->dl_tfi = 0xFF;
      }
   }
   else if (!cgrlc_dl_tbf_req->ctrl_ack_bit  AND
               (grlc_t_status(T3192) > 0)       AND 
               #ifdef _TARGET_ 
                (grlc_t_status(T3192) < 25)
               #else
                (grlc_t_status(T3192) < 65) 
               #endif
              )
    {
      TRACE_EVENT_P1("XXXX accepting DL Ass T3192=%ld",grlc_t_status(T3192));
      if ( rd_state EQ RD_REL_ACK OR
           rd_state EQ RD_REL_UACK )
      {
        sig_tm_rd_nor_rel();
        tm_deactivate_tbf(TBF_TYPE_DL);
        grlc_data->dl_tfi = 0xFF;
      }
    }

      grlc_data->downlink_tbf.rlc_mode    = cgrlc_dl_tbf_req->rlc_mode;
      grlc_data->downlink_tbf.cs_type     = (T_CODING_SCHEME)cgrlc_dl_tbf_req->cs_mode;
      grlc_data->downlink_tbf.mac_mode    = cgrlc_dl_tbf_req->mac_mode;
      grlc_data->downlink_tbf.nts         = cgrlc_dl_tbf_req->nts_max;
      grlc_data->downlink_tbf.ts_mask     = cgrlc_dl_tbf_req->tn_mask;
      grlc_data->downlink_tbf.t3192_val   = cgrlc_dl_tbf_req->t3192_val;

      grlc_data->dl_tbf_start_time       = cgrlc_dl_tbf_req->starting_time;

      tm_activate_tbf ( TBF_TYPE_DL );

      tm_tfi_handling  (cgrlc_dl_tbf_req->starting_time,CGRLC_TBF_MODE_DL,0xFF,cgrlc_dl_tbf_req->tfi);

      sig_tm_rd_assign();

    
      if(cgrlc_dl_tbf_req->polling_bit NEQ 0xFF)
        tm_handle_polling_bit(cgrlc_dl_tbf_req->starting_time,cgrlc_dl_tbf_req->polling_bit);


      tm_ul_tbf_ind(); /* dl tbf during access mode, ul tbf will be established over downlink*/
      break;
    default:
      {
        /* This shall never happen, but in case, GRLC shall inform GRR about the 
         * immediate release of the TBF. Otherwise GRLC and GRR are running out
         * of synchronisation and the whole system hangs.
         */
        PALLOC( cgrlc_tbf_rel_ind, CGRLC_TBF_REL_IND );

        TRACE_ERROR( "CGRLC_DL_TBF_REQ unexpected, so send release ind!" );
      
        cgrlc_tbf_rel_ind->tbf_mode      = CGRLC_TBF_MODE_DL;
        cgrlc_tbf_rel_ind->tbf_rel_cause = CGRLC_TBF_REL_ABNORMAL;
        cgrlc_tbf_rel_ind->v_c_value     = FALSE;
        cgrlc_tbf_rel_ind->dl_trans_id   = grlc_data->downlink_tbf.trans_id;

        PSEND( hCommGRR, cgrlc_tbf_rel_ind );
      }
      break;
  }
  PFREE(cgrlc_dl_tbf_req);

} /* tm_cgrlc_dl_tbf_req() */

/*
+------------------------------------------------------------------------------
| Function    : tm_cgrlc_tbf_rel_req
+------------------------------------------------------------------------------
| Description : Handles the primitive cgrlc_tbf_rel_req
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_cgrlc_tbf_rel_req ( T_CGRLC_TBF_REL_REQ       *cgrlc_tbf_rel_req )
{ 
  BOOL rel_ul = FALSE;
  BOOL rel_dl = FALSE;
  BOOL mod_ul = FALSE;
  BOOL mod_dl = FALSE;


  TRACE_FUNCTION( "tm_cgrlc_tbf_rel_req" );


  switch( GET_STATE( TM ) )
  {
    case TM_PTM:
      /*
       * 1. abnomal release uplink            --> immediate release
       * 2. normal release uplink             --> normal tbf release after current pdu is transmitted
       * 3. abnormal release downlink no poll --> immediate release
       * 4. abnormal release downlink with poll--> release after poll is sent
       * release both tbfs in case of testmode B
       */

      if( (cgrlc_tbf_rel_req->tbf_mode EQ CGRLC_TBF_MODE_UL) OR
          (cgrlc_tbf_rel_req->tbf_mode EQ CGRLC_TBF_MODE_DL_UL)
#if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH
          OR
          (cgrlc_tbf_rel_req->tbf_mode EQ CGRLC_TBF_MODE_2PA)
#endif
        )
      {
        if(grlc_data->testmode.mode EQ CGRLC_LOOP)
        {
           rel_ul = TRUE;
           rel_dl = TRUE;
        }
        else
        {
           if(cgrlc_tbf_rel_req->tbf_rel_cause EQ CGRLC_TBF_REL_ABNORMAL)
           {
              rel_ul = TRUE;
           }
           else
           {
              mod_ul = TRUE;
           }
        }

      }
      if( (cgrlc_tbf_rel_req->tbf_mode EQ CGRLC_TBF_MODE_DL) OR
          (cgrlc_tbf_rel_req->tbf_mode EQ CGRLC_TBF_MODE_DL_UL))
      {
        if(grlc_data->testmode.mode EQ CGRLC_LOOP)
        {
           rel_ul = TRUE;
           rel_dl = TRUE;
        }
        else
        {
           if(cgrlc_tbf_rel_req->rel_fn EQ  CGRLC_STARTING_TIME_NOT_PRESENT)
           {
               rel_dl = TRUE;
           }
           else
           {
               mod_dl = TRUE;
           }
        }

      }

      if(mod_ul)
      {
        if(grlc_data->ru.next_prim < PRIM_QUEUE_SIZE_TOTAL)
        {
          grlc_data->prim_queue[grlc_data->ru.next_prim].start_new_tbf = 1; 
          TRACE_EVENT_P5("QUEUE_STATUS BEFORE start=%d,next=%d active=%d rlc_oct=%ld sdu_len=%ld"
                                                    ,grlc_data->prim_start_tbf
                                                    ,grlc_data->ru.next_prim
                                                    ,grlc_data->ru.active_prim
                                                    ,grlc_data->ru.rlc_octet_cnt
                                                    ,grlc_data->ru.sdu_len);
          sig_tm_ru_queue_status();
          TRACE_EVENT_P5("QUEUE_STATUS AFTER start=%d,next=%d active=%d rlc_oct=%ld sdu_len=%ld"
                                                    ,grlc_data->prim_start_tbf
                                                    ,grlc_data->ru.next_prim
                                                    ,grlc_data->ru.active_prim
                                                    ,grlc_data->ru.rlc_octet_cnt
                                                    ,grlc_data->ru.sdu_len);
        }
      }
      if ( rel_ul AND
          (cgrlc_tbf_rel_req->rel_fn NEQ CGRLC_STARTING_TIME_NOT_PRESENT))
      {
        sig_tm_ru_abrel(cgrlc_tbf_rel_req->rel_fn, TRUE);
        mod_ul = TRUE;
        rel_ul = FALSE;
      }

      if(mod_dl)
      {  
        sig_tm_rd_abrel(cgrlc_tbf_rel_req->rel_fn, TRUE);
      }


      if(rel_dl AND rel_ul)
      {
        tm_abort_tbf(grlc_data->tbf_type);
      }
      else if(rel_dl)
      {
        tm_abort_tbf(TBF_TYPE_DL);
      }
      else if(rel_ul)
      {
#if defined REL99 AND defined TI_PS_FF_TBF_EST_PACCH
        if(grlc_data->tbf_type EQ TBF_TYPE_TP_ACCESS )
          tm_abort_tbf(TBF_TYPE_TP_ACCESS);
         else
#endif
        tm_abort_tbf(TBF_TYPE_UL);
      }


      if(grlc_data->tbf_type EQ TBF_TYPE_NULL)
      {
        SET_STATE(TM,TM_WAIT_4_PIM);
        sig_tm_ru_reset_poll_array();
      }
      break;
    default:
      TRACE_ERROR( "CGRLC_TBF_REL_REQ unexpected" );
      break;
  }
  PFREE(cgrlc_tbf_rel_req);

} /* tm_cgrlc_tbf_rel_req() */

/*
+------------------------------------------------------------------------------
| Function    : tm_cgrlc_tbf_rel_res
+------------------------------------------------------------------------------
| Description : Handles the primitive cgrlc_tbf_rel_res
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_cgrlc_tbf_rel_res ( T_CGRLC_TBF_REL_RES *cgrlc_tbf_rel_res )
{ 

#if !defined (NTRACE)

  BOOL       trace    = FALSE;
  T_REL_TYPE rel_type = grlc_data->rel_type;

#endif /* #if !defined (NTRACE) */

  TRACE_FUNCTION( "tm_cgrlc_tbf_rel_res" );

  /*
   * Check for consistency: Only requested releases shall be indicated by GRR.
   */
  if( cgrlc_tbf_rel_res->tbf_mode EQ CGRLC_TBF_MODE_DL_UL OR
      cgrlc_tbf_rel_res->tbf_mode EQ CGRLC_TBF_MODE_DL       )
  {
    if( ( grlc_data->rel_type & REL_TYPE_DL ) EQ REL_TYPE_DL )
    {
      grlc_data->rel_type &= ( ~ ( REL_TYPE_DL ) );
    }

#if !defined (NTRACE)

    else
    {
      trace = TRUE;
    } 

#endif /* #if !defined (NTRACE) */

  }

  /*
   * Check for consistency: Only requested releases shall be indicated by GRR.
   */
  if( cgrlc_tbf_rel_res->tbf_mode EQ CGRLC_TBF_MODE_DL_UL OR
      cgrlc_tbf_rel_res->tbf_mode EQ CGRLC_TBF_MODE_UL       )
  {
    if( ( grlc_data->rel_type & REL_TYPE_UL ) EQ REL_TYPE_UL )
    {
      grlc_data->rel_type &= ( ~ ( REL_TYPE_UL ) );
    }

#if !defined (NTRACE)

    else
    {
      trace = TRUE;
    } 

#endif /* #if !defined (NTRACE) */

  }

#if !defined (NTRACE)

  /*
   * Inconsistency deteced.
   */
  if( trace EQ TRUE )
  {
    TRACE_EVENT_P3
      ( "tm_cgrlc_tbf_rel_res: unexpected release response - tbf_mode = %d, rel_type (old) = %d, rel_type (new) = %d",
        cgrlc_tbf_rel_res->tbf_mode, rel_type, grlc_data->rel_type );
  }

#endif /* #if !defined (NTRACE) */

  if( grlc_data->rel_type EQ REL_TYPE_NULL )
  {  
    switch( GET_STATE( TM ) )
    {
    case TM_ACCESS_DISABLED:
    case TM_ACCESS_PREPARED:
      break;
    case TM_WAIT_4_PIM:
      SET_STATE(TM,TM_PIM);
      sig_tm_ru_reset_poll_array();
      tm_handle_test_mode_cnf( grlc_data->testmode.mode EQ CGRLC_TEST_MODE_RELEASE );
      grlc_data->tm.n_res_req            = 0;

      /*lint -fallthrough*/

    case TM_PIM:
      /*
       * reset ta value
       */
      grlc_data->ta_value = 0xFF;  

      /*lint -fallthrough*/

    case TM_PTM:
      tm_ul_tbf_ind();
      break;
    default:
      TRACE_ERROR( "CGRLC_TBF_REL_RES unexpected" );
      break;
    }
  }
  PFREE(cgrlc_tbf_rel_res);

} /* tm_cgrlc_tbf_rel_res() */

/*
+------------------------------------------------------------------------------
| Function    : tm_cgrlc_data_req
+------------------------------------------------------------------------------
| Description : Handles the primitive cgrlc_data_req
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_cgrlc_data_req ( T_CGRLC_DATA_REQ          *cgrlc_data_req )
{ 
  TRACE_FUNCTION( "tm_cgrlc_data_req" );


  switch( GET_STATE( TM ) )
  {
    case TM_PAM:
    case TM_PTM:
      tm_store_ctrl_blk( cgrlc_data_req->blk_owner, ( void* )cgrlc_data_req->data_array ) ;
      break;
    default:
      TRACE_ERROR( "CGRLC_DATA_REQ unexpected" );
      break;
  }
  PFREE(cgrlc_data_req);

} /* tm_cgrlc_data_req() */

/*
+------------------------------------------------------------------------------
| Function    : tm_cgrlc_poll_req
+------------------------------------------------------------------------------
| Description : Handles the primitive cgrlc_poll_req
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_cgrlc_poll_req ( T_CGRLC_POLL_REQ          *cgrlc_poll_req )
{ 
  TRACE_FUNCTION( "tm_cgrlc_poll_req" );


  switch( GET_STATE( TM ) )
  {
    case TM_PAM:
      /*
       * handle cpap polling bit, no save pass directly to layer1, poll will 
       * be sent with the first call
       */

      grlc_data->next_poll_fn      = cgrlc_poll_req->poll_fn;
      grlc_data->ul_poll_pos_index = 0;
      
      if(grlc_data->burst_type NEQ CGRLC_BURST_TYPE_NB) 
      { 
        grlc_send_access_burst(cgrlc_poll_req->tn);
      }
      else 
      {
        T_U_GRLC_CTRL_ACK u_ctrl_ack; /* built pca, do not use ccd, because IA is stored*/
        u_ctrl_ack.msg_type  = U_GRLC_CTRL_ACK_c;
        u_ctrl_ack.pctrl_ack = cgrlc_poll_req->ctrl_ack;
        grlc_set_buf_tlli( &u_ctrl_ack.tlli_value, grlc_data->uplink_tbf.tlli );

        grlc_send_normal_burst((UBYTE *)&u_ctrl_ack, NULL, cgrlc_poll_req->tn);
      }

      break;
    case TM_PTM:
      grlc_save_poll_pos(cgrlc_poll_req->poll_fn,
                         cgrlc_poll_req->tn,
                         0xFF,
                         cgrlc_poll_req->poll_b_type,
                         cgrlc_poll_req->ctrl_ack);
      break;
    default:
      TRACE_ERROR( "CGRLC_POLL_REQ unexpected" );
      break;
  }
  PFREE(cgrlc_poll_req);

} /* tm_cgrlc_poll_req() */

/*
+------------------------------------------------------------------------------
| Function    : tm_cgrlc_access_status_req
+------------------------------------------------------------------------------
| Description : Handles the primitive cgrlc_access_status_req
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_cgrlc_access_status_req ( T_CGRLC_ACCESS_STATUS_REQ *cgrlc_access_status_req )
{ 
  TRACE_FUNCTION( "tm_cgrlc_access_status_req" );


  switch( GET_STATE( TM ) )
  {
    case TM_PIM:
    case TM_PAM:
      tm_ul_tbf_ind();
      break;
    default:
      TRACE_ERROR( "CGRLC_ACCESS_STATUS_REQ unexpected" );
      break;
  }
  PFREE(cgrlc_access_status_req);

} /* tm_cgrlc_access_status_req() */

/*
+------------------------------------------------------------------------------
| Function    : tm_cgrlc_test_mode_req
+------------------------------------------------------------------------------
| Description : Handles the primitive cgrlc_test_mode_req
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_cgrlc_test_mode_req ( T_CGRLC_TEST_MODE_REQ     *cgrlc_test_mode_req )
{  
  UBYTE pdus_to_queue;
  UBYTE count = 0;

  TRACE_FUNCTION( "tm_cgrlc_test_mode_req" );

  TRACE_EVENT_P1( "cgrlc_test_mode_req test mode is activ %x",cgrlc_test_mode_req->test_mode_flag);
  
  switch( GET_STATE( TM ) )
  {
    case TM_PIM:
    case TM_PTM:
     /* 
      * save the test mode data
      */

      grlc_data->testmode.mode   = cgrlc_test_mode_req->test_mode_flag; 

      grlc_data->testmode.n_pdu         = (ULONG)cgrlc_test_mode_req->no_of_pdus;
      grlc_data->testmode.dl_ts_offset  = cgrlc_test_mode_req->dl_timeslot_offset;


      if (grlc_data->testmode.mode EQ CGRLC_LOOP)
      {
        TRACE_EVENT("testmode b");
        switch(grlc_data->tbf_type)
        {
          case TBF_TYPE_DL:
            /*
             * request uplink tbf over existing DL
             */
            tm_queue_test_mode_prim(1);
            /*
             * set received buffer to special values
             */
            grlc_data->testmode.rec_data[0].block_status = 0xFEFE;
            grlc_data->testmode.rec_data[0].e_bit        = 0xFE;
            memset(grlc_data->testmode.rec_data[0].payload, 0xFE,50);
            grlc_data->testmode.rec_data[1].block_status = 0xFEFE;
            grlc_data->testmode.rec_data[1].e_bit        = 0xFE;
            memset(grlc_data->testmode.rec_data[1].payload, 0xFE,50);
            /*
             * If the "Downlink Timeslot Offset" is set to 3, TN3 shall be treated as the first downlink
             * timeslot if a TBF is established in TN3. If TN3 does not support a TBF, the first active 
             * timeslot after TN3 shall be treated as the first downlink timeslot. The counting sequence 
             * is continuous through TN7 and TN0.
             */
            while (!((0x80>>grlc_data->testmode.dl_ts_offset) & grlc_data->dl_tn_mask) && (count < 8))
            {
              if (grlc_data->testmode.dl_ts_offset > 7)
                grlc_data->testmode.dl_ts_offset = (UBYTE)-1;
              grlc_data->testmode.dl_ts_offset++;
              count++;
            }
            TRACE_EVENT_P1 ("downlink timeslot offset is %d", grlc_data->testmode.dl_ts_offset);
            break;
          default:
            TRACE_EVENT_P1("unexpected tbf type for testmode B:tbf_type=%d",grlc_data->tbf_type);
            break;
        }        

      }
      else  /* it is testmode A with regular PDU amount */ 
      {
        if (grlc_data->testmode.n_pdu EQ 0)
        {
          /*
           * In case of Testmode A and 0 PDUs are requested the MS may 
           * optionally interprete this as infinitive duration TBF.
           */
          TRACE_EVENT("testmode a infinite");
          grlc_data->testmode.n_pdu -= 1;
        }
        else
        {
          TRACE_EVENT_P1("testmode a %ld pdus",grlc_data->testmode.n_pdu);
        }
        /*
         * (PRIM_QUEUE_SIZE-1) to avoid the full prime queue situation in test mode.
         * It should also not be more then 50*64 byte, which are queue here.
         * The remainig PDUs will be queued when a PDU is completely transmitted.
         */
        if (grlc_data->testmode.n_pdu < (PEI_PRIM_QUEUE_SIZE/2))
        {
          pdus_to_queue = (UBYTE) grlc_data->testmode.n_pdu;
          grlc_data->testmode.n_pdu = 0;
        }
        else
        {
          pdus_to_queue = (PEI_PRIM_QUEUE_SIZE/2);
          grlc_data->testmode.n_pdu -= (PEI_PRIM_QUEUE_SIZE/2);
        }
        /*
         *  generation of pseudo primitve to start the test mode tbf TBF
         */
        tm_queue_test_mode_prim(pdus_to_queue);

        grlc_prbs(INITIALIZE, 0, 0);
        if(!grlc_data->testmode.ptr_test_data)
        {
          MALLOC(grlc_data->testmode.ptr_test_data,50/*Max. RLC Block Length*/);
        }
      }

      break;
    default:
      TRACE_ERROR( "CGRLC_TEST_MODE_REQ  unexpected" );
      TRACE_EVENT_P1("tm state %d", grlc_data->tm.state);
      break;
  }


  PFREE(cgrlc_test_mode_req);

} /* tm_cgrlc_test_mode_req() */



/*
+------------------------------------------------------------------------------
| Function    : tm_cgrlc_test_end_req
+------------------------------------------------------------------------------
| Description : Handles the primitive CGRLC_TEST_END_REQ
|               GRLC have to leave the test mode. The leaving procedure is 
|               finished with the transmission of GMMRR_TEST_MODE_CNF
| Parameters  : *gmmrr_suspend_req - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_cgrlc_test_end_req ( T_CGRLC_TEST_END_REQ *cgrlc_test_end_req )
{ 
  TRACE_FUNCTION( "tm_cgrlc_test_end_req" );

  tm_abort_tbf( grlc_data->tbf_type );

  /*
   * delete all primitives in queue.
   */
  tm_delete_prim_queue();

  SET_STATE(TM,TM_WAIT_4_PIM);

  grlc_data->tm.n_acc_req_procedures = 0;
  grlc_data->tm.n_res_req            = 0; /* reset counter of resource requests during access */
  
  PFREE(cgrlc_test_end_req);

} /* tm_cgrlc_test_end_req() */



/*
+------------------------------------------------------------------------------
| Function    : tm_cgrlc_ta_value_req
+------------------------------------------------------------------------------
| Description : Handles the primitive cgrlc_ta_value_req
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_cgrlc_ta_value_req ( T_CGRLC_TA_VALUE_REQ      *cgrlc_ta_value_req )
{ 
  TRACE_FUNCTION( "tm_cgrlc_ta_value_req" );

  grlc_data->ta_value = cgrlc_ta_value_req->ta_value;

  PFREE(cgrlc_ta_value_req);

} /* tm_cgrlc_ta_value_req() */

/*
+------------------------------------------------------------------------------
| Function    : tm_cgrlc_ready_timer_config_req
+------------------------------------------------------------------------------
| Description : Handles the primitive tm_cgrlc_ready_timer_config_req
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_cgrlc_ready_timer_config_req 
               ( T_CGRLC_READY_TIMER_CONFIG_REQ *cgrlc_ready_timer_config_req )
{ 
  TRACE_FUNCTION( "tm_cgrlc_ready_timer_config_req" );

  grlc_data->ready_timer.handling = READY_TIMER_HANDLING_ENABLED;
  grlc_data->ready_timer.value    = cgrlc_ready_timer_config_req->t3314_val; 

  if( grlc_data->ready_timer.value EQ CGRLC_DEACTIVATED )
  {
    grlc_enter_ready_state( );
  }

  PFREE(cgrlc_ready_timer_config_req);

} /* (tm_cgrlc_ready_timer_config_req) */

/*
+------------------------------------------------------------------------------
| Function    : tm_cgrlc_force_to_standby_req
+------------------------------------------------------------------------------
| Description : Handles the primitive tm_cgrlc_force_to_standby_req
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_cgrlc_force_to_standby_req 
                   ( T_CGRLC_FORCE_TO_STANDBY_REQ *cgrlc_force_to_standby_req )
{ 
  TRACE_FUNCTION( "tm_cgrlc_force_to_standby_req" );

 /*
  * By receiving this primitive the Ready Timer State will be forced to Standby and
  * the running Ready Timer will be stopped
  */
  grlc_enter_standby_state( );

  PFREE(cgrlc_force_to_standby_req);

} /* (tm_cgrlc_force_to_standby_req) */
/*
+------------------------------------------------------------------------------
| Function    : tm_cgrlc_pwr_ctrl_req
+------------------------------------------------------------------------------
| Description : 
|
| Parameters  : 
|
+------------------------------------------------------------------------------
*/
GLOBAL void tm_cgrlc_pwr_ctrl_req ( T_CGRLC_PWR_CTRL_REQ *pwr_ctrl_req )
{
  TRACE_FUNCTION( "tm_cgrlc_pwr_ctrl_req" );

  tm_prcs_pwr_ctrl( &pwr_ctrl_req->pwr_ctrl );

  PFREE( pwr_ctrl_req );

} /* tm_cgrlc_pwr_ctrl_req */