diff src/cs/drivers/drv_core/uart/uart.c @ 0:945cf7f506b2

src/cs: chipsetsw import from tcs211-fcmodem binary blobs and LCD demo files have been excluded, all line endings are LF only
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 25 Sep 2016 22:50:11 +0000
parents
children beff67c568cf
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cs/drivers/drv_core/uart/uart.c	Sun Sep 25 22:50:11 2016 +0000
@@ -0,0 +1,1501 @@
+/*******************************************************************************
+ *
+ * UART.C
+ *
+ * This module allows to use the UARTs of chipset 1.5 in interrupt mode for
+ * the Receive side and in polling mode for the Transmit side.
+ * The driver calls a user's function when characters are received.
+ *
+ * (C) Texas Instruments 1999
+ *
+ ******************************************************************************/
+
+#include "l1sw.cfg"
+#include "chipset.cfg" 
+#include "board.cfg"
+
+#if (OP_L1_STANDALONE == 0)
+  #include "main/sys_types.h"
+#else
+  #include "sys_types.h"
+#endif
+
+#include "uart/traceswitch.h"
+#include "uart.h"
+
+#include <string.h>
+
+#include "memif/mem.h"
+
+#if (BOARD != 34)
+/*
+ * Needed to reset and restart the sleep timer in case of incoming characters.
+ */
+
+#if (OP_L1_STANDALONE == 1)
+  #include "serialswitch_core.h"
+#else
+  #include "uart/serialswitch.h" 
+#endif
+
+extern SYS_BOOL uart_sleep_timer_enabled;
+#endif
+
+#define BUFFER_SIZE (512) /* In bytes. */
+#define FIFO_SIZE    (64) /* In bytes. */
+
+#define STX                  0x02
+#define DLE                  0x10
+
+/*
+ * TLR is used to program the RX FIFO trigger levels. FCR[7:4] are  not used.
+ */
+ 
+#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         */
+
+
+/*
+ * Supplementary control register.
+ */
+
+#define TX_EMPTY_CTL_IT (0x08)
+#define RX_CTS_WAKE_UP_ENABLE_BIT (4) /* Use RESET_BIT and SET_BIT macros. */
+
+/*
+ * Enhanced feature register.
+ */
+ 
+#define ENHANCED_FEATURE_BIT (4) /* Use RESET_BIT and SET_BIT macros. */
+
+/*
+ * 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 MDTR (0x01) /* Data terminal ready. */
+#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) */
+
+/*
+ * Interrupt identification register.
+ * Bit 0 is set to 0 if an IT is pending.
+ * Bits 1 and 2 are used to identify the IT.
+ */
+
+#define IIR_BITS_USED  (0x07)
+#define IT_NOT_PENDING (0x01)
+#define RX_DATA        (0x04)
+#define TX_EMPTY       (0x02)
+#define MODEM_STATUS   (0x00)
+
+/*
+ * 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               */
+#define DIV_EN_BIT    (7)
+
+/*
+ * FIFO control register.
+ */
+
+#define FIFO_ENABLE   (0x01)
+#define RX_FIFO_RESET (0x02)
+#define TX_FIFO_RESET (0x04)
+
+/*
+ * 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);
+
+
+/* 
+ * This macro allows to know if the RX buffer is full. It must be called only
+ * from the RX interrupt handler. If it is called from the application, the
+ * rx_in pointer may be updated if a RX interrupt occurs.
+ */
+
+#define RX_BUFFER_FULL(UART)                                      \
+            (((UART)->rx_in == (UART)->rx_out - 1) ||             \
+             ((UART)->rx_in == (UART)->rx_out + BUFFER_SIZE - 1))
+
+
+/* 
+ * This allows monitor the last 32 inbound buffers gotten from the RX FIFO.
+ */
+
+//#define UART_RX_BUFFER_DUMP
+
+#ifdef UART_RX_BUFFER_DUMP
+struct {
+    char rx_buffer[(BUFFER_SIZE + 1) << 5];
+    char *rx_in;
+    int  errors_count;
+    int  wrong_interrupt_status;
+} uart_rx_buffer_dump = {0};
+#endif
+
+
+typedef struct s_uart {
+
+    SYS_UWORD32 base_address;
+
+    /*
+     * Buffers management.
+     */
+    
+    char rx_buffer[BUFFER_SIZE + 1];
+    char *rx_in;
+    char *rx_out;
+    void (*callback_function) (void);
+
+    /*
+     * Errors counters.
+     */
+
+    SYS_UWORD32 framing_error;
+    SYS_UWORD32 parity_error;
+    SYS_UWORD32 overrun_error;
+
+    /*
+     * Framing flags.
+     */
+
+    SYS_BOOL dle_detected;
+    SYS_BOOL inframe;
+    SYS_BOOL encapsulation_flag;
+    unsigned char frame_length;
+
+} t_uart;
+
+static t_uart uart_parameter[NUMBER_OF_TR_UART];
+
+static const SYS_UWORD32 base_address[NUMBER_OF_TR_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[] =
+{
+      2, /* 406250 baud. */
+      7, /* 115200 baud. */
+     14, /*  57600 baud. */
+     21, /*  38400 baud. */
+     24, /*  33900 baud. */
+     28, /*  28800 baud. */
+     42, /*  19200 baud. */
+     56, /*  14400 baud. */
+     84, /*   9600 baud. */
+    169, /*   4800 baud. */
+     83, /*   2400 baud. */
+    165, /*   1200 baud. */
+     74, /*    600 baud. */
+    148, /*    300 baud. */
+     40, /*    150 baud. */
+     81  /*     75 baud. */
+};
+
+static const SYS_UWORD8 dlh[] =
+{
+     0, /* 406250 baud. */
+     0, /* 115200 baud. */
+     0, /*  57600 baud. */
+     0, /*  38400 baud. */
+     0, /*  33900 baud. */
+     0, /*  28800 baud. */
+     0, /*  19200 baud. */
+     0, /*  14400 baud. */
+     0, /*   9600 baud. */
+     0, /*   4800 baud. */
+     1, /*   2400 baud. */
+     2, /*   1200 baud. */
+     5, /*    600 baud. */
+    10, /*    300 baud. */
+    21, /*    150 baud. */
+    42  /*     75 baud. */
+};
+
+
+/*******************************************************************************
+ *
+ *                              read_rx_fifo
+ * 
+ * Purpose  : Check the bytes written into the RX FIFO. Characters are not
+ *            written in the RX buffer if it is full. The HISR is called if
+ *            enough characters are received.
+ *
+ * Arguments: In : uart: pointer on UART structure.
+ *            Out: none
+ *
+ * Returns  : none
+ *
+ ******************************************************************************/
+
+static void
+read_rx_fifo (t_uart *uart)
+{
+    volatile SYS_UWORD8 status;
+    int                 error_detected;
+    SYS_UWORD8          char_received;
+
+#if (BOARD != 34)
+    /*
+     * 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_activate_timer_hisr ();
+    uart_sleep_timer_enabled = 1;
+#endif
+    
+    status = READ_UART_REGISTER (uart, LSR);
+
+    while (status & DR) { /* While RX FIFO is not empty... */
+
+        error_detected = 0;
+
+        char_received = READ_UART_REGISTER (uart, RHR);
+
+        /*
+         * Check if an error (overrun, parity, framing or break) is associated with the
+         * received data. If there is an error the byte is not copied into the
+         * RX buffer.
+         */
+
+        if (status & (OE | PE | FE | BI)) {
+
+            if (status & PE)
+                uart->parity_error++;
+
+            if (status & FE)
+                uart->framing_error++;
+
+            if (status & OE)
+                uart->overrun_error++;
+
+            error_detected = 1;
+        }
+
+        /*
+         * If there is no error the byte is copied into the RX
+         * buffer if it is not full.
+         */
+
+        if (!error_detected && !RX_BUFFER_FULL (uart)) {
+
+            *(uart->rx_in++) = char_received;
+
+            if (uart->rx_in == &(uart->rx_buffer[0]) + BUFFER_SIZE + 1)
+                uart->rx_in = &(uart->rx_buffer[0]);
+
+#ifdef UART_RX_BUFFER_DUMP
+            *(uart_rx_buffer_dump.rx_in)++ = char_received;
+
+            if (uart_rx_buffer_dump.rx_in == uart_rx_buffer_dump.rx_buffer + sizeof (uart_rx_buffer_dump.rx_buffer))
+                uart_rx_buffer_dump.rx_in = uart_rx_buffer_dump.rx_buffer;
+        }
+        else {
+            uart_rx_buffer_dump.errors_count++;
+#endif
+        }
+
+        status = READ_UART_REGISTER (uart, LSR);
+    }
+
+    /*
+     * Call the user's function.
+     */
+
+    if (uart->callback_function != NULL)
+        (*(uart->callback_function)) ();
+}
+
+/*******************************************************************************
+ *
+ *                           initialize_uart_sleep
+ * 
+ * Purpose  : Performs basic UART hardware initialization including sleep mode.
+ *
+ * Arguments: In : uart_id : UART id.
+ *            Out: none
+ *
+ * Returns: none
+ *
+ * Warning: Parameters are not verified.
+ *
+ ******************************************************************************/
+
+void
+initialize_uart_sleep (T_tr_UartId uart_id)
+{
+    t_uart     *uart;
+    int        index;
+    SYS_UWORD8 dummy;
+
+    for (index = 0; index < NUMBER_OF_TR_UART; index++)
+        uart_parameter[index].base_address = base_address[index];
+        
+    uart = &(uart_parameter[uart_id]);
+
+    /*
+     * Mask all interrupts causes and disable sleep mode.
+     */
+
+    WRITE_UART_REGISTER (uart, IER, 0x00);
+
+    /*
+     * Reset UART mode configuration.
+     */
+     
+    WRITE_UART_REGISTER (uart, MDR1, RESET_DEFAULT_STATE);
+
+    /*
+     * LCR[7:0] = 0xBF to allow to access EFR 
+     * EFR[4] = 1 to allow to program IER[4].
+     */
+     
+    WRITE_UART_REGISTER (uart, LCR, 0xBF);
+    SET_BIT (uart, EFR, ENHANCED_FEATURE_BIT);
+    WRITE_UART_REGISTER (uart, LCR, 0x83);
+
+    /*
+     * Enable FIFO and reset them.
+     */
+
+    WRITE_UART_REGISTER (uart, FCR, FIFO_ENABLE   |
+                                    RX_FIFO_RESET |
+                                    TX_FIFO_RESET);
+
+    /*
+     * Program the baud generator (dummy 115200).
+     */
+
+    WRITE_UART_REGISTER (uart, DLL, 0x07);
+    WRITE_UART_REGISTER (uart, DLM, 0x00);
+
+    /*
+     * LCR[7] = 0 to allow to access IER and RHR - normal mode.
+     */
+     
+    RESET_BIT (uart, LCR, DIV_EN_BIT);
+
+    /*
+     * Select UART mode.
+     */
+     
+    WRITE_UART_REGISTER (uart, MDR1, UART_MODE);
+
+    /*
+     * Clear Interrupt and check that Rx FIFO is empty.
+     */
+
+    dummy = READ_UART_REGISTER (uart, IIR);
+
+    while (READ_UART_REGISTER (uart, LSR) & DR)
+	    dummy = READ_UART_REGISTER (uart, RHR);
+
+#if ((CHIPSET != 5) && (CHIPSET != 6))
+    /*
+     * Enable sleep mode.
+     */
+
+    WRITE_UART_REGISTER (uart, IER, IER_SLEEP);
+#endif
+}
+
+
+/*******************************************************************************
+ *
+ *                               UA_Init
+ * 
+ * Purpose  : Initializes the module and the UART.
+ *
+ * Arguments: In : uart_id : UART id.
+ *                 baudrate: baud rate selected.
+ *                 callback: user's function called characters are received.
+ *            Out: none
+ *
+ * Returns: none
+ *
+ * Warning: Parameters are not verified.
+ *
+ ******************************************************************************/
+
+void
+UA_Init (T_tr_UartId uart_id,
+         T_tr_Baudrate baudrate,
+         void (callback_function (void)))
+{
+    t_uart *uart;
+    int    index;
+
+#ifdef UART_RX_BUFFER_DUMP
+    uart_rx_buffer_dump.rx_in = uart_rx_buffer_dump.rx_buffer;
+#endif
+
+    for (index = 0; index < NUMBER_OF_TR_UART; index++)
+        uart_parameter[index].base_address = base_address[index];
+        
+    uart = &(uart_parameter[uart_id]);
+
+    uart->rx_in  = &(uart->rx_buffer[0]);
+    uart->rx_out = &(uart->rx_buffer[0]);
+
+    uart->callback_function = callback_function;
+
+    uart->framing_error = 0;
+    uart->parity_error  = 0;
+    uart->overrun_error = 0;
+
+    uart->dle_detected = 0;
+    uart->inframe = 0;
+    uart->encapsulation_flag = 0;
+    uart->frame_length = 0;
+
+    /*
+     * Mask all interrupts causes and disable sleep 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);
+    
+    /*
+     * 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, UART_MODE             |
+                                     IR_SLEEP_DISABLED     |
+                                     SIR_TX_WITHOUT_ACREG2 |
+                                     FRAME_LENGTH_METHOD);
+
+#if ((CHIPSET == 5) || (CHIPSET == 6))
+    /*
+     * Unmask RX interrupt
+     */
+
+    WRITE_UART_REGISTER (uart, IER, ERBI);
+#else
+    /*
+     * Unmask RX interrupt and allow sleep mode.
+     */
+
+    WRITE_UART_REGISTER (uart, IER, ERBI | IER_SLEEP);
+#endif
+}
+
+/*******************************************************************************
+ *
+ *                           UA_ReadNChars
+ * 
+ * Purpose  : Reads N characters from the RX buffer.
+ *
+ * Arguments: In : uart_id      : UART id.
+ *                 buffer       : buffer address where the characters are
+ *                                copied.
+ *                 chars_to_read: number of characters to read.
+ *            Out: none
+ *
+ * Returns  : The number of characters read.
+ *
+ * Warning: Parameters are not verified.
+ *
+ ******************************************************************************/
+
+SYS_UWORD32
+UA_ReadNChars (T_tr_UartId uart_id,
+               char *buffer,
+               SYS_UWORD32 chars_to_read)
+{
+    SYS_UWORD32 chars_in_rx_buffer;
+    SYS_UWORD32 chars_to_copy;
+    SYS_UWORD32 chars_written;
+    char        *rx_in;
+    t_uart      *uart;
+    
+    uart = &(uart_parameter[uart_id]);
+
+    /*
+     * A copy of the rx_in pointer is used because it may be updated by
+     * the interrupt handler.
+     * Get the number of bytes available in the RX buffer.
+     */
+         
+    rx_in = uart->rx_in;
+
+    if (uart->rx_out <= rx_in)
+        chars_in_rx_buffer = (SYS_UWORD32) (rx_in - uart->rx_out);
+    else
+        chars_in_rx_buffer = (SYS_UWORD32) (rx_in - uart->rx_out + BUFFER_SIZE + 1);
+
+    /*
+     * No more bytes than those received may be written in the output buffer.
+     */
+
+    if (chars_in_rx_buffer >= chars_to_read)
+        chars_to_copy = chars_to_read;
+    else
+        chars_to_copy = chars_in_rx_buffer;
+
+    chars_written = chars_to_copy;
+
+    /*
+     * Write the received bytes in the output buffer.
+     */
+
+    while (chars_to_copy) {
+
+        *(buffer++) = *(uart->rx_out++);
+        chars_to_copy--;
+
+        if (uart->rx_out == &(uart->rx_buffer[0]) + BUFFER_SIZE + 1)
+            uart->rx_out = &(uart->rx_buffer[0]);
+    }
+
+    return (chars_written);
+}
+
+/*******************************************************************************
+ *
+ *                           UA_ReadNBytes
+ * 
+ * Purpose  : Reads and destuff N bytes from the RX buffer.
+ *
+ * Arguments: In : uart_id      : UART id.
+ *                 buffer       : buffer address where the bytes are copied.
+ *                 chars_to_read: number of bytes to read.
+ *            Out: eof_detected : indicates if an EOF has been detected. Possible
+ *                                values are:
+ *                                 - 0: EOF not detected,
+ *                                 - 1: EOF detected and no more bytes left,
+ *                                 - 2: EOF not detected and more bytes left.
+ *                                      Users must invoke this function one more
+ *                                      time in order to get those remaining
+ *                                      bytes,
+ *                                 - 3: EOF detected and more bytes left. Users
+ *                                      must invoke this function one more time
+ *                                      in order to get those remaining bytes.
+ *
+ * Returns  : The number of bytes read.
+ *
+ * Warning: Parameters are not verified.
+ *
+ ******************************************************************************/
+
+SYS_UWORD32
+UA_ReadNBytes (T_tr_UartId uart_id,
+               char *buffer_p,
+               SYS_UWORD32 bytes_to_read,
+               SYS_BOOL *eof_detected_p)
+{
+    SYS_UWORD32 bytes_written;
+    SYS_UWORD32 bytes_in_rx_buffer;
+    SYS_UWORD32 bytes_to_process;
+    t_uart      *uart_p;
+    char        *rx_in_p;
+
+    bytes_written = 0;
+    uart_p = &(uart_parameter[uart_id]);
+
+    /*
+     * A copy of the rx_in pointer is used because it may be updated by
+     * the interrupt handler.
+     * Get the number of bytes available in the RX buffer.
+    */
+
+    rx_in_p = uart_p->rx_in;
+
+    if (uart_p->rx_out <= rx_in_p)
+        bytes_in_rx_buffer = (SYS_UWORD32) (rx_in_p - uart_p->rx_out);
+    else
+        bytes_in_rx_buffer = (SYS_UWORD32) (rx_in_p - uart_p->rx_out + BUFFER_SIZE + 1);
+
+    /*
+     * No more bytes than those received may be processed and then written
+     * in the output buffer.
+     */
+
+    if (bytes_in_rx_buffer > bytes_to_read) {
+        bytes_to_process = bytes_to_read;
+
+        /*
+         * More bytes left. Users must invoke this function one more time
+		 * in order to get those remaining bytes.
+		 */
+
+        *eof_detected_p  = 2;
+    }
+    else {
+        bytes_to_process = bytes_in_rx_buffer;
+
+        /*
+         * No more bytes left.
+		 */
+
+        *eof_detected_p  = 0;
+    }
+
+    /*
+     * Perform the byte destuffing and then write the "valid" received bytes in
+     * the output buffer.
+     */
+
+	while ((bytes_to_process) && !(*eof_detected_p & 0x01)) {
+
+        switch (*(uart_p->rx_out)) {
+
+            /*
+             * Current byte is DLE.
+             */
+
+            case DLE:
+                                                        
+                if (!uart_p->dle_detected) {
+
+                    /*
+                     * No DLE previously detected => 
+                     * Skip the current byte and set the flag.
+                     */
+
+                    uart_p->dle_detected = 1;
+                    uart_p->rx_out++;
+                }
+
+                else { /* if (uart_p->dle_detected) */
+
+                    if (uart_p->inframe) {
+
+                        /*
+                         * DLE previously detected AND currently inside of a frame =>
+                         * Copy the current byte in the output buffer, reset the flag
+                         * and increase the frame length.
+                         */
+
+                        uart_p->dle_detected = 0;
+                        uart_p->frame_length++;
+                        *(buffer_p++) = *(uart_p->rx_out++);
+                        bytes_written++;
+                    }
+
+                    else { /* if (!uart_p->inframe) */
+
+                        /*
+                         * DLE previously detected AND currently outside of a frame =>
+                         * Skip the current byte.
+                         */
+
+                        uart_p->rx_out++;
+                    }
+                }
+
+            break; /* case DLE */
+
+            /*
+             * Current byte is STX.
+             */
+
+            case STX:
+                                                      
+                if ((!uart_p->dle_detected) && (uart_p->inframe)) {
+
+                    /*
+                     * No DLE previously detected AND currently inside of a frame.
+                     */
+
+                    if (uart_p->frame_length) {
+
+                        /*
+                         * Frame length is not zero (End of Frame) => 
+                         * Skip the current byte and set the flags (EOF).
+                         */
+
+                        uart_p->inframe = 0;
+                        uart_p->frame_length = 0;
+                        uart_p->rx_out++;
+
+                        /*
+                         * More bytes left.
+                         */
+
+                        if ((*eof_detected_p == 0) && (bytes_to_process))
+                            *eof_detected_p = 2;
+
+                        /*
+                         * EOF detected.
+                         */
+
+                        (*eof_detected_p)++;
+                    }
+
+                    else { /* if (!uart_p->frame_length) */
+
+                        /*
+                         * Frame length is zero (STX followed by another STX =
+                         * Synchro lost but start of a new frame) =>
+                         * Skip the current byte and keep the flag set.
+                         */
+
+                        uart_p->rx_out++;
+                    }
+                }
+
+                else if ((!uart_p->dle_detected) && (!uart_p->inframe)) {
+
+                    /*
+                     * No DLE previously detected AND currently outside of a
+                     * frame (Start of Frame) =>
+                     * Skip the current byte and set the flag.
+                     */
+
+                    uart_p->inframe = 1;
+                    uart_p->rx_out++;
+                }
+
+                else if ((uart_p->dle_detected) && (uart_p->inframe)) {
+
+                    /*
+                     * DLE previously detected AND currently inside of a frame =>
+                     * Copy the current byte in the output buffer, reset the flag
+                     * and increase the frame length.
+                     */
+
+                    uart_p->dle_detected = 0;
+                    uart_p->frame_length++;
+                    *(buffer_p++) = *(uart_p->rx_out++);
+                    bytes_written++;
+                }
+
+                else if ((uart_p->dle_detected) && (!uart_p->inframe)) {
+
+                    /*
+                     * DLE previously detected AND currently outside of a frame =>
+                     * Skip the current byte and reset the flag.
+                     */
+
+                    uart_p->dle_detected = 0;
+                    uart_p->rx_out++;
+                }
+
+            break; /* case STX */
+
+            /*
+             * Current byte is neither DLE nor STX.
+             */
+
+            default:
+
+                if (uart_p->inframe) {
+
+                    /*
+                     * Currently inside of a frame =>
+                     * Copy the current byte in the output buffer and increase
+                     * the frame length.
+                     */
+
+                    uart_p->frame_length++;
+                    *(buffer_p++) = *(uart_p->rx_out++);
+                    bytes_written++;
+                }
+
+                else { /* if (!uart_p->inframe) */
+
+                    /*
+                     * Currently outside of a frame =>
+                     * Skip the current byte.
+                     */
+
+                    uart_p->rx_out++;
+                }
+
+            break; /* default */
+        }
+
+        if (uart_p->rx_out == &(uart_p->rx_buffer[0]) + BUFFER_SIZE + 1)
+            uart_p->rx_out = &(uart_p->rx_buffer[0]);
+
+        bytes_to_process--;
+    }
+
+    return (bytes_written);
+}
+
+
+/*******************************************************************************
+ *
+ *                           UA_WriteNChars
+ * 
+ * Purpose  : Writes N characters in the TX FIFO.
+ *
+ * Arguments: In : uart_id       : UART id.
+ *                 buffer        : buffer address from which characters are
+ *                                 written.
+ *                 bytes_to_write: number of bytes to write.
+ *            Out: none
+ *
+ * Returns  : Number of bytes written.
+ *
+ * Warning: Parameters are not verified.
+ *
+ ******************************************************************************/
+
+SYS_UWORD32
+UA_WriteNChars (T_tr_UartId uart_id,
+                char *buffer,
+                SYS_UWORD32 chars_to_write)
+{
+    SYS_UWORD32 chars_in_tx_fifo;
+    SYS_UWORD32 chars_written;
+    t_uart      *uart;
+    
+    chars_written = 0;
+    uart = &(uart_parameter[uart_id]);
+
+#if ((CHIPSET != 5) && (CHIPSET != 6))
+    /*
+     * Disable sleep mode.
+     */
+              
+    WRITE_UART_REGISTER (
+        uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP);
+#endif
+
+    /*
+     * Copy the input buffer to the TX FIFO.
+     * Ulyssse Bug #44: TX FIFO full status bit (SSR[1]) is corrupted during
+     * one period of Bclock => Workaround S/W.
+     * Write in TX FIFO only if FIFO is empty instead of writing in TX FIFO
+     * while FIFO is not full.
+     */
+
+    if (READ_UART_REGISTER (uart, LSR) & THRE) {
+
+        chars_in_tx_fifo = 0;
+
+        while ((chars_written < chars_to_write) &&
+		       (chars_in_tx_fifo < FIFO_SIZE)) {
+
+            WRITE_UART_REGISTER (uart, THR, *(buffer++));
+            chars_written++;
+            chars_in_tx_fifo++;
+        }
+    }
+
+#if ((CHIPSET != 5) && (CHIPSET != 6))
+    /*
+     * Re-enable sleep mode.
+     */
+
+    WRITE_UART_REGISTER ( 
+        uart, IER, READ_UART_REGISTER (uart, IER) | IER_SLEEP);
+#endif
+
+    return (chars_written);
+}
+
+
+/*******************************************************************************
+ *
+ *                           UA_EncapsulateNChars
+ * 
+ * Purpose  : Writes N characters in the TX FIFO in encapsulating them with 2
+ *            STX bytes (one at the beginning and one at the end).
+ *
+ * Arguments: In : uart_id       : UART id.
+ *                 buffer        : buffer address from which characters are
+ *                                 written.
+ *                 chars_to_write: number of chars to write.
+ *            Out: none
+ *
+ * Returns  : Number of chars written.
+ *
+ * Warning: Parameters are not verified.
+ *
+ ******************************************************************************/
+
+SYS_UWORD32
+UA_EncapsulateNChars (T_tr_UartId uart_id,
+                      char *buffer,
+                      SYS_UWORD32 chars_to_write)
+{
+    SYS_UWORD32 chars_written;
+    SYS_UWORD32 chars_in_tx_fifo;
+    t_uart      *uart;
+    
+    chars_written = 0;
+    uart = &(uart_parameter[uart_id]);
+
+#if ((CHIPSET != 5) && (CHIPSET != 6))
+    /*
+     * Disable sleep mode.
+     */
+              
+    WRITE_UART_REGISTER (
+        uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP);
+#endif
+
+    /*
+     * Copy the input buffer to the TX FIFO.
+     * Ulyssse Bug #44: TX FIFO full status bit (SSR[1]) is corrupted during
+     * one period of Bclock => Workaround S/W.
+     * Write in TX FIFO only if FIFO is empty instead of writing in TX FIFO
+     * while FIFO is not full.
+     */
+
+    if (READ_UART_REGISTER (uart, LSR) & THRE) {
+
+        chars_in_tx_fifo = 0;
+
+        /*
+         * Check if the message has been already encapsulated.
+         */
+
+        if (!uart->encapsulation_flag) {
+            /*
+             * Write STX in the TX FIFO and set the flag.
+             */
+
+            WRITE_UART_REGISTER (uart, THR, STX);
+            chars_in_tx_fifo++;
+            uart->encapsulation_flag = 1;
+        }
+
+        /*
+         * Keep one char margin in the TX FIFO for the last STX.
+         */
+
+        while ((chars_written < chars_to_write) &&
+               (chars_in_tx_fifo < (FIFO_SIZE-1))) {
+
+            WRITE_UART_REGISTER (uart, THR, *(buffer++));
+            chars_written++;
+            chars_in_tx_fifo++;
+        }
+
+        /*
+         * Append STX byte at the end if the frame is complete.
+         */
+
+        if (chars_written == chars_to_write) {
+
+            /*
+             * Write STX in the TX FIFO and reset the flag.
+             */
+
+            WRITE_UART_REGISTER (uart, THR, STX);
+            uart->encapsulation_flag = 0;
+        }
+    }
+
+#if ((CHIPSET != 5) && (CHIPSET != 6))
+    /*
+     * Re-enable sleep mode.
+     */
+
+    WRITE_UART_REGISTER ( 
+        uart, IER, READ_UART_REGISTER (uart, IER) | IER_SLEEP);
+#endif
+
+    return (chars_written);
+}
+
+
+/*******************************************************************************
+ *
+ *                           UA_WriteNBytes
+ * 
+ * Purpose  : Writes N bytes in the TX FIFO in encapsulating with 2 STX bytes
+ *            at the beginning and the end of the frame, and in making byte
+ *            stuffing.
+ *
+ * Arguments: In : uart_id       : UART id.
+ *                 buffer        : buffer address from which bytes are
+ *                                 written.
+ *                 bytes_to_write: number of bytes to write.
+ *            Out: none
+ *
+ * Returns  : Number of bytes written.
+ *
+ * Warning: Parameters are not verified.
+ *
+ ******************************************************************************/
+
+SYS_UWORD32
+UA_WriteNBytes (T_tr_UartId uart_id,
+                SYS_UWORD8 *buffer,
+                SYS_UWORD32 bytes_to_write)
+{
+    SYS_UWORD32 bytes_written;
+    SYS_UWORD32 bytes_in_tx_fifo;
+    t_uart      *uart;
+        
+    bytes_written = 0;
+    uart = &(uart_parameter[uart_id]);
+
+#if ((CHIPSET != 5) && (CHIPSET != 6))
+    /*
+     * Disable sleep mode.
+     */
+              
+    WRITE_UART_REGISTER (
+        uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP);
+#endif
+
+    /*
+     * Copy the input buffer to the TX FIFO.
+     * Ulyssse Bug #44: TX FIFO full status bit (SSR[1]) is corrupted during
+     * one period of Bclock => Workaround S/W.
+     * Write in TX FIFO only if FIFO is empty instead of writing in TX FIFO
+     * while FIFO is not full.
+     */
+
+    if (READ_UART_REGISTER (uart, LSR) & THRE) {
+
+        bytes_in_tx_fifo = 0;
+
+        /*
+         * Check if the message has been already encapsulated.
+         */
+
+        if (!uart->encapsulation_flag) {
+
+            /*
+             * Write STX in the TX FIFO and set the flag.
+             */
+
+            WRITE_UART_REGISTER (uart, THR, STX);
+            bytes_in_tx_fifo++;
+            uart->encapsulation_flag = 1;
+        }
+
+        /*
+         * Keep 2 chars margin in the FIFO, one for the stuffing (if necessary)
+         * and one for the last STX.
+         */
+
+        while ((bytes_written < bytes_to_write) && 
+               (bytes_in_tx_fifo < (FIFO_SIZE-2))) {
+
+            /*
+             * Check for STX or DLE in order to perform the stuffing.
+             */
+
+            if ((*(buffer) == STX) || (*(buffer) == DLE)) {
+
+                /*
+                 * Write DLE in the TX FIFO.
+                 */
+
+                WRITE_UART_REGISTER (uart, THR, DLE);
+                bytes_in_tx_fifo++;
+            }
+
+            WRITE_UART_REGISTER (uart, THR, *(buffer++));
+            bytes_written++;
+            bytes_in_tx_fifo++;
+        }
+
+        /*
+         * Append STX byte at the end if the frame is complete.
+         */
+
+        if (bytes_written == bytes_to_write) {
+
+            /*
+             * Write STX in the TX FIFO and reset the flag.
+             */
+
+            WRITE_UART_REGISTER (uart, THR, STX);
+            uart->encapsulation_flag = 0;
+        }
+    }
+
+#if ((CHIPSET != 5) && (CHIPSET != 6))
+    /*
+     * Re-enable sleep mode.
+     */
+
+    WRITE_UART_REGISTER ( 
+        uart, IER, READ_UART_REGISTER (uart, IER) | IER_SLEEP);
+#endif
+
+    return (bytes_written);
+}
+
+
+/*******************************************************************************
+ *
+ *                            UA_WriteChar
+ * 
+ * Purpose  : Writes a character in the TX FIFO.
+ *
+ * Arguments: In : uart: UART id.
+ *                 character
+ *            Out: none
+ *
+ * Returns  : none
+ *
+ * Warning: Parameters are not verified.
+ *
+ ******************************************************************************/
+
+void
+UA_WriteChar (T_tr_UartId uart_id,
+              char character)
+{
+    (void) UA_WriteNChars (uart_id, &character, 1);
+}
+
+/*******************************************************************************
+ *
+ *                          UA_WriteString
+ * 
+ * Purpose  : Writes a null terminated string in the TX FIFO.
+ *
+ * Arguments: In : uart_id: UART id.
+ *                 buffer : buffer address from which characters are written.
+ *            Out: none
+ *
+ * Returns  : none
+ *
+ * Warning: Parameters are not verified.
+ *
+ ******************************************************************************/
+
+void
+UA_WriteString (T_tr_UartId uart_id,
+                char *buffer)
+{
+    (void) UA_WriteNChars (uart_id, buffer, strlen (buffer));
+}
+
+/*******************************************************************************
+ *
+ *                             UA_EnterSleep
+ * 
+ * Purpose  : Checks if UART is ready to enter Deep Sleep. If ready, enables
+ *            wake-up interrupt.
+ *
+ * Arguments: In : uart_id : UART id.
+ *            Out: none
+ *
+ * Returns: 0	 : Deep Sleep is not possible.
+ *          >= 1 : Deep Sleep is possible.
+ *
+ * Warning: Parameters are not verified.
+ *
+ ******************************************************************************/
+
+SYS_BOOL
+UA_EnterSleep (T_tr_UartId uart_id)
+{
+    t_uart              *uart;
+    SYS_BOOL            deep_sleep;
+    volatile SYS_UWORD8 status;
+        
+    uart = &(uart_parameter[uart_id]);
+    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
+
+        /*
+         * Mask RX interrupt.
+         */
+
+        WRITE_UART_REGISTER (
+            uart, IER, READ_UART_REGISTER (uart, IER) & ~ERBI);
+
+        /*
+         * Enable the wake-up interrupt.
+         */
+
+        ENABLE_WAKEUP_INTERRUPT (uart);
+
+        deep_sleep = 1;
+    }
+
+    return (deep_sleep);
+}
+
+/*******************************************************************************
+ *
+ *                              UA_WakeUp
+ * 
+ * Purpose  : Wakes up UART after Deep Sleep.
+ *
+ * Arguments: In : uart_id : UART id.
+ *            Out: none
+ *
+ * Returns: none
+ *
+ * Warning: Parameters are not verified.
+ *
+ ******************************************************************************/
+
+void
+UA_WakeUp (T_tr_UartId uart_id)
+{
+    t_uart *uart;
+       
+    uart = &(uart_parameter[uart_id]);
+
+    /*
+     * Disable the wake-up interrupt.
+     */
+
+    DISABLE_WAKEUP_INTERRUPT (uart);
+
+    /*
+     * Unmask RX interrupts.
+     */
+
+    WRITE_UART_REGISTER (
+        uart, IER, READ_UART_REGISTER (uart, IER) | ERBI);
+
+#if ((CHIPSET != 5) && (CHIPSET != 6))
+    /*
+     * Allow sleep mode.
+     */
+
+    WRITE_UART_REGISTER ( 
+        uart, IER, READ_UART_REGISTER (uart, IER) | IER_SLEEP);
+#endif
+}
+
+/*******************************************************************************
+ *
+ *                       UA_InterruptHandler
+ * 
+ * Purpose  : Interrupt handler.
+ *
+ * Arguments: In : uart_id         : origin of interrupt
+ *                 interrupt_status: source of interrupt
+ *            Out: none
+ *
+ * Returns  : none
+ *
+ ******************************************************************************/
+
+void
+UA_InterruptHandler (T_tr_UartId uart_id,
+                     SYS_UWORD8 interrupt_status)
+{
+    t_uart *uart;
+   
+    uart = &(uart_parameter[uart_id]);
+
+    switch (interrupt_status) {
+
+        case RX_DATA:
+
+            read_rx_fifo (uart);
+
+        break;
+
+        default:
+
+#ifdef UART_RX_BUFFER_DUMP
+            uart_rx_buffer_dump.wrong_interrupt_status++;
+#endif
+
+            /* No Processing */
+
+        break;
+    }
+}