view src/cs/drivers/drv_app/uart/uartfax.c @ 166:7409b22cac61

fc-target.cfg config header renamed to more sensible fc-target.h
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 07 Apr 2019 00:56:07 +0000
parents 397e3a3274ea
children ba3693cbd40e
line wrap: on
line source

/*******************************************************************************
 *
 * UARTFAX.C
 *
 * This driver allows to control the UARTs of chipset 1.5 for fax and data
 * services. It performs flow control: RTS/CTS, XON/XOFF.
 *
 * On C & D-Sample, DCD and DTR signals are supported on UART modem only with 2
 * I/Os.
 *
 * On E-Sample, DCD and DTR signals are directly handled by Calypso+.
 *
 * On Calypso, RTS and CTS are supported on both UARTs.
 *
 * On Calypso+, RTS and CTS are supported on UART Modem1 & IrDA. UART Modem2 is
 * not available through DB9 connector on E-Sample.
 *
 * (C) Texas Instruments 1999 - 2003
 *
 ******************************************************************************/

/*
 * E-Sample
 *
 * UART Modem1                  UART Irda
 *
 *     DB9   Calypso+               DB9   Calypso+
 *
 * 1   DCD   DCD      output    1   1, 6 and 4 are connected together on DB9
 * 2   RX    TX       output    2   RX    TX2       output
 * 3   TX    RX       input     3   TX    RX2       input
 * 4   DTR   DSR      input     4   
 * 5   GND                      5   GND
 * 6   NC                       6   
 * 7   RTS   CTS      input     7   RTS   CTS2      input
 * 8   CTS   RTS      output    8   CTS   RTS2      output
 * 9   NC                       9   NC
 *
 */

/*
 * C & D-Sample
 *
 * UART Modem                   UART Irda
 *
 *     DB9   Calypso                DB9   Calypso
 *
 * 1   DCD   I/O 2    output    1   1, 6 and 4 are connected together on DB9
 * 2   RX    TX       output    2   RX    TX2       output
 * 3   TX    RX       input     3   TX    RX2       input
 * 4   DTR   I/O 3    input     4   
 * 5   GND                      5   GND
 * 6   NC                       6   
 * 7   RTS   CTS      input     7   RTS   CTS2      input
 * 8   CTS   RTS      output    8   CTS   RTS2      output
 * 9   NC                       9   NC
 *
 */

/*
 * B-Sample
 *
 * UART Modem                   UART Irda
 *
 *     DB9   Ulysse                 DB9   Ulysse
 *
 * 1   1, 6 and 4 are connected together on DB9 (Modem and Irda)
 * 2   RX    TX                 2   RX    TX
 * 3   TX    RX                 3   TX    RX
 * 4                            4
 * 5   GND                      5   GND
 * 6                            6
 * 7   RTS   CTS                7   7 and 8 are connected together on DB9
 * 8   CTS   RTS                8
 * 9   NC                       9   NC
 *
 */
 
#include "swconfig.cfg"

#include "l1sw.cfg"

#if (OP_L1_STANDALONE == 0)
  #include "rv.cfg"
#endif
#include "board.cfg"
#include "chipset.cfg"
#ifdef BLUETOOTH_INCLUDED
#include "btemobile.cfg"
#endif

#include "fc-target.h"


#include <string.h>
#include "nucleus.h"

#include "main/sys_types.h"
#include "faxdata.h"
#include "uartfax.h"

/*
 * Needed to reset and restart the sleep timer in case of incoming characters.
 */

#include "serialswitch.h"
extern SYS_BOOL uart_sleep_timer_enabled;

/*
 * rv_general.h is needed for macros Min & Min3.
 */

#include "rv/rv_general.h"

#include "memif/mem.h"

#if ((BOARD == 8) || (BOARD == 9) || (BOARD == 40) || (BOARD == 41))
  #include "armio/armio.h"
#endif

/* 
 * Maximal value for an unsigned 32 bits.
 */

#define MAX_UNSIGNED_32 (4294967295)

#define FIFO_SIZE (64) /* In bytes. */


/*
 * TLR is used to program the RX FIFO trigger levels. FCR[7:4] are  not used.
 * No trigger level used for TX FIFO. THR_IT generated on TX FIFO empty.
 */
 
#define RX_FIFO_TRIGGER_LEVEL (12 << 4)


/*
 * 16750 addresses. Registers accessed when LCR[7] = 0.
 */

#define RHR (0x00) /* Rx buffer register - Read access   */
#define THR (0x00) /* Tx holding register - Write access */
#define IER (0x01) /* Interrupt enable register          */

/*
 * 16750 addresses. Registers accessed when LCR[7] = 1.
 */

#define DLL (0x00) /* Divisor latch (LSB) */
#define DLM (0x01) /* Divisor latch (MSB) */


/*
 * EFR is accessed when LCR[7:0] = 0xBF.
 */

#define EFR (0x02) /* Enhanced feature register */


/*
 * 16750 addresses. Bit 5 of the FCR register is accessed when LCR[7] = 1.
 */

#define IIR (0x02)  /* Interrupt ident. register - Read only */
#define FCR (0x02)  /* FIFO control register - Write only    */
#define LCR (0x03)  /* Line control register                 */
#define MCR (0x04)  /* Modem control register                */
#define LSR (0x05)  /* Line status register                  */
#define MSR (0x06)  /* Modem status register                 */
#define TCR  (0x06) /* Transmission control register         */
#define TLR  (0x07) /* Trigger level register                */
#define MDR1 (0x08) /* Mode definition register 1            */
#define SCR  (0x10) /* Supplementary Control register        */
#define SSR  (0x11) /* Supplementary Status register         */
#define UASR (0x0E) /* Autobauding Status register           */

/*
 * Supplementary control register.
 */

#define TX_EMPTY_CTL_IT (0x08)
#define RX_CTS_WAKE_UP_ENABLE_BIT (4) /* Use RESET_BIT and SET_BIT macros. */
#define DSR_IT_BIT                (5) /* Use RESET_BIT and SET_BIT macros. */

/*
 * Enhanced feature register.
 */
 
#define ENHANCED_FEATURE_BIT (4) /* Use RESET_BIT and SET_BIT macros. */
#define AUTO_CTS_BIT         (7) /* Transmission is halted when the CTS pin is high (inactive). */

/*
 * Mode definition register 1.
 */

#define UART_MODE             (0x00)
#define SIR_MODE              (0x01)
#define UART_MODE_AUTOBAUDING (0x02) /* Reserved in UART/IrDA. */
#define RESET_DEFAULT_STATE   (0x07)
#define IR_SLEEP_DISABLED     (0x00)
#define IR_SLEEP_ENABLED      (0x08)
#define SIR_TX_WITHOUT_ACREG2 (0x00) /* Reserved in UART/modem. */
#define SIR_TX_WITH_ACREG2    (0x20) /* Reserved in UART/modem. */
#define FRAME_LENGTH_METHOD   (0x00) /* Reserved in UART/modem. */
#define EOT_BIT_METHOD        (0x80) /* Reserved in UART/modem. */

/*
 * Supplementary Status Register
 */

#define TX_FIFO_FULL (0x01)


/*
 * Interrupt enable register.
 */

#define ERBI  (0x01) /* Enable received data available interrupt            */
#define ETBEI (0x02) /* Enable transmitter holding register empty interrupt */
#define ELSI  (0x04) /* Enable receiver line status interrupt               */
#define EDSSI (0x08) /* Enable modem status interrupt                       */
#define IER_SLEEP (0x10)  /* Enable sleep mode                              */

/*
 * Modem control register.
 */

#define MDCD (0x01) /* Data Carrier Detect. */
#define MRTS (0x02) /* Request To Send.     */
#define TCR_TLR_BIT (6)

/*
 * Line status register.
 */

#define DR   (0x01) /* Data ready                                  */
#define OE   (0x02) /* Overrun error                               */
#define PE   (0x04) /* Parity error                                */
#define FE   (0x08) /* Framing error                               */
#define BI   (0x10) /* Break interrupt                             */
#define THRE (0x20) /* Transmitter holding register (FIFO empty)   */
#define TEMT (0x40) /* Transmitter empty (FIFO and TSR both empty) */

#define BYTE_ERROR (OE | PE | FE | BI)

/*
 * 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_PENDING       (0x01)
#define RX_DATA          (0x04)
#define TX_EMPTY         (0x02)
#define MODEM_STATUS     (0x00)

/*
 * Modem status register.
 */

#define DELTA_CTS (0x01)
#define DELTA_DSR (0x02)
#define MCTS      (0x10) /* Clear to send       */
#define MDSR      (0x20) /* Data set ready      */

/*
 * Line control register.
 */

#define WLS_5         (0x00) /* Word length: 5 bits                    */
#define WLS_6         (0x01) /* Word length: 6 bits                    */
#define WLS_7         (0x02) /* Word length: 7 bits                    */
#define WLS_8         (0x03) /* Word length: 8 bits                    */
#define STB           (0x04) /* Number of stop bits: 0: 1, 1: 1,5 or 2 */
#define PEN           (0x08) /* Parity enable                          */
#define EPS           (0x10) /* Even parity select                     */
#define BREAK_CONTROL (0x40) /* Enable a break condition               */
#define DLAB          (0x80) /* Divisor latch access bit               */

/*
 * FIFO control register.
 */

#define FIFO_ENABLE   (0x01)
#define RX_FIFO_RESET (0x02)
#define TX_FIFO_RESET (0x04)

/*
 * These constants define the states of the escape sequence detection.
 */

#define INITIALIZATION       (0)
#define NO_ESCAPE_SEQUENCE   (1)
#define ONE_CHAR_DETECTED    (2)
#define TWO_CHARS_DETECTED   (3)
#define THREE_CHARS_DETECTED (4)

#define CHARACTERS_IN_ESC_SEQ        (3)
#define DEFAULT_ESC_SEQ_CHARACTER    '+'
#define DEFAULT_GUARD_PERIOD      (1000) /* 1 second. */

/*
 * 3 HISR are used to avoid to execute operations from the LISR.
 */
 
#define RX_HISR_PRIORITY      (2)




// NGENGE increase hisr stack otherwise overflows with multiple callbacks
//#define RX_HISR_STACK_SIZE  (512) /* Bytes. */ 
#define RX_HISR_STACK_SIZE  (768) /* Bytes. */ 




#define TX_HISR_PRIORITY      (2)



// NGENGE increase hisr stack otherwise overflows with multiple callbacks
//#define TX_HISR_STACK_SIZE  (512) /* Bytes. */ 
#define TX_HISR_STACK_SIZE  (768) /* Bytes. */ 




#define V24_HISR_PRIORITY     (2)
#define V24_HISR_STACK_SIZE (512) /* Bytes. */ 

/*
 * When the break interrupt indicator (BI) is set in the line status register
 * (LSR), it indicates that the received data input was held in the low state
 * for longer than a full-word transmission time. In the FIFO mode, when a break
 * occurs, only one 0 character is loaded into the FIFO. The next character
 * transfer is enabled after SIN goes to the marking state for at least two RCLK
 * samples and then receives the next valid start bit.
 * This constant defined a defined break length returned by the US_GetLineState
 * function.
 */

#define MINIMAL_BREAK_LENGTH (2)

#define BREAK_HISR_PRIORITY     (2)
#define BREAK_HISR_STACK_SIZE (512) /* Bytes. */

/*
 * These macros allow to read and write a UART register.
 */

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

#define WRITE_UART_REGISTER(UART,REG,VALUE)                                     \
            *((volatile SYS_UWORD8 *) ((UART)->base_address + (REG))) = (VALUE)

#define RESET_BIT(UART,REG,BIT)    \
			(WRITE_UART_REGISTER ( \
			     UART, REG, READ_UART_REGISTER (UART, REG) & ~(1 << (BIT))))

#define SET_BIT(UART,REG,BIT)      \
			(WRITE_UART_REGISTER ( \
			     UART, REG, READ_UART_REGISTER (UART, REG) | (1 << (BIT))))


/*
 * These macros allow to enable or disable the wake-up interrupt.
 */

#define ENABLE_WAKEUP_INTERRUPT(UART)   \
	SET_BIT(UART, SCR, RX_CTS_WAKE_UP_ENABLE_BIT);

#define DISABLE_WAKEUP_INTERRUPT(UART)   \
	RESET_BIT(UART, SCR, RX_CTS_WAKE_UP_ENABLE_BIT);


/*
 * These macros allow to enable or disable the DSR interrupt.
 */

#define ENABLE_DSR_INTERRUPT(UART)   \
	SET_BIT(UART, SCR, DSR_IT_BIT);

#define DISABLE_DSR_INTERRUPT(UART)   \
	RESET_BIT(UART, SCR, DSR_IT_BIT);


/*
 * The transmitter is disabled only when the application disables the driver.
 * To disable the driver, the receiver and the transmitter are disabled by the
 * application. The transmitter is disabled first to test if the driver is
 * disabled.
 */

#define DRIVER_DISABLED(UART) ((UART)->tx_stopped_by_application)

#define DISABLE_DRIVER(UART)                       \
        {                                          \
            (UART)->tx_stopped_by_application = 1; \
            (UART)->rx_stopped_by_application = 1; \
        }

#define ENABLE_DRIVER(UART)                        \
        {                                          \
            (UART)->rx_stopped_by_application = 0; \
            (UART)->tx_stopped_by_application = 0; \
        }

/*
 * Low and high watermarks for the RX buffer. If it is enabled, the flow
 * control is activated or deactivated according to these values.
 * The high watermark value allows to copy an array filled with the RX FIFO
 * into the RX buffer. 
 */

#define RX_LOW_WATERMARK(RX_BUFFER_SIZE)  (FIFO_SIZE)
#define RX_HIGH_WATERMARK(RX_BUFFER_SIZE) ((RX_BUFFER_SIZE) - 2 * FIFO_SIZE)

/* 
 * This macro allows to know if the RX buffer is full. It must be called only
 * from the RX HISR. If it is called from the application, the rx_in and 
 * rx_fifo_in pointers may be updated if a RX interrupt occurs or if the 
 * RX HISR is activated.
 */

#define RX_BUFFER_FULL(UART)                                          \
            (((UART)->rx_in == (UART)->rx_out - 1) ||                 \
             ((UART)->rx_in == (UART)->rx_out + (UART)->buffer_size))

/*
 * This macro allows to know if the TX buffer is empty.
 */

#define TX_BUFFER_EMPTY(UART)                                         \
            ((UART)->tx_in == (UART)->tx_out)

/*
 * This macro is used to convert a time (unit: ms) into a number of TDMA.
 * 1 TDMA = 4.6 ms (23/5).
 */

#define CONVERT_TIME_IN_TDMA(TIME) (((TIME) * 5) / 23)

/*
 * This structure describes an UART compatible with the UART 16750 and
 * contains some fields to manage this UART.
 */

typedef struct s_uart {

    SYS_UWORD32 base_address;

    /*
     * HISR executed from the RX/TX interrupt handler.
     */
     
    NU_HISR rx_hisr_ctrl_block;
    NU_HISR tx_hisr_ctrl_block;
    NU_HISR v24_hisr_ctrl_block;

    char    rx_hisr_stack[RX_HISR_STACK_SIZE];
    char    tx_hisr_stack[TX_HISR_STACK_SIZE];
    char    v24_hisr_stack[V24_HISR_STACK_SIZE];
    
    /*
     * 2 arrays are used to store bytes read in RX FIFO. A UART RX interrupt
     * may occur while executing RX operations in RX HISR. To avoid overwriting
     * the array in which received bytes are stored, a second array is used.
     */
     
    SYS_UWORD8  *rx_buffer_used_by_rx_lisr;
    SYS_UWORD8  *rx_buffer_used_by_rx_hisr;
    SYS_UWORD8  rx_fifo_byte_1[FIFO_SIZE];
    SYS_UWORD8  rx_fifo_byte_2[FIFO_SIZE];
    SYS_UWORD16 bytes_in_rx_buffer_1;
    SYS_UWORD16 bytes_in_rx_buffer_2;
    
    /*
     * RX and TX buffers.
     * One character is not used in each buffer to allow to know if the buffer
     * is empty or not (See macro RX_BUFFER_FULL). If buffers are empty,
     * rx_in = rx_out and tx_in = tx_out. It is impossible to use fields to
     * count the number of bytes in each buffer because these fields may be
     * updated from the application and from the interrupt handlers. That avoids
     * to have conflicts.
     */

    SYS_UWORD16 buffer_size;
    SYS_UWORD16 rx_threshold_level;
    SYS_UWORD16 tx_threshold_level;
    SYS_UWORD8  rx_buffer[FD_MAX_BUFFER_SIZE + 1];
    SYS_UWORD8  tx_buffer[FD_MAX_BUFFER_SIZE + 1];
    SYS_UWORD8  *rx_in;
    SYS_UWORD8  *rx_out;
    SYS_UWORD8  *tx_in;
    SYS_UWORD8  *tx_out;

    /*
     * Escape sequence.
     * the field esc_seq_modified may have 2 values:
     *      - 0: No modification.
     *      - 1: Parameters are in the process of modification: The detection
     *           is stopped.
     */

    NU_TIMER      guard_period_timer_ctrl_block;
    SYS_UWORD8    esc_seq_modified;
    SYS_UWORD8    esc_seq_detection_state;
    SYS_UWORD8    esc_seq_character;
    UNSIGNED      guard_period;
    UNSIGNED      current_time;
    UNSIGNED      previous_time;

    /*
     * Flow control.
     */

    T_flowCtrlMode     flow_control_mode;
    SYS_BOOL           send_xon_xoff;
    SYS_UWORD8         xon_xoff_to_send;
    SYS_UWORD8         xon_character;
    SYS_UWORD8         xoff_character;
    SYS_BOOL           rx_stopped_by_application;
    SYS_BOOL           rx_stopped_by_driver;
    SYS_BOOL           rx_stopped_by_lisr;
    SYS_BOOL           tx_stopped_by_application;
    SYS_BOOL           tx_stopped_by_driver;
    /* SYS_BOOL           tx_stopped_by_lisr;*/

    /*
     * Break.
     */

    SYS_BOOL     break_received;
    SYS_BOOL     break_to_send;
    SYS_BOOL     break_in_progress;
    NU_HISR      break_hisr_ctrl_block;
    char         break_hisr_stack[BREAK_HISR_STACK_SIZE];
    NU_TIMER     break_timer_ctrl_block;
    UNSIGNED     baudrate;
    UNSIGNED     autobauding;	
    UNSIGNED     bits_per_char; /* Including start, stop and parity bits. */
    UNSIGNED     break_length;  /* In bytes. */
    UNSIGNED     time_without_character;

    /*
     * Callback (UAF_ReadData and UAF_WriteData).
     * rd: read, wr: write.
     */

    SYS_BOOL   esc_seq_received;
    SYS_UWORD8 rts_level; /* RTS on RS232 side, CTS on chipset side.
                             1: The RS232 line is deactivated (low). */

#if (UARTFAX_CLASSIC_DTR_DCD || (CHIPSET == 12))
    SYS_UWORD8 dtr_level; /* Controlled with an I/O on C & D-Sample and
                             handled by Calypso+ on E-Sample.
                             1: The RS232 line is deactivated (low). */
    /*
     * When the DTR interrupt is detected the user's Rx callback function must
     * be called but if the Rx FIFO is not empty the Rx HISR must be activated
     * to read the bytes received in the Rx FIFO and to put them into the Rx
     * buffer before to call the user's Rx callback function.
     * If the Rx HISR is activated due to a Rx interrupt the user's Rx callback
     * function will be called if conditions to call it are fulfilled. If it is
     * activated due to the DTR interrupt the user's Rx callback function must
     * be called without any conditions.
     * Because the Rx HISR may have been activated but not executed before the
     * DTR interrupt we must be sure that the user's Rx callback function will
     * be called for each Rx HISR activation. Call is done for Rx HISR activated
     * on Rx interrupt if conditions are fulfilled.
     * A circular buffer of 2 elements is used to memorize the source of
     * interrupt. Before the activation of the Rx HISR, the source of interrupt
     * is memorized into this array. When the code of the Rx HISR is executed
     * the user's Rx callback function is called if the source of interrupt was
     * the DTR interrupt regardless of the other conditions.
     * The level of DTR is saved to provide the level detected on Rx interrupt
     * or DTR interrupt in the 'state' parameter of the user's Rx callback
     * function.
     */                             

    SYS_BOOL   dtr_change_detected[2];
    SYS_UWORD8 dtr_level_saved[2];
    SYS_UWORD8 index_it;
    SYS_UWORD8 index_hisr;
#endif /* BOARD 8 or 9 or 40 or 41 or CHIPSET 12 */                            
    
    SYS_BOOL         reading_suspended;
    SYS_BOOL         writing_suspended;
    SYS_BOOL         rd_call_from_hisr_in_progress;
    SYS_BOOL         wr_call_from_hisr_in_progress;
    T_reInstMode     rd_call_setup;
    T_reInstMode     wr_call_setup;
    SYS_UWORD8       *rd_address[2];
    SYS_UWORD8       *wr_address[2];
    SYS_UWORD16      rd_size_before_call[2];
    SYS_UWORD16      rd_size_after_call[2];
    SYS_UWORD16      wr_size_before_call[2];
    SYS_UWORD16      wr_size_after_call[2];

    void (*readOutFunc) (SYS_BOOL cldFromIrq,
                         T_reInstMode *reInstall,
                         SYS_UWORD8 nsource,
                         SYS_UWORD8 *source[],
                         SYS_UWORD16 size[],
                         SYS_UWORD32 state);

    void (*writeInFunc) (SYS_BOOL cldFromIrq,
                         T_reInstMode *reInstall,
                         SYS_UWORD8 ndest,
                         SYS_UWORD8 *dest[],
                         SYS_UWORD16 size[]);

    /*
     * These fields are used to store the state defined in UAF_GetLineState.The
     * first field is used when UAF_GetLineState and UAF_ReadData are not called.
     * When one of these functions is called the second field is used. That
     * avoids to lose events when UAF_GetLineState or UAF_ReadData resets the
     * first field.
     */

    SYS_UWORD32 state_1;
    SYS_UWORD32 state_2;
    SYS_UWORD32 *state;

    /*
     * Errors counters.
     */

    SYS_UWORD32 framing_error;
    SYS_UWORD32 parity_error;
    SYS_UWORD32 overrun_error;
    SYS_UWORD32 spurious_interrupts;

    SYS_UWORD16 max_rx_fifo_level;

} t_uart;


