view src/aci2/alr/alr_em.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   :
+-----------------------------------------------------------------------------
|  Copyright 2002 Texas Instruments Berlin, AG
|                 All rights reserved.
|
|                 This file is confidential and a trade secret of Texas
|                 Instruments Berlin, AG
|                 The receipt of or possession of this file does not convey
|                 any rights to reproduce or disclose its contents or to
|                 manufacture, use, or sell anything it may describe, in
|                 whole, or in part, without the specific written consent of
|                 Texas Instruments Berlin, AG.
+-----------------------------------------------------------------------------
|  Purpose :  This Module defines the engineering mode (EM) device driver for the
|             G23 protocol stack. This driver is used to control all engineering
|             mode related functions.
+-----------------------------------------------------------------------------
*/

#ifndef ALR_EM_C
#define ALR_EM_C

#define ENTITY_PL

/*==== INCLUDES ===================================================*/
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "typedefs.h"
#include "pconst.cdg"
#include "mconst.cdg"
#include "message.h"
#include "ccdapi.h"
#include "vsi.h"
#include "custom.h"
#include "gsm.h"
#include "prim.h"
#include "cnf_alr.h"
#include "mon_alr.h"
#include "pei.h"
#include "tok.h"
#include "pcm.h"

#ifdef GPRS
#include "alr_gprs.h"
#endif

#ifdef GPRS
#ifdef _TARGET_
#include "inth/iq.h"
#endif
/*
 *	obsolete (msb / 2002-04-25)
#include "armio/armio.h"
 */
#endif

#include "alr.h"
#include "alr_em.h"


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

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

/*==== PRIVAT =====================================================*/

/*==== VARIABLES ==================================================*/
#if defined (FF_EM_MODE) AND defined (ALR)

/* Event tracing flags for EM */
GLOBAL BOOL alr_v[EM_MAX_ALR_EVENTS];

LOCAL  UBYTE             em_alr_trace_occured = 0;


/*
  These variables are used between entities. Even this is not a clean solution it is a straigth forward
  way to reduce the overhead to a minimum. A clean solution would be based on an only usage of primitives
  which would stress the os with no aditional advantage!!
*/
GLOBAL volatile  UBYTE             em_l1_sem_buffer [EM_L1_SEM_SIZE];    /*lint -esym(765,em_l1_sem_buffer) | external could be made static | used externally  */
GLOBAL volatile  UBYTE             em_l1_sem_index  = 0;								 /*lint -esym(765,em_l1_sem_index)  | external could be made static | used externally  */

static T_HANDLE  sem_EM_L1;

#define ENTER_CRITICAL_SECTION(sem) if (alr_em_enter_critical_section(sem))return FALSE;
#define LEAVE_CRITICAL_SECTION(sem) if (alr_em_leave_critical_section(sem))return FALSE;

#endif /* FF_EM_MODE */

/*==== FUNCTIONS ==================================================*/
#if defined (FF_EM_MODE) AND defined (ALR)

LOCAL  UBYTE em_l1_sem       (UBYTE length, UBYTE * data);
LOCAL  int   em_l1_sem_clear (void);
LOCAL  void  alr_em_first_event_check (void); /*Check for ACI - Notification*/

static void alr_em_semaphore_err (void);

#if !defined(SYST_TRACE)
#define SYST_TRACE(a) vsi_o_ttrace(0, TC_SYSTEM, a);
#endif  /* !SYST_TRACE */

static int alr_em_enter_critical_section (T_HANDLE sem);
static int alr_em_leave_critical_section (T_HANDLE sem);


/*
+------------------------------------------------------------------------------
|  Function     : em_init_l1_event_trace
+------------------------------------------------------------------------------
|  Description  :  Initialize the event tracing flags
|
|  Parameters   :
|
|  Return       :
|
+------------------------------------------------------------------------------
*/
GLOBAL void em_init_l1_event_trace(void)
{
 UBYTE i;

 TRACE_FUNCTION("em_init_l1_event_trace ()");

 for(i=0; i<EM_MAX_ALR_EVENTS; i++)
   alr_v[i] = 0;
}

