view src/cs/drivers/drv_core/uart/serialswitch_core.c @ 303:f76436d19a7a default tip

!GPRS config: fix long-standing AT+COPS chance hanging bug There has been a long-standing bug in FreeCalypso going back years: sometimes in the AT command bring-up sequence of an ACI-only MS, the AT+COPS command would produce only a power scan followed by cessation of protocol stack activity (only L1 ADC traces), instead of the expected network search sequence. This behaviour was seen in different FC firmware versions going back to Citrine, and seemed to follow some law of chance, not reliably repeatable. This bug has been tracked down and found to be specific to !GPRS configuration, stemming from our TCS2/TCS3 hybrid and reconstruction of !GPRS support that was bitrotten in TCS3.2/LoCosto version. ACI module psa_mms.c, needed only for !GPRS, was missing in the TCS3 version and had to be pulled from TCS2 - but as it turns out, there is a new field in the MMR_REG_REQ primitive that needs to be set correctly, and that psa_mms.c module is the place where this initialization needed to be added.
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 08 Jun 2023 08:23:37 +0000
parents 4e78acac3d88
children
line wrap: on
line source

/*******************************************************************************
 *
 * SERIALSWITCH_CORE.C
 *
 * This module allows managing the use of the serial ports of TI GSM Evaluation
 * Boards.
 * An application may have to send several serial data flows. The board on which
 * the application is running may have one or several devices. The purpose of
 * this module is to establish connections between the serial data flows and the
 * serial devices at runtime, when the application is started.
 *
 * (C) Texas Instruments 1999 - 2003
 *
 ******************************************************************************/
/*
 * 17/12/03
 * Duplication of serialswitch.c for L1 standalone only
 *
 ******************************************************************************/

#define __SERIALSWITCH_CORE_C__

#define __STANDARD_H__ /* Avoid to define UBYTE, SYS_UWORD16 and UINT32. */

#include "l1sw.cfg"
#include "chipset.cfg"


#if (OP_L1_STANDALONE == 0)
  #include "main/sys_types.h"
#else
  #include "sys_types.h"
#endif

#include "nucleus.h"

#include "traceswitch.h"
#include "serialswitch_core.h" 

#include "uart/uart.h"

#include "memif/mem.h" 

#define DUMMY_DEVICE (0)

#define IIR (0x02) /* UART interrupt ident. register - Read only  */
#define SCR (0x10) /* UART suppl. control register   - Read/Write */
#define SSR (0x11) /* UART suppl. status register    - Read only  */

/*
 * Interrupt identification register.
 * Bit 0 is set to 0 if an IT is pending.
 * Bits 1 and 2 are used to identify the IT.
 */

#define IIR_BITS_USED  (0x07)
#define IT_NOT_PENDING (0x01)

/*
 * Supplementary Control Register
 */

#define RX_CTS_WAKE_UP_ENABLE_BIT (4)

/*
 * Supplementary Status Register
 */

#define RX_CTS_WAKE_UP_STS (0x02) /* Wake-up interrupt occurred  */

/*
 * This macro allows to read an UART register.
 */

#define READ_UART_REGISTER(UART,REG) \
            *((volatile SYS_UWORD8 *) ((UART)->base_address + (REG)))


/*
 * This macro allows to disable the UART's wake-up interrupt.
 */

#define DISABLE_WAKE_UP_INTERRUPT(UART) \
            *((volatile SYS_UWORD8 *) ((UART)->base_address + SCR)) &= \
                ~(1 << (RX_CTS_WAKE_UP_ENABLE_BIT)); 

/*
 * Wake-up time duration in seconds and in number of TDMAs.
 * 1 TDMA = (6 / 1300) s = 0.004615 s (= 4.615 ms).
 */

#define WAKE_UP_TIME_DURATION (10)  /* 10 seconds */
#define WAKE_UP_TIME_IN_TDMA  (WAKE_UP_TIME_DURATION * 1300 / 6)


/*
 * Global uartswitch variable as read from FFS.
 * It is supposed that NUMBER_OF_TR_UART, NUMBER_OF_FD_UART
 * and NUMBER_OF_BT_UART have the same values.
 */

#define DUMMY             ('0')
#define G23_PANEL         ('G')
#define RIVIERA_TRACE_MUX ('R')
#define FD_AT_COMMAND     ('D')
#define BLUETOOTH_HCI     ('B')

#if (CHIPSET == 12)
  char ser_cfg_info[NUMBER_OF_TR_UART] = {DUMMY, DUMMY, DUMMY};
#else
  char ser_cfg_info[NUMBER_OF_TR_UART] = {DUMMY, DUMMY};
#endif
static SYS_UWORD16 serial_cfg = 0x0048; /* All dummies */

/*
 * Types of flows supported.
 */

typedef enum {
    TRACE_FLOW
#if (OP_L1_STANDALONE == 0)
    , FAX_DATA_FLOW,
    BLUETOOTH_HCI_FLOW
#endif
} t_flow_type;

/*
 * For each serial data flow, a set of function pointers allows calling the
 * functions associated to a serial device.
 */