static t_uart uart_parameters;


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


/*
 * DLL (LSB) and DLH (MSB) registers values using the 13 MHz clock.
 */

static const SYS_UWORD8 dll[] =
{
      0, /*   Auto baud:               */
     81, /*     75 baud.                */
     40, /*    150 baud.                */
    148, /*    300 baud.                */
     74, /*    600 baud.                */
    165, /*   1200 baud.                */
     83, /*   2400 baud.                */
    169, /*   4800 baud.                */
    113, /*   7200 baud.                */
     84, /*   9600 baud.                */
     56, /*  14400 baud.                */
     42, /*  19200 baud.                */
     28, /*  28800 baud.                */
     24, /*  33900 baud: not supported. */
     21, /*  38400 baud.                */
     14, /*  57600 baud.                */
      7, /* 115200 baud.                */
      0, /* 203125 baud: not supported. */
      0, /* 406250 baud: not supported. */
      0  /* 812500 baud: not supported. */
};

static const SYS_UWORD8 dlh[] = 
{
    0, /*   Auto baud:               */
   42, /*     75 baud.                */
   21, /*    150 baud.                */
   10, /*    300 baud.                */
    5, /*    600 baud.                */
    2, /*   1200 baud.                */
    1, /*   2400 baud.                */
    0, /*   4800 baud.                */
    0, /*   7200 baud.                */
    0, /*   9600 baud.                */
    0, /*  14400 baud.                */
    0, /*  19200 baud.                */
    0, /*  28800 baud.                */
    0, /*  33900 baud: not supported. */
    0, /*  38400 baud.                */
    0, /*  57600 baud.                */
    0, /* 115200 baud.                */
    0, /* 203125 baud: not supported. */
    0, /* 406250 baud: not supported. */
    0  /* 812500 baud: not supported. */
};

static const UNSIGNED baudrate_value[] =
{
         1,
        75,
       150,
       300,
       600,
      1200,
      2400,
      4800,
      7200,
      9600,
     14400,
     19200,
     28800,
         0, /* Not supported. */
     38400,
     57600,
    115200,
         0, /* Not supported. */
         0, /* Not supported. */
         0  /* Not supported. */
};


 

/*******************************************************************************
 *
 *                          get_bytes_in_rx_buffer
 * 
 * Purpose  : Gets the number of bytes in the RX buffer.
 *
 * Arguments: In : uart: Pointer on the UART structure.
 *            Out: none
 *
 * Returns  : The number of bytes in the RX buffer.
 *
 ******************************************************************************/

static SYS_UWORD16
get_bytes_in_rx_buffer (t_uart *uart)
{
    SYS_UWORD16 bytes_in_rx_buffer;
    volatile SYS_UWORD8 *rx_in;

    rx_in = uart->rx_in;

    if (uart->rx_out <= rx_in)
        bytes_in_rx_buffer = (SYS_UWORD16) (rx_in - uart->rx_out);
    else
        bytes_in_rx_buffer =
            (SYS_UWORD16) (rx_in - uart->rx_out + uart->buffer_size + 1);

    return (bytes_in_rx_buffer);
}

/*******************************************************************************
 *
 *                          get_bytes_in_tx_buffer
 * 
 * Purpose  : Gets the number of bytes in the TX buffer.
 *
 * Arguments: In : uart: Pointer on the UART structure.
 *            Out: none
 *
 * Returns  : The number of bytes in the TX buffer.
 *
 ******************************************************************************/

static SYS_UWORD16
get_bytes_in_tx_buffer (t_uart *uart)
{
    SYS_UWORD16 bytes_in_tx_buffer;
    volatile SYS_UWORD8 *tx_out;

    tx_out = uart->tx_out;

    if (tx_out <= uart->tx_in)
        bytes_in_tx_buffer = (SYS_UWORD16) (uart->tx_in - tx_out);
    else
        bytes_in_tx_buffer =
            (SYS_UWORD16) (uart->tx_in - tx_out + uart->buffer_size + 1);

    return (bytes_in_tx_buffer);
}

/*******************************************************************************
 *
 *                              compute_break_time
 * 
 * Purpose  : Computes a number of TDMA from 3 parameters:
 *              - baudrate,
 *              - bits per character including start bit, stop bits and parity,
 *              - number of characters.
 *            Due to the TDMA value (4.6 ms), a minimal value is sent: 2 TDMA.
 *
 * Arguments: In : baudrate
 *                 bits_per_char
 *                 number_of_chars
 *            Out: none
 *
 * Returns  : The number of TDMA.
 *
 ******************************************************************************/

static UNSIGNED
compute_break_time (UNSIGNED baudrate,
                    UNSIGNED bits_per_char,
                    UNSIGNED number_of_chars)
{
    UNSIGNED number_of_tdma;

    number_of_tdma = CONVERT_TIME_IN_TDMA (
                         1000 * bits_per_char * number_of_chars / baudrate);

    if (number_of_tdma == 0)
        number_of_tdma = 1;

    number_of_tdma++;

    return (number_of_tdma);
}

/*******************************************************************************
 *
 *                          update_reading_callback
 * 
 * Purpose  : Updates the sizes array and the addresses array and get and builds
 *            the state parameter defined in UAF_GetLineState to call the
 *            readOutFunc function.
 *
 * Arguments: In : uart       : Pointer on the UART structure.
 *                 call_source: 0: application, 1: HISR (Rx or V24), 3: Rx HISR
 *            Out: none
 *
 * Returns  : none
 *
 ******************************************************************************/

static void
update_reading_callback (t_uart *uart,
                         SYS_BOOL call_source)
{
    SYS_UWORD32  state;
    SYS_UWORD8  dtr_level;
    SYS_UWORD8  fragments_number;
    SYS_UWORD16 bytes_in_rx_buffer;
    volatile SYS_UWORD8 *rx_in;

    /*
     * Update the sizes array and the addresses array.
     * A copy of rx_in is used because it may be updated by the interrupt
     * handler if this function is called from the application.
     */

    rx_in = uart->rx_in;
    
    if (uart->rx_out < rx_in) {

        fragments_number = 1;

        uart->rd_address[0] = uart->rx_out;
        uart->rd_size_before_call[0] = (SYS_UWORD16) (rx_in - uart->rx_out);
        uart->rd_size_after_call[0] = uart->rd_size_before_call[0];

        uart->rd_size_before_call[1] = 0;
        uart->rd_size_after_call[1] = 0;

        bytes_in_rx_buffer = uart->rd_size_before_call[0];

    } else if (rx_in == uart->rx_out) { /* RX buffer empty. */
        
        fragments_number = 1;

        uart->rd_address[0] = uart->rx_out;
        uart->rd_size_before_call[0] = 0;
        uart->rd_size_after_call[0] = 0;

        uart->rd_size_before_call[1] = 0;
        uart->rd_size_after_call[1] = 0;

        bytes_in_rx_buffer = 0;
                    
    } else {
    
        fragments_number = 2;

        uart->rd_address[0] = uart->rx_out;
        uart->rd_size_before_call[0] =
            uart->buffer_size + 1 - (SYS_UWORD16) (uart->rx_out -
                                               &(uart->rx_buffer[0]));
        uart->rd_size_after_call[0] = uart->rd_size_before_call[0];

        uart->rd_address[1] = &(uart->rx_buffer[0]);
        uart->rd_size_before_call[1] = (SYS_UWORD16) (rx_in -
                                                  &(uart->rx_buffer[0]));
        uart->rd_size_after_call[1] = uart->rd_size_before_call[1];

        bytes_in_rx_buffer =
            uart->rd_size_before_call[0] + uart->rd_size_before_call[1];

        if (!uart->rd_size_before_call[1])
            fragments_number = 1;
    }

    /*
     * Build the state parameter defined in UAF_GetLineState.
     * The field state_2 is used when state_1 is set to 0 to avoid to
     * lose events detected in the RX interrupt handler.
     */

#if (UARTFAX_CLASSIC_DTR_DCD || (CHIPSET == 12))
    if (call_source == 3) /* Call from Rx HISR */
        dtr_level = uart->dtr_level_saved[uart->index_hisr];
    else
        dtr_level = uart->dtr_level;
#endif

    state = uart->state_2;
    uart->state_2 = 0;
    uart->state = &(uart->state_2);

    state |= uart->state_1;
    uart->state_1 = 0;
    uart->state = &(uart->state_1);

    state |= ((((SYS_UWORD32) uart->rts_level) << RTS) |

#if (UARTFAX_CLASSIC_DTR_DCD || (CHIPSET == 12))
              (((SYS_UWORD32) dtr_level) << DTR) |
#endif

              (((SYS_UWORD32) (uart->tx_stopped_by_application  |
                         uart->tx_stopped_by_driver)) << TXSTP) |

              (((SYS_UWORD32) (uart->rx_stopped_by_application  |
                         uart->rx_stopped_by_driver)) << RXSTP) |

              (((SYS_UWORD32) (uart->buffer_size - bytes_in_rx_buffer)) << RXBLEV));

    /*
     * Fields SA, SB and X are set according to the flow control:
     *
     *       None    RTS/CTS    XON/XOFF
     * SA    DTR     DTR        DTR
     * SB    RTS     0          RTS
     * X     0       RTS        XON:0 XOFF:1 (transmitter)
     *
     * DTR is supported on C, D & E-Sample.
     */

#if (UARTFAX_CLASSIC_DTR_DCD || (CHIPSET == 12))
    state |= (((SYS_UWORD32) uart->dtr_level) << SA);
#endif

    if (uart->flow_control_mode != fc_rts)
        state |= (((SYS_UWORD32) uart->rts_level) << SB);

    if (uart->flow_control_mode == fc_rts)
        state |= (((SYS_UWORD32) uart->rts_level) << X);
            
    else if ((uart->flow_control_mode == fc_xoff) &&
             (uart->tx_stopped_by_application ||
              uart->tx_stopped_by_driver))
        state |= (1 << X);

    /*
     * Call the readOutFunc function with these parameters.
     */

    uart->rd_call_setup = rm_notDefined;

    (*(uart->readOutFunc)) (call_source & 0x01, /* From HISR or application */
                            &(uart->rd_call_setup),
                            fragments_number,
                            &(uart->rd_address[0]),
                            &(uart->rd_size_after_call[0]),
                            state);
}

/*******************************************************************************
 *
 *                          update_writing_callback
 * 
 * Purpose  : Updates the sizes array and the addresses array to call the
 *            writeInFunc function.
 *
 * Arguments: In : uart      : Pointer on the UART structure.
 *                 call_source: 0: application, 1: HISR
 *            Out: none
 *
 * Returns  : none
 *
 ******************************************************************************/

static void
update_writing_callback (t_uart *uart,
                         SYS_BOOL call_source)
{
    SYS_UWORD8 fragments_number;
    volatile SYS_UWORD8 *tx_out;

    /*
     * Update the array of sizes and the array of addresses.
     * A copy of tx_out is used because it may be updated by the interrupt
     * handler if this function is called from the application.
     */

    tx_out = uart->tx_out;
    
    if (uart->tx_in < tx_out) {

        fragments_number = 1;

        uart->wr_address[0] = uart->tx_in;
        uart->wr_size_before_call[0] =
            (SYS_UWORD16) (tx_out - uart->tx_in - 1);
        uart->wr_size_after_call[0] = uart->wr_size_before_call[0];

        uart->wr_size_before_call[1] = 0;
        uart->wr_size_after_call[1] = 0;
                                    
    } else if (tx_out == &(uart->tx_buffer[0])) {

        fragments_number = 1;
        
        uart->wr_address[0] = uart->tx_in;
        uart->wr_size_before_call[0] =
            uart->buffer_size - 
            (SYS_UWORD16) (uart->tx_in - &(uart->tx_buffer[0]));
        uart->wr_size_after_call[0] = uart->wr_size_before_call[0];

        uart->wr_size_before_call[1] = 0;
        uart->wr_size_after_call[1] = 0;

    } else {
    
        fragments_number = 2;

        uart->wr_address[0] = uart->tx_in;
        uart->wr_size_before_call[0] =
            uart->buffer_size + 1 - 
            (SYS_UWORD16) (uart->tx_in - &(uart->tx_buffer[0]));
        uart->wr_size_after_call[0] = uart->wr_size_before_call[0];

        uart->wr_address[1] = &(uart->tx_buffer[0]);
        uart->wr_size_before_call[1] =
            (SYS_UWORD16) (tx_out - &(uart->tx_buffer[0]) - 1);
        uart->wr_size_after_call[1] = uart->wr_size_before_call[1];

        if (!uart->wr_size_before_call[1])
            fragments_number = 1;
    }

    /*
     * Call the writeInFunc function with these parameters;
     */

    uart->wr_call_setup = rm_notDefined;

    (*(uart->writeInFunc)) (call_source,
                            &(uart->wr_call_setup),
                            fragments_number,
                            &(uart->wr_address[0]),
                            &(uart->wr_size_after_call[0]));
}

/*******************************************************************************
 *
 *                                  stop_break
 * 
 * Purpose  : The timer is activated to expire when a time corresponding to the
 *            sending time of 2 characters at least has elapsed. After a break,
 *            no character may be sent during this period.
 *
 * Arguments: In : id: parameter not used.
 *            Out: none
 *
 * Returns  : none
 *
 ******************************************************************************/

static VOID
stop_break (UNSIGNED id)
{
    t_uart *uart;

    uart = &uart_parameters;

    uart->break_to_send = 0;
    uart->break_in_progress = 0;

#if ((CHIPSET != 5) && (CHIPSET != 6))
    /*
     * Disable sleep mode.
     */
          
    WRITE_UART_REGISTER (
        uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP);
#endif

    /*
     * Unmask Tx interrupt.
     */

    WRITE_UART_REGISTER (
        uart, IER, READ_UART_REGISTER (uart, IER) | ETBEI);
}

/*******************************************************************************
 *
 *                          hisr_start_break
 * 
 * Purpose  : Enables the timer used to control the time without character.
 *
 * Arguments: In : none
 *            Out: none
 *
 * Returns  : none
 *
 ******************************************************************************/

static VOID
hisr_start_break (VOID)
{
    t_uart *uart;

    uart = &uart_parameters;

    (void) NU_Control_Timer (&(uart->break_timer_ctrl_block),
                             NU_DISABLE_TIMER);

    (void) NU_Reset_Timer (&(uart->break_timer_ctrl_block),
                           stop_break,
                           uart->time_without_character,
                           0, /* The timer expires once. */
                           NU_DISABLE_TIMER);

    (void) NU_Control_Timer (&(uart->break_timer_ctrl_block),
                             NU_ENABLE_TIMER);
}

/*******************************************************************************
 *
 *                              stop_receiver
 * 
 * Purpose  : Activates DTR or RTS or sends XOFF. 
 *
 * Arguments: In : uart: Pointer on the UART structure.
 *            Out: none
 *
 * Returns  : none
 *
 ******************************************************************************/

static void
stop_receiver (t_uart *uart)
{
#if ((CHIPSET != 5) && (CHIPSET != 6))
    /*
     * Disable sleep mode.
     */
          
    WRITE_UART_REGISTER (
        uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP);
#endif

    switch (uart->flow_control_mode) {

    case fc_rts:

        /*
         * CTS (RTS on UART side) is deactivated (high).
         */

        WRITE_UART_REGISTER (
            uart, MCR, READ_UART_REGISTER (uart, MCR) & ~MRTS);
        break;

    case fc_xoff:

        uart->xon_xoff_to_send = uart->xoff_character;
        uart->send_xon_xoff = 1;

        /*
         * Unmask Tx interrupt.
         */
          
        WRITE_UART_REGISTER (
            uart, IER, READ_UART_REGISTER (uart, IER) | ETBEI);
        break;
    }
}

/*******************************************************************************
 *
 *                              start_receiver
 * 
 * Purpose  : Deactivates DTR or RTS or sends XON.
 *
 * Arguments: In : uart: Pointer on the UART structure.
 *            Out: none
 *
 * Returns  : none
 *
 ******************************************************************************/