/*
+------------------------------------------------------------------------------
|  Function     : l1_em_l1_event_req
+------------------------------------------------------------------------------
|  Description  :  Set the event tracing flags according the bitmask
|
|  Parameters   :  Primitive    - Bitmask
|
|  Return       :
|
+------------------------------------------------------------------------------
*/

GLOBAL const void l1_em_l1_event_req (T_EM_L1_EVENT_REQ *em_l1_event_req)
{
 UBYTE i;

 TRACE_FUNCTION("l1_em_l1_event_req ()");

 /*
  *  The event tracing flags are set according the bitmask. alr_v[i] are
  *  the flags belonging to the event number described in 8443.601
 */
 for(i=1; i<33; i++)  {
   alr_v[i] = ((em_l1_event_req->bitmask_l1_l & (0x01<<(i-1))) > 0) ? TRUE : FALSE;
 }

 for(i=33; i<(EM_MAX_ALR_EVENTS); i++)  {
   alr_v[i] = ((em_l1_event_req->bitmask_l1_h & (0x01<<(i-1))) > 0) ? TRUE : FALSE;
 }

 /*
  * A new event trace is generated therefor the flag is set to zero.
 */
 em_alr_trace_occured = 0;

 PFREE(em_l1_event_req);
}

/*
+------------------------------------------------------------------------------
|  Function     : em_write_buffer_2
+------------------------------------------------------------------------------
|  Description  :  Perform buffer check and store corresponding data in it.
|
|  Parameters   :  Event number
|
|  Return       :  TRUE/FALSE
|
+------------------------------------------------------------------------------
*/
GLOBAL UBYTE em_write_buffer_2 (UBYTE event_no)
{
 UBYTE em_l1_event_buffer[2];
 UBYTE em_l1_buffer_write = 0;
 UBYTE length = 2;

 TRACE_FUNCTION("alr_em_write_buffer_2 ()");

 /*
   ACI is informed about the first event trace, used for later data processing.
 */
 alr_em_first_event_check();

 memset(em_l1_event_buffer, 0, 2);

 em_l1_event_buffer[em_l1_buffer_write++] = event_no;             /* Event number */
 em_l1_event_buffer[em_l1_buffer_write++] = length-2;             /* Value length - 0 equals no data */

 return (em_l1_sem (length, em_l1_event_buffer));               /* Data is stored inside buffer, reset flag */
}

/*
+------------------------------------------------------------------------------
|  Function     : em_write_buffer_3
+------------------------------------------------------------------------------
|  Description  :  Perform buffer check and store corresponding data in it.
|
|  Parameters   :  Event number, data value
|
|  Return       :  TRUE/FALSE
|
+------------------------------------------------------------------------------
*/
GLOBAL UBYTE em_write_buffer_3  (UBYTE event_no, UBYTE value)
{
 UBYTE em_l1_event_buffer[3];
 UBYTE em_l1_buffer_write = 0;
 UBYTE length = 3;

 TRACE_FUNCTION("alr_em_write_buffer_3 ()");

 /*
   ACI is informed about the first event trace, used for later data processing.
 */
 alr_em_first_event_check();

 memset(em_l1_event_buffer, 0, 3);

 em_l1_event_buffer[em_l1_buffer_write++] = event_no;               /* Event number */
 em_l1_event_buffer[em_l1_buffer_write++] = length-2;               /* Value length - 0 equals no value */
 em_l1_event_buffer[em_l1_buffer_write++] = value;                  /* Data to be stored */

 return (em_l1_sem (length, em_l1_event_buffer));                 /* Data is stored inside buffer, reset flag */
}