typedef struct s_tr_functions {

    T_tr_UartId   device;
    
    void (*tr_Init) (T_tr_UartId device,
                     T_tr_Baudrate baudrate,
                     void (callback_function (void)));
                         
    SYS_UWORD32 (*tr_ReadNChars) (T_tr_UartId device,
                                  char *buffer,
                                  SYS_UWORD32 chars_to_read);

    SYS_UWORD32 (*tr_ReadNBytes) (T_tr_UartId device,
                                  char *buffer,
                                  SYS_UWORD32 chars_to_read,
                                  SYS_BOOL *eof_detected);

    SYS_UWORD32 (*tr_WriteNChars) (T_tr_UartId device,
                                   char *buffer,
                                   SYS_UWORD32 chars_to_write);

    SYS_UWORD32 (*tr_EncapsulateNChars) (T_tr_UartId device,
                                         char *buffer,
                                         SYS_UWORD32 chars_to_write);

    SYS_UWORD32 (*tr_WriteNBytes) (T_tr_UartId device,
                                   SYS_UWORD8 *buffer,
                                   SYS_UWORD32 chars_to_write);

    void  (*tr_WriteChar) (T_tr_UartId device,
                           char character);

    void  (*tr_WriteString) (T_tr_UartId device,
                             char *buffer);

    SYS_BOOL (*tr_EnterSleep) (T_tr_UartId device);

    void (*tr_WakeUp) (T_tr_UartId device);

} t_tr_functions;


/*
 * Prototypes of dummy functions.
 * Dummy functions for Trace.
 */

static void dummy_tr_Init (T_tr_UartId device,
                           T_tr_Baudrate baudrate,
                           void (callback_function (void)));
 
static SYS_UWORD32 dummy_tr_ReadNChars (T_tr_UartId device,
                                        char *buffer,
                                        SYS_UWORD32 chars_to_read);

static SYS_UWORD32 dummy_tr_ReadNBytes (T_tr_UartId device,
                                        char *buffer,
                                        SYS_UWORD32 chars_to_read,
                                        SYS_BOOL *eof_detected);
 
static SYS_UWORD32 dummy_tr_WriteNChars (T_tr_UartId device,
                                         char *buffer,
                                         SYS_UWORD32 chars_to_write);
 
static SYS_UWORD32 dummy_tr_EncapsulateNChars (T_tr_UartId device,
                                               char *buffer,
                                               SYS_UWORD32 chars_to_write);
 
static SYS_UWORD32 dummy_tr_WriteNBytes (T_tr_UartId device,
                                         SYS_UWORD8 *buffer,
                                         SYS_UWORD32 chars_to_write);
 
static void dummy_tr_WriteChar (T_tr_UartId device,
                                char character);
 
static void dummy_tr_WriteString (T_tr_UartId device,
                                  char *buffer);
 
static SYS_BOOL dummy_tr_EnterSleep (T_tr_UartId device);
 
static void dummy_tr_WakeUp (T_tr_UartId device);
 

 

/*
 * Constants tables representing the various possible configurations
 * for Trace, Fax & Data and Bluetooth HCI according to the different devices.
 * Constant table for Trace using no device.
 */

static const t_tr_functions dummy_trace = {

    (T_tr_UartId) DUMMY_DEVICE,
    dummy_tr_Init,
    dummy_tr_ReadNChars,
    dummy_tr_ReadNBytes,
    dummy_tr_WriteNChars,
    dummy_tr_EncapsulateNChars,
    dummy_tr_WriteNBytes,
    dummy_tr_WriteChar,
    dummy_tr_WriteString,
    dummy_tr_EnterSleep,
    dummy_tr_WakeUp
};

/*
 * Constant table for Trace using UART IrDA.
 */

static const t_tr_functions uart_irda_trace = {

    UA_UART_0,
    UA_Init,
    UA_ReadNChars,
    UA_ReadNBytes,
    UA_WriteNChars,
    UA_EncapsulateNChars,
    UA_WriteNBytes,
    UA_WriteChar,
    UA_WriteString,
    UA_EnterSleep,
    UA_WakeUp
};

/*
 * Constant table for Trace using UART Modem.
 */

static const t_tr_functions uart_modem_trace = {

    UA_UART_1,
    UA_Init,
    UA_ReadNChars,
    UA_ReadNBytes,
    UA_WriteNChars,
    UA_EncapsulateNChars,
    UA_WriteNBytes,
    UA_WriteChar,
    UA_WriteString,
    UA_EnterSleep,
    UA_WakeUp
};

#if (CHIPSET == 12)
  /*
   * Constant table for Trace using UART Modem2.
   */

  static const t_tr_functions uart_modem2_trace = {

      UA_UART_2,
      UA_Init,
      UA_ReadNChars,
      UA_ReadNBytes,
      UA_WriteNChars,
      UA_EncapsulateNChars,
      UA_WriteNBytes,
      UA_WriteChar,
      UA_WriteString,
      UA_EnterSleep,
      UA_WakeUp
  };
#endif



/*
 * UART structure used for UARTs.
 */
 