static void
start_receiver (t_uart *uart)
{
#if ((CHIPSET != 5) && (CHIPSET != 6))
    /*
     * Disable sleep mode.
     */
          
    WRITE_UART_REGISTER (
        uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP);
#endif

    switch (uart->flow_control_mode) {

    case fc_rts:

        /*
         * CTS (RTS on UART side) is activated (low).
         */

        WRITE_UART_REGISTER (
            uart, MCR, READ_UART_REGISTER (uart, MCR) | MRTS);
        break;

    case fc_xoff:

        uart->xon_xoff_to_send = uart->xon_character;
        uart->send_xon_xoff = 1;

        /*
         * Unmask Tx interrupt.
         */
          
        WRITE_UART_REGISTER (
            uart, IER, READ_UART_REGISTER (uart, IER) | ETBEI);
        break;
    }
}

/*******************************************************************************
 *
 *                          add_esc_seq_char_in_rx_buffer
 * 
 * Purpose  : Writes one escape sequence character in the RX buffer.
 *
 * Arguments: In : uart: Pointer on the UART structure.
 *            Out: none
 *
 * Returns  : none
 *
 ******************************************************************************/

static void
add_esc_seq_char_in_rx_buffer (t_uart *uart)
{
    /*
     * IF the RX buffer is not full, write an escape sequence character in the
     * RX buffer and check wrap-around.
     */

    if (!RX_BUFFER_FULL (uart)) {

        *(uart->rx_in++) = uart->esc_seq_character;

        if (uart->rx_in == &(uart->rx_buffer[0]) + uart->buffer_size + 1)
            uart->rx_in = &(uart->rx_buffer[0]);
    }
}

/*******************************************************************************
 *
 *                      analyze_guard_period_timer_expiration
 * 
 * Purpose  : According to the state of the escape sequence detection, 1 or 2
 *            escape sequence characters may be written into the TX buffer or
 *            the escape sequence is declared as detected.
 *            If 1 or 2 escape sequence characters have been detected the
 *            guard period must not expire.
 *            If 3 characters have been detected the escape sequence must
 *            expire.
 *
 * Arguments: In : id: parameter not used.
 *            Out: none
 *
 * Returns  : none 
 *
 ******************************************************************************/

static VOID
analyze_guard_period_timer_expiration (UNSIGNED id)
{
    t_uart *uart;
    SYS_UWORD16 bytes_in_rx_buffer;

    uart = &uart_parameters;

    switch (uart->esc_seq_detection_state) {
    
    case ONE_CHAR_DETECTED:
    
        /*
         * 1 escape sequence character has been detected. The guard period has
         * ellapsed. This character is written into the TX buffer.
         */
        
        add_esc_seq_char_in_rx_buffer (uart);
        break;
        
    case TWO_CHARS_DETECTED:
    
        /*
         * 2 escape sequence characters have been detected. The guard period has
         * ellapsed. These characters are written into the TX buffer.
         */
        
        add_esc_seq_char_in_rx_buffer (uart);
        add_esc_seq_char_in_rx_buffer (uart);

        break;
        
    case THREE_CHARS_DETECTED:

        /*
         * 3 escape sequence characters have been detected and the guard period
         * has ellapsed. The escape sequence is detected.
         */    
         
        uart->esc_seq_received = 1;
        *(uart->state) |= (1 << ESC);
        
        break;
    }
    
    uart->esc_seq_detection_state = NO_ESCAPE_SEQUENCE;
    
    /*
     * If the high watermark is reached, RTS is activated or XOFF is sent
     * according to the flow control mode.
     */

    bytes_in_rx_buffer = get_bytes_in_rx_buffer (uart);

    if ((uart->flow_control_mode != fc_none) &&
        (bytes_in_rx_buffer >= RX_HIGH_WATERMARK (uart->buffer_size))) {

        /*
         * Check if receipt must be stopped.
         */

        if (!uart->rx_stopped_by_driver) {

            uart->rx_stopped_by_driver = 1;
            if (!uart->rx_stopped_by_application)
                stop_receiver (uart);
        }
    }

    /*
     * If a reading was suspended or if the callback function is installed,
     * it is called if one of these conditions is fulfiled:
     *      - the RX threshold level is reached,
     *      - a break has been detected,
     *      - an escape sequence has been detected,
     */

    if ((!uart->rd_call_from_hisr_in_progress) &&
        (uart->reading_suspended ||
         (uart->rd_call_setup == rm_reInstall))) {

        if ((bytes_in_rx_buffer >= uart->rx_threshold_level) ||
            uart->break_received ||
            uart->esc_seq_received) {

            uart->rd_call_from_hisr_in_progress = 1;
            update_reading_callback (uart, 1); /* 1: call from HISR. */

            uart->reading_suspended = 0;
            uart->break_received = 0;
            uart->esc_seq_received = 0;
        }
    }
}

/*******************************************************************************
 *
 *                          stop_guard_period_timer
 * 
 * Purpose  : Stops the timer used to detect the guard period expiration.
 *
 * Arguments: In : uart: Pointer on the UART structure.
 *            Out: none
 *
 * Returns  : none 
 *
 ******************************************************************************/

static void
stop_guard_period_timer (t_uart *uart)
{
    (void) NU_Control_Timer (&(uart->guard_period_timer_ctrl_block),
                             NU_DISABLE_TIMER);
}

/*******************************************************************************
 *
 *                          start_guard_period_timer
 * 
 * Purpose  : Starts a timer which expires if the guard period has ellapsed.
 *
 * Arguments: In : uart: Pointer on the UART structure.
 *            Out: none
 *
 * Returns  : none 
 *
 ******************************************************************************/

static void
start_guard_period_timer (t_uart *uart)
{
    (void) NU_Control_Timer (&(uart->guard_period_timer_ctrl_block),
                             NU_DISABLE_TIMER);

    (void) NU_Reset_Timer (&(uart->guard_period_timer_ctrl_block),
                           analyze_guard_period_timer_expiration,
                           uart->guard_period,
                           0, /* The timer expires once. */
                           NU_DISABLE_TIMER);

    (void) NU_Control_Timer (&(uart->guard_period_timer_ctrl_block),
                             NU_ENABLE_TIMER);
}

/*******************************************************************************
 *
 *                          detect_escape_sequence
 * 
 * Purpose  : The state machine used to detect an escape sequence is updated
 *            according to the array of bytes to analyse. If the state machine
 *            goes to the initial state due to a break in the sequence
 *            detection, the previous characters are put into the RX buffer.
 *
 * Arguments: In : uart: Pointer on the UART structure.
 *            Out: none
 *
 * Returns  : 0: Break in detection or a sequence has been detected. 
 *            1: A sequence may be detected.
 *
 ******************************************************************************/

static int
detect_escape_sequence (t_uart *uart)
{
    int      detection_result;
    SYS_UWORD8    *rx_fifo_byte;
    SYS_UWORD16   bytes_in_rx_buffer;
    UNSIGNED elapsed_time;

    detection_result = 0;

    rx_fifo_byte = uart->rx_buffer_used_by_rx_hisr;
    if (rx_fifo_byte == &(uart->rx_fifo_byte_1[0]))
        bytes_in_rx_buffer = uart->bytes_in_rx_buffer_1;
    else
        bytes_in_rx_buffer = uart->bytes_in_rx_buffer_2;

    if (uart->current_time > uart->previous_time)
        elapsed_time = uart->current_time - uart->previous_time;
    else
        elapsed_time =
            MAX_UNSIGNED_32 - uart->previous_time + uart->current_time;

    switch (uart->esc_seq_detection_state) {

    case INITIALIZATION:

        /*
         * It is the first character received. It may be the first character
         * of an escape sequence. The elapsed_time variable is set to the
         * guard period value to consider this character as the first character
         * of an escape sequence.
         */

        if (!uart->esc_seq_modified) {

            elapsed_time = uart->guard_period;
            uart->esc_seq_detection_state = NO_ESCAPE_SEQUENCE;
        }

        /* No break! */

    case NO_ESCAPE_SEQUENCE:

        /*
         * To go to the next state (one, two or three characters detected):
         *      - a guard period must have elapsed since the last receipt,
         *      - the characters must belong to the escape sequence.
         */

        if ((elapsed_time >= uart->guard_period) &&
            (!uart->esc_seq_modified)) {

            switch (bytes_in_rx_buffer) {

            case 1:

                if (*rx_fifo_byte++ == uart->esc_seq_character) {
                
                    uart->esc_seq_detection_state = ONE_CHAR_DETECTED;
                    start_guard_period_timer (uart);
                    detection_result = 1;
                }

                break;

            case 2:

                if ((*rx_fifo_byte++ == uart->esc_seq_character) &&
                    (*rx_fifo_byte++ == uart->esc_seq_character)) {
                    
                    uart->esc_seq_detection_state = TWO_CHARS_DETECTED;
                    start_guard_period_timer (uart);
                    detection_result = 1;
                }
                                    
                break;

            case 3:

                if ((*rx_fifo_byte++ == uart->esc_seq_character) &&
                    (*rx_fifo_byte++ == uart->esc_seq_character) &&
                    (*rx_fifo_byte++ == uart->esc_seq_character)) {
                        
                    uart->esc_seq_detection_state = THREE_CHARS_DETECTED;
                    start_guard_period_timer (uart);
                    detection_result = 1;
                }
                    
                break;

            default:
            
                /*
                 * No action.
                 */

                break;
            }
        }

        uart->previous_time = uart->current_time;

        break;

    case ONE_CHAR_DETECTED:

        /*
         * To go to the next state (two or three characters detected):
         *      - the difference between the current time and the previous time
         *        must be less than the guard period,
         *      - the characters must belong to the escape sequence.
         * Otherwise, an escape sequence character is written in the RX buffer.
         */

        if (!uart->esc_seq_modified) {

            switch (bytes_in_rx_buffer) {

            case 1:

                if (*rx_fifo_byte++ == uart->esc_seq_character) {
                
                    uart->esc_seq_detection_state = TWO_CHARS_DETECTED;
                    detection_result = 1;                
                }

                break;

            case 2:

                if ((*rx_fifo_byte++ == uart->esc_seq_character) &&
                    (*rx_fifo_byte++ == uart->esc_seq_character)) {
                
                    start_guard_period_timer (uart); /* Reset the timer. */
                       
                    uart->esc_seq_detection_state = THREE_CHARS_DETECTED;
                    detection_result = 1;                    
                }
                    
                break;

            default:

                /*
                 * No action.
                 */

                break;
            }
        }

        if (!detection_result) {

            add_esc_seq_char_in_rx_buffer (uart);

            uart->previous_time = uart->current_time;
            uart->esc_seq_detection_state = NO_ESCAPE_SEQUENCE;
        }

        break;

    case TWO_CHARS_DETECTED:

        /*
         * To go to the next state (three chars detected):
         *      - the difference between the current time and the previous time
         *        must be less than the guard period,
         *      - the character must belong to the escape sequence.
         * Otherwise, 2 escape sequence characters are written in the RX buffer.
         */

        if (!uart->esc_seq_modified) {

            switch (bytes_in_rx_buffer) {

            case 1:

                if (*rx_fifo_byte++ == uart->esc_seq_character) {

                    start_guard_period_timer (uart); /* Reset the timer. */
                    
                    uart->esc_seq_detection_state = THREE_CHARS_DETECTED;
                    detection_result = 1;
                }
                
                break;

            default:

                /*
                 * No action.
                 */

                break;
            }
        }

        if (!detection_result) {

            add_esc_seq_char_in_rx_buffer (uart);
            add_esc_seq_char_in_rx_buffer (uart);

            uart->previous_time = uart->current_time;
            uart->esc_seq_detection_state = NO_ESCAPE_SEQUENCE;
        }

        break;

    case THREE_CHARS_DETECTED:

        /*
         * An escape sequence is detected if a guard period has elapsed since
         * the last receipt. Otherwise, 3 escape sequence characters are
         * written in the RX buffer.
         */

        stop_guard_period_timer (uart);

        add_esc_seq_char_in_rx_buffer (uart);
        add_esc_seq_char_in_rx_buffer (uart);
        add_esc_seq_char_in_rx_buffer (uart);

        uart->previous_time = uart->current_time;
        uart->esc_seq_detection_state = NO_ESCAPE_SEQUENCE;

        break;
    }

    return (detection_result);
}

/*******************************************************************************
 *
 *                              send_break
 * 
 * Purpose  : This function may only called if the TX FIFO is empty.
 *            Null characters are written in the TX FIFO. The number of bytes to
 *            write has been defined with UAF_SetLineState. Enables the break
 *            condition.
 *
 * Arguments: In : uart: Pointer on the UART structure.
 *            Out: none
 *
 * Returns  : Number of bytes sent.
 *
 ******************************************************************************/

static SYS_UWORD16
send_break (t_uart *uart)
{
    SYS_UWORD16 bytes_in_tx_fifo;

    bytes_in_tx_fifo = 0;
    uart->break_in_progress = 1;

#if ((CHIPSET != 5) && (CHIPSET != 6))
    /*
     * Disable sleep mode.
     */

    WRITE_UART_REGISTER (
        uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP);
#endif

    WRITE_UART_REGISTER (
        uart, LCR, READ_UART_REGISTER (uart, LCR) | BREAK_CONTROL);
      
#if ((CHIPSET != 5) && (CHIPSET != 6))
    /*
     * Re-enable sleep mode.
     */

/* BELOW LINES WERE COMMENTED TO DISABLE SLEEP MODE IN DRIVER */
/*
    WRITE_UART_REGISTER (
        uart, IER, READ_UART_REGISTER (uart, IER) | IER_SLEEP);

        */
#endif

    while (uart->break_length) {

        WRITE_UART_REGISTER (uart, THR, 0x00);
        uart->break_length--;
        bytes_in_tx_fifo++;
    }

    return (bytes_in_tx_fifo);
}

/*******************************************************************************
 *
 *                              build_rx_fifo_array
 * 
 * Purpose  : Reads the RX FIFO to build an array with bytes read.
 *            A byte is written in this array if no error is detected. 
 *
 * Arguments: In : uart: Pointer on the UART structure.
 *            Out: none
 *
 * Returns  : The number of bytes in RX FIFO.
 *
 ******************************************************************************/

static SYS_UWORD16
build_rx_fifo_array (t_uart *uart)
{
    SYS_UWORD8  status;
    SYS_UWORD8  *first_byte;
    SYS_UWORD8  *current_byte;
    SYS_UWORD16 *bytes_in_rx_buffer;
    SYS_UWORD16 bytes_received;
    SYS_UWORD8 cbyte;

    volatile int x;

    x = 1;

    bytes_received = 0;
    
    
    /*
     * Switch to the other buffer.
     */
     
    first_byte = uart->rx_buffer_used_by_rx_lisr;
    if (first_byte == &(uart->rx_fifo_byte_1[0])) {
    
        first_byte = &(uart->rx_fifo_byte_2[0]);
        bytes_in_rx_buffer = &(uart->bytes_in_rx_buffer_2);
    
    } else {
    
        first_byte = &(uart->rx_fifo_byte_1[0]);
        bytes_in_rx_buffer = &(uart->bytes_in_rx_buffer_1);
    }

    current_byte = first_byte;

    if (*bytes_in_rx_buffer) {
 

    	/* The Rx buffer is not empty and is being used by HISR ! */
    	/* Hence stop the flow control */
	stop_receiver (uart); 

     /*
       * Reset LCR[7] (DLAB) to have access to the RBR, THR and IER registers.
       */
       WRITE_UART_REGISTER (uart, LCR, READ_UART_REGISTER (uart, LCR) & ~DLAB);
     
       /* Mask The Rx  and interrupt */
       
       WRITE_UART_REGISTER (
            uart, IER, READ_UART_REGISTER (uart, IER) &
                       ~(ERBI | EDSSI));
       
       uart->rx_stopped_by_lisr = 1;
      	return (bytes_received);
      	
      	}

    uart->rx_buffer_used_by_rx_lisr = first_byte;
    
    status = READ_UART_REGISTER (uart, LSR);

    /*
     * Build an array with the bytes contained in the RX FIFO.
     */

    while (status & DR) { /* While RX FIFO is not empty... */

        *current_byte = READ_UART_REGISTER (uart, RHR);

        /*
         * Check if a parity error or a framing error is associated with the
         * received data. If there is an error the byte is not copied into the
         * bytes array.
         */

        if (status & BYTE_ERROR) {

            if (status & OE)
                uart->overrun_error++;

            if (status & PE)
                uart->parity_error++;

            if (status & FE)
                uart->framing_error++;

            /*
             * Check break detection.
             */

            if (status & BI) {
            
                uart->break_received = 1;
                *(uart->state) |=
                    ((1 << BRK) | (MINIMAL_BREAK_LENGTH << BRKLEN));
            }

        } else /* No error */ 
            current_byte++;

        status = READ_UART_REGISTER (uart, LSR);
    }

    bytes_received = (SYS_UWORD16) (current_byte - first_byte);
    *bytes_in_rx_buffer = bytes_received;

    /*
     * Re-switch to the other buffer if no valid character has been received.
     */

    if (!bytes_received) {
         
        if (uart->rx_buffer_used_by_rx_lisr == &(uart->rx_fifo_byte_1[0]))
            uart->rx_buffer_used_by_rx_lisr = &(uart->rx_fifo_byte_2[0]);
        
        else
            uart->rx_buffer_used_by_rx_lisr = &(uart->rx_fifo_byte_1[0]);
    }

    if (bytes_received > uart->max_rx_fifo_level)
        uart->max_rx_fifo_level = bytes_received;
        
    return (bytes_received);
}

/*******************************************************************************
 *
 *                              empty_rx_fifo
 * 
 * Purpose  : Read the RX FIFO.
 *
 * Arguments: In : uart: Pointer on the UART structure.
 *            Out: none
 *
 * Returns  : none
 *
 ******************************************************************************/

static void
empty_rx_fifo (t_uart *uart)
{
    SYS_UWORD16 bytes_in_rx_fifo;
    volatile SYS_UWORD8 dummy_byte;

    bytes_in_rx_fifo = 0;

    while (READ_UART_REGISTER (uart, LSR) & DR) {

        dummy_byte = READ_UART_REGISTER (uart, RHR);
        bytes_in_rx_fifo++;
    }

    if (bytes_in_rx_fifo > uart->max_rx_fifo_level)
        uart->max_rx_fifo_level = bytes_in_rx_fifo;
}

/*******************************************************************************
 *
 *                          hisr_execute_rx_operations
 * 
 * Purpose  : If an escape sequence is detected or if a break in the detection
 *            has occured RX FIFO bytes are written in the RX buffer. 
 *            If the software flow control is used bytes are analyzed to know
 *            if a XON or a XOFF character is received to stop or start the
 *            transmitter. 
 *            If a flow control is used and if the high watermark of the RX
 *            buffer is reached the receiver is stopped.
 *            If the RX threshold level is reached the callback mechanism is
 *            activated.
 *
 * Arguments: In : none
 *            Out: none
 *
 * Returns  : none
 *
 ******************************************************************************/