/*
+------------------------------------------------------------------------------
|  Function     : em_write_buffer_3a
+------------------------------------------------------------------------------
|  Description  :  Perform buffer check and store corresponding data in it.
|
|  Parameters   :  Event number, data value (USHORT)
|
|  Return       :  TRUE/FALSE
|
+------------------------------------------------------------------------------
*/
GLOBAL UBYTE em_write_buffer_3a (UBYTE event_no, USHORT value)
{
 UBYTE em_l1_event_buffer[4];
 UBYTE em_l1_buffer_write = 0;
 UBYTE length = 4;

 TRACE_FUNCTION("alr_em_write_buffer_4 ()");

 /*
   ACI is informed about the first event trace, used for later data processing.
 */
 alr_em_first_event_check();

 memset(em_l1_event_buffer, 0, 4);

 em_l1_event_buffer[em_l1_buffer_write++] = event_no;              /* Event number */
 em_l1_event_buffer[em_l1_buffer_write++] = length-2;              /* Value length - 0 equals no value */
 em_l1_event_buffer[em_l1_buffer_write++] = (UBYTE)(value >> 8);   /* Data to be stored - MSB first */
 em_l1_event_buffer[em_l1_buffer_write++] = (UBYTE)(value);        /* LSB second */

 return (em_l1_sem (length, em_l1_event_buffer));                /* Data is stored inside buffer, reset flag */
}

/*
+------------------------------------------------------------------------------
|  Function     : em_write_buffer_4
+------------------------------------------------------------------------------
|  Description  :  Perform buffer check and store corresponding data in it.
|
|  Parameters   :  Event number, data value1 & value2
|
|  Return       :  TRUE/FALSE
|
+------------------------------------------------------------------------------
*/
GLOBAL UBYTE em_write_buffer_4  (UBYTE event_no, UBYTE value1, UBYTE value2)
{
 UBYTE em_l1_event_buffer[4];
 UBYTE em_l1_buffer_write = 0;
 UBYTE length = 4;

 TRACE_FUNCTION("alr_em_write_buffer_4 ()");

 /*
   ACI is informed about the first event trace, used for later data processing.
 */
 alr_em_first_event_check();

 memset(em_l1_event_buffer, 0, 4);

 em_l1_event_buffer[em_l1_buffer_write++] = event_no;               /* Event number */
 em_l1_event_buffer[em_l1_buffer_write++] = length-2;               /* Value length - 0 equals no value */
 em_l1_event_buffer[em_l1_buffer_write++] = value1;                 /* Data to be stored */
 em_l1_event_buffer[em_l1_buffer_write++] = value2;                 /* Data to be stored */

 return (em_l1_sem (length, em_l1_event_buffer));                 /* Data is stored inside buffer, reset flag */
}

/*
+------------------------------------------------------------------------------
|  Function     : em_l1_sem_init
+------------------------------------------------------------------------------
|  Description  :  Initialize the semaphor for alr event traces.
|
|  Parameters   :  void
|
|  Return       :  void
|
+------------------------------------------------------------------------------
*/
GLOBAL void em_l1_sem_init (void)
{
  sem_EM_L1  = vsi_s_open (VSI_CALLER "EM_L1_SEM",1);

  if (sem_EM_L1 NEQ VSI_ERROR)
    em_l1_sem_clear ();
  else
    SYST_TRACE ("D1:canīt open semaphore \"EM_D1_SEM\"");
}

/*
+------------------------------------------------------------------------------
|  Function     : em_l1_sem_exit
+------------------------------------------------------------------------------
|  Description  :  Close the semaphor for alr event traces.
|
|  Parameters   :  void
|
|  Return       :  void
|
+------------------------------------------------------------------------------
*/
GLOBAL void em_l1_sem_exit (void)
{
  if (sem_EM_L1 NEQ VSI_ERROR)
    vsi_s_close (VSI_CALLER sem_EM_L1);
}

/*
+------------------------------------------------------------------------------
|  Function     : em_l1_sem_clear
+------------------------------------------------------------------------------
|  Description  :  Reset the index of the semaphor.
|
|  Parameters   :  void
|
|  Return       :  UBYTE
|
+------------------------------------------------------------------------------
*/
LOCAL int em_l1_sem_clear (void)
{
  ENTER_CRITICAL_SECTION (sem_EM_L1);
  em_l1_sem_index = 0;
  LEAVE_CRITICAL_SECTION (sem_EM_L1);

  SYST_TRACE ("L1:em_l1_sem_index cleared");
  return TRUE;
}