typedef struct s_uart {
    
    SYS_UWORD32 base_address;
    SYS_BOOL    device_used;
    SYS_BOOL    deep_sleep_set_up;
    t_flow_type flow_type;
    SYS_WORD16  flow_id;
    void (*interrupt_handler) (int uart_id,
                               SYS_UWORD8 interrupt_status);
    
} t_uart;

static const t_tr_functions *tr_functions[SER_MAX_NUMBER_OF_FLOWS];


/*
 * Timer used for duration control when UARTs are waked up by an interrupt or
 * each time any new incoming characters are received; This timer prevents the
 * system to enter deep sleep mode.
 */

static NU_TIMER uart_sleep_timer;
       SYS_BOOL uart_sleep_timer_enabled;

/*
 * HISR used to reset and restart the sleep timer from an UART use by a Trace
 * flow in case of incoming characters.
 */

#define TIMER_HISR_PRIORITY      (2)
#define TIMER_HISR_STACK_SIZE  (512) /* Bytes. */ 

static NU_HISR timer_hisr_ctrl_block;
static char    timer_hisr_stack[TIMER_HISR_STACK_SIZE];

/*
 * For next arrays, it is supposed that NUMBER_OF_TR_UART, NUMBER_OF_FD_UART
 * and NUMBER_OF_BT_UART have the same values.
 * An index on an internal uart for trace, fax & data or bluetooth hci reffers
 * to the same uart device.
 */
 
static t_uart int_uart[NUMBER_OF_TR_UART];

#if ((CHIPSET == 2) || (CHIPSET == 3))
  static SYS_UWORD32 uart_spurious_interrupts;
#elif ((CHIPSET == 4) || (CHIPSET == 5) || (CHIPSET == 6) || (CHIPSET == 7) || (CHIPSET == 8) || (CHIPSET == 9) || (CHIPSET == 10) || (CHIPSET == 11) || (CHIPSET == 12))
  static SYS_UWORD32 uart_modem_spurious_interrupts;
  static SYS_UWORD32 uart_irda_spurious_interrupts;
#endif
#if (CHIPSET == 12)
  static SYS_UWORD32 uart_modem2_spurious_interrupts;
#endif

static const SYS_UWORD32 uart_base_address[NUMBER_OF_TR_UART] =
{
    MEM_UART_IRDA,
    MEM_UART_MODEM
    #if (CHIPSET == 12)
      , MEM_UART_MODEM2
    #endif
};

 
/*******************************************************************************
 *
 *                              dummy_tr_Init
 *
 * Purpose: No action.
 *
 * Parameters: See SER_tr_Init.
 *
 * Return: none
 *
 ******************************************************************************/
 
static void
dummy_tr_Init (T_tr_UartId device,
               T_tr_Baudrate baudrate,
               void (callback_function (void)))
{
    /*
     * No action.
     */
}

/*******************************************************************************
 *
 *                          dummy_tr_ReadNChars
 *
 * Purpose: No action.
 *
 * Parameters: See SER_tr_ReadNChars.
 *
 * Return: 0
 *
 ******************************************************************************/
 
static SYS_UWORD32
dummy_tr_ReadNChars (T_tr_UartId device,
                     char *buffer,
                     SYS_UWORD32 chars_to_read)
{
    return (0);
}

/*******************************************************************************
 *
 *                          dummy_tr_ReadNBytes
 *
 * Purpose: No action.
 *
 * Parameters: See SER_tr_ReadNBytes.
 *
 * Return: 0
 *
 ******************************************************************************/
 
static SYS_UWORD32
dummy_tr_ReadNBytes (T_tr_UartId device,
                     char *buffer,
                     SYS_UWORD32 chars_to_read,
                     SYS_BOOL *eof_detected)
{
    return (0);
}

/*******************************************************************************
 *
 *                          dummy_tr_WriteNChars
 *
 * Purpose: No action.
 *
 * Parameters: See SER_tr_WriteNChars.
 *
 * Return: The number of character to write.
 *
 ******************************************************************************/
 
static SYS_UWORD32
dummy_tr_WriteNChars (T_tr_UartId device,
                      char *buffer,
                      SYS_UWORD32 chars_to_write)
{
    return (chars_to_write);
}

/*******************************************************************************
 *
 *                          dummy_tr_EncapsulateNChars
 *
 * Purpose: No action.
 *
 * Parameters: See SER_tr_EncapsulateNChars.
 *
 * Return: The number of character to write.
 *
 ******************************************************************************/
 
static SYS_UWORD32
dummy_tr_EncapsulateNChars (T_tr_UartId device,
                      char *buffer,
                      SYS_UWORD32 chars_to_write)
{
    return (chars_to_write);
}

/*******************************************************************************
 *
 *                          dummy_tr_WriteNBytes
 *
 * Purpose: No action.
 *
 * Parameters: See SER_tr_WriteNBytes.
 *
 * Return: The number of byte to write.
 *
 ******************************************************************************/
 
static SYS_UWORD32
dummy_tr_WriteNBytes (T_tr_UartId device,
                      SYS_UWORD8 *buffer,
                      SYS_UWORD32 chars_to_write)
{
    return (chars_to_write);
}