static VOID
hisr_execute_rx_operations (VOID)
{
    SYS_UWORD16 bytes_free_in_rx_buffer;
    SYS_UWORD16 wrap_around_counter;
    SYS_UWORD16 bytes_in_rx_buffer;
    SYS_UWORD16 bytes_read;
    SYS_UWORD16 bytes_to_copy;
    SYS_UWORD8  *current_byte;
    SYS_UWORD8  xon_xoff_detected;
    t_uart *uart;

    uart = &uart_parameters;
    
    /*
     * Since new characters have been received, the sleep timer is reset then
     * restarted preventing the system to enter deep-sleep for a new period of
     * time.
     */

    SER_restart_uart_sleep_timer ();
    uart_sleep_timer_enabled = 1;

#if (UARTFAX_CLASSIC_DTR_DCD || (CHIPSET == 12))
    uart->index_hisr = (uart->index_hisr + 1) & 0x01; /* 0 or 1 */
#endif

    xon_xoff_detected = 0;
    
    /*
     * Switch to the other buffer.
     */
     
    current_byte = uart->rx_buffer_used_by_rx_hisr;
    if (current_byte == &(uart->rx_fifo_byte_1[0])) {
    
        current_byte = &(uart->rx_fifo_byte_2[0]);
        bytes_read = uart->bytes_in_rx_buffer_2;
    
    } else {
    
        current_byte = &(uart->rx_fifo_byte_1[0]);
        bytes_read = uart->bytes_in_rx_buffer_1;
    }

    uart->rx_buffer_used_by_rx_hisr = current_byte;

    /*
     * All bytes are copied into the RX buffer only if an escape sequence has
     * been detected or a break in the detection has occured.
     */

    if (!detect_escape_sequence (uart)) {

        if (uart->rx_out > uart->rx_in)
            bytes_free_in_rx_buffer = (SYS_UWORD16) (uart->rx_out - uart->rx_in - 1);
        else
            bytes_free_in_rx_buffer =
                (SYS_UWORD16) (uart->buffer_size + uart->rx_out - uart->rx_in);

        wrap_around_counter = uart->buffer_size + 1 -
                              (SYS_UWORD16) (uart->rx_in - &(uart->rx_buffer[0]));
        
        if (uart->flow_control_mode == fc_xoff) {
        
            /*
             * For SW Flow Control, need to further investigate the processing
             * in order to improve the performance of the driver, and in order
             * to avoid managing the wrap around of the circular buffer each
             * time a character is copied.
             */
        
            while (bytes_read && bytes_free_in_rx_buffer) {

                /*
                 * If the data received is XON or XOFF, the transmitter is
                 * enabled (XON) or disabled (XOFF).
                 */

                if (*current_byte == uart->xoff_character) {

                    uart->tx_stopped_by_driver = 1;
                    xon_xoff_detected = 1;

                } else if (*current_byte == uart->xon_character) {

                    uart->tx_stopped_by_driver = 0;
                    xon_xoff_detected = 1;

#if ((CHIPSET != 5) && (CHIPSET != 6))
                    /*
                     * Disable sleep mode.
                     */
          
                    WRITE_UART_REGISTER (
                        uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP);
#endif

                    /*
                     * Unmask Tx interrupt.
                     */
          
                    WRITE_UART_REGISTER (
                        uart, IER, READ_UART_REGISTER (uart, IER) | ETBEI);

                } else {
    
                    *(uart->rx_in++) = *current_byte;

                    wrap_around_counter--;
                    if (!wrap_around_counter) {
                    
                        uart->rx_in = &(uart->rx_buffer[0]);
                        wrap_around_counter = uart->buffer_size + 1;
                    }
                    
                    bytes_free_in_rx_buffer--;
                }

                current_byte++;
                bytes_read--;
            }
        } else { /* No Flow Control or HW Flow Control */
                
            /*
             * Figure out the most restricting condition.
             */

            bytes_to_copy =
                Min3 (bytes_free_in_rx_buffer, wrap_around_counter, bytes_read);
                          
            /*
             * Copy characters into the circular Rx buffer.
             */
        
            memcpy (uart->rx_in, current_byte, bytes_to_copy);

            /*
             * Update first the variables associated to blocking conditions:
             * if (bytes_read = 0) OR
             *    (bytes_free_in_rx_buffer = 0) => No more characters to copy.
             */
                
            bytes_free_in_rx_buffer	-= bytes_to_copy;
            bytes_read -= bytes_to_copy;
                
            wrap_around_counter -= bytes_to_copy;
            if (!wrap_around_counter)
                    uart->rx_in = &(uart->rx_buffer[0]);
            else
                uart->rx_in += bytes_to_copy;

            /*
             * Check if there are still some characters to copy.
             */

            if (bytes_read && bytes_free_in_rx_buffer) {

                /*
                 * Update the remaining variables and figure out again the
                 * most restricting condition. Since (bytes_read = 0) and
                 * (bytes_free_in_rx_buffer = 0) are blocking conditions, if
                 * we reach that point it means that the wrap around condition
                 * has just occurred and it is not needed to manage it again.
                 */

                current_byte += bytes_to_copy;
                bytes_to_copy = Min (bytes_read, bytes_free_in_rx_buffer);

                /*
                 * Copy characters into the circular Rx buffer and update
                 * current pointer.
                 */

                memcpy (uart->rx_in, current_byte, bytes_to_copy);

                uart->rx_in += bytes_to_copy;
                
                /*
                 * bytes_free_in_rx_buffer not updated since not used anymore.
                 */
                   bytes_read -= bytes_to_copy;
              
            }
            else {
            	     bytes_read = 0;
            }
        } /* end if (uart->flow_control_mode == fc_xoff) */


        /*
         * If the high watermark is reached, RTS is activated or XOFF is
         * sent according to the flow control mode.
         */

        bytes_in_rx_buffer = get_bytes_in_rx_buffer (uart);

        if ((uart->flow_control_mode != fc_none) &&
            (bytes_in_rx_buffer >= RX_HIGH_WATERMARK (uart->buffer_size))) {

            /*
             * Check if receipt must be stopped.
             */

            if (!uart->rx_stopped_by_driver) {

                uart->rx_stopped_by_driver = 1;
                if (!uart->rx_stopped_by_application)
                    stop_receiver (uart);
            }
        }

        /*
         * If a reading was suspended or if the callback function is installed,
         * it is called if one of these conditions is fulfiled:
         *      - the RX threshold level is reached,
         *      - a break has been detected,
         */

        if ((!uart->rd_call_from_hisr_in_progress) &&
            (uart->reading_suspended ||
             (uart->rd_call_setup == rm_reInstall))) {

            if ((bytes_in_rx_buffer >= uart->rx_threshold_level) ||
#if (UARTFAX_CLASSIC_DTR_DCD || (CHIPSET == 12))
                uart->dtr_change_detected[uart->index_hisr] ||
#endif
                uart->break_received ||
                xon_xoff_detected) {


                uart->rd_call_from_hisr_in_progress = 1;
                update_reading_callback (uart, 3); /* 3: call from Rx HISR. */

                uart->reading_suspended = 0;
                uart->break_received = 0;
                uart->esc_seq_received = 0;
#if (UARTFAX_CLASSIC_DTR_DCD || (CHIPSET == 12))
                uart->dtr_change_detected[uart->index_hisr] = 0;
#endif
            }
        }

    }



    WRITE_UART_REGISTER (uart, LCR, READ_UART_REGISTER (uart, LCR) & ~DLAB);
              
    /* Mask The Rx and Modem status interrupt */
    WRITE_UART_REGISTER (
               uart, IER, READ_UART_REGISTER (uart, IER) &
                       ~(ERBI | EDSSI));
              
       if ((uart->rx_buffer_used_by_rx_hisr) == &(uart->rx_fifo_byte_1[0])) {
       	 
  	      	 uart->bytes_in_rx_buffer_1 = 0;
           	 
    	    } else {
    	                
               uart->bytes_in_rx_buffer_2 = 0;
        }

       
       WRITE_UART_REGISTER (uart, LCR, READ_UART_REGISTER (uart, LCR) & ~DLAB);
              
        /* Unmask The Rx and Modem status interrupt*/
       WRITE_UART_REGISTER (
               uart, IER, READ_UART_REGISTER (uart, IER) |
                       (ERBI | EDSSI));

        if(uart->rx_stopped_by_lisr  ) {
       	if (!uart->rx_stopped_by_driver) {
   		 

              uart->rx_stopped_by_lisr = 0;
        
              /*
                * Reset LCR[7] (DLAB) to have access to the RBR, THR and IER registers.
                */
              WRITE_UART_REGISTER (uart, LCR, READ_UART_REGISTER (uart, LCR) & ~DLAB);
         

              /* UnMask The Rx interrupt */
              WRITE_UART_REGISTER (
               uart, IER, READ_UART_REGISTER (uart, IER) |
                       (ERBI | EDSSI));
             
              start_receiver (uart);
             
       	}
    }

}

/*******************************************************************************
 *
 *                          hisr_execute_v24_operations
 * 
 * Purpose  : The user's function is called if all conditions to call it are
 *            fulfiled.
 *
 * Arguments: In : none
 *            Out: none
 *
 * Returns  : none
 *
 ******************************************************************************/

static VOID
hisr_execute_v24_operations (VOID)
{
    t_uart *uart;

    uart = &uart_parameters;

    /*
     * If a reading was suspended or if the callback function is installed,
     * it is called.
     */

    if ((!DRIVER_DISABLED (uart)) &&
        (!uart->rd_call_from_hisr_in_progress) &&
        (uart->reading_suspended || (uart->rd_call_setup == rm_reInstall))) {

        uart->rd_call_from_hisr_in_progress = 1;
        update_reading_callback (uart, 1); /* 1: call from HISR. */
        uart->reading_suspended = 0;
        uart->break_received = 0;
        uart->esc_seq_received = 0;
    }

}

/*******************************************************************************
 *
 *                          hisr_execute_tx_operations
 * 
 * Purpose  : Writes bytes from the TX buffer to the TX FIFO.
 *            The user's function is called if all conditions to call it are
 *            fulfiled.
 *
 * Arguments: In : none
 *            Out: none
 *
 * Returns  : none
 *
 ******************************************************************************/

static VOID
hisr_execute_tx_operations (VOID)
{
    SYS_UWORD16 bytes_in_tx_buffer;
    SYS_UWORD16 bytes_in_tx_fifo;
    SYS_UWORD16 wrap_around_counter;
    SYS_UWORD16 bytes_to_write;
    t_uart *uart;
    int counter;


    uart = &uart_parameters;

    /*
     * A TX interrupt may have occured during the previous TX HISR. This case
     * may appear when a HISR having a higher priority has been activated when
     * the TX HISR was activated. When the next TX HISR is activated, the TX
     * FIFO may not be empty. Nothing is done until a TX interrupt will occur.
     * The RX HISR will be activated again and the TX FIFO will be empty.
     */

    if (READ_UART_REGISTER (uart, LSR) & THRE) {

        bytes_in_tx_fifo = 0;
    
        /*
         * A request to send a XON/XOFF character may have been done by the 
         * RX interrupt handler. The byte can be written because we are sure
         * that the TX FIFO is not full.
         */

        if (uart->send_xon_xoff) {

            WRITE_UART_REGISTER (uart, THR, uart->xon_xoff_to_send);
            uart->send_xon_xoff = 0;
            bytes_in_tx_fifo++;
        }

        if ((!uart->tx_stopped_by_application) &&
            (!uart->tx_stopped_by_driver)) {

            bytes_in_tx_buffer = get_bytes_in_tx_buffer (uart);
            wrap_around_counter =
                uart->buffer_size + 1 - (SYS_UWORD16) (uart->tx_out -
                                                  &(uart->tx_buffer[0]));

            /*
             * Figure out the most restricting condition.
             */

#if ((CHIPSET == 3) || (CHIPSET == 4) || (CHIPSET == 5) || (CHIPSET == 6))
            /*
             * Loading of only (FIFO_SIZE - 1) characters in the Tx FIFO to
             * avoid the generation of a spurious Tx FIFO almost empty
             * interrupt (Ulysse bug report #35).
             */

            bytes_to_write =
                Min3 (bytes_in_tx_buffer, wrap_around_counter,
                      (FIFO_SIZE - 1 - bytes_in_tx_fifo));
#elif ((CHIPSET == 7) || (CHIPSET == 8) || (CHIPSET == 9) || (CHIPSET == 10) || (CHIPSET == 11) || (CHIPSET == 12))
            /*
             * Bug corrected on Calypso rev. A, rev. B, C035, Ulysse C035,
             * Calypso Lite & Calypso+.
             */

            bytes_to_write =
                Min3 (bytes_in_tx_buffer, wrap_around_counter,
                (FIFO_SIZE - bytes_in_tx_fifo));
#endif

            /*
             * Write characters into the Tx FIFO.
             */

            for (counter = 0; counter < bytes_to_write; counter++)
                WRITE_UART_REGISTER (uart, THR, *(uart->tx_out++));

            /*
             * Update the variables associated to blocking conditions:
             * if (bytes_in_tx_buffer = 0) OR
             *    (bytes_in_tx_fifo = FIFO_SIZE) => No more characters to copy.
             */

            bytes_in_tx_buffer -= bytes_to_write;
            bytes_in_tx_fifo += bytes_to_write;

            wrap_around_counter -= bytes_to_write;
            if (!wrap_around_counter)
                uart->tx_out = &(uart->tx_buffer[0]);

            /*
             * Check if there are still some characters to write.
             */

            if (bytes_in_tx_buffer &&
#if ((CHIPSET == 3) || (CHIPSET == 4) || (CHIPSET == 5) || (CHIPSET == 6))
                (bytes_in_tx_fifo < (FIFO_SIZE - 1))) {
#elif ((CHIPSET == 7) || (CHIPSET == 8) || (CHIPSET == 9) || (CHIPSET == 10) || (CHIPSET == 11) || (CHIPSET == 12))
                (bytes_in_tx_fifo < FIFO_SIZE)) {
#endif

                /*
                 * Figure out again the most restricting condition. Since
                 * (bytes_in_tx_buffer = 0) and	(bytes_in_tx_fifo = FIFO_SIZE)
                 * are blocking conditions, if we reach that point it means
                 * that the wrap around condition has just occurred and it is
                 * not needed to manage it again.
                 */

#if ((CHIPSET == 3) || (CHIPSET == 4) || (CHIPSET == 5) || (CHIPSET == 6))
                bytes_to_write =
                    Min (bytes_in_tx_buffer,
                         (FIFO_SIZE - 1 - bytes_in_tx_fifo));
#elif ((CHIPSET == 7) || (CHIPSET == 8) || (CHIPSET == 9) || (CHIPSET == 10) || (CHIPSET == 11) || (CHIPSET == 12))
                bytes_to_write =
                    Min (bytes_in_tx_buffer,
                         (FIFO_SIZE - bytes_in_tx_fifo));
#endif

                /*
                 * Write characters into the Tx FIFO and update associated
                 * variables.
                 */

                for (counter = 0; counter < bytes_to_write; counter++)
                    WRITE_UART_REGISTER (uart, THR, *(uart->tx_out++));

                bytes_in_tx_buffer += bytes_to_write;
                bytes_in_tx_fifo += bytes_to_write;
            }

            /*
             * If a writing was suspended or if the callback function is
             * installed, it is called if the TX threshold level is reached.
             */

            if ((!DRIVER_DISABLED (uart)) &&
                (!uart->wr_call_from_hisr_in_progress) &&
                (bytes_in_tx_buffer <= uart->tx_threshold_level) &&
                ((uart->wr_call_setup == rm_reInstall) ||
                 uart->writing_suspended)) {

                uart->writing_suspended = 0;

                uart->wr_call_from_hisr_in_progress = 1;
                update_writing_callback (uart, 1); /* 1: call from HISR. */
            }
        } /* end if ((!uart->tx_stopped_by_application) && */
          /*         (!uart->tx_stopped_by_driver))        */

        if (bytes_in_tx_fifo)

            /*
             * Unmask Tx interrupt.
             */
          
            WRITE_UART_REGISTER (
                uart, IER, READ_UART_REGISTER (uart, IER) | ETBEI);

        else {

            if ((!bytes_in_tx_fifo) && (uart->break_to_send))
                bytes_in_tx_fifo = send_break (uart);
        }

#if ((CHIPSET != 5) && (CHIPSET != 6))
        /*
         * Re-enable the sleep mode.
         */

/* BELOW LINES WERE COMMENTED TO DISABLE SLEEP MODE IN DRIVER */
/*
        WRITE_UART_REGISTER (
            uart, IER, READ_UART_REGISTER (uart, IER) | IER_SLEEP);

            */
#endif
    }
}

/*******************************************************************************
 *
 *                              read_rx_fifo
 * 
 * Purpose  : Reads the RX FIFO. If the driver is enabled bytes are written in
 *            an array to be analyzed by the RX HISR.
 *
 * Arguments: In : uart: Pointer on the UART structure.
 *            Out: none
 *
 * Returns  : none
 *
 ******************************************************************************/

static void
read_rx_fifo (t_uart *uart)
{

    /*
     * If the driver is disabled the RX FIFO is read to acknoledge the
     * interrupt else bytes received are written into an array which will be
     * analyzed from the RX HISR.
     */
     
    if (DRIVER_DISABLED (uart))
        empty_rx_fifo (uart);

    else if (build_rx_fifo_array (uart)){
        (void) NU_Activate_HISR (&(uart->rx_hisr_ctrl_block));
        
    	}
    

}

/*******************************************************************************
 *
 *                          check_v24_input_lines
 * 
 * Purpose  : Check the V.24 input lines. According to the states of the input
 *            lines and to the flow control mode selected, the transmitter is
 *            enabled or disabled. The reading callback function is called if
 *            it is installed and if all conditions are fulfiled.
 *
 * Arguments: In : uart: Pointer on the UART structure.
 *            Out: none
 *
 * Returns  : none
 *
 ******************************************************************************/

static void
check_v24_input_lines (t_uart *uart)
{
    SYS_BOOL v24_input_line_changed;
    volatile SYS_UWORD8 modem_status;

    modem_status = READ_UART_REGISTER (uart, MSR);
    v24_input_line_changed = 0;

    if (modem_status & DELTA_CTS) {

        v24_input_line_changed = 1;

        if (modem_status & MCTS)
            uart->rts_level = 0;
        else
            uart->rts_level = 1;
    }

#if (CHIPSET == 12)
    else if (modem_status & DELTA_DSR) {
	 v24_input_line_changed = 1;

        if (modem_status & MDSR)
        {
            uart->dtr_level = 0;
	     if (uart->flow_control_mode != fc_dtr  && uart->baudrate == baudrate_value[FD_BAUD_AUTO])
            UAF_SetComPar (UAF_UART_1, FD_BAUD_AUTO, bpc_8, sb_1, pa_none); /* switch back to autobaud */
        }
        else
            uart->dtr_level = 1;

        /*
         * The reading callback function has to be called. But bytes received before
         * the change of state of DTR must be copied into the RX buffer before to
         * call it.
         */
         
        if (READ_UART_REGISTER (uart, LSR) & DR) { /* If Rx FIFO is not empty */
    
            /*
             * The Rx FIFO will be read to fill one of the two buffers and the Rx
             * HISR will be activated.
             */
           
            uart->index_it = (uart->index_it + 1) & 0x01; /* 0 or 1 */
            uart->dtr_change_detected[uart->index_it] = 1;
            uart->dtr_level_saved[uart->index_it] = uart->dtr_level;
            read_rx_fifo (uart);
            
        } else
            v24_input_line_changed = 1;
    }
#endif

    /*
     * When the hardware flow control is selected, if the RS 232 input signal is
     * deactivated (low), the transmitter is stopped.
     */

    if (uart->flow_control_mode == fc_rts) {
        
        if (uart->rts_level) {
            uart->tx_stopped_by_driver = 1;
        }    

        else {
            
            uart->tx_stopped_by_driver = 0;
            #ifdef CONFIG_TARGET_GTAMODEM
                AI_ResetBit(1);
            #endif

#if ((CHIPSET != 5) && (CHIPSET != 6))
            /*
             * Disable sleep mode.
             */
          
            WRITE_UART_REGISTER (
                uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP);
#endif

            /*
             * Unmask Tx interrupt.
             */

            WRITE_UART_REGISTER (
                uart, IER, READ_UART_REGISTER (uart, IER) | ETBEI);

        }
    }

    if (v24_input_line_changed)
        (void) NU_Activate_HISR (&(uart->v24_hisr_ctrl_block));
}