/*
+------------------------------------------------------------------------------
|  Function     : em_l1_sem_reset
+------------------------------------------------------------------------------
|  Description  :  Clears the content of the semaphor, must called after em_l1_sem_read.
|
|  Parameters   :  void
|
|  Return       :  UBYTE
|
+------------------------------------------------------------------------------
*/
GLOBAL int em_l1_sem_reset (void)  /*lint -esym(765,em_l1_sem_reset) | external could be made static | used externally  */
{
/*  ENTER_CRITICAL_SECTION (sem_EM_L1); */
  em_l1_sem_index = 0;
  LEAVE_CRITICAL_SECTION (sem_EM_L1);

  SYST_TRACE ("L1:em_l1_sem_index reseted");
  return TRUE;
}

/*
+------------------------------------------------------------------------------
|  Function     : em_l1_sem_read
+------------------------------------------------------------------------------
|  Description  :  Reads the content of the semaphor.
|
|  Parameters   :  void
|
|  Return       :  UBYTE
|
+------------------------------------------------------------------------------
*/
GLOBAL int em_l1_sem_read (void)  /*lint -esym(765,em_l1_sem_read) | external could be made static | used externally  */
{
  USHORT    semCount;
  TRACE_FUNCTION ("em_l1_sem_read()");

  if (vsi_s_status (VSI_CALLER sem_EM_L1, &semCount) NEQ VSI_OK)
  {
    alr_em_semaphore_err();
    return TRUE;
  }
  if (semCount EQ 0)
  {
    vsi_o_ttrace(VSI_CALLER TC_EVENT, "semCount = %d", semCount);
    SYST_TRACE ("semCount EQ 0");
    return TRUE;
  }

  ENTER_CRITICAL_SECTION (sem_EM_L1);
  /*
   * The l1/alr semaphor will be read by the engineering mode via aci,
   * therefore the functions em_l1_sem_read and em_l1_sem_reset are defined
   * as global. To ensure that during reading only aci has access to the
   * semaphor the macro LEAVE_CRITICAL_SECTION is called after the read process
   * toke place - in the em_l1_sem_resest function.
   */
  return TRUE;
}

/*
  Return value TRUE/FALSE - TRUE keeps the event flag valid, FALSE indicates a successful flag handle
*/
/*
+------------------------------------------------------------------------------
|  Function     : em_l1_sem
+------------------------------------------------------------------------------
|  Description  :  Writes the data inside the semaphor.
|
|  Parameters   :  void
|
|  Return       :  UBYTE
|
+------------------------------------------------------------------------------
*/
LOCAL UBYTE em_l1_sem (UBYTE length, UBYTE *data)
{
 USHORT    semCount;
 USHORT    write_index;
 UBYTE     i;

 TRACE_FUNCTION ("em_l1_sem()");


 if (vsi_s_status (VSI_CALLER sem_EM_L1, &semCount) NEQ VSI_OK)
 {
   alr_em_semaphore_err();
   return TRUE;
 }
 if (semCount EQ 0)
 {
   vsi_o_ttrace(VSI_CALLER TC_EVENT, "semCount = %d", semCount);
   SYST_TRACE ("semCount EQ 0");
   return TRUE;
 }

 /*
 *  buffer overflow protection
 */
 if ( ((write_index = em_l1_sem_index) + length) > EM_L1_SEM_SIZE )
 {
   TRACE_FUNCTION ("alr buffer full");
   return FALSE;
 }

 ENTER_CRITICAL_SECTION(sem_EM_L1);

 for (i=0; i<length; i++)
   em_l1_sem_buffer[em_l1_sem_index++] = *(data++);


 LEAVE_CRITICAL_SECTION (sem_EM_L1);
 return FALSE;                                           /* indicates that flag was handled */
} /* endfunc em_l1_sem */