/*******************************************************************************
 *
 *                              dummy_tr_WriteChar
 *
 * Purpose: No action.
 *
 * Parameters: See SER_tr_WriteChar.
 *
 * Return: none
 *
 ******************************************************************************/
 
static void
dummy_tr_WriteChar (T_tr_UartId device,
                    char character)
{
    /*
     * No action.
     */
}

/*******************************************************************************
 *
 *                          dummy_tr_WriteString
 *
 * Purpose: No action.
 *
 * Parameters: See SER_tr_WriteString.
 *
 * Return: none
 *
 ******************************************************************************/
 
static void
dummy_tr_WriteString (T_tr_UartId device,
                      char *buffer)
{
    /*
     * No action.
     */
}

/*******************************************************************************
 *
 *                          dummy_tr_EnterSleep
 *
 * Purpose: No action.
 *
 * Parameters: See SER_tr_EnterSleep.
 *
 * Return: 1
 *
 ******************************************************************************/
 
static SYS_BOOL
dummy_tr_EnterSleep (T_tr_UartId device)
{
    return (1);
}

/*******************************************************************************
 *
 *                           dummy_tr_WakeUp
 *
 * Purpose: No action.
 *
 * Parameters: See SER_tr_WakeUp.
 *
 * Return: none
 *
 ******************************************************************************/
 
static void
dummy_tr_WakeUp (T_tr_UartId device)
{
    /*
     * No action.
     */
}



/*******************************************************************************
 *
 *                     analyze_uart_sleep_timer_expiration
 * 
 * Purpose  : The timer has just expired. If requested, UARTs can again be set
 *            up to enter Deep Sleep.
 *
 * Arguments: In : id: parameter not used.
 *            Out: none
 *
 * Returns  : none 
 *
 ******************************************************************************/

static VOID
analyze_uart_sleep_timer_expiration (UNSIGNED id)
{
    /*
     * Timer has expired.
     * UARTs can again be set up for Deep Sleep.
     */

    (void) NU_Control_Timer (&uart_sleep_timer,
                             NU_DISABLE_TIMER);
      
    uart_sleep_timer_enabled = 0;
}

/*******************************************************************************
 *
 *                          start_uart_sleep_timer
 * 
 * Purpose  : Starts the sleep timer once UARTs have been waked-up by an
 *            interrupt or if new incoming characters have been received.
 *
 * Arguments: In : none
 *            Out: none
 *
 * Returns  : none 
 *
 ******************************************************************************/

static void
start_uart_sleep_timer (void)
{
    /*
     * UART sleep timer is started.
     * UARTs can't no more be set up for Deep Sleep until the timer expires.
     */

    (void) NU_Reset_Timer (&uart_sleep_timer,
                           &analyze_uart_sleep_timer_expiration,
                           WAKE_UP_TIME_IN_TDMA,
                           0, /* The timer expires once. */
                           NU_DISABLE_TIMER);

    (void) NU_Control_Timer (&uart_sleep_timer,
                             NU_ENABLE_TIMER);
}

/*******************************************************************************
 *
 *                              set_flow_functions
 *
 * Purpose: Initializes a serial data flow functions set with the set of
 *          functions of the selected device.
 *
 * Parameters: In : flow         : index of the serial data flow
 *                  serial_driver: allows knowing which set of functions must
 *                                 be selected
 *             Out: none
 *
 * Return: none
 *
 ******************************************************************************/

static void
set_flow_functions (int flow,
                    T_SerialDriver serial_driver)
{

    switch (serial_driver) {

    case UART_IRDA_TRACE:
    case UART_MODEM_TRACE:
    #if (CHIPSET == 12)
      case UART_MODEM2_TRACE:
    #endif

        if (serial_driver == UART_IRDA_TRACE)
            tr_functions[flow] = &uart_irda_trace;
        else {
          #if (CHIPSET == 12)
            if (serial_driver == UART_MODEM2_TRACE)
                tr_functions[flow] = &uart_modem2_trace;
            else
          #endif
                tr_functions[flow] = &uart_modem_trace;
        }

        int_uart[tr_functions[flow]->device].device_used = 1;
        int_uart[tr_functions[flow]->device].flow_type   = TRACE_FLOW;
        int_uart[tr_functions[flow]->device].flow_id     = flow;
        int_uart[tr_functions[flow]->device].interrupt_handler =
                                      UA_InterruptHandler;
        break;

    case DUMMY_TRACE:

        tr_functions[flow] = &dummy_trace;
        break;

    }
}

/*******************************************************************************
 *
 *                          SER_InitSerialConfig
 *
 * Purpose: The parameter serial_info allows knowing all serial information
 *          necessary to set up the serial configuration of an application.
 *          From this information, the function is able to determine if the
 *          current serial configuration read out from the flash memory is
 *          valid. If it does not correspond to an allowed configuration, the
 *          default configuration is selected. This function must be called at
 *          the application's initialization, but never after.
 *
 * Parameters: In : serial_info: application serial information like the default
 *                               configuration and all allowed configurations.
 *             Out: none
 *
 * Return: none
 *
 ******************************************************************************/