/*******************************************************************************
 *
 *                              fill_tx_fifo
 * 
 * Purpose  : If the TX buffer is not empty, and if there is no break in
 *            progress, bytes are written into the TX FIFO until the TX FIFO is
 *            full or the TX buffer is empty. Else, if there is a break to send
 *            an all 0s character is written into the TX FIFO and a break is
 *            declared in progress to avoid to fill the TX FIFO on the next
 *            interrupt.
 *            When the TX FIFO is empty and if a break is in progress, the break
 *            length is programmed: all 0s characters are written into the TX
 *            FIFO. The number of bytes has been defined previously with the
 *            UAF_SetLineState function. The break condition is enabled.
 *            When the TX FIFO and the transmitter shift register (TSR) are both
 *            empty and if a break is in progress, the break condition is 
 *            disabled.
 *            When bytes are written from the TX buffer to the TX FIFO, the
 *            writing callback function is called if it is installed and if all
 *            conditions are fulfiled.
 *
 * Arguments: In : uart: Pointer on the UART structure.
 *            Out: none
 *
 * Returns  : none
 *
 ******************************************************************************/

static void
fill_tx_fifo (t_uart *uart)
{
#if ((CHIPSET != 5) && (CHIPSET != 6))
    /*
     * Disable sleep mode.
     */

    WRITE_UART_REGISTER (
        uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP);
#endif

    /*
     * Mask Tx interrupt.
     */

    WRITE_UART_REGISTER (
        uart, IER, READ_UART_REGISTER (uart, IER) & ~ETBEI);

    /*
     * If a break is in progress, bytes of the TX buffer are not written into
     * the TX FIFO.
     */

    if (!uart->break_in_progress)
        (void) NU_Activate_HISR (&(uart->tx_hisr_ctrl_block));    

    else {

        /*
         * The break HISR is activated and the break condition is cleared.
         */

        WRITE_UART_REGISTER (
            uart, LCR, READ_UART_REGISTER (uart, LCR) & ~BREAK_CONTROL);

        (void) NU_Activate_HISR (&(uart->break_hisr_ctrl_block));
    }
}

/*******************************************************************************
 *
 *                                UAF_Init
 * 
 * Purpose  : Initializes the UART hardware and installs interrupt handlers.
 *            The parameters are set to the default values:
 *               - 19200 baud,
 *               - 8 bits / character,
 *               - no parity,
 *               - 1 stop bit,
 *               - no flow control.
 *            All functionalities of the UART driver are disabled.
 *
 * Arguments: In : uartNo: Used UART.
 *            Out: none
 *
 * Returns  : FD_OK           : Successful operation.
 *            FD_NOT_SUPPORTED: Wrong UART number.
 *            FD_INTERNAL_ERR : Internal problem.
 *
 ******************************************************************************/

T_FDRET
UAF_Init (T_fd_UartId uartNo)
{
    t_uart *uart;
    volatile SYS_UWORD8 status;

    /*
     * Check UART number.
     * A return is used to simplify the code.
     * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware
     * flow control is not supported.
     * DCD and DTR are not supported on UART Irda on C & D-Sample.
     * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample.
     */

    if (uartNo != UAF_UART_1)
        return (FD_NOT_SUPPORTED);

    uart = &uart_parameters;

    /*
     * Create the 3 HISR actived in the RX/TX and V24 interrupt handlers.
     * A return is used to simplify the code if an error occurs.
     * All stacks are entirely filled with the pattern 0xFE.
     */
     
    memset (&(uart->rx_hisr_stack[0]), 0xFE, RX_HISR_STACK_SIZE);

    if (NU_Create_HISR (&(uart->rx_hisr_ctrl_block),
                        "UAF_Rx",
                        hisr_execute_rx_operations,
                        RX_HISR_PRIORITY,
                        &(uart->rx_hisr_stack[0]),
                        RX_HISR_STACK_SIZE) != NU_SUCCESS)

        return (FD_INTERNAL_ERR);

    memset (&(uart->tx_hisr_stack[0]), 0xFE, TX_HISR_STACK_SIZE);

    if (NU_Create_HISR (&(uart->tx_hisr_ctrl_block),
                        "UAF_Tx",
                        hisr_execute_tx_operations,
                        TX_HISR_PRIORITY,
                        &(uart->tx_hisr_stack[0]),
                        TX_HISR_STACK_SIZE) != NU_SUCCESS)

        return (FD_INTERNAL_ERR);

    memset (&(uart->v24_hisr_stack[0]), 0xFE, V24_HISR_STACK_SIZE);

    if (NU_Create_HISR (&(uart->v24_hisr_ctrl_block),
                        "UAF_V24",
                        hisr_execute_v24_operations,
                        V24_HISR_PRIORITY,
                        &(uart->v24_hisr_stack[0]),
                        V24_HISR_STACK_SIZE) != NU_SUCCESS)

        return (FD_INTERNAL_ERR);

    /*
     * Create the HISR used to send a break.
     * A return is used to simplify the code if an error occurs.
     * The stack is entirely filled with the pattern 0xFE.
     */

    memset (&(uart->break_hisr_stack[0]), 0xFE, BREAK_HISR_STACK_SIZE);

    if (NU_Create_HISR (&(uart->break_hisr_ctrl_block),
                        "UAF_Brk",
                        hisr_start_break,
                        BREAK_HISR_PRIORITY,
                        &(uart->break_hisr_stack[0]),
                        BREAK_HISR_STACK_SIZE) != NU_SUCCESS)

        return (FD_INTERNAL_ERR);

    /*
     * Create a timer used in the break HISR.
     * A return is used to simplify the code if an error occurs.
     */

    if (NU_Create_Timer (&(uart->break_timer_ctrl_block),
                         "Break",
                         stop_break,
                         0, /* Parameter supplied to the routine: not used. */
                         1, /* This parameter is set when the timer is reset. */
                         0, /* The timer expires once. */
                         NU_DISABLE_TIMER) != NU_SUCCESS)

        return (FD_INTERNAL_ERR);

    /*
     * Create a timer used in the detection of the escape sequence.
     * A return is used to simplify the code if an error occurs.
     */

    if (NU_Create_Timer (&(uart->guard_period_timer_ctrl_block),
                         "Esc seq",
                         analyze_guard_period_timer_expiration,
                         0, /* Parameter supplied to the routine: not used. */
                         1, /* This parameter is set when the timer is reset. */
                         0, /* The timer expires once. */
                         NU_DISABLE_TIMER) != NU_SUCCESS)

        return (FD_INTERNAL_ERR);

    /*
     * These data are used to send a break.
     * A character has: 8 data bits + 1 start bit + 1 stop bit = 10 bits.
     */

    uart->baudrate = baudrate_value[FD_BAUD_19200];
    uart->autobauding = 0;	
    uart->bits_per_char = 10;

    /*
     * UART base address.
     */

    uart->base_address = base_address[uartNo];

    /*
     * Select the current array used to store received bytes.
     */
     
    uart->rx_buffer_used_by_rx_lisr = &(uart->rx_fifo_byte_2[0]);
    uart->rx_buffer_used_by_rx_hisr = &(uart->rx_fifo_byte_2[0]);
    
    /*
     * RX and TX buffers.
     */

    uart->buffer_size        = FD_MAX_BUFFER_SIZE;
    uart->rx_threshold_level = 1;
    uart->tx_threshold_level = 0;
    uart->rx_in              = &(uart->rx_buffer[0]);
    uart->rx_out             = &(uart->rx_buffer[0]);
    uart->tx_in              = &(uart->tx_buffer[0]);
    uart->tx_out             = &(uart->tx_buffer[0]);

    /*
     * Escape sequence.
     */

    uart->esc_seq_modified        = 0;
    uart->esc_seq_detection_state = INITIALIZATION;
    uart->esc_seq_character       = DEFAULT_ESC_SEQ_CHARACTER;
    uart->guard_period            = CONVERT_TIME_IN_TDMA (
                                         DEFAULT_GUARD_PERIOD);

    /*
     * Flow control.
     */

    uart->flow_control_mode         = fc_none;
    uart->send_xon_xoff             = 0;
    uart->rx_stopped_by_application = 1;
    uart->rx_stopped_by_driver      = 0;
    uart->rx_stopped_by_lisr      = 0;
    uart->tx_stopped_by_application = 1;
    uart->tx_stopped_by_driver      = 0;

    /*
     * Break.
     */

    uart->break_received    = 0;
    uart->break_to_send     = 0;
    uart->break_in_progress = 0;

    /*
     * Callback (UAF_ReadData and UAF_WriteData).
     */

    uart->esc_seq_received  = 0;

    uart->reading_suspended             = 0;
    uart->writing_suspended             = 0;
    uart->rd_call_from_hisr_in_progress = 0;
    uart->wr_call_from_hisr_in_progress = 0;
    uart->rd_call_setup                 = rm_noInstall;
    uart->wr_call_setup                 = rm_noInstall;

    /*
     * State defined in UAF_GetLineState.
     */

    uart->state_1 = 0;
    uart->state_2 = 0;
    uart->state   = &(uart->state_1);

    /*
     * Errors counters.
     */

    uart->framing_error       = 0;
    uart->parity_error        = 0;
    uart->overrun_error       = 0;
    uart->spurious_interrupts = 0;

    uart->max_rx_fifo_level   = 0;

    /*
     * Mask all interrupts causes and disable sleep mode and low power mode.
     */

    WRITE_UART_REGISTER (uart, IER, 0x00);

    /*
     * Reset UART mode configuration.
     */
     
    WRITE_UART_REGISTER (uart, MDR1, RESET_DEFAULT_STATE   |
                                     IR_SLEEP_DISABLED     |
                                     SIR_TX_WITHOUT_ACREG2 |
                                     FRAME_LENGTH_METHOD);

    /*
     * FIFO configuration.
     * EFR[4] = 1 to allow to program FCR[5:4] and MCR[7:5].
     */
     
    WRITE_UART_REGISTER (uart, LCR, 0xBF);
    SET_BIT (uart, EFR, ENHANCED_FEATURE_BIT);

    /*
     * Select the word length, the number of stop bits , the parity and set
     * LCR[7] (DLAB) to allow to program FCR, DLL and DLM.
     */

    WRITE_UART_REGISTER (uart, LCR, WLS_8 | DLAB);

    /*
     * Program the trigger levels.
     * MCR[6] must be set to 1.
     */
     
    SET_BIT (uart, MCR, TCR_TLR_BIT);
    WRITE_UART_REGISTER (uart, TCR, 0x0F);
    WRITE_UART_REGISTER (uart, TLR, RX_FIFO_TRIGGER_LEVEL);
    RESET_BIT (uart, MCR, TCR_TLR_BIT);

    /*
     * Force the generation of THR_IT on TX FIFO empty: SCR[3] = 1.
     */

    WRITE_UART_REGISTER (
        uart, SCR, READ_UART_REGISTER (uart, SCR) | TX_EMPTY_CTL_IT);
    
    /*
     * Program the FIFO control register. Bit 0 must be set when other FCR bits
     * are written to or they are not programmed.
     * FCR is a write-only register. It will not be modified.
     */

    WRITE_UART_REGISTER (uart, FCR, FIFO_ENABLE   |
                                    RX_FIFO_RESET | /* self cleared */
                                    TX_FIFO_RESET); /* self cleared */

    /*
     * Program the baud generator.
     */

    WRITE_UART_REGISTER (uart, DLL, dll[FD_BAUD_19200]);
    WRITE_UART_REGISTER (uart, DLM, dlh[FD_BAUD_19200]);

    /*
     * Reset LCR[7] (DLAB) to have access to the RBR, THR and IER registers.
     */

    WRITE_UART_REGISTER (uart, LCR, READ_UART_REGISTER (uart, LCR) & ~DLAB);

    /*
     * Select UART mode.
     */
     
    WRITE_UART_REGISTER (uart, MDR1, UART_MODE             |
                                     IR_SLEEP_DISABLED     |
                                     SIR_TX_WITHOUT_ACREG2 |
                                     FRAME_LENGTH_METHOD);

    /*
     * Read the state of RTS (RTS on RS232, CTS on chipset).
     */

    status = READ_UART_REGISTER (uart, MSR);

    if (status & MCTS)
        uart->rts_level = 0;
    else
        uart->rts_level = 1;

#if UARTFAX_CLASSIC_DTR_DCD
    /*
     * On C & D-Sample, 2 I/O are used to control DCD and DTR on UART Modem.
     * DCD: I/O 2 (output)
     * DTR: I/O 3 (input)
     */
     
    #define EXTENDED_MCU_REG (0xFFFEF006) /* Extended MCU register       */
    #define ASIC_CONFIG_REG  (0xFFFEF008) /* Asic Configuration register */

    #define IO_DTR (10) /* I/O 3; bit 10 of Asic Configuration register */
    #define IO_DCD ( 6) /* I/O 2; bit 6 of Extended MCU register        */

    /*
     * Select I/O for DCD and configure it as output.
     * DCD should start HIGH (not asserted).
     */

    *((volatile SYS_UWORD16 *) EXTENDED_MCU_REG) &= ~(1 << IO_DCD);
    AI_ConfigBitAsOutput (ARMIO_DCD);
    AI_SetBit (ARMIO_DCD);

    /*
     * Select I/O for DTR and configure it as input.
     * An interrupt is used to detect a change of state of DTR. Falling edge
     * or rising edge is selected according to the state of DTR.
     */
    
    *((volatile SYS_UWORD16 *) ASIC_CONFIG_REG) &= ~(1 << IO_DTR);
    AI_ConfigBitAsInput (ARMIO_DTR);
    uart->dtr_level = AI_ReadBit (ARMIO_DTR);

    if (uart->dtr_level)
        AI_SelectIOForIT (ARMIO_DTR, ARMIO_FALLING_EDGE);
    else
        AI_SelectIOForIT (ARMIO_DTR, ARMIO_RISING_EDGE);
        
    AI_UnmaskIT (ARMIO_MASKIT_GPIO);

    /*
     * Reset the 2 indexes of the circular buffer of 2 elements.
     * The circular buffer does not need to be initialized.
     */
     
    uart->index_it = 0;
    uart->index_hisr = 0;
#elif (CHIPSET == 12)
    /*
     * DCD and DTR are directly handled by Calypso+.
     * Force DCD pin to HIGH
     */

    WRITE_UART_REGISTER (uart, MCR, READ_UART_REGISTER(uart, MCR) & ~MDCD);

    /*
     * Read the state of DTR (DTR on RS232, DSR on chipset).
     */

    status = READ_UART_REGISTER (uart, MSR);

    if (status & MDSR)
        uart->dtr_level = 0;
    else
        uart->dtr_level = 1;

    /*
     * Reset the 2 indexes of the circular buffer of 2 elements.
     * The circular buffer does not need to be initialized.
     */
     
    uart->index_it = 0;
    uart->index_hisr = 0;
#endif /* BOARD == 8, 9, 40 or 41, CHIPSET == 12 */
    
    /*
     * Unmask RX interrupt and the modem status interrupt.
     */

    WRITE_UART_REGISTER (uart, IER, ERBI | EDSSI);

#if (CHIPSET == 12)
    /*
     * Unmask DSR interrupt in order to detect a change of state of DTR.
     */

	ENABLE_DSR_INTERRUPT (uart);
#endif

    return (FD_OK);
}

/*******************************************************************************
 *
 *                               UAF_Enable
 * 
 * Purpose  : The functionalities of the UART driver are disabled or enabled.
 *            In the deactivated state, all information about the communication
 *            parameters should be stored and recalled if the driver is again
 *            enabled. When the driver is enabled the RX and TX buffers are
 *            cleared.
 *
 * Arguments: In : uartNo: Used UART.
 *               : enable: 1: enable the driver
 *                         0: disable the driver
 *            Out: none
 *
 * Returns  : FD_OK           : Successful operation.
 *            FD_NOT_SUPPORTED: Wrong UART number.
 *            FD_INTERNAL_ERR : Internal problem with the hardware.
 *
 ******************************************************************************/

T_FDRET
UAF_Enable (T_fd_UartId uartNo,
            SYS_BOOL enable)
{
    t_uart  *uart;

    /*
     * Check UART number.
     * A return is used to simplify the code.
     * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware
     * flow control is not supported.
     * DCD and DTR are not supported on UART Irda on C & D-Sample.
     * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample.
     */

    if (uartNo != UAF_UART_1)
        return (FD_NOT_SUPPORTED);

    /*
     * There is no case where FD_INTERNAL_ERR may be returned.
     */
     
    uart = &uart_parameters;

    if (enable) {

        uart->rx_stopped_by_driver = 0;
            
        ENABLE_DRIVER (uart);
        start_receiver (uart);

    } else {

        DISABLE_DRIVER (uart);
        stop_receiver (uart);

        uart->tx_in = &(uart->tx_buffer[0]);
        uart->rx_in = &(uart->rx_buffer[0]);
        uart->tx_out = uart->tx_in;
        uart->rx_out = uart->rx_in;
    }

    return (FD_OK);
}

/*******************************************************************************
 *
 *                            UAF_SetComPar
 * 
 * Purpose  : Sets up the communication parameters: baud rate, bits per
 *            character, number of stop bits, parity.
 *
 * Arguments: In : uartNo  : Used UART.
 *                 baudrate: Used baud rate.
 *                 bpc     : Used bits per character.
 *                 sb      : Used stop bits.
 *                 parity  : Used parity.
 *            Out: none
 *
 * Returns  : FD_OK           : Successful operation.
 *            FD_NOT_SUPPORTED: The specified parameters don't fit to the
 *                              capabilities of the UART or wrong UART number.
 *            FD_INTERNAL_ERR : Internal problem with the hardware.
 *
 ******************************************************************************/