/*
+------------------------------------------------------------------------------
|  Function     : alr_em_semaphore_err
+------------------------------------------------------------------------------
|  Description  :  Semaphor error
|
|
|  Parameters   :  void
|
|  Return       :  void
|
+------------------------------------------------------------------------------
*/
static void alr_em_semaphore_err (void)
{
 static UCHAR out = 0;
  if (!out)
  {
    out = 1;
    vsi_o_ttrace(VSI_CALLER TC_EVENT, "semaphore error");
  }
}

/*
+------------------------------------------------------------------------------
|  Function     : alr_em_enter_critical_section
+------------------------------------------------------------------------------
|  Description  :  Check on critical section entrance
|
|
|  Parameters   :  Handle
|
|  Return       :  -1  semaphore error
|					0  Ok.
|
+------------------------------------------------------------------------------
*/

#if defined (NEW_FRAME)
static int alr_em_enter_critical_section (T_HANDLE sem)
#else
static int alr_em_enter_critical_section (T_VSI_SHANDLE sem)
#endif /* NEW_FRAME */
{
 if (vsi_s_get (VSI_CALLER sem) NEQ VSI_OK)
 {
  alr_em_semaphore_err();
  return -1;
 }
 else
 {
  return 0;
 }
}/* endfunc rr_enter_critical_section */


/*
+------------------------------------------------------------------------------
|  Function     : alr_em_leave_critical_section
+------------------------------------------------------------------------------
|  Description  :  Check on critical section exit
|
|
|  Parameters   :  Handle
|
|  Return       :  -1  semaphore error
|					0  Ok.
|
+------------------------------------------------------------------------------
*/
#if defined (NEW_FRAME)
static int alr_em_leave_critical_section (T_HANDLE sem)
#else
static int alr_em_leave_critical_section (T_VSI_SHANDLE sem)
#endif /* NEW_FRAME */
{
 if (vsi_s_release (VSI_CALLER sem) NEQ VSI_OK)
 {
  alr_em_semaphore_err();
  return -1;
 }
 else
 {
  return 0;
 }
}/* endfunc rr_leave_critical_section */

/*
+------------------------------------------------------------------------------
|  Function     : alr_em_error_cause
+------------------------------------------------------------------------------
|  Description  :  Check the error cause and store it in the event buffer
|
|  Parameters   :  Cause
|
|  Return       :  None
|
+------------------------------------------------------------------------------
*/

GLOBAL void alr_em_error_cause (UBYTE cause, USHORT arfcn)

{
  switch(cause)
  {
  case CS_BCCH_READ_ERROR:
    {  /* Power measurement request */
      ALR_EM_BCCH_READ_ERROR;
      break;
    }
  case CS_DOWN_LINK_FAIL:
  {  /* Downlink signalling failure */
    ALR_EM_DOWNLINK_FAILURE;
    break;
  }
  case CS_NO_BCCH_AVAIL:
    {  /* neighbourcell BCCH not available */
      ALR_EM_NEIGHBOURCELL_BCCH(EM_NOT_AVAIL);
      break;
    }
  }/*switch*/
}/* alr_em_error_cause */


/*
+------------------------------------------------------------------------------
|  Function     : alr_em_first_event_check()
+------------------------------------------------------------------------------
|  Description  :  Checks if first EM-Event ocured
|
|  Parameters   :  None
|
|  Return       :  None
|
+------------------------------------------------------------------------------
*/

 /*
   ACI is informed about the first event trace, used for later data processing.
 */
LOCAL void alr_em_first_event_check (void)

{
 TRACE_FUNCTION("alr_em_first_event_check()");
 if(em_alr_trace_occured EQ 0)
 {
  PALLOC(em_notification, EM_DATA_IND);
  em_notification->entity = EM_L1;
  PSENDX(MMI, em_notification);
  em_alr_trace_occured++;
 }
}/* alr_em_first_event_check */



#endif /* FF_EM_MODE */



#endif /* ALR_EM_C */