void
SER_InitSerialConfig (T_AppliSerialInfo *serial_info)
{
    int            uart_id;
    int            flow;
    T_SerialDriver serial_driver;
    SYS_UWORD16    *allowed_config;
    SYS_UWORD8     nb_allowed_config;
    SYS_BOOL       valid_config_selected;
    SYS_BOOL       uart_used;
    SYS_BOOL       uart_used_for_trace;
    SYS_UWORD16    current_config;
    SYS_UWORD16    *pt_current_config = &(current_config);

    /*
	 * Basic UARTs initializations.
	 */

    for (uart_id = 0; uart_id < NUMBER_OF_TR_UART; uart_id++) {

        int_uart[uart_id].base_address = uart_base_address[uart_id];
        int_uart[uart_id].device_used = 0;
        int_uart[uart_id].deep_sleep_set_up = 0;
    }
						  
#if ((CHIPSET == 2) || (CHIPSET == 3))
    uart_spurious_interrupts = 0;
#elif ((CHIPSET == 4) || (CHIPSET == 5) || (CHIPSET == 6) || (CHIPSET == 7) || (CHIPSET == 8) || (CHIPSET == 9) || (CHIPSET == 10) || (CHIPSET == 11) || (CHIPSET == 12))
    uart_modem_spurious_interrupts = 0;
    uart_irda_spurious_interrupts = 0;
#endif
#if (CHIPSET == 12)
    uart_modem2_spurious_interrupts = 0;
#endif
    uart_sleep_timer_enabled = 0;

    /*
     * Compute the current serial configuration.
     */

    for (uart_id = 0; uart_id < NUMBER_OF_TR_UART; uart_id++) {

        switch (ser_cfg_info[uart_id]) { 

            case G23_PANEL:
                serial_cfg = serial_cfg +
                    ((uart_id + 1) << (12 - (4 * SER_PROTOCOL_STACK)));
                break;

            case RIVIERA_TRACE_MUX:
                serial_cfg = serial_cfg +
                    ((uart_id + 1) << (12 - (4 * SER_LAYER_1)));
                break;

            case FD_AT_COMMAND:
                serial_cfg = serial_cfg +
                    ((uart_id + 1) << (12 - (4 * SER_FAX_DATA)));
                break;

            case BLUETOOTH_HCI:
                serial_cfg = serial_cfg +
                    ((uart_id + 1) << (12 - (4 * SER_BLUETOOTH_HCI)));
                break;

            case DUMMY:
                break;
        }
    }

    current_config = serial_cfg;
    valid_config_selected = 0;
    nb_allowed_config = serial_info->num_config;

    /*
     * Checks if the current serial config is one of the allowed.
     */
     
    while ((nb_allowed_config > 0) && !valid_config_selected) {
        
        nb_allowed_config--;
        allowed_config = (SYS_UWORD16 *)
                          &(serial_info->allowed_config[nb_allowed_config]);
        
        if (*pt_current_config == *allowed_config)
            valid_config_selected = 1;
    }

    /*
	 * If not, the default configuration is selected.
	 */

    if (!valid_config_selected) {

        pt_current_config = (SYS_UWORD16 *)&(serial_info->default_config);

    }

    /*
     * The serial data flow functions set is initialized.
     */

    flow = 0;
    while (flow < SER_MAX_NUMBER_OF_FLOWS) {
        
        serial_driver = (T_SerialDriver)
                            (((*pt_current_config) >> (12 - flow * 4)) & 0x000F);

        set_flow_functions (flow, serial_driver);
        flow++;
    }
    
    /*
     * Checks if both UARTs are used.
     * If not, performs minimum initialization including Sleep Mode.
     * Checks also if at least one UART is used by a Trace flow.
     * If so, create a HISR in order to reset and restart the sleep timer
     * in case of incoming characters.
     */

    uart_used = 0;
    uart_used_for_trace = 0;
    for (uart_id = 0; uart_id < NUMBER_OF_TR_UART; uart_id++) {

        if (!(int_uart[uart_id].device_used))
		    initialize_uart_sleep ((T_tr_UartId) uart_id);

        else { /* if (int_uart[uart_id].device_used) */

            uart_used = 1;  /* At least one UART is used */

            if (int_uart[uart_id].flow_type == TRACE_FLOW) {

                /* At least one UART used by a Trace flow */
                uart_used_for_trace = 1;
            }
        }
    }

    /*
     * If at least one uart is used, create a timer to figure out if the system
     * can enter deep sleep mode regarding the UARTs.
     */

    if (uart_used) {

        (void) NU_Create_Timer (
                   &uart_sleep_timer,
                   "Sleep",
                   &analyze_uart_sleep_timer_expiration,
                   0, /* Parameter supplied to the routine: not used. */
                   WAKE_UP_TIME_IN_TDMA,
                   0, /* The timer expires once. */
                   NU_DISABLE_TIMER);

        /*
         * If at least one uart is used by a Trace flow, create a HISR to reset
         * and restart the sleep timer.
         */

        if (uart_used_for_trace) {

            /*
             * The HISR entry function is the same function than the one called
             * by the Rx HISR of the UARTFAX, since the only aim is to reset
             * and restart the sleep timer in case of incoming characters on
             * the Trace UART.
             */

            (void) NU_Create_HISR (
                       &timer_hisr_ctrl_block,
                       "Tim_HISR",
                       SER_restart_uart_sleep_timer,
                       TIMER_HISR_PRIORITY,
                       &(timer_hisr_stack[0]),
                       TIMER_HISR_STACK_SIZE);
        }
    }
}