T_FDRET
UAF_SetComPar (T_fd_UartId uartNo,
               T_baudrate baudrate,
               T_bitsPerCharacter bpc,
               T_stopBits sb,
               T_parity parity)
{
    t_uart *uart;
    volatile SYS_UWORD8 mcr_value;
    volatile SYS_UWORD8 status;

    /*
     * Check UART number.
     * A return is used to simplify the code.
     * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware
     * flow control is not supported.
     * DCD and DTR are not supported on UART Irda on C & D-Sample.
     * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample.
     */

    if (uartNo != UAF_UART_1)
        return (FD_NOT_SUPPORTED);

    /*
     * There is no case where FD_INTERNAL_ERR may be returned.
     * pa_space is not supported. Some baudrates are not supported too.
     * A return is used to simplify the code.
     */

    if ((!baudrate_value[baudrate]) ||
        (parity == pa_space))

        return (FD_NOT_SUPPORTED);

    uart = &uart_parameters;

    /*
     * Mask all interrupts causes and disable sleep mode and low power mode.
     */

    WRITE_UART_REGISTER (uart, IER, 0x00);

#if UARTFAX_CLASSIC_DTR_DCD
    AI_MaskIT (ARMIO_MASKIT_GPIO);
#elif (CHIPSET == 12)
    DISABLE_DSR_INTERRUPT (uart);
#endif

    /*
     * Reset UART mode configuration.
     */
     
    WRITE_UART_REGISTER (uart, MDR1, RESET_DEFAULT_STATE   |
                                     IR_SLEEP_DISABLED     |
                                     SIR_TX_WITHOUT_ACREG2 |
                                     FRAME_LENGTH_METHOD);

    /*
     * FIFO configuration.
     * EFR[4] = 1 to allow to program FCR[5:4] and MCR[7:5].
     */
     
    WRITE_UART_REGISTER (uart, LCR, 0xBF);
    SET_BIT (uart, EFR, ENHANCED_FEATURE_BIT);

    /*
     * Select the word length, the number of stop bits , the parity and set
     * LCR[7] (DLAB) to allow to program FCR, DLL and DLM.
     */

    uart->baudrate = baudrate_value[baudrate];
    uart->autobauding = (baudrate == FD_BAUD_AUTO);  /* if autobauding enable trigger */
    uart->bits_per_char = 1; /* Start bit. */
    mcr_value = DLAB;

    if (bpc == bpc_7) {
    
        mcr_value |= WLS_7;
        uart->bits_per_char += 7;

    } else {

        mcr_value |= WLS_8;
        uart->bits_per_char += 8;
    }

    if (sb == sb_2) {

        mcr_value |= STB;
        uart->bits_per_char += 2;

    } else
        uart->bits_per_char += 1;

    switch (parity) {

    case pa_even:

        mcr_value |= (PEN | EPS);
        uart->bits_per_char += 1;

        break;

    case pa_odd:

        mcr_value |= PEN;
        uart->bits_per_char += 1;

        break;

    default:

        /*
         * There is nothing to do.
         */

        break;
    }

    WRITE_UART_REGISTER (uart, LCR, mcr_value);

    /*
     * Program the trigger levels.
     * MCR[6] must be set to 1.
     */
     
    SET_BIT (uart, MCR, TCR_TLR_BIT);
    WRITE_UART_REGISTER (uart, TCR, 0x0F);
    WRITE_UART_REGISTER (uart, TLR, RX_FIFO_TRIGGER_LEVEL);
    RESET_BIT (uart, MCR, TCR_TLR_BIT);

    /*
     * Force the generation of THR_IT on TX FIFO empty: SCR[3] = 1.
     */

    WRITE_UART_REGISTER (
        uart, SCR, READ_UART_REGISTER (uart, SCR) | TX_EMPTY_CTL_IT);
    
    /*
     * Program the FIFO control register. Bit 0 must be set when other FCR bits
     * are written to or they are not programmed.
     * FCR is a write-only register. It will not be modified.
     */

    WRITE_UART_REGISTER (uart, FCR, FIFO_ENABLE   |
                                    RX_FIFO_RESET | /* self cleared */
                                    TX_FIFO_RESET); /* self cleared */

    /*
     * Program the baud generator.
     */

    WRITE_UART_REGISTER (uart, DLL, dll[baudrate]);
    WRITE_UART_REGISTER (uart, DLM, dlh[baudrate]);

    /*
     * Reset LCR[7] (DLAB) to have access to the RBR, THR and IER registers.
     */

    WRITE_UART_REGISTER (uart, LCR, READ_UART_REGISTER (uart, LCR) & ~DLAB);

    /*
     * Select UART mode.
     */
     
    WRITE_UART_REGISTER (uart, MDR1,  ((baudrate==FD_BAUD_AUTO)?
                                         UART_MODE_AUTOBAUDING:
                                         UART_MODE)             |
                                     IR_SLEEP_DISABLED     |
                                     SIR_TX_WITHOUT_ACREG2 |
                                     FRAME_LENGTH_METHOD);

    /*
     * Read the state of RTS (RTS on RS232, CTS on chipset).
     */

    status = READ_UART_REGISTER (uart, MSR);

    if (status & MCTS)
        uart->rts_level = 0;
    else
        uart->rts_level = 1;

#if UARTFAX_CLASSIC_DTR_DCD
    /*
     * Read the state of DTR and select the edge.
     */
         
    uart->dtr_level = AI_ReadBit (ARMIO_DTR);
    
    if (uart->dtr_level)
        AI_SelectIOForIT (ARMIO_DTR, ARMIO_FALLING_EDGE);
    else
        AI_SelectIOForIT (ARMIO_DTR, ARMIO_RISING_EDGE);
        
    AI_UnmaskIT (ARMIO_MASKIT_GPIO);
#elif (CHIPSET == 12)
    /*
     * Read the state of DTR - No need to reload MSR register since its value
     * is still stored in the "status" local variable.
     */

    if (status & MDSR)
        uart->dtr_level = 0;
    else
        uart->dtr_level = 1;
#endif

#if ((CHIPSET == 5) || (CHIPSET == 6))
    /*
     * Unmask RX and TX interrupts and the modem status interrupt. 
     */

    WRITE_UART_REGISTER (uart, IER, ERBI | ETBEI | EDSSI);
#elif (CHIPSET == 12)
    /*
     * Unmask RX and TX interrupts and the modem status interrupt... 
     */

    WRITE_UART_REGISTER (uart, IER, ERBI | ETBEI | EDSSI);

    /*
     * ... Then, unmask DSR interrupt...
     */

	ENABLE_DSR_INTERRUPT (uart);  

    /*
     * ... And finally allow sleep mode.
     */

   /* BELOW LINES WERE COMMENTED TO DISABLE SLEEP MODE IN DRIVER */
    /*
    WRITE_UART_REGISTER (uart, IER, READ_UART_REGISTER (uart, IER) | IER_SLEEP);
    */
#else
    /*
     * Unmask RX and TX interrupts and the modem status interrupt 
     * and allow sleep mode.
     */
    /* BELOW LINES WERE COMMENTED TO DISABLE SLEEP MODE IN DRIVER */

    /* WRITE_UART_REGISTER (uart, IER, ERBI | ETBEI | EDSSI | IER_SLEEP);*/

    WRITE_UART_REGISTER (uart, IER, ERBI | ETBEI | EDSSI);
#endif


    return (FD_OK);
}

/*******************************************************************************
 *
 *                            UAF_SetBuffer
 * 
 * Purpose  : Sets up the size of the circular buffers to be used in the UART
 *            driver. This function may be called only if the UART is disabled
 *            with UAF_Enable.
 *
 * Arguments: In : uartNo     : Used UART.
 *                 bufSize    : Specifies the size of the circular buffer.
 *                 rxThreshold: Amount of received bytes that leads to a call
 *                              to suspended read-out function which is passed
 *                              to the function UAF_ReadData.
 *                 txThreshold: Amount of bytes in the TX buffer to call the
 *                              suspended write-in function which is passed to
 *                              the function UAF_WriteData
 *            Out: none
 *
 * Returns  : FD_OK           : Successful operation.
 *            FD_NOT_SUPPORTED: bufSize exceeds the maximal possible
 *                              capabilities of the driver or the threshold
 *                              values don't correspond to the bufSize or
 *                              wrong UART number.
 *            FD_INTERNAL_ERR : Internal problem with the hardware or the
 *                              function has been called while the UART is
 *                              enabled.
 *
 ******************************************************************************/

T_FDRET
UAF_SetBuffer (T_fd_UartId uartNo,
               SYS_UWORD16 bufSize,
               SYS_UWORD16 rxThreshold,
               SYS_UWORD16 txThreshold)
{
    T_FDRET result;
    t_uart *uart;

    /*
     * Check UART number.
     * A return is used to simplify the code.
     * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware
     * flow control is not supported.
     * DCD and DTR are not supported on UART Irda on C & D-Sample.
     * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample.
     */

    if (uartNo != UAF_UART_1)
        return (FD_NOT_SUPPORTED);

    if ((bufSize > FD_MAX_BUFFER_SIZE) ||
        (rxThreshold > FD_MAX_BUFFER_SIZE) ||
        (txThreshold > FD_MAX_BUFFER_SIZE))

        result = FD_NOT_SUPPORTED;

    else {
    
        uart = &uart_parameters;
        
        if (!DRIVER_DISABLED (uart))
            result = FD_INTERNAL_ERR;

        else if (RX_HIGH_WATERMARK (bufSize) < RX_LOW_WATERMARK (bufSize))
            result = FD_NOT_SUPPORTED;

        else {
        
            uart->buffer_size = bufSize;
            uart->rx_threshold_level = rxThreshold;
            uart->tx_threshold_level = txThreshold;

            result = FD_OK;
        }
    }

    return (result);
}

/*******************************************************************************
 *
 *                             UAF_SetFlowCtrl
 * 
 * Purpose  : Changes the flow control mode of the UART driver.
 *            If a flow control is activated, DTR is activated or XOFF is sent
 *            if the RX buffer is not able to store the received characters else
 *            DTR is deactivated or XON is sent.
 *
 * Arguments: In : uartNo: Used UART.
 *                 fcMode: flow control mode (none, DTR/DSR, RTS/CTS, XON/XOFF).
 *                 XON   : ASCII code of the XON character.
 *                 XOFF  : ASCII code of the XOFF character.
 *            Out: none
 *
 * Returns  : FD_OK           : Successful operation.
 *            FD_NOT_SUPPORTED: The flow control mode is not supported or wrong
 *                              UART number.
 *            FD_INTERNAL_ERR : Internal problem with the hardware.
 *
 ******************************************************************************/

T_FDRET
UAF_SetFlowCtrl (T_fd_UartId uartNo,
                 T_flowCtrlMode fcMode,
                 SYS_UWORD8 XON,
                 SYS_UWORD8 XOFF)
{
    T_FDRET result;
    t_uart  *uart;

    /*
     * Check UART number.
     * A return is used to simplify the code.
     * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware
     * flow control is not supported.
     * DCD and DTR are not supported on UART Irda on C & D-Sample.
     * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample.
     */

    if (uartNo != UAF_UART_1)
        return (FD_NOT_SUPPORTED);

    /*
     * There is no case where FD_INTERNAL_ERR may be returned.
     * The DTR/DSR protocol is not supported.
     */

    if (fcMode == fc_dtr)
        result = FD_NOT_SUPPORTED;

    else {
    
        uart = &uart_parameters;

        uart->tx_stopped_by_driver = 0;

        
        uart->xon_character = XON;
        uart->xoff_character = XOFF;
        uart->flow_control_mode = fcMode;

#if ((CHIPSET != 5) && (CHIPSET != 6))
        /*
         * Disable sleep mode.
         */

        WRITE_UART_REGISTER (
            uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP);
#endif

        WRITE_UART_REGISTER (
            uart, MCR, READ_UART_REGISTER (uart, MCR) | MRTS);
          
#if ((CHIPSET != 5) && (CHIPSET != 6))
        /*
         * Re-enable sleep mode.
         */
         /* BELOW LINES WERE COMMENTED TO DISABLE SLEEP MODE IN DRIVER */
         /*
        WRITE_UART_REGISTER (
            uart, IER, READ_UART_REGISTER (uart, IER) | IER_SLEEP);
            */
#endif
        
        if (fcMode == fc_rts) {
#if 1 // Dmitriy: enable hardware assisted CTS 
            volatile SYS_UWORD8 oldValue;

            oldValue = READ_UART_REGISTER (uart, LCR);
            
            // LCR value to allow acces to EFR
     
            WRITE_UART_REGISTER (uart, LCR, 0xBF);
            
            // enable hardware assisted CTS
            
            SET_BIT (uart, EFR, AUTO_CTS_BIT);
            
            WRITE_UART_REGISTER (uart, LCR, oldValue);    
#endif
            if (uart->rts_level)
                uart->tx_stopped_by_driver = 1;
        }

        /*
         * If the high watermark is reached, RTS is activated or XOFF is sent
         * according to the flow control mode. Else, RTS is deactivated or XON
         * is sent.
         */

        if (fcMode != fc_none) {

            if (get_bytes_in_rx_buffer (uart) >= RX_HIGH_WATERMARK (
                                                     uart->buffer_size)) {

                uart->rx_stopped_by_driver = 1;
                stop_receiver (uart);

            } else if (!DRIVER_DISABLED (uart)) {

                uart->rx_stopped_by_driver = 0;
                start_receiver (uart);
            }
            
        } else {
        
            uart->rx_stopped_by_driver = 0;
            uart->tx_stopped_by_driver = 0;
        }

        result = FD_OK;
    }

    return (result);
}

/*******************************************************************************
 *
 *                               UAF_SetEscape
 * 
 * Purpose  : To return to the command mode at the ACI while a data connection
 *            is established, an escape sequence has to be detected.
 *            To distinguish between user data and the escape sequence a
 *            defined guard period is necessary before and after this sequence.
 *
 * Arguments: In:  uartNo     : Used UART.
 *                 escChar    : ASCII character which could appear three times
 *                              as an escape sequence.
 *                 guardPeriod: Denotes the minimal duration of the rest before
 *                              the first and after the last character of the
 *                              escape sequence, and the maximal receiving
 *                              duration of the whole escape string. This value
 *                              is expressed in ms.
 *            Out: none
 *
 * Returns  : FD_OK           : Successful operation.
 *            FD_NOT_SUPPORTED: Wrong UART number.
 *            FD_INTERNAL_ERR : Internal problem with the hardware.
 *
 ******************************************************************************/

T_FDRET
UAF_SetEscape (T_fd_UartId uartNo,
               SYS_UWORD8 escChar,
               SYS_UWORD16 guardPeriod)
{
    t_uart  *uart;

    /*
     * Check UART number.
     * A return is used to simplify the code.
     * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware
     * flow control is not supported.
     * DCD and DTR are not supported on UART Irda on C & D-Sample.
     * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample.
     */

    if (uartNo != UAF_UART_1)
        return (FD_NOT_SUPPORTED);

    /*
     * There is no case where FD_INTERNAL_ERR may be returned.
     */

    uart = &uart_parameters;

    uart->esc_seq_modified = 1;
    uart->esc_seq_character = escChar;
    uart->guard_period = CONVERT_TIME_IN_TDMA ((UNSIGNED) guardPeriod);
    uart->esc_seq_modified = 0; /* Set to 0 by the RX interrupt handler. */

    return (FD_OK);
}

/*******************************************************************************
 *
 *                              UAF_InpAvail
 * 
 * Purpose  : Returns the number of characters available in the RX buffer of the
 *            driver. If the driver is disabled the function returns 0.
 *
 * Arguments: In : uartNo: Used UART.
 *            Out: none
 *
 * Returns  : >= 0            : The returned value is the amount of data in the
 *                              RX buffer.
 *            FD_NOT_SUPPORTED: Wrong UART number.
 *            FD_NOT_READY    : The function is called while the callback of the
 *                              readOutFunc function is activated and still not
 *                              terminated.
 *            FD_INTERNAL_ERR : Internal problem with the hardware.
 *
 ******************************************************************************/

T_FDRET
UAF_InpAvail (T_fd_UartId uartNo)
{
    T_FDRET result;
    t_uart  *uart;
    SYS_UWORD16  bytes_read;
    SYS_UWORD16  bytes_in_rx_buffer;

    /*
     * Check UART number.
     * A return is used to simplify the code.
     * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware
     * flow control is not supported.
     * DCD and DTR are not supported on UART Irda on C & D-Sample.
     * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample.
     */

    if (uartNo != UAF_UART_1)
        return (FD_NOT_SUPPORTED);

    /*
     * There is no case where FD_INTERNAL_ERR may be returned.
     */

    uart = &uart_parameters;

    if (uart->rd_call_setup == rm_notDefined)
        result = FD_NOT_READY;

    else if (DRIVER_DISABLED (uart))
        result = 0;

    else {

        bytes_in_rx_buffer = get_bytes_in_rx_buffer (uart);

        /*
         * Update reading pointer of the RX buffer if a callback from LISR
         * has been done.
         */

        if (uart->rd_call_from_hisr_in_progress) {

            bytes_read = uart->rd_size_before_call[0] -
                         uart->rd_size_after_call[0] +
                         uart->rd_size_before_call[1] -
                         uart->rd_size_after_call[1];

            uart->rx_out += bytes_read;

            if (uart->rx_out >= &(uart->rx_buffer[0]) + uart->buffer_size + 1)
                uart->rx_out = uart->rx_out - uart->buffer_size - 1;

            /*
             * Check if the low watermark is reached to enable the receiver.
             */

            bytes_in_rx_buffer = get_bytes_in_rx_buffer (uart);

            if ((uart->flow_control_mode != fc_none) &&
                (bytes_in_rx_buffer <= RX_LOW_WATERMARK (uart->buffer_size))) {

                if ((!uart->rx_stopped_by_application) &&
                    uart->rx_stopped_by_driver)
                    start_receiver (uart);

                uart->rx_stopped_by_driver = 0;
            }

            uart->rd_call_from_hisr_in_progress = 0;
        }

        result = (T_FDRET) bytes_in_rx_buffer;
    }

    return (result);
}

/*******************************************************************************
 *
 *                             UAF_OutpAvail
 * 
 * Purpose  : Returns the number of free characters in TX buffer of the driver.
 *            If the driver is disabled the function returns 0.
 *
 * Arguments: In : uartNo: Used UART.
 *            Out: none
 *
 * Returns  : >= 0            : The returned value is the amount of data in the
 *                              TX buffer.
 *            FD_NOT_SUPPORTED: Wrong UART number.
 *            FD_NOT_READY    : The function is called while the callback of the
 *                              writeInFunc function is activated and still not
 *                              terminated.
 *            FD_INTERNAL_ERR : Internal problem with the hardware.
 *
 ******************************************************************************/

