FreeCalypso > hg > fc-selenite
view src/cs/drivers/drv_app/uart/uartfax_dp.c @ 122:7c68000b87cf
targets: c155 added
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Wed, 07 Nov 2018 06:55:49 +0000 |
parents | b6a5e36de839 |
children |
line wrap: on
line source
/******************************************************************************* * * UARTFAX.C * * This driver allows to control the UARTs of chipset 1.5 for fax and data * services. It performs flow control: RTS/CTS, XON/XOFF. * * (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); }