/*******************************************************************************
 *
 * All functions SER_tr_xxx and SER_fd_xxx call a function of the UART trace
 * driver or the UART fax & data driver.
 * All functions SER_bt_xxx call a function of the UART Bluetooth HCI driver.
 * See the function call for parameters and return values.
 *
 ******************************************************************************/
 
void
SER_tr_Init (int serial_data_flow,
             T_tr_Baudrate baudrate,
             void (callback_function (void)))
{
    tr_functions[serial_data_flow]->tr_Init (
                tr_functions[serial_data_flow]->device, baudrate, callback_function);
}

SYS_UWORD32
SER_tr_ReadNChars (int serial_data_flow,
                   char *buffer,
                   SYS_UWORD32 chars_to_read)
{
    return (tr_functions[serial_data_flow]->tr_ReadNChars (
                tr_functions[serial_data_flow]->device, buffer, chars_to_read));
}

SYS_UWORD32
SER_tr_ReadNBytes (int serial_data_flow,
                   char *buffer,
                   SYS_UWORD32 chars_to_read,
                   SYS_BOOL *eof_detected)
{
    return (tr_functions[serial_data_flow]->tr_ReadNBytes (
                tr_functions[serial_data_flow]->device, buffer, chars_to_read, eof_detected));
}

SYS_UWORD32
SER_tr_WriteNChars (int serial_data_flow,
                    char *buffer,
                    SYS_UWORD32 chars_to_write)
{
    return (tr_functions[serial_data_flow]->tr_WriteNChars (
                tr_functions[serial_data_flow]->device, buffer, chars_to_write));
}

SYS_UWORD32
SER_tr_EncapsulateNChars (int serial_data_flow,
                          char *buffer,
                          SYS_UWORD32 chars_to_write)
{
    return (tr_functions[serial_data_flow]->tr_EncapsulateNChars (
                tr_functions[serial_data_flow]->device, buffer, chars_to_write));
}

SYS_UWORD32
SER_tr_WriteNBytes (int serial_data_flow,
                    SYS_UWORD8 *buffer,
                    SYS_UWORD32 chars_to_write)
{
    return (tr_functions[serial_data_flow]->tr_WriteNBytes (
                tr_functions[serial_data_flow]->device, buffer, chars_to_write));
}

void
SER_tr_WriteChar (int serial_data_flow,
                  char character)
{
    tr_functions[serial_data_flow]->tr_WriteChar (
                tr_functions[serial_data_flow]->device, character);
}

void
SER_tr_WriteString (int serial_data_flow,
                    char *buffer)
{
    tr_functions[serial_data_flow]->tr_WriteString (
                tr_functions[serial_data_flow]->device, buffer);
}

SYS_BOOL
SER_tr_EnterSleep (int serial_data_flow)
{
    return (tr_functions[serial_data_flow]->tr_EnterSleep (
                tr_functions[serial_data_flow]->device));
}

void
SER_tr_WakeUp (int serial_data_flow)
{
    tr_functions[serial_data_flow]->tr_WakeUp (
                tr_functions[serial_data_flow]->device);
}



/*******************************************************************************
 *
 *                          SER_UartSleepStatus
 *
 * Purpose: This function checks if both UARTs are ready to enter Deep Sleep. 
 *
 * Parameters: In : none
 *             Out: none 
 *
 * Return: 0	 : Deep Sleep is not possible.
 *         >= 1  : Deep Sleep is possible.
 *
 ******************************************************************************/

SYS_BOOL
SER_UartSleepStatus (void)
{
    t_uart   *uart;
    int      uart_id;
    SYS_BOOL status;

    /*
     * Check first if the sleep timer is active or if a Dynamic Switch is
     * being processed. A return is used to simplify the code.
     */

    if (uart_sleep_timer_enabled)
	    return (0);

    /*
     * Check if both UARTs are ready to enter Deep Sleep.
     */

    status = 1;
    uart_id = 0;
    while ((uart_id < NUMBER_OF_TR_UART) &&
           (status)) {

           uart = &(int_uart[uart_id]);

           /*
            * Check if the specified UART is actually used.
            */

           if (uart->device_used) {

               /*
                * Check if the specified UART is used by a Trace or
                * by a Fax & Data flow.
                */

               if (uart->flow_type == TRACE_FLOW)
                   status = SER_tr_EnterSleep (uart->flow_id);

               else
                   status = 0;

               if (status) {

                   /*
    	            * The specified UART is now set up for Deep Sleep.
    	            */

                   uart->deep_sleep_set_up = 1;

               }
           }

           uart_id++;
    }

    /*
     * Check if Deep Sleep is finally possible.
     * If not revert eventual Deep Sleep settings.
     */

    if (!status) {

        for (uart_id = 0; uart_id < NUMBER_OF_TR_UART; uart_id++) {

            uart = &(int_uart[uart_id]);

            /*
             * If the specified used UART has already been set up for
             * Deep Sleep, revert these settings.
             */

            if ((uart->device_used) &&
                (uart->deep_sleep_set_up)) {
				
                /*
                 * Check if the specified UART is used by a Trace or
                 * by a Fax & Data flow.
                 * Bluetooth HCI can not yet handled Deep Sleep Mode.
                 */

                if (uart->flow_type == TRACE_FLOW)
                    SER_tr_WakeUp (uart->flow_id);

                uart->deep_sleep_set_up = 0;

            }
        }
    }

    return (status);
}


/*******************************************************************************
 *
 *                            SER_WakeUpUarts
 *
 * Purpose: This function wakes up used UARTs after Deep Sleep.
 *
 * Parameters: In : none
 *             Out: none 
 *
 * Return: none
 *
 ******************************************************************************/

void
SER_WakeUpUarts (void)
{
    t_uart   *uart;
    int      uart_id;

    if (uart_sleep_timer_enabled)
        start_uart_sleep_timer ();

    for (uart_id = 0; uart_id < NUMBER_OF_TR_UART; uart_id++) {

        uart = &(int_uart[uart_id]);

        /*
         * Check if the specified UART is actually used, and has not yet
		 * been waked up.
         */

        if ((uart->device_used) &&
            (uart->deep_sleep_set_up)) {

            /*
             * Check if the specified UART is used by a Trace or
             * by a Fax & Data flow.
             * Bluetooth HCI can not yet handled Deep Sleep Mode.
             */

            if (uart->flow_type == TRACE_FLOW)
                SER_tr_WakeUp (uart->flow_id);

            /*
             * The specified UART is no more set up for Deep Sleep.
             */

            uart->deep_sleep_set_up = 0;

        }
    }
}


/*******************************************************************************
 *
 *                         SER_restart_uart_sleep_timer
 * 
 * Purpose  : Resets and restarts the sleep timer each time some characters are
 *            received.
 *
 * Arguments: In : none
 *            Out: none
 *
 * Returns  : none
 *
 ******************************************************************************/

void
SER_restart_uart_sleep_timer (void)
{
    /*
     * First disable the timer.
     */

    (void) NU_Control_Timer (&uart_sleep_timer,
                             NU_DISABLE_TIMER);

    /*
     * Then start again this timer for a new period.
     */

    start_uart_sleep_timer ();
}


/*******************************************************************************
 *
 *                            SER_activate_timer_hisr
 * 
 * Purpose  : Activates the timer HISR to reset and restart the sleep timer
 *            each time some characters are received.
 *
 * Arguments: In : none
 *            Out: none
 *
 * Returns  : none
 *
 ******************************************************************************/

void
SER_activate_timer_hisr (void)
{
    (void) NU_Activate_HISR (&timer_hisr_ctrl_block);
}


#if ((CHIPSET == 2) || (CHIPSET == 3))

/*******************************************************************************
 *
 *                                SER_uart_handler
 * 
 * Purpose  : UART interrupt handler.
 *
 * Arguments: In : none
 *            Out: none
 *
 * Returns  : none
 *
 ******************************************************************************/

void
SER_uart_handler (void)
{
    SYS_UWORD8 interrupt_status;
    t_uart     *uart;
    int        uart_id;
    SYS_BOOL   it_identified;

    it_identified = 0;

    /*
     * Check first for a wake-up interrupt.
     */

    uart_id = 0;
    while ((uart_id < NUMBER_OF_TR_UART) &&
           (!it_identified)) {

           uart = &(int_uart[uart_id]);
           interrupt_status = READ_UART_REGISTER (uart, SSR);

           if (interrupt_status & RX_CTS_WAKE_UP_STS) { /* Wake-up IT has occurred */

               it_identified = 1;
               uart_sleep_timer_enabled = 1;
			   DISABLE_WAKE_UP_INTERRUPT (uart);
           }

           uart_id++;
    }

    /*
     * If no wake-up interrupt has been detected, check then systematically
     * both UARTs for other interrupt causes.
     */

    if (!it_identified) {

        for (uart_id = 0; uart_id < NUMBER_OF_TR_UART; uart_id++) {

            uart = &(int_uart[uart_id]);
            interrupt_status = READ_UART_REGISTER (uart, IIR) & IIR_BITS_USED;

            if (!(interrupt_status & IT_NOT_PENDING)) {

                it_identified = 1;
                (*(uart->interrupt_handler)) (uart_id, interrupt_status);

            } else {

                if ((uart_id == UA_UART_1) && (!it_identified))
                uart_spurious_interrupts++;
            }
        }
    }
}

#elif ((CHIPSET == 4) || (CHIPSET == 5) || (CHIPSET == 6) || (CHIPSET == 7) || (CHIPSET == 8) || (CHIPSET == 9) || (CHIPSET == 10) || (CHIPSET == 11) || (CHIPSET == 12))

/*******************************************************************************
 *
 *                                SER_uart_modem_handler
 * 
 * Purpose  : UART MODEM interrupt handler.
 *
 * Arguments: In : none
 *            Out: none
 *
 * Returns  : none
 *
 ******************************************************************************/

void
SER_uart_modem_handler (void)
{
    SYS_UWORD8 interrupt_status;
    t_uart     *uart;
    SYS_BOOL   it_wakeup_identified;

    it_wakeup_identified = 0;
    uart = &(int_uart[UA_UART_1]);

    /*
     * Check first for a wake-up interrupt.
     */

    interrupt_status = READ_UART_REGISTER (uart, SSR);

    if (interrupt_status & RX_CTS_WAKE_UP_STS) { /* Wake-up IT has occurred */

        it_wakeup_identified = 1;
        uart_sleep_timer_enabled = 1;
        DISABLE_WAKE_UP_INTERRUPT (uart);
    }

    /*
     * If no wake-up interrupt has been detected, check UART for other
     * interrupt causes.
     */

    if (!it_wakeup_identified) {

        interrupt_status = READ_UART_REGISTER (uart, IIR) & IIR_BITS_USED;

        if (!(interrupt_status & IT_NOT_PENDING))
            (*(uart->interrupt_handler)) (UA_UART_1, interrupt_status);

        else
            uart_modem_spurious_interrupts++;
    }
}


/*******************************************************************************
 *
 *                                SER_uart_irda_handler
 * 
 * Purpose  : UART IrDA interrupt handler.
 *
 * Arguments: In : none
 *            Out: none
 *
 * Returns  : none
 *
 ******************************************************************************/

void
SER_uart_irda_handler (void)
{
    SYS_UWORD8 interrupt_status;
    t_uart     *uart;
    SYS_BOOL   it_wakeup_identified;

    it_wakeup_identified = 0;
    uart = &(int_uart[UA_UART_0]);

    /*
     * Check first for a wake-up interrupt.
     */

    interrupt_status = READ_UART_REGISTER (uart, SSR);

    if (interrupt_status & RX_CTS_WAKE_UP_STS) { /* Wake-up IT has occurred */

        it_wakeup_identified = 1;
        uart_sleep_timer_enabled = 1;
        DISABLE_WAKE_UP_INTERRUPT (uart);
    }

    /*
     * If no wake-up interrupt has been detected, check UART for other
     * interrupt causes.
     */

    if (!it_wakeup_identified) {

        interrupt_status = READ_UART_REGISTER (uart, IIR) & IIR_BITS_USED;

        if (!(interrupt_status & IT_NOT_PENDING))
            (*(uart->interrupt_handler)) (UA_UART_0, interrupt_status);

        else
            uart_irda_spurious_interrupts++;
    }
}

#endif

#if (CHIPSET == 12)
  /*******************************************************************************
   *
   *                                SER_uart_modem2_handler
   * 
   * Purpose  : UART IrDA interrupt handler.
   *
   * Arguments: In : none
   *            Out: none
   *
   * Returns  : none
   *
   ******************************************************************************/

  void
  SER_uart_modem2_handler (void)
  {
      SYS_UWORD8 interrupt_status;
      t_uart     *uart;
      SYS_BOOL   it_wakeup_identified;

      it_wakeup_identified = 0;
      uart = &(int_uart[UA_UART_2]);

      /*
       * Check first for a wake-up interrupt.
       */

      interrupt_status = READ_UART_REGISTER (uart, SSR);

      if (interrupt_status & RX_CTS_WAKE_UP_STS) { /* Wake-up IT has occurred */

          it_wakeup_identified = 1;
          uart_sleep_timer_enabled = 1;
          DISABLE_WAKE_UP_INTERRUPT (uart);
      }

      /*
       * If no wake-up interrupt has been detected, check UART for other
       * interrupt causes.
       */

      if (!it_wakeup_identified) {

          interrupt_status = READ_UART_REGISTER (uart, IIR) & IIR_BITS_USED;

          if (!(interrupt_status & IT_NOT_PENDING))
              (*(uart->interrupt_handler)) (UA_UART_2, interrupt_status);
        
          else
              uart_modem2_spurious_interrupts++;
      }
  }

#endif

/*
 * Temporary functions. 
 */

void
UT_Init (int device_id,
         T_tr_Baudrate baudrate,
         void (callback_function (void)))
{
    SER_tr_Init (SER_PROTOCOL_STACK, baudrate, callback_function);
}

SYS_UWORD32
UT_ReadNChars (int device_id,
               char *buffer,
               SYS_UWORD32 chars_to_read)
{
    return (SER_tr_ReadNChars (SER_PROTOCOL_STACK, buffer, chars_to_read));
}

SYS_UWORD32
UT_WriteNChars (int device_id,
                char *buffer,
                SYS_UWORD32 chars_to_write)
{
    return (SER_tr_WriteNChars (SER_PROTOCOL_STACK, buffer, chars_to_write));
}

void
UT_WriteChar (int device_id,
              char character)
{
    SER_tr_WriteChar (SER_PROTOCOL_STACK, character);
}

void
UT_WriteString (int device_id,
                char *buffer)
{
    SER_tr_WriteString (SER_PROTOCOL_STACK, buffer);
}