T_FDRET
UAF_OutpAvail (T_fd_UartId uartNo)
{
    T_FDRET result;
    t_uart  *uart;
    SYS_UWORD16  bytes_written;

    /*
     * Check UART number.
     * A return is used to simplify the code.
     * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware
     * flow control is not supported.
     * DCD and DTR are not supported on UART Irda on C & D-Sample.
     * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample.
     */

    if (uartNo != UAF_UART_1)
        return (FD_NOT_SUPPORTED);

    /*
     * There is no case where FD_INTERNAL_ERR may be returned.
     */

    uart = &uart_parameters;

    if (uart->wr_call_setup == rm_notDefined)
        result = FD_NOT_READY;

    else if (DRIVER_DISABLED (uart))
        result = 0;

    else {

        /*
         * Update reading pointer of the TX buffer if a callback from LISR
         * has been done.
         */

        if (uart->wr_call_from_hisr_in_progress) {

            bytes_written = uart->wr_size_before_call[0] -
                            uart->wr_size_after_call[0] +
                            uart->wr_size_before_call[1] -
                            uart->wr_size_after_call[1];

            uart->tx_in += bytes_written;

            if (uart->tx_in >= &(uart->tx_buffer[0]) + uart->buffer_size + 1)
                uart->tx_in = uart->tx_in - uart->buffer_size - 1;

            uart->wr_call_from_hisr_in_progress = 0;

            /*
             * if the TX FIFO is empty, unmask TX empty interrupt.
             */

            if (!uart->tx_stopped_by_driver &&
                (READ_UART_REGISTER (uart, LSR) & THRE))
            {
#if ((CHIPSET != 5) && (CHIPSET != 6))
                /*
                 * Disable sleep mode.
                 */
          
                WRITE_UART_REGISTER (
                   uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP);
#endif

                /*
                 * Unmask Tx interrupt.
                 */
          
                WRITE_UART_REGISTER (
                    uart, IER, READ_UART_REGISTER (uart, IER) | ETBEI);
            }
        }

        result = (T_FDRET) (uart->buffer_size - get_bytes_in_tx_buffer (uart));
    }

    return (result);
}

/*******************************************************************************
 *
 *                             UAF_EnterSleep
 * 
 * Purpose  : Checks if UART is ready to enter Deep Sleep. If ready, enables
 *            wake-up interrupt.
 *
 * Arguments: In : uartNo: Used UART.
 *            Out: none
 *
 * Returns  : 0	              : Deep Sleep is not possible.
 *            >= 1            : Deep Sleep is possible.
 *            FD_NOT_SUPPORTED: Wrong UART number.
 *
 * Warning: Parameters are not verified.
 *
 ******************************************************************************/

T_FDRET
UAF_EnterSleep (T_fd_UartId uartNo)
{
    t_uart              *uart;
    SYS_BOOL            deep_sleep;
    volatile SYS_UWORD8 status;
    
    /*
     * Check UART number.
     * A return is used to simplify the code.
     * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware
     * flow control is not supported.
     * DCD and DTR are not supported on UART Irda on C & D-Sample.
     * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample.
     */

    if (uartNo != UAF_UART_1)
        return (FD_NOT_SUPPORTED);

    uart = &uart_parameters;
    deep_sleep = 0;

    /*
	 * Check if RX & TX FIFOs are both empty
	 */

    status = READ_UART_REGISTER (uart, LSR);

    if (!(status & DR) &&
        (status & TEMT)) {

#if ((CHIPSET != 5) && (CHIPSET != 6))
        /*
         * Disable sleep mode.
         */
              
        WRITE_UART_REGISTER (
            uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP);
#endif

#if (CHIPSET == 12)
        /*
         * Mask DSR interrupt.
         */

        DISABLE_DSR_INTERRUPT (uart);
#endif

        /*
         * Mask RX, TX and the modem status interrupts.
         */

        WRITE_UART_REGISTER (
            uart, IER, READ_UART_REGISTER (uart, IER) &
                       ~(ERBI | ETBEI | EDSSI));

        /*
         * Enable the wake-up interrupt.
         */

        ENABLE_WAKEUP_INTERRUPT (uart);

        deep_sleep = 1;
    }

    return (deep_sleep);
}

/*******************************************************************************
 *
 *                              UAF_WakeUp
 * 
 * Purpose  : Wakes up UART after Deep Sleep.
 *
 * Arguments: In : uartNo: Used UART.
 *            Out: none
 *
 * Returns  : FD_OK           : Successful operation.
 *            FD_NOT_SUPPORTED: Wrong UART number.
 *
 * Warning: Parameters are not verified.
 *
 ******************************************************************************/

T_FDRET
UAF_WakeUp (T_fd_UartId uartNo)
{
    t_uart *uart;
   
    /*
     * Check UART number.
     * A return is used to simplify the code.
     * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware
     * flow control is not supported.
     * DCD and DTR are not supported on UART Irda on C & D-Sample.
     * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample.
     */

    if (uartNo != UAF_UART_1)
        return (FD_NOT_SUPPORTED);

    uart = &uart_parameters;

    /*
     * Disable the wake-up interrupt.
     */

    DISABLE_WAKEUP_INTERRUPT (uart);

    /*
     * Unmask RX and modem status interrupts.
     */

    WRITE_UART_REGISTER (
        uart, IER, READ_UART_REGISTER (uart, IER) | (ERBI | EDSSI));

#if (CHIPSET == 12)
    /*
     * Unmask DSR interrupt.
     */

    ENABLE_DSR_INTERRUPT (uart);
#endif

#if ((CHIPSET != 5) && (CHIPSET != 6))
    /*
     * Allow sleep mode.
     */
  /* BELOW LINES WERE COMMENTED TO DISABLE SLEEP MODE IN DRIVER */  
  /*
    WRITE_UART_REGISTER ( 
        uart, IER, READ_UART_REGISTER (uart, IER) | IER_SLEEP);
        */
#endif

    return (FD_OK);
}

/*******************************************************************************
 *
 *                              UAF_ReadData
 * 
 * Purpose  : To read the received characters out of the RX buffer the address
 *            of a function is passed. If characters are available, the driver
 *            calls this function and pass the address and the amount of
 *            readable characters. Because the RX buffer is circular, the
 *            callback function may be called with more than one address of
 *            buffer fragment.
 *            The readOutFunc function modifies the contents  of the size array
 *            to return the driver the number of processed characters. Each
 *            array entry is decremented by the number of bytes read in the
 *            fragment.
 *            If the UAF_ReadData is called while the RX buffer is empty, it
 *            depends on the suspend parameter to suspend the call-back or to
 *            leave without any operation. In the case of suspension, the
 *            return value of UAF_ReadData is UAF_SUSPENDED. A delayed call-back
 *            will be performed if:
 *              - the RX buffer reachs the adjusted threshold (rxThreshold of
 *                UAF_SetBuffer),
 *              - the state of a V.24 input line has changed,
 *              - a break is detected,
 *              - an escape sequence is detected.
 *            If no suspension is necessary the function returns the number of
 *            processed bytes.
 *
 * Arguments: In : uartNo     : Used UART.
 *                 suspend    : mode of suspension in case of RX buffer empty.
 *                 readOutFunc: Callback function.
 *                              cldFromIrq: The driver sets this parameter to 1
 *                                          if the callback function is called
 *                                          from an interrupt service routine.
 *                              reInstall : The call-back function sets this
 *                                          parameter to rm_reInstall if the
 *                                          driver must call again the callback
 *                                          function when the RX threshold level
 *                                          is reached. Else it will be set to
 *                                          rm_noInstall. Before to call the
 *                                          readOutFunc function this parameter
 *                                          is set to rm_notDefined.
 *                              nsource   : Informed the callback function about
 *                                          the number of fragments which are
 *                                          ready to copy from the circular RX
 *                                          buffer.
 *                              source    : Array which contains the addresses
 *                                          of the fragments.
 *                              size      : Array which contains the sizes of
 *                                          each fragments.
 *                              state     : The state parameter is the status
 *                                          of the V.24 lines and the break / 
 *                                          escape detection. The state
 *                                          parameter is described in the
 *                                          specification of UAF_GetLineState.
 *            Out: none
 *
 * Returns  : >= 0            : Succesful operation. Amount of processed bytes.
 *            FD_NOT_SUPPORTED: Wrong UART number.
 *            FD_SUSPENDED    : The callback is suspended until the buffer or
 *                              state condition changed.
 *            FD_NOT_READY    : The function is called while the callback is
 *                              activated and still not terminated.
 *            FD_INTERNAL_ERR : Internal problems with the hardware.
 *
 ******************************************************************************/

T_FDRET
UAF_ReadData (T_fd_UartId uartNo,
              T_suspendMode suspend,
              void (readOutFunc (SYS_BOOL cldFromIrq,
                                 T_reInstMode *reInstall,
                                 SYS_UWORD8 nsource,
                                 SYS_UWORD8 *source[],
                                 SYS_UWORD16 size[],
                                 SYS_UWORD32 state)))
{
    T_FDRET result;
    t_uart *uart;
    SYS_UWORD16  bytes_read;
    SYS_UWORD16  bytes_in_rx_buffer;

    /*
     * Check UART number.
     * A return is used to simplify the code.
     * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware
     * flow control is not supported.
     * DCD and DTR are not supported on UART Irda on C & D-Sample.
     * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample.
     */

    if (uartNo != UAF_UART_1)
        return (FD_NOT_SUPPORTED);

    /*
     * There is no case where FD_INTERNAL_ERR may be returned.
     */

    uart = &uart_parameters;

    if (uart->rd_call_setup == rm_notDefined)
        result = FD_NOT_READY;

    else if (get_bytes_in_rx_buffer (uart) || uart->esc_seq_received) {

        uart->readOutFunc = readOutFunc;
        update_reading_callback (uart, 0); /* 0: call from application. */

        bytes_read = uart->rd_size_before_call[0] -
                     uart->rd_size_after_call[0] +
                     uart->rd_size_before_call[1] -
                     uart->rd_size_after_call[1];

        uart->rx_out += bytes_read;

        if (uart->rx_out >= &(uart->rx_buffer[0]) + uart->buffer_size + 1)
            uart->rx_out = uart->rx_out - uart->buffer_size - 1;

        /*
         * Check if the low watermark is reached to enable the receiver.
         */

        if ((uart->flow_control_mode != fc_none) &&
            (get_bytes_in_rx_buffer (uart) <= RX_LOW_WATERMARK (
                                                  uart->buffer_size))) {

            if ((!uart->rx_stopped_by_application) &&
                uart->rx_stopped_by_driver && (!uart->rx_stopped_by_lisr))
                start_receiver (uart);

            uart->rx_stopped_by_driver = 0;
        }

        uart->esc_seq_received = 0;
        result = (T_FDRET) bytes_read;

    } else  if (suspend == sm_suspend) {

        uart->readOutFunc = readOutFunc;
        uart->reading_suspended = 1;
        result = FD_SUSPENDED;

    } else {
        
        /*
         * The previous callback function is deinstalled.
         */
             
        uart->rd_call_setup = rm_noInstall;
        uart->reading_suspended = 0;
        result = 0; /* 0 byte read. */
    }

    return (result);
}

/*******************************************************************************
 *
 *                              UAF_WriteData
 * 
 * Purpose  : To write characters into the TX buffer the address of a function
 *            is passed. If free space is available in the buffer, the driver
 *            calls this function and passes the destination address and the
 *            amount of space. Because the TX buffer is circular, the callback
 *            function may be called with more than one address of buffer
 *            fragment.
 *            The writeInFunc function modifies the contents of the size array
 *            to return the driver the number of processed bytes. Each array
 *            entry is decremented  by the number of bytes written in this
 *            fragment.
 *            If the UAF_WriteData function is called while the TX buffer is
 *            full, it depends on the suspend parameter to suspend the
 *            call-back or to leave this function without any operation. In the
 *            case of suspension the returned value of the UAF_WriteData is
 *            UAF_SUSPENDED. A delayed call-back will be performed if the TX
 *            buffer reaches the adjusted threshold (txThreshold of
 *            UAF_SetBuffer). If no suspension is necessary the function returns
 *            the number of processed bytes.
 *
 * Arguments: In : uartNo     : Used UART.
 *                 suspend    : mode of suspension in case of TX buffer empty.
 *                 writeInFunc: Callback function. 
 *                              cldFromIrq: The driver sets this parameter to 1
 *                                          if the call-back function is called
 *                                          from an interrupt service routine.
 *                              reInstall : The callback function sets this
 *                                          parameter to rm_reInstall if the
 *                                          driver must call again the callback
 *                                          function when the TX threshold level
 *                                          is reached. Else it will be set to
 *                                          rm_noInstall. Before to call the
 *                                          writeInFunc function this parameter
 *                                          is set to rm_notDefined.
 *                              ndest     : Informed the callback function about
 *                                          the number of fragments which are
 *                                          available in the TX buffer.
 *                              dest      : Array which contains the addresses
 *                                          of the fragments.
 *                              size      : Array which contains the sizes of
 *                                          each fragments.
 *            Out: none
 *
 * Returns  : >= 0            : Succesful operation. Amount of processed bytes.
 *            FD_NOT_SUPPORTED: Wrong UART number.
 *            FD_SUSPENDED    : The callback is suspended until the buffer
 *                              condition changed.
 *            FD_NOT_READY    : The function is called while the callback is
 *                              activated and still not terminated.
 *            FD_INTERNAL_ERR : Internal problems with the hardware.
 *
 ******************************************************************************/

T_FDRET
UAF_WriteData (T_fd_UartId uartNo,
               T_suspendMode suspend,
               void (writeInFunc (SYS_BOOL cldFromIrq,
                                  T_reInstMode *reInstall,
                                  SYS_UWORD8 ndest,
                                  SYS_UWORD8 *dest[],
                                  SYS_UWORD16 size[])))
{
    T_FDRET result;
    t_uart *uart;
    SYS_UWORD16  bytes_written;

    /*
     * Check UART number.
     * A return is used to simplify the code.
     * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware
     * flow control is not supported.
     * DCD and DTR are not supported on UART Irda on C & D-Sample.
     * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample.
     */

    if (uartNo != UAF_UART_1)
        return (FD_NOT_SUPPORTED);

    /*
     * There is no case where FD_INTERNAL_ERR may be returned.
     */

    uart = &uart_parameters;

    if (uart->wr_call_setup == rm_notDefined)
        result = FD_NOT_READY;

    else if ((!DRIVER_DISABLED (uart)) &&
             (get_bytes_in_tx_buffer (uart) < uart->buffer_size)) {

        uart->writeInFunc = writeInFunc;
        update_writing_callback (uart, 0); /* 0: call from application. */

        bytes_written = uart->wr_size_before_call[0] -
                        uart->wr_size_after_call[0] +
                        uart->wr_size_before_call[1] -
                        uart->wr_size_after_call[1];

        uart->tx_in += bytes_written;

        if (uart->tx_in >= &(uart->tx_buffer[0]) + uart->buffer_size + 1)
            uart->tx_in = uart->tx_in - uart->buffer_size - 1;

	/* If we have been stopped due to high RTS, we have to
	 * wake up application processor by IRQ via IO1 -HW */
	#ifdef CONFIG_TARGET_GTAMODEM
	    if (uart->tx_stopped_by_driver)
		AI_SetBit(1);
	#endif

        /*
         * If:
         *      - there is no break to send,
         *      - the flow control is not activated,
         * unmask the TX empty interrupt to be able to send characters.
         */
        if (!uart->break_to_send &&
            !uart->tx_stopped_by_driver)
        {    
#if ((CHIPSET != 5) && (CHIPSET != 6))
            /*
             * Disable sleep mode.
             */
          
            WRITE_UART_REGISTER (
                uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP);
#endif

            /*
             * Unmask Tx interrupt.
             */
          
            WRITE_UART_REGISTER (
                uart, IER, READ_UART_REGISTER (uart, IER) | ETBEI);
        }

        result = (T_FDRET) bytes_written;

    } else  if (suspend == sm_suspend) {

        uart->writeInFunc = writeInFunc;
        uart->writing_suspended = 1;
        result = FD_SUSPENDED;

    } else {
        
        /*
         * The previous callback function is deinstalled.
         */
             
        uart->wr_call_setup = rm_noInstall;
        uart->writing_suspended = 0;
        result = 0;
    }

    return (result);
}

/*******************************************************************************
 *
 *                              UAF_StopRec
 * 
 * Purpose  : If a flow control mode is set, this function tells the terminal
 *            equipment that no more data can be received.
 *            XON/XOFF: XOFF is sent.
 *            DTR/DSR : DTR is desactivated.
 *            RTS/CTS : RTS is deactivated.
 *
 * Arguments: In : uartNo: Used UART.
 *            Out: none
 *
 * Returns  : FD_OK           : Successful operation.
 *            FD_NOT_SUPPORTED: Wrong UART number.
 *            FD_INTERNAL_ERR : Internal problem with the hardware.
 *
 ******************************************************************************/

T_FDRET
UAF_StopRec (T_fd_UartId uartNo)
{
    t_uart *uart;

    /*
     * Check UART number.
     * A return is used to simplify the code.
     * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware
     * flow control is not supported.
     * DCD and DTR are not supported on UART Irda on C & D-Sample.
     * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample.
     */

    if (uartNo != UAF_UART_1)
        return (FD_NOT_SUPPORTED);

    /*
     * There is no case where FD_INTERNAL_ERR may be returned.
     */

    uart = &uart_parameters;

    if (uart->flow_control_mode != fc_none)
        stop_receiver (uart);

    uart->rx_stopped_by_application = 1;

    return (FD_OK);
}

/*******************************************************************************
 *
 *                              UAF_StartRec
 * 
 * Purpose  : If a flow control mode is set, this function tells the terminal
 *            equipment that the receiver is again able to receive more data.
 *            If the buffer has already reached the high water mark the driver
 *            sends the signal only if the buffer drains to a low water mark.
 *            XON/XOFF: XON is sent.
 *            DTR/DSR : DTR is activated.
 *            RTS/CTS : RTS is activated.
 *
 * Arguments: In : uartNo: Used UART.
 *            Out: none
 *
 * Returns  : FD_OK           : Successful operation.
 *            FD_NOT_SUPPORTED: Wrong UART number.
 *            FD_INTERNAL_ERR : Internal problem with the hardware.
 *
 ******************************************************************************/

T_FDRET 
UAF_StartRec (T_fd_UartId uartNo)
{
    t_uart *uart;

    /*
     * Check UART number.
     * A return is used to simplify the code.
     * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware
     * flow control is not supported.
     * DCD and DTR are not supported on UART Irda on C & D-Sample.
     * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample.
     */

    if (uartNo != UAF_UART_1)
        return (FD_NOT_SUPPORTED);

    /*
     * There is no case where FD_INTERNAL_ERR may be returned.
     */

    uart = &uart_parameters;

    if ((uart->flow_control_mode != fc_none) && (!uart->rx_stopped_by_driver))
        start_receiver (uart);

    uart->rx_stopped_by_application = 0;

    return (FD_OK);
}

/*******************************************************************************
 *
 *                            UAF_GetLineState
 * 
 * Purpose  : Returns the state of the V.24 lines, the flow control state and
 *            the result of the break/escape detection process as a bit field.
 *
 * Arguments: In : uartNo: Used UART.
 *            Out: state : State of the V.24 lines, the flow control state and
 *                         the result of the break/escape sequence detection
 *                         process as a bit field.
 *
 * Returns  : FD_OK           : Successful operation.
 *            FD_NOT_SUPPORTED: Wrong UART number.
 *            FD_NOT_READY    : The function is called while the callback of 
 *                              the readOutFunc function is activated and still
 *                              not terminated.
 *            FD_INTERNAL_ERR : Internal problem with the hardware.
 *
 ******************************************************************************/

T_FDRET
UAF_GetLineState (T_fd_UartId uartNo,
                  SYS_UWORD32 *state)
{
    T_FDRET result;
    t_uart *uart;

    /*
     * Check UART number.
     * A return is used to simplify the code.
     * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware
     * flow control is not supported.
     * DCD and DTR are not supported on UART Irda on C & D-Sample.
     * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample.
     */

    if (uartNo != UAF_UART_1)
        return (FD_NOT_SUPPORTED);

    /*
     * There is no case where FD_INTERNAL_ERR may be returned.
     * Signals not supported are reported as 0.
     */

    uart = &uart_parameters;

    if (uart->rd_call_setup == rm_notDefined)
        result = FD_NOT_READY;

    else {

        /*
         * The field state_2 is used when state_1 is set to 0 to avoid to
         * lose events detected in the RX interrupt handler.
         * Fields BRK and BRKLEN are set when a break is detected.
         * The field ESC is set when an escape sequence is detected. 
         */

        *state = uart->state_2;
        uart->state_2 = 0;
        uart->state = &(uart->state_2);

        *state |= uart->state_1;
        uart->state_1 = 0;
        uart->state = &(uart->state_1);

        *state |= ((((SYS_UWORD32) uart->rts_level) << RTS) |
        
#if (UARTFAX_CLASSIC_DTR_DCD || (CHIPSET == 12))
                   (((SYS_UWORD32) uart->dtr_level) << DTR) |
#endif

                   (((SYS_UWORD32) (uart->tx_stopped_by_application  |
                              uart->tx_stopped_by_driver)) << TXSTP) |

                   (((SYS_UWORD32) (uart->rx_stopped_by_application  |
                              uart->rx_stopped_by_driver)) << RXSTP) |

                   (((SYS_UWORD32) (uart->buffer_size - 
                              get_bytes_in_rx_buffer (uart))) << RXBLEV));
                                 
        /*
         * Fields SA, SB and X are set according to the flow control:
         *
         *       None    RTS/CTS    XON/XOFF
         * SA    DTR     DTR        DTR
         * SB    RTS     0          RTS
         * X     0       RTS        XON:0 XOFF:1 (transmitter)
         *
         * DTR is supported on C, D & E-Sample.
         */

#if (UARTFAX_CLASSIC_DTR_DCD || (CHIPSET == 12))
        *state |= (((SYS_UWORD32) uart->dtr_level) << SA);
#endif

        if (uart->flow_control_mode != fc_rts)
            *state |= (((SYS_UWORD32) uart->rts_level) << SB);

        if (uart->flow_control_mode == fc_rts)
            *state |= (((SYS_UWORD32) uart->rts_level) << X);
            
        else if ((uart->flow_control_mode == fc_xoff) &&
                 (uart->tx_stopped_by_application ||
                  uart->tx_stopped_by_driver))
            *state |= (1 << X);

        result = FD_OK;
    }

    return (result);
}

/*******************************************************************************
 *
 *                            UAF_SetLineState
 * 
 * Purpose  : Sets the states of the V.24 status lines according to the bit
 *            field of the parameter state.
 *
 * Arguments: In : uartNo: Used UART.
 *                 state : Bit field. Only the signals which are marked with
 *                         the 'set' access can be used to change the state of
 *                         the signal.
 *                 mask  : Bit field with the same structure as state. Each bit
 *                         in state corresponds to a bit in mask. Settabled
 *                         bits marked by a 1 are manipulated by the driver.
 *            Out: none
 *
 * Returns  : FD_OK           : Successful operation.
 *            FD_NOT_SUPPORTED: Wrong UART number.
 *            FD_INTERNAL_ERR : Internal problem with the hardware.
 *
 ******************************************************************************/

T_FDRET
UAF_SetLineState (T_fd_UartId uartNo,
                  SYS_UWORD32 state,
                  SYS_UWORD32 mask)
{
    t_uart  *uart;
    UNSIGNED break_length;

    /*
     * Check UART number.
     * A return is used to simplify the code.
     * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware
     * flow control is not supported.
     * DCD and DTR are not supported on UART Irda on C & D-Sample.
     * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample.
     */

    if (uartNo != UAF_UART_1)
        return (FD_NOT_SUPPORTED);

    uart = &uart_parameters;

    /*
     * There is no case where FD_INTERNAL_ERR may be returned.
     * DCD is supported on C, D & E-Sample. The SA field is not supported because
     * DSR is not supported on all platforms.
     */

#if (UARTFAX_CLASSIC_DTR_DCD || (CHIPSET == 12))
    if (mask & (1 << SA))
#else
    if ((mask & (1 << SA)) || (mask & (1 << DCD)))
#endif
        return (FD_NOT_SUPPORTED); /* Return used to simplify the code */
        
    /*
     * Check if a break has to be sent.
     */

    uart->break_length = (UNSIGNED) ((state >> BRKLEN) & 0xFF);

    if (state & (1 << BRK) && (mask & (1 << BRK))) {

        if (uart->break_length > FIFO_SIZE)
            return (FD_NOT_SUPPORTED); /* Return used to simplify the code */

        else {

            uart->time_without_character =
                compute_break_time (uart->baudrate, uart->bits_per_char, 3);

            uart->break_to_send = 1;

            /*
             * If the TX FIFO is empty the break is send from this function
             * else the interrupt handler will send the break.
             */

            if (READ_UART_REGISTER (uart, LSR) & TEMT)
                send_break(uart);
        }
    }

#if ((CHIPSET != 5) && (CHIPSET != 6))
    /*
     * Disable sleep mode.
     */

    WRITE_UART_REGISTER (
        uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP);
#endif

    /*
     * The CTS field is ignored if the X bit in the mask is set. In this case
     * the X bit controls CTS.
     */

    if (mask & (1 << CTS)) {
    
        if (uart->flow_control_mode != fc_rts) {
        
            /*
             * As the RTS/CTS flow control is not selected, the X bit does not
             * control CTS. CTS needs only to be activated or deactivated
             * according to the value of the CTS field.
             */

            if (state & (1 << CTS))
                WRITE_UART_REGISTER (
                    uart, MCR, READ_UART_REGISTER (uart, MCR) | MRTS);

            else
                WRITE_UART_REGISTER (
                    uart, MCR, READ_UART_REGISTER (uart, MCR) & ~MRTS);

        } else if (!(mask & (1 << X))) {

            /*
             * The RTS/CTS flow control is selected but the X bit in the mask
             * is null. Then the CTS bit controls CTS and the receiver must be
             * stopped or started according to the state of the CTS bit.
             * The receiver is started only if it was not stopped by the driver
             * and if it was stopped by the application.
             */
             
            if (state & (1 << CTS)) {

                if (!uart->rx_stopped_by_application) {
                
                    if (!uart->rx_stopped_by_driver)
                        stop_receiver (uart);

                    uart->rx_stopped_by_application = 1;
                }
                
            } else {
                
                if ((!uart->rx_stopped_by_driver) &&
                    uart->rx_stopped_by_application)
                    start_receiver (uart);

                uart->rx_stopped_by_application = 0;
            }
        }
    }

    /*
     * The DCD field is ignored if the SB bit of the mask is set.
     */

#if (UARTFAX_CLASSIC_DTR_DCD || (CHIPSET == 12))

    if (!(mask & (1 << SB)) && (mask & (1 << DCD))) {

        if (state & (1 << DCD)) {
            /* Turn on DCD */
            #if (CHIPSET == 12)
                WRITE_UART_REGISTER (uart, MCR, READ_UART_REGISTER(uart, MCR) | MDCD);
            #else
                AI_ResetBit (ARMIO_DCD);
            #endif
        } else {
            /* Turn off DCD */
            #if (CHIPSET == 12)
                WRITE_UART_REGISTER (uart, MCR, READ_UART_REGISTER(uart, MCR) & ~MDCD);
            #else
                AI_SetBit (ARMIO_DCD);
            #endif
        }
    }

#endif /* BOARD 8 or 9 or 40 or 41 or CHIPSET 12 */

    /*
     * Signals are set according to fields SA, SB and X states and flow
     * control:
     *
     *       None    RTS/CTS    XON/XOFF
     * SA    0 (ns)  0 (ns)     0 (ns)
     * SB    DCD     DCD        DCD
     * X     ignore  CTS        XON:0 XOFF:1 (receiver)
     *
     * ns: signal not supported.
     * DCD is supported on C, D & E-Sample.
     */

#if (UARTFAX_CLASSIC_DTR_DCD || (CHIPSET == 12))

    if (mask & (1 << SB)) {

        if (state & (1 << SB)) {
            /* Turn on DCD */
            #if (CHIPSET == 12)
                WRITE_UART_REGISTER (uart, MCR, READ_UART_REGISTER(uart, MCR) | MDCD);
            #else
                AI_ResetBit (ARMIO_DCD);
            #endif
        } else {
            /* Turn off DCD */
            #if (CHIPSET == 12)
                WRITE_UART_REGISTER (uart, MCR, READ_UART_REGISTER(uart, MCR) & ~MDCD);
            #else
                AI_SetBit (ARMIO_DCD);
            #endif
        }
    }

#endif /* BOARD 8 or 9 or 40 or 41 or CHIPSET 12 */
        
    if ((mask & (1 << X)) &&
        (uart->flow_control_mode != fc_none)) {

        if (state & (1 << X)) {
                
            if (!uart->rx_stopped_by_application) {
                
                if (!uart->rx_stopped_by_driver)
                    stop_receiver (uart);

                uart->rx_stopped_by_application = 1;
            }
                
        } else {
                
            /*
             * The receiver is started only if it is not stopped by the driver
             * and if it is stopped by the application.
             */

            if ((!uart->rx_stopped_by_driver) &&
                uart->rx_stopped_by_application)
                start_receiver (uart);

            uart->rx_stopped_by_application = 0;
        }
    }

#if ((CHIPSET != 5) && (CHIPSET != 6))
    /*
     * Re-enable sleep mode.
     */
    /* BELOW LINES WERE COMMENTED TO DISABLE SLEEP MODE IN DRIVER */ 
    /*
    WRITE_UART_REGISTER (
        uart, IER, READ_UART_REGISTER (uart, IER) | IER_SLEEP);
        */
#endif

    return (FD_OK);
}

/*******************************************************************************
 *
 *                           UAF_InterruptHandler
 * 
 * Purpose  : Interrupt handler.
 *
 * Arguments: In : uart_id         : origin of interrupt
 *                 interrupt_status: source of interrupt
 *            Out: none
 *
 * Returns  : none
 *
 ******************************************************************************/

void
UAF_InterruptHandler (T_fd_UartId uart_id,
                      SYS_UWORD8 interrupt_status)
{

    t_uart *uart;

    /*
     * uart_id is not used.
     */

    uart = &uart_parameters;

    uart->current_time = NU_Retrieve_Clock ();

    /*
     * Causes of interrupt:
     *      - trigger level reached,
     *      - character time-out indication,
     *      - transmitter holding register empty,
     *      - modem status.
     */

    switch (interrupt_status) {

    case RX_DATA:

#if (UARTFAX_CLASSIC_DTR_DCD || (CHIPSET == 12))
        uart->index_it = (uart->index_it + 1) & 0x01; /* 0 or 1 */
        uart->dtr_change_detected[uart->index_it] = 0;
        uart->dtr_level_saved[uart->index_it] = uart->dtr_level;
#endif
        read_rx_fifo (uart);

        // Disable Autobaud and lock baudrate upon first received character
        if (uart->autobauding != 0)
        {
          /* MSMSMSMS */
          SYS_UWORD8 uasr;
          T_baudrate baudrate;
          T_bitsPerCharacter bpc;
          T_parity parity;

          WRITE_UART_REGISTER (uart, LCR, READ_UART_REGISTER (uart, LCR) | DLAB);


          uasr = READ_UART_REGISTER (uart, UASR);

          switch (uasr & 0x1F)
          {
            case 0x01: baudrate = FD_BAUD_115200; break;
            case 0x02: baudrate = FD_BAUD_57600; break;
            case 0x03: baudrate = FD_BAUD_38400; break;
            case 0x04: baudrate = FD_BAUD_28800; break;
            case 0x05: baudrate = FD_BAUD_19200; break;
            case 0x06: baudrate = FD_BAUD_14400; break;
            case 0x07: baudrate = FD_BAUD_9600; break;
            case 0x08: baudrate = FD_BAUD_4800; break;
            case 0x09: baudrate = FD_BAUD_2400; break;
            case 0x0A: baudrate = FD_BAUD_1200; break;
            default: /* no baudrate detected, abort for now */
              return;
          }

          switch (uasr>>5 & 0x01)
          {
            case 0x00: bpc = bpc_7; break;
            case 0x01: bpc = bpc_8; break;
          }

          switch (uasr>>6 & 0x03)
          {
            case 0x00: parity = pa_none; break;
            case 0x01: parity = pa_space; break;
            case 0x02: parity = pa_even; break;
            case 0x03: parity = pa_odd; break;
          }

          UAF_SetComPar (UAF_UART_1,
                         baudrate,
                         bpc,
                         sb_1,
                         parity);

          uart->baudrate = baudrate_value[FD_BAUD_AUTO]; /* remember autobauding */
        }

        break;

    case TX_EMPTY:

        fill_tx_fifo (uart);
        break;

    case MODEM_STATUS:

        check_v24_input_lines (uart);
        break;
    }
}

/*******************************************************************************
 *
 *                              UAF_CheckXEmpty
 * 
 * Purpose  : Checks the empty condition of the Transmitter.
 *
 * Arguments: In : uartNo: Used UART.
 *            Out: none
 *
 * Returns  : FD_OK           : Empty condition OK.
 *            FD_NOT_SUPPORTED: Wrong UART number.
 *            FD_NOT_READY    : Empty condition not OK.
 *            FD_INTERNAL_ERR : Internal problem with the hardware.
 *
 ******************************************************************************/

T_FDRET
UAF_CheckXEmpty (T_fd_UartId uartNo)
{
    T_FDRET result;
    t_uart *uart;
    SYS_UWORD8 status;

    /*
     * Check UART number.
     * A return is used to simplify the code.
     * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware
     * flow control is not supported.
     * DCD and DTR are not supported on UART Irda on C & D-Sample.
     * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample.
     */

    if (uartNo != UAF_UART_1)
        return (FD_NOT_SUPPORTED);

    /*
     * There is no case where FD_INTERNAL_ERR may be returned.
	 */

    result = FD_OK;
    
    uart = &uart_parameters;
    status = READ_UART_REGISTER (uart, LSR);

    /*
     * Checks if:
     *     - the TX SW Buffer is empty,
     *     - the TX HW FIFO is empty (THRE),
     *     - the Transmitter Shift Register is empty (TEMT).
     */

    if (!(TX_BUFFER_EMPTY (uart)) ||
        !(status & THRE) ||
        !(status & TEMT))

        result = FD_NOT_READY;

    return (result);
}

#if UARTFAX_CLASSIC_DTR_DCD
/*******************************************************************************
 *
 *                              UAF_DTRInterruptHandler
 *
 * Purpose  : This function is only used on C & D-Sample. On this platform, the
 *            DTR signal is controlled with an I/O. A change of state of this
 *            signal is detected with an interrupt. This function is called when
 *            this interrupt occurs.
 *
 * Arguments: In : none
 *            Out: none
 *
 * Returns  : none
 *
 ******************************************************************************/

void
UAF_DTRInterruptHandler (void)
{
    t_uart *uart;
    
    uart = &uart_parameters;
    
    /*
     * Read the state of DTR and change the edge to detect the next change
     * of DTR.
     */
     
    uart->dtr_level = AI_ReadBit (ARMIO_DTR);
    
    if (uart->dtr_level)
    	{
        AI_SelectIOForIT (ARMIO_DTR, ARMIO_FALLING_EDGE);
	 if (uart->flow_control_mode != fc_dtr  && uart->baudrate == baudrate_value[FD_BAUD_AUTO])
        UAF_SetComPar (UAF_UART_1, FD_BAUD_AUTO, bpc_8, sb_1, pa_none);
       }
    else
        AI_SelectIOForIT (ARMIO_DTR, ARMIO_RISING_EDGE);
        
    /*
     * The reading callback function has to be called. But bytes received before
     * the change of state of DTR must be copied into the RX buffer before to
     * call it.
     */
     
    if (READ_UART_REGISTER (uart, LSR) & DR) { /* If Rx FIFO is not empty */
    
        /*
         * The Rx FIFO will be read to fill one of the two buffers and the Rx
         * HISR will be activated.
         */
       
        uart->index_it = (uart->index_it + 1) & 0x01; /* 0 or 1 */
        uart->dtr_change_detected[uart->index_it] = 1;
        uart->dtr_level_saved[uart->index_it] = uart->dtr_level;
        read_rx_fifo (uart);
        
    } else
        (void) NU_Activate_HISR (&(uart->v24_hisr_ctrl_block));
    
}
#endif /* BOARD 8 or 9 or 40 or 41 */

#ifdef SERIAL_DYNAMIC_SWITCH
/*******************************************************************************
 *
 *                                UAF_Exit
 * 
 * Purpose  : 
 *
 * Arguments: In : uartNo: Used UART.
 *            Out: none
 *
 * Returns  : FD_OK           : Successful operation.
 *            FD_NOT_SUPPORTED: Wrong UART number.
 *            FD_INTERNAL_ERR : Internal problem.
 *
 ******************************************************************************/

T_FDRET
UAF_Exit (T_fd_UartId uartNo)
{
    t_uart *uart;

    /*
     * Check UART number.
     * A return is used to simplify the code.
     * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware
     * flow control is not supported.
     * DCD and DTR are not supported on UART Irda on C & D-Sample.
     * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample.
     */

    if (uartNo != UAF_UART_1)
        return (FD_NOT_SUPPORTED);

    uart = &uart_parameters;

    /*
     * Delete the 3 HISR actived in the RX/TX and V24 interrupt handlers.
     * A return is used to simplify the code if an error occurs.
     */

    if (NU_Delete_HISR (&(uart->rx_hisr_ctrl_block)) != NU_SUCCESS)
        return (FD_INTERNAL_ERR);

    if (NU_Delete_HISR (&(uart->tx_hisr_ctrl_block)) != NU_SUCCESS)
        return (FD_INTERNAL_ERR);

    if (NU_Delete_HISR (&(uart->v24_hisr_ctrl_block)) != NU_SUCCESS)
        return (FD_INTERNAL_ERR);

    /*
     * Delete the HISR used to send a break.
     * A return is used to simplify the code if an error occurs.
     */

    if (NU_Delete_HISR (&(uart->break_hisr_ctrl_block)) != NU_SUCCESS)
        return (FD_INTERNAL_ERR);

    /*
     * Disable and then delete the timer used in the break HISR
     * A return is used to simplify the code if an error occurs.
     */

    (void) NU_Control_Timer (&(uart->break_timer_ctrl_block),
                             NU_DISABLE_TIMER);

    if (NU_Delete_Timer (&(uart->break_timer_ctrl_block)) != NU_SUCCESS)
        return (FD_INTERNAL_ERR);

    /*
     * Disable and then delete the timer used in the detection of the escape
     * sequence. A return is used to simplify the code if an error occurs.
     */

    (void) NU_Control_Timer (&(uart->guard_period_timer_ctrl_block),
                             NU_DISABLE_TIMER);

    if (NU_Delete_Timer (&(uart->guard_period_timer_ctrl_block)) != NU_SUCCESS)
        return (FD_INTERNAL_ERR);

    /*
     * At that point, all HISRs and Timers have been successfully deleted.
     */

    return (FD_OK);
}
#endif /* (defined BTEMOBILE && (CHIPSET != 12)) */