FreeCalypso > hg > tcs211-fcmodem
diff chipsetsw/drivers/drv_app/uart/uartfax_dp.c @ 0:509db1a7b7b8
initial import: leo2moko-r1
author | Space Falcon <falcon@ivan.Harhan.ORG> |
---|---|
date | Mon, 01 Jun 2015 03:24:05 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chipsetsw/drivers/drv_app/uart/uartfax_dp.c Mon Jun 01 03:24:05 2015 +0000 @@ -0,0 +1,4204 @@ +/******************************************************************************* + * + * 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. + * + * (C) Texas Instruments 1999 + * + ******************************************************************************/ + +/* + * DB9 16750 + * + * 1 DCD DTR output + * 2 RX SOUT output + * 3 TX SIN input + * 4 DTR DSR input + * 5 GND + * 6 DSR (connected to DTR (DB9) if J1 is used) + * 7 RTS CTS input + * 8 CTS RTS output + * 9 nc + */ +#include <string.h> +#include "nucleus.h" + +#include "config/chipset.cfg" +#include "config/board.cfg" + +#include "main/sys_types.h" +#include "uart/faxdata.h" +#include "uart/uartfax.h" +#include "memif/mem.h" + + +short uart_initialized = 0; + + +/* + * 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 */ + + +/* + * 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 (0x00) /* 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) */ + +#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) +#define RX_HISR_STACK_SIZE (512) /* Bytes. */ +#define TX_HISR_PRIORITY (2) +#define TX_HISR_STACK_SIZE (512) /* 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); + + +/* + * This macro is used to simplify the code in detect_escape_sequence. + */ + +#define CHECK_RX_FIFO_OUT_WRAP_AROUND(UART) \ + { \ + if (rx_fifo_out == \ + &((UART)->rx_fifo_byte[0]) + (UART)->rx_fifo_buffer_size + 1) \ + rx_fifo_out = &((UART)->rx_fifo_byte[0]); \ + } + +/* + * This macro is created to simplify the code. It allows to write a byte from + * the TX buffer to the TX FIFO. + * The tx_out pointer is incremented before to write the character into the + * TX FIFO because an interrupt may occur between the two operations. + */ + +#define WRITE_ONE_TX_BUFFER_BYTE_IN_TX_FIFO(UART) \ + { \ + SYS_UWORD8 buffer_byte; \ + \ + if (get_bytes_in_tx_buffer (UART)) { \ + \ + buffer_byte = *((UART)->tx_out++); \ + WRITE_UART_REGISTER (UART, THR, buffer_byte); \ + \ + if ((UART)->tx_out == \ + &((UART)->tx_buffer[0]) + (UART)->buffer_size + 1) \ + \ + (UART)->tx_out = &((UART)->tx_buffer[0]); \ + } \ + } + +/* + * 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) + +/* + * Size of the intermediate circular buffer used to store RX FIFO bytes before + * to analyze them from the RX HISR. + */ + +#define RX_FIFO_BUFFER_SIZE (2 * FIFO_SIZE) + + + +typedef void (*T_HISR_ENTRY)(void); +typedef void (*T_TIMER_FUNCTION)(UNSIGNED); + +static void hisr_execute_rx_entry_point_1(void); +static void hisr_execute_rx_entry_point_2(void); +static void hisr_execute_tx_entry_point_1(void); +static void hisr_execute_tx_entry_point_2(void); +static void hisr_execute_v24_entry_point_1(void); +static void hisr_execute_v24_entry_point_2(void); +static void hisr_start_break_entry_point_1(void); +static void hisr_start_break_entry_point_2(void); +static void stop_break_entry_point_1(UNSIGNED); +static void stop_break_entry_point_2(UNSIGNED); +static void analyze_guard_period_timer_expiration_entry_1(UNSIGNED); +static void analyze_guard_period_timer_expiration_entry_2(UNSIGNED); + + +const T_TIMER_FUNCTION analyze_guard_period_timer_expiration_tab[NUMBER_OF_FD_UART] = +{ + analyze_guard_period_timer_expiration_entry_1, + analyze_guard_period_timer_expiration_entry_2 +}; + +const T_TIMER_FUNCTION stop_break_tab[NUMBER_OF_FD_UART] = +{ + stop_break_entry_point_1, + stop_break_entry_point_2 +}; + +const T_HISR_ENTRY hisr_execute_rx_tab[NUMBER_OF_FD_UART] = +{ + hisr_execute_rx_entry_point_1, + hisr_execute_rx_entry_point_2 +}; + +const T_HISR_ENTRY hisr_execute_tx_tab[NUMBER_OF_FD_UART] = +{ + hisr_execute_tx_entry_point_1, + hisr_execute_tx_entry_point_2 +}; + +const T_HISR_ENTRY hisr_execute_v24_tab[NUMBER_OF_FD_UART] = +{ + hisr_execute_v24_entry_point_1, + hisr_execute_v24_entry_point_2 +}; + +const T_HISR_ENTRY hisr_start_break_tab[NUMBER_OF_FD_UART] = +{ + hisr_start_break_entry_point_1, + hisr_start_break_entry_point_2 +}; + + + +/* + * 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 tx_stopped_by_application; + SYS_BOOL tx_stopped_by_driver; + + /* + * 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 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_UWORD8 cts_level; /* 1: The RS232 line is deactivated (low). */ + SYS_BOOL esc_seq_received; + + 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[NUMBER_OF_FD_UART]; + +static const SYS_UWORD32 base_address[NUMBER_OF_FD_UART] = +{ + MEM_UART_IRDA, + MEM_UART_MODEM +}; + + +/* + * DLL (LSB) and DLH (MSB) registers values using the 13 MHz clock. + */ + +static const SYS_UWORD8 dll[] = +{ + 0, /* Auto baud: not supported. */ + 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: not supported. */ + 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[] = +{ + 0, /* Not supported. */ + 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: LISR, 1: application. + * Out: none + * + * Returns : none + * + ******************************************************************************/ + +static void +update_reading_callback (t_uart *uart, + SYS_BOOL call_source) +{ + SYS_UWORD32 state; + 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. + */ + + 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->cts_level) << RTS) | + + (((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 0 (ns) 0 (ns) 0 (ns) + * SB RTS 0 RTS + * X 0 RTS XON:0 XOFF:1 (transmitter) + * + * ns: signal not supported. + * DTR/DSR flow control is not supported. + */ + + if (uart->flow_control_mode != fc_rts) + state |= (((SYS_UWORD32) uart->cts_level) << SB); + + if (uart->flow_control_mode == fc_rts) + state |= (((SYS_UWORD32) uart->cts_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: LISR, 1: application. + * 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 sizes array and the addresses array. + * 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 : uartNo: Irda or Modem + * Out: none + * + * Returns : none + * + ******************************************************************************/ + +static VOID +stop_break (T_fd_UartId uartNo) +{ + t_uart *uart; + + uart = &(uart_parameters[uartNo]); + + uart->break_to_send = 0; + uart->break_in_progress = 0; + + /* + * Disable sleep mode then unmask Tx interrupt. + */ + + WRITE_UART_REGISTER ( + uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP); + + WRITE_UART_REGISTER ( + uart, IER, READ_UART_REGISTER (uart, IER) | ETBEI); +} + +static VOID +stop_break_entry_point_1(UNSIGNED id) +{ + stop_break( UAF_UART_0 ); // uart Irda +} +static VOID +stop_break_entry_point_2(UNSIGNED id) +{ + stop_break( UAF_UART_1 ); // uart Modem +} + +/******************************************************************************* + * + * 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 (T_fd_UartId uartNo) +{ + t_uart *uart; + + uart = &(uart_parameters[uartNo]); + + (void) NU_Control_Timer (&(uart->break_timer_ctrl_block), + NU_DISABLE_TIMER); + + + (void) NU_Reset_Timer (&(uart->break_timer_ctrl_block), + stop_break_tab[uartNo], + uart->time_without_character, + 0, /* The timer expires once. */ + NU_DISABLE_TIMER); + + (void) NU_Control_Timer (&(uart->break_timer_ctrl_block), + NU_ENABLE_TIMER); +} +static VOID +hisr_start_break_entry_point_1( VOID ) +{ + hisr_start_break( UAF_UART_0 ); // uart Irda +} + +static VOID +hisr_start_break_entry_point_2( VOID ) +{ + hisr_start_break( UAF_UART_1 ); // uart Modem +} + +/******************************************************************************* + * + * 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) +{ + /* + * Disable sleep mode. + */ + + WRITE_UART_REGISTER ( + uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP); + + 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) +{ + /* + * Disable sleep mode. + */ + + WRITE_UART_REGISTER ( + uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP); + + 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 (T_fd_UartId uartNo) +{ + t_uart *uart; + SYS_UWORD16 bytes_in_rx_buffer; + + uart = &(uart_parameters[uartNo]); + + 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; + } + } +} +static VOID +analyze_guard_period_timer_expiration_entry_1(UNSIGNED id) +{ + analyze_guard_period_timer_expiration( UAF_UART_0 ); // uart Irda +} + +static VOID +analyze_guard_period_timer_expiration_entry_2(UNSIGNED id) +{ + analyze_guard_period_timer_expiration( UAF_UART_1 ); // uart Modem +} + +/******************************************************************************* + * + * 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_fd_UartId uartNo) +{ + t_uart *uart; + + uart = &(uart_parameters[uartNo]); + + (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_tab[uartNo], + 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_fd_UartId uartNo) +{ + t_uart *uart; + int detection_result; + SYS_UWORD8 *rx_fifo_byte; + SYS_UWORD16 bytes_in_rx_buffer; + UNSIGNED elapsed_time; + + uart = &(uart_parameters[uartNo]); + 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(uartNo); + 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 (uartNo); + 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 (uartNo); + 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 (uartNo); /* 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 (uartNo); /* 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; + + /* + * Disable sleep mode. + */ + + WRITE_UART_REGISTER ( + uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP); + + WRITE_UART_REGISTER ( + uart, LCR, READ_UART_REGISTER (uart, LCR) | BREAK_CONTROL); + + /* + * Re-enable sleep mode. + */ + + WRITE_UART_REGISTER ( + uart, IER, READ_UART_REGISTER (uart, IER) | IER_SLEEP); + + 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; + + 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; + 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 + 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 ( T_fd_UartId uartNo ) +{ + SYS_UWORD16 bytes_free_in_rx_buffer; + SYS_UWORD16 wrap_around_counter; + SYS_UWORD16 bytes_in_rx_buffer; + SYS_UWORD16 bytes_read; + SYS_UWORD8 *current_byte; + SYS_UWORD8 xon_xoff_detected; + t_uart *uart; + + xon_xoff_detected = 0; + + uart = &(uart_parameters[uartNo]); + + /* + * 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 (uartNo)) { + + 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) { + + 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; + + /* + * Disable sleep mode then unmask Tx interrupt. + */ + + WRITE_UART_REGISTER ( + uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP); + + 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 { + + while (bytes_read && bytes_free_in_rx_buffer) { + + *(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; + } + + bytes_free_in_rx_buffer--; + bytes_read--; + } + } + + /* + * 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) || + 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; + } + } + } +} + +static VOID +hisr_execute_rx_entry_point_1 ( VOID ) +{ + hisr_execute_rx_operations( UAF_UART_0 ); //uart Irda +} +static VOID +hisr_execute_rx_entry_point_2 ( VOID ) +{ + hisr_execute_rx_operations( UAF_UART_1 ); //uart Modem +} + +/******************************************************************************* + * + * 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 (T_fd_UartId uartNo) +{ + t_uart *uart; + + uart = &(uart_parameters[uartNo]); + + /* + * 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; + } +} + +static VOID +hisr_execute_v24_entry_point_1( VOID ) +{ + hisr_execute_v24_operations( UAF_UART_0 ); // uart Irda +} + +static VOID +hisr_execute_v24_entry_point_2( VOID ) +{ + hisr_execute_v24_operations( UAF_UART_1 ); // uart Modem +} + + +/******************************************************************************* + * + * 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 (T_fd_UartId uartNo) +{ + SYS_UWORD16 bytes_in_tx_buffer; + SYS_UWORD16 bytes_in_tx_fifo; + SYS_UWORD16 wrap_around_counter; + t_uart *uart; + + uart = &(uart_parameters[uartNo]); + + /* + * 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])); + + /* + * 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), instead of checking SSR[0]. + * In normal mode for THR interrupt (i.e. use of trigger level) + * must only load (FIFO_SIZE - Trigger_Level - 1) + */ + + while (bytes_in_tx_buffer && + //!(READ_UART_REGISTER (uart, SSR) & TX_FIFO_FULL)) { + (bytes_in_tx_fifo < FIFO_SIZE)) { + + WRITE_UART_REGISTER (uart, THR, *(uart->tx_out++)); + bytes_in_tx_buffer--; + bytes_in_tx_fifo++; + + wrap_around_counter--; + if (!wrap_around_counter) { + + uart->tx_out = &(uart->tx_buffer[0]); + wrap_around_counter = uart->buffer_size + 1; + } + } + + /* + * 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. */ + } + } + + if (bytes_in_tx_fifo) + + /* + * Unmask Tx interrupt. + */ + + WRITE_UART_REGISTER ( + uart, IER, READ_UART_REGISTER (uart, IER) | ETBEI); + + if ((!bytes_in_tx_fifo) && (uart->break_to_send)) + bytes_in_tx_fifo = send_break (uart); + + /* + * Re-enable the sleep mode. + */ + + WRITE_UART_REGISTER ( + uart, IER, READ_UART_REGISTER (uart, IER) | IER_SLEEP); + + } +} + + +static VOID +hisr_execute_tx_entry_point_1 ( VOID ) +{ + hisr_execute_tx_operations( UAF_UART_0 ); //uart Irda +} + +static VOID +hisr_execute_tx_entry_point_2 ( VOID ) +{ + hisr_execute_tx_operations( UAF_UART_1 ); //uart Modem +} + +/******************************************************************************* + * + * 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); +#if (BOARD == 31) + else if ((*((volatile SYS_UWORD16 *) ARMIO_IN) & 0x0100) == 0x0000) + empty_rx_fifo (uart); +#endif + 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->cts_level = 0; + else + uart->cts_level = 1; + } + + /* + * 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->cts_level) + uart->tx_stopped_by_driver = 1; + + else { + + uart->tx_stopped_by_driver = 0; + + /* + * Disable sleep mode then unmask Tx interrupt. + */ + + WRITE_UART_REGISTER ( + uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP); + + 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) +{ + + /* + * Disable sleep mode then mask Tx interrupt. + */ + + WRITE_UART_REGISTER ( + uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP); + + 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; + int index; + +#if ((CHIPSET == 2) || (CHIPSET == 3) || (CHIPSET == 4)) + /* + * 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-Sample. + */ + + if ( (uartNo != UAF_UART_1) && (uartNo != UAF_UART_0) ) + return (FD_NOT_SUPPORTED); +#endif + + for (index = 0; index < NUMBER_OF_FD_UART; index++) + uart_parameters[index].base_address = base_address[index]; + + + uart = &(uart_parameters[uartNo]); + + /* + * 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. + */ + + if (uart_initialized==0){ + memset (&(uart->rx_hisr_stack[0]), 0xFE, RX_HISR_STACK_SIZE); + memset (&(uart->tx_hisr_stack[0]), 0xFE, TX_HISR_STACK_SIZE); + memset (&(uart->v24_hisr_stack[0]), 0xFE, V24_HISR_STACK_SIZE); + memset (&(uart->break_hisr_stack[0]), 0xFE, BREAK_HISR_STACK_SIZE); + uart_initialized = 1; + } + + + if (NU_Create_HISR (&(uart->rx_hisr_ctrl_block), + "Rx", + hisr_execute_rx_tab[uartNo], + RX_HISR_PRIORITY, + &(uart->rx_hisr_stack[0]), + RX_HISR_STACK_SIZE) != NU_SUCCESS) + + return (FD_INTERNAL_ERR); + + if (NU_Create_HISR (&(uart->tx_hisr_ctrl_block), + "Tx", + hisr_execute_tx_tab[uartNo], + TX_HISR_PRIORITY, + &(uart->tx_hisr_stack[0]), + TX_HISR_STACK_SIZE) != NU_SUCCESS) + + return (FD_INTERNAL_ERR); + + if (NU_Create_HISR (&(uart->v24_hisr_ctrl_block), + "UAF_V24", + hisr_execute_v24_tab[uartNo], + 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. + */ + + if (NU_Create_HISR (&(uart->break_hisr_ctrl_block), + "UAF_Brk", + hisr_start_break_tab[uartNo], + 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_tab[uartNo], + 0, /* Parameter supplied to the routine: not used. */ + 0, /* 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_tab[uartNo], + 0, /* Parameter supplied to the routine: not used. */ + 0, /* 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_115200]; + 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->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_115200]); + WRITE_UART_REGISTER (uart, DLM, dlh[FD_BAUD_115200]); + + /* + * 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 CTS, DSR and DCD. + */ + + status = READ_UART_REGISTER (uart, MSR); + + if (status & MCTS) + uart->cts_level = 0; + else + uart->cts_level = 1; + + /* + * Unmask RX interrupt and the modem status interrupt. + */ + + WRITE_UART_REGISTER (uart, IER, ERBI | EDSSI); + + 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 : enable: 1: enable the driver + * 0: disable the driver + * Out: none + * + * Returns : FD_OK : Successful operation. + * FD_INTERNAL_ERR : Internal problem with the hardware. + * + ******************************************************************************/ + +T_FDRET +UAF_Enable (T_fd_UartId uartNo, SYS_BOOL enable) +{ + t_uart *uart; + + /* + * There is no case where FD_INTERNAL_ERR may be returned. + */ + + uart = &(uart_parameters[uartNo]); + + 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 : 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. + * 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; + + /* + * 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. + */ + baudrate = FD_BAUD_115200; + + if ((!baudrate_value[baudrate]) || + (parity == pa_space)) + + return (FD_NOT_SUPPORTED); + + uart = &(uart_parameters[uartNo]); + + /* + * 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. + */ + + uart->baudrate = baudrate_value[baudrate]; + 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, UART_MODE | + IR_SLEEP_DISABLED | + SIR_TX_WITHOUT_ACREG2 | + FRAME_LENGTH_METHOD); + + /* + * Read the state of CTS, DSR and DCD. + */ + + status = READ_UART_REGISTER (uart, MSR); + + if (status & MCTS) + uart->cts_level = 0; + else + uart->cts_level = 1; + + /* + * Unmask RX and TX interrupts and the modem status interrupt + * and allow sleep mode. + */ + + WRITE_UART_REGISTER (uart, IER, ERBI | ETBEI | EDSSI | IER_SLEEP); + WRITE_UART_REGISTER (uart, IER, ERBI | ETBEI | EDSSI); + + 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 : 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. + * 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; + + if ((bufSize > FD_MAX_BUFFER_SIZE) || + (rxThreshold > FD_MAX_BUFFER_SIZE) || + (txThreshold > FD_MAX_BUFFER_SIZE)) + + result = FD_NOT_SUPPORTED; + + else { + + uart = &(uart_parameters[uartNo]); + + 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 : 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. + * 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; + + /* + * 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[uartNo]); + + uart->tx_stopped_by_driver = 0; + + + uart->xon_character = XON; + uart->xoff_character = XOFF; + uart->flow_control_mode = fcMode; + + /* + * Disable sleep mode. + */ + + WRITE_UART_REGISTER ( + uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP); + + WRITE_UART_REGISTER ( + uart, MCR, READ_UART_REGISTER (uart, MCR) | MRTS); + + /* + * Re-enable sleep mode. + */ + + WRITE_UART_REGISTER ( + uart, IER, READ_UART_REGISTER (uart, IER) | IER_SLEEP); + + if (fcMode == fc_rts) { + + if (uart->cts_level) + uart->tx_stopped_by_driver = 1; + } + + /* + * If the high watermark is reached, DTR or RTS is activated or XOFF is + * sent according to the flow control mode. Else, DTR 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 : 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_INTERNAL_ERR : Internal problem with the hardware. + * + ******************************************************************************/ + +T_FDRET +UAF_SetEscape (T_fd_UartId uartNo, + SYS_UWORD8 escChar, + SYS_UWORD16 guardPeriod) +{ + t_uart *uart; + + /* + * There is no case where FD_INTERNAL_ERR may be returned. + */ + + uart = &(uart_parameters[uartNo]); + + 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 : none + * Out: none + * + * Returns : >= 0 : The returned value is the amount of data in the + * RX buffer. + * 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; + + /* + * There is no case where FD_INTERNAL_ERR may be returned. + */ + + uart = &(uart_parameters[uartNo]); + + 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 : none + * Out: none + * + * Returns : >= 0 : The returned value is the amount of data in the + * TX buffer. + * 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; + + /* + * There is no case where FD_INTERNAL_ERR may be returned. + */ + + uart = &(uart_parameters[uartNo]); + + 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)) + { + /* + * Disable sleep mode then unmask Tx interrupt. + */ + + WRITE_UART_REGISTER ( + uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP); + + 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 : none + * Out: none + * + * Returns: 0 : Deep Sleep is not possible. + * >= 1 : Deep Sleep is possible. + * + * Warning: Parameters are not verified. + * + ******************************************************************************/ + +T_FDRET +UAF_EnterSleep (T_fd_UartId uartNo) +{ + t_uart *uart; + SYS_BOOL deep_sleep; + volatile SYS_UWORD8 status; + + uart = &(uart_parameters[uartNo]); + deep_sleep = 0; + + /* + * Check if RX & TX FIFOs are both empty + */ + + status = READ_UART_REGISTER (uart, LSR); + + if (!(status & DR) && + (status & TEMT)) { + + /* + * Disable sleep mode. + */ + + WRITE_UART_REGISTER ( + uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP); + + /* + * 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 : none + * Out: none + * + * Returns: FD_OK : Successful operation. + * + * Warning: Parameters are not verified. + * + ******************************************************************************/ + +T_FDRET +UAF_WakeUp (T_fd_UartId uartNo) +{ + t_uart *uart; + + uart = &(uart_parameters[uartNo]); + + /* + * Disable the wake-up interrupt. + */ + + DISABLE_WAKEUP_INTERRUPT (uart); + + /* + * Unmask RX and modem status interrupts then allow sleep mode. + */ + + WRITE_UART_REGISTER ( + uart, IER, READ_UART_REGISTER (uart, IER) | (ERBI | EDSSI)); + + WRITE_UART_REGISTER ( + uart, IER, READ_UART_REGISTER (uart, IER) | IER_SLEEP); + + 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 : 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_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; + + /* + * There is no case where FD_INTERNAL_ERR may be returned. + */ + + uart = &(uart_parameters[uartNo]); + + 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) + 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 RX 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 : 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 + * readOutFunc function this parameter + * is set to rm_notDefined. + * nsource : 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_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; + + /* + * There is no case where FD_INTERNAL_ERR may be returned. + */ + + uart = &(uart_parameters[uartNo]); + + 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)) { + +#if (BOARD == 31) + /*while ((*((volatile SYS_UWORD16 *) ARMIO_IN) & 0x0100) == 0x0000) + { + *((volatile SYS_UWORD16 *) ARMIO_OUT) &= ~(0x0040); + }*/ + if ((*((volatile SYS_UWORD16 *) ARMIO_IN) & 0x0100) == 0x0000) + { + *((volatile SYS_UWORD16 *) ARMIO_OUT) &= ~(0x0040); + NU_Sleep(4); // 1.84 ms + } + *((volatile SYS_UWORD16 *) ARMIO_OUT) |= 0x0040; + +#endif + 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: + * - 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) + { + /* + * Disable sleep mode then unmask Tx interrupt. + */ + + WRITE_UART_REGISTER ( + uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP); + + 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 : none + * Out: none + * + * Returns : FD_OK : Successful operation. + * FD_INTERNAL_ERR : Internal problem with the hardware. + * + ******************************************************************************/ + +T_FDRET +UAF_StopRec (T_fd_UartId uartNo) +{ + t_uart *uart; + + /* + * There is no case where FD_INTERNAL_ERR may be returned. + */ + + uart = &(uart_parameters[uartNo]); + + 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 : none + * Out: none + * + * Returns : FD_OK : Successful operation. + * FD_INTERNAL_ERR : Internal problem with the hardware. + * + ******************************************************************************/ + +T_FDRET +UAF_StartRec (T_fd_UartId uartNo) +{ + t_uart *uart; + + /* + * There is no case where FD_INTERNAL_ERR may be returned. + */ + + uart = &(uart_parameters[uartNo]); + + 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 resukt of the break/escape detection process as a bit field. + * + * Arguments: In : none + * 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_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; + + /* + * There is no case where FD_INTERNAL_ERR may be returned. + * Signals not supported are reported as 0. + */ + + uart = &(uart_parameters[uartNo]); + + 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->cts_level) << RTS) | + + (((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 0 (ns) 0 (ns) 0 (ns) + * SB RTS 0 RTS + * X 0 RTS XON:0 XOFF:1 (transmitter) + * + * ns: signal not supported. + * DTR/DSR flow control is not supported. + */ + + if (uart->flow_control_mode != fc_rts) + *state |= (((SYS_UWORD32) uart->cts_level) << SB); + + if (uart->flow_control_mode == fc_rts) + *state |= (((SYS_UWORD32) uart->cts_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 : 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_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; + + uart = &(uart_parameters[uartNo]); + + /* + * There is no case where FD_INTERNAL_ERR may be returned. + * DTR is not supported. The SA field is ignored. + */ + + if ((mask & (1 << SA)) || (mask & (1 << DCD))) + 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); + } + } + + /* + * Disable sleep mode. + */ + + WRITE_UART_REGISTER ( + uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP); + + /* + * The CTS field is ignored if the RTS/CTS flow control is selected. + */ + + 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 (!(mask & (1 << SB)) && (mask & (1 << DCD))) { + + if (state & (1 << DCD)) + WRITE_UART_REGISTER ( + uart, MCR, READ_UART_REGISTER (uart, MCR) | MDTR); + + else + WRITE_UART_REGISTER ( + uart, MCR, READ_UART_REGISTER (uart, MCR) & ~MDTR); + } + + /* + * 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. + * DTR/DSR flow control is not supported. + */ + + if (mask & (1 << SB)) { + + if (state & (1 << SB)) + WRITE_UART_REGISTER ( + uart, MCR, READ_UART_REGISTER (uart, MCR) | MDTR); + + else + WRITE_UART_REGISTER ( + uart, MCR, READ_UART_REGISTER (uart, MCR) & ~MDTR); + } + + + 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; + } + } + + /* + * Re-enable sleep mode. + */ + + WRITE_UART_REGISTER ( + uart, IER, READ_UART_REGISTER (uart, IER) | IER_SLEEP); + + 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_id]); + + 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: + + read_rx_fifo (uart); + 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 : none + * Out: none + * + * Returns : FD_OK : Empty condition OK. + * 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; + + /* + * There is no case where FD_INTERNAL_ERR may be returned. + */ + + result = FD_OK; + + uart = &(uart_parameters[uartNo]); + 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); +} +