FreeCalypso > hg > fc-tourmaline
view src/cs/drivers/drv_app/uart/uartfax.c @ 274:fa22012c4a39
CST: remove AT%Nxxxx old AEC control
This crude method of enabling and configuring AEC is not compatible
with L1_NEW_AEC, and even for the old AEC it did not support every
possible combination. It is time for this hack to go. The new and
proper way of enabling and configuring AEC is via RiViera Audio Service
audio mode facility, either audio mode files or full access write,
most directly accessible via fc-tmsh auw 12 for free experimentation.
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Thu, 29 Jul 2021 18:57:36 +0000 |
parents | 03793f41f9bc |
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. * * On C & D-Sample, DCD and DTR signals are supported on UART modem only with 2 * I/Os. * * On E-Sample, DCD and DTR signals are directly handled by Calypso+. * * On Calypso, RTS and CTS are supported on both UARTs. * * On Calypso+, RTS and CTS are supported on UART Modem1 & IrDA. UART Modem2 is * not available through DB9 connector on E-Sample. * * (C) Texas Instruments 1999 - 2003 * ******************************************************************************/ /* * E-Sample * * UART Modem1 UART Irda * * DB9 Calypso+ DB9 Calypso+ * * 1 DCD DCD output 1 1, 6 and 4 are connected together on DB9 * 2 RX TX output 2 RX TX2 output * 3 TX RX input 3 TX RX2 input * 4 DTR DSR input 4 * 5 GND 5 GND * 6 NC 6 * 7 RTS CTS input 7 RTS CTS2 input * 8 CTS RTS output 8 CTS RTS2 output * 9 NC 9 NC * */ /* * C & D-Sample * * UART Modem UART Irda * * DB9 Calypso DB9 Calypso * * 1 DCD I/O 2 output 1 1, 6 and 4 are connected together on DB9 * 2 RX TX output 2 RX TX2 output * 3 TX RX input 3 TX RX2 input * 4 DTR I/O 3 input 4 * 5 GND 5 GND * 6 NC 6 * 7 RTS CTS input 7 RTS CTS2 input * 8 CTS RTS output 8 CTS RTS2 output * 9 NC 9 NC * */ /* * B-Sample * * UART Modem UART Irda * * DB9 Ulysse DB9 Ulysse * * 1 1, 6 and 4 are connected together on DB9 (Modem and Irda) * 2 RX TX 2 RX TX * 3 TX RX 3 TX RX * 4 4 * 5 GND 5 GND * 6 6 * 7 RTS CTS 7 7 and 8 are connected together on DB9 * 8 CTS RTS 8 * 9 NC 9 NC * */ #include "swconfig.cfg" #include "l1sw.cfg" #if (OP_L1_STANDALONE == 0) #include "rv.cfg" #endif #include "board.cfg" #include "chipset.cfg" #ifdef BLUETOOTH_INCLUDED #include "btemobile.cfg" #endif #include "fc-target.h" #include <string.h> #include "nucleus.h" #include "main/sys_types.h" #include "faxdata.h" #include "uartfax.h" /* * Needed to reset and restart the sleep timer in case of incoming characters. */ #include "serialswitch.h" extern SYS_BOOL uart_sleep_timer_enabled; /* * rv_general.h is needed for macros Min & Min3. */ #include "rv/rv_general.h" #include "memif/mem.h" #if ((BOARD == 8) || (BOARD == 9) || (BOARD == 40) || (BOARD == 41)) #include "armio/armio.h" #endif #ifdef CONFIG_TANGO_MODEM extern SYS_UWORD8 AI_Tango_pinmux[4]; #endif /* * Maximal value for an unsigned 32 bits. */ #define MAX_UNSIGNED_32 (4294967295) #define FIFO_SIZE (64) /* In bytes. */ /* * TLR is used to program the RX FIFO trigger levels. FCR[7:4] are not used. * No trigger level used for TX FIFO. THR_IT generated on TX FIFO empty. */ #define RX_FIFO_TRIGGER_LEVEL (12 << 4) /* * 16750 addresses. Registers accessed when LCR[7] = 0. */ #define RHR (0x00) /* Rx buffer register - Read access */ #define THR (0x00) /* Tx holding register - Write access */ #define IER (0x01) /* Interrupt enable register */ /* * 16750 addresses. Registers accessed when LCR[7] = 1. */ #define DLL (0x00) /* Divisor latch (LSB) */ #define DLM (0x01) /* Divisor latch (MSB) */ /* * EFR is accessed when LCR[7:0] = 0xBF. */ #define EFR (0x02) /* Enhanced feature register */ /* * 16750 addresses. Bit 5 of the FCR register is accessed when LCR[7] = 1. */ #define IIR (0x02) /* Interrupt ident. register - Read only */ #define FCR (0x02) /* FIFO control register - Write only */ #define LCR (0x03) /* Line control register */ #define MCR (0x04) /* Modem control register */ #define LSR (0x05) /* Line status register */ #define MSR (0x06) /* Modem status register */ #define TCR (0x06) /* Transmission control register */ #define TLR (0x07) /* Trigger level register */ #define MDR1 (0x08) /* Mode definition register 1 */ #define SCR (0x10) /* Supplementary Control register */ #define SSR (0x11) /* Supplementary Status register */ #define UASR (0x0E) /* Autobauding Status register */ /* * Supplementary control register. */ #define TX_EMPTY_CTL_IT (0x08) #define RX_CTS_WAKE_UP_ENABLE_BIT (4) /* Use RESET_BIT and SET_BIT macros. */ #define DSR_IT_BIT (5) /* Use RESET_BIT and SET_BIT macros. */ /* * Enhanced feature register. */ #define ENHANCED_FEATURE_BIT (4) /* Use RESET_BIT and SET_BIT macros. */ #define AUTO_CTS_BIT (7) /* Transmission is halted when the CTS pin is high (inactive). */ /* * Mode definition register 1. */ #define UART_MODE (0x00) #define SIR_MODE (0x01) #define UART_MODE_AUTOBAUDING (0x02) /* Reserved in UART/IrDA. */ #define RESET_DEFAULT_STATE (0x07) #define IR_SLEEP_DISABLED (0x00) #define IR_SLEEP_ENABLED (0x08) #define SIR_TX_WITHOUT_ACREG2 (0x00) /* Reserved in UART/modem. */ #define SIR_TX_WITH_ACREG2 (0x20) /* Reserved in UART/modem. */ #define FRAME_LENGTH_METHOD (0x00) /* Reserved in UART/modem. */ #define EOT_BIT_METHOD (0x80) /* Reserved in UART/modem. */ /* * Supplementary Status Register */ #define TX_FIFO_FULL (0x01) /* * Interrupt enable register. */ #define ERBI (0x01) /* Enable received data available interrupt */ #define ETBEI (0x02) /* Enable transmitter holding register empty interrupt */ #define ELSI (0x04) /* Enable receiver line status interrupt */ #define EDSSI (0x08) /* Enable modem status interrupt */ #define IER_SLEEP (0x10) /* Enable sleep mode */ /* * Modem control register. */ #define MDCD (0x01) /* Data Carrier Detect. */ #define MRTS (0x02) /* Request To Send. */ #define TCR_TLR_BIT (6) /* * Line status register. */ #define DR (0x01) /* Data ready */ #define OE (0x02) /* Overrun error */ #define PE (0x04) /* Parity error */ #define FE (0x08) /* Framing error */ #define BI (0x10) /* Break interrupt */ #define THRE (0x20) /* Transmitter holding register (FIFO empty) */ #define TEMT (0x40) /* Transmitter empty (FIFO and TSR both empty) */ #define BYTE_ERROR (OE | PE | FE | BI) /* * Interrupt identification register. * Bit 0 is set to 0 if an IT is pending. * Bits 1 and 2 are used to identify the IT. */ #define IIR_BITS_USED (0x07) #define IT_PENDING (0x01) #define RX_DATA (0x04) #define TX_EMPTY (0x02) #define MODEM_STATUS (0x00) /* * Modem status register. */ #define DELTA_CTS (0x01) #define DELTA_DSR (0x02) #define MCTS (0x10) /* Clear to send */ #define MDSR (0x20) /* Data set ready */ /* * Line control register. */ #define WLS_5 (0x00) /* Word length: 5 bits */ #define WLS_6 (0x01) /* Word length: 6 bits */ #define WLS_7 (0x02) /* Word length: 7 bits */ #define WLS_8 (0x03) /* Word length: 8 bits */ #define STB (0x04) /* Number of stop bits: 0: 1, 1: 1,5 or 2 */ #define PEN (0x08) /* Parity enable */ #define EPS (0x10) /* Even parity select */ #define BREAK_CONTROL (0x40) /* Enable a break condition */ #define DLAB (0x80) /* Divisor latch access bit */ /* * FIFO control register. */ #define FIFO_ENABLE (0x01) #define RX_FIFO_RESET (0x02) #define TX_FIFO_RESET (0x04) /* * These constants define the states of the escape sequence detection. */ #define INITIALIZATION (0) #define NO_ESCAPE_SEQUENCE (1) #define ONE_CHAR_DETECTED (2) #define TWO_CHARS_DETECTED (3) #define THREE_CHARS_DETECTED (4) #define CHARACTERS_IN_ESC_SEQ (3) #define DEFAULT_ESC_SEQ_CHARACTER '+' #define DEFAULT_GUARD_PERIOD (1000) /* 1 second. */ /* * 3 HISR are used to avoid to execute operations from the LISR. */ #define RX_HISR_PRIORITY (2) // NGENGE increase hisr stack otherwise overflows with multiple callbacks //#define RX_HISR_STACK_SIZE (512) /* Bytes. */ #define RX_HISR_STACK_SIZE (768) /* Bytes. */ #define TX_HISR_PRIORITY (2) // NGENGE increase hisr stack otherwise overflows with multiple callbacks //#define TX_HISR_STACK_SIZE (512) /* Bytes. */ #define TX_HISR_STACK_SIZE (768) /* Bytes. */ #define V24_HISR_PRIORITY (2) #define V24_HISR_STACK_SIZE (512) /* Bytes. */ /* * When the break interrupt indicator (BI) is set in the line status register * (LSR), it indicates that the received data input was held in the low state * for longer than a full-word transmission time. In the FIFO mode, when a break * occurs, only one 0 character is loaded into the FIFO. The next character * transfer is enabled after SIN goes to the marking state for at least two RCLK * samples and then receives the next valid start bit. * This constant defined a defined break length returned by the US_GetLineState * function. */ #define MINIMAL_BREAK_LENGTH (2) #define BREAK_HISR_PRIORITY (2) #define BREAK_HISR_STACK_SIZE (512) /* Bytes. */ /* * These macros allow to read and write a UART register. */ #define READ_UART_REGISTER(UART,REG) \ *((volatile SYS_UWORD8 *) ((UART)->base_address + (REG))) #define WRITE_UART_REGISTER(UART,REG,VALUE) \ *((volatile SYS_UWORD8 *) ((UART)->base_address + (REG))) = (VALUE) #define RESET_BIT(UART,REG,BIT) \ (WRITE_UART_REGISTER ( \ UART, REG, READ_UART_REGISTER (UART, REG) & ~(1 << (BIT)))) #define SET_BIT(UART,REG,BIT) \ (WRITE_UART_REGISTER ( \ UART, REG, READ_UART_REGISTER (UART, REG) | (1 << (BIT)))) /* * These macros allow to enable or disable the wake-up interrupt. */ #define ENABLE_WAKEUP_INTERRUPT(UART) \ SET_BIT(UART, SCR, RX_CTS_WAKE_UP_ENABLE_BIT); #define DISABLE_WAKEUP_INTERRUPT(UART) \ RESET_BIT(UART, SCR, RX_CTS_WAKE_UP_ENABLE_BIT); /* * These macros allow to enable or disable the DSR interrupt. */ #define ENABLE_DSR_INTERRUPT(UART) \ SET_BIT(UART, SCR, DSR_IT_BIT); #define DISABLE_DSR_INTERRUPT(UART) \ RESET_BIT(UART, SCR, DSR_IT_BIT); /* * The transmitter is disabled only when the application disables the driver. * To disable the driver, the receiver and the transmitter are disabled by the * application. The transmitter is disabled first to test if the driver is * disabled. */ #define DRIVER_DISABLED(UART) ((UART)->tx_stopped_by_application) #define DISABLE_DRIVER(UART) \ { \ (UART)->tx_stopped_by_application = 1; \ (UART)->rx_stopped_by_application = 1; \ } #define ENABLE_DRIVER(UART) \ { \ (UART)->rx_stopped_by_application = 0; \ (UART)->tx_stopped_by_application = 0; \ } /* * Low and high watermarks for the RX buffer. If it is enabled, the flow * control is activated or deactivated according to these values. * The high watermark value allows to copy an array filled with the RX FIFO * into the RX buffer. */ #define RX_LOW_WATERMARK(RX_BUFFER_SIZE) (FIFO_SIZE) #define RX_HIGH_WATERMARK(RX_BUFFER_SIZE) ((RX_BUFFER_SIZE) - 2 * FIFO_SIZE) /* * This macro allows to know if the RX buffer is full. It must be called only * from the RX HISR. If it is called from the application, the rx_in and * rx_fifo_in pointers may be updated if a RX interrupt occurs or if the * RX HISR is activated. */ #define RX_BUFFER_FULL(UART) \ (((UART)->rx_in == (UART)->rx_out - 1) || \ ((UART)->rx_in == (UART)->rx_out + (UART)->buffer_size)) /* * This macro allows to know if the TX buffer is empty. */ #define TX_BUFFER_EMPTY(UART) \ ((UART)->tx_in == (UART)->tx_out) /* * This macro is used to convert a time (unit: ms) into a number of TDMA. * 1 TDMA = 4.6 ms (23/5). */ #define CONVERT_TIME_IN_TDMA(TIME) (((TIME) * 5) / 23) /* * This structure describes an UART compatible with the UART 16750 and * contains some fields to manage this UART. */ typedef struct s_uart { SYS_UWORD32 base_address; /* * HISR executed from the RX/TX interrupt handler. */ NU_HISR rx_hisr_ctrl_block; NU_HISR tx_hisr_ctrl_block; NU_HISR v24_hisr_ctrl_block; char rx_hisr_stack[RX_HISR_STACK_SIZE]; char tx_hisr_stack[TX_HISR_STACK_SIZE]; char v24_hisr_stack[V24_HISR_STACK_SIZE]; /* * 2 arrays are used to store bytes read in RX FIFO. A UART RX interrupt * may occur while executing RX operations in RX HISR. To avoid overwriting * the array in which received bytes are stored, a second array is used. */ SYS_UWORD8 *rx_buffer_used_by_rx_lisr; SYS_UWORD8 *rx_buffer_used_by_rx_hisr; SYS_UWORD8 rx_fifo_byte_1[FIFO_SIZE]; SYS_UWORD8 rx_fifo_byte_2[FIFO_SIZE]; SYS_UWORD16 bytes_in_rx_buffer_1; SYS_UWORD16 bytes_in_rx_buffer_2; /* * RX and TX buffers. * One character is not used in each buffer to allow to know if the buffer * is empty or not (See macro RX_BUFFER_FULL). If buffers are empty, * rx_in = rx_out and tx_in = tx_out. It is impossible to use fields to * count the number of bytes in each buffer because these fields may be * updated from the application and from the interrupt handlers. That avoids * to have conflicts. */ SYS_UWORD16 buffer_size; SYS_UWORD16 rx_threshold_level; SYS_UWORD16 tx_threshold_level; SYS_UWORD8 rx_buffer[FD_MAX_BUFFER_SIZE + 1]; SYS_UWORD8 tx_buffer[FD_MAX_BUFFER_SIZE + 1]; SYS_UWORD8 *rx_in; SYS_UWORD8 *rx_out; SYS_UWORD8 *tx_in; SYS_UWORD8 *tx_out; /* * Escape sequence. * the field esc_seq_modified may have 2 values: * - 0: No modification. * - 1: Parameters are in the process of modification: The detection * is stopped. */ NU_TIMER guard_period_timer_ctrl_block; SYS_UWORD8 esc_seq_modified; SYS_UWORD8 esc_seq_detection_state; SYS_UWORD8 esc_seq_character; UNSIGNED guard_period; UNSIGNED current_time; UNSIGNED previous_time; /* * Flow control. */ T_flowCtrlMode flow_control_mode; SYS_BOOL send_xon_xoff; SYS_UWORD8 xon_xoff_to_send; SYS_UWORD8 xon_character; SYS_UWORD8 xoff_character; SYS_BOOL rx_stopped_by_application; SYS_BOOL rx_stopped_by_driver; SYS_BOOL rx_stopped_by_lisr; SYS_BOOL tx_stopped_by_application; SYS_BOOL tx_stopped_by_driver; /* SYS_BOOL tx_stopped_by_lisr;*/ /* * Break. */ SYS_BOOL break_received; SYS_BOOL break_to_send; SYS_BOOL break_in_progress; NU_HISR break_hisr_ctrl_block; char break_hisr_stack[BREAK_HISR_STACK_SIZE]; NU_TIMER break_timer_ctrl_block; UNSIGNED baudrate; UNSIGNED autobauding; UNSIGNED bits_per_char; /* Including start, stop and parity bits. */ UNSIGNED break_length; /* In bytes. */ UNSIGNED time_without_character; /* * Callback (UAF_ReadData and UAF_WriteData). * rd: read, wr: write. */ SYS_BOOL esc_seq_received; SYS_UWORD8 rts_level; /* RTS on RS232 side, CTS on chipset side. 1: The RS232 line is deactivated (low). */ #if (UARTFAX_CLASSIC_DTR_DCD || (CHIPSET == 12)) SYS_UWORD8 dtr_level; /* Controlled with an I/O on C & D-Sample and handled by Calypso+ on E-Sample. 1: The RS232 line is deactivated (low). */ /* * When the DTR interrupt is detected the user's Rx callback function must * be called but if the Rx FIFO is not empty the Rx HISR must be activated * to read the bytes received in the Rx FIFO and to put them into the Rx * buffer before to call the user's Rx callback function. * If the Rx HISR is activated due to a Rx interrupt the user's Rx callback * function will be called if conditions to call it are fulfilled. If it is * activated due to the DTR interrupt the user's Rx callback function must * be called without any conditions. * Because the Rx HISR may have been activated but not executed before the * DTR interrupt we must be sure that the user's Rx callback function will * be called for each Rx HISR activation. Call is done for Rx HISR activated * on Rx interrupt if conditions are fulfilled. * A circular buffer of 2 elements is used to memorize the source of * interrupt. Before the activation of the Rx HISR, the source of interrupt * is memorized into this array. When the code of the Rx HISR is executed * the user's Rx callback function is called if the source of interrupt was * the DTR interrupt regardless of the other conditions. * The level of DTR is saved to provide the level detected on Rx interrupt * or DTR interrupt in the 'state' parameter of the user's Rx callback * function. */ SYS_BOOL dtr_change_detected[2]; SYS_UWORD8 dtr_level_saved[2]; SYS_UWORD8 index_it; SYS_UWORD8 index_hisr; #endif /* BOARD 8 or 9 or 40 or 41 or CHIPSET 12 */ SYS_BOOL reading_suspended; SYS_BOOL writing_suspended; SYS_BOOL rd_call_from_hisr_in_progress; SYS_BOOL wr_call_from_hisr_in_progress; T_reInstMode rd_call_setup; T_reInstMode wr_call_setup; SYS_UWORD8 *rd_address[2]; SYS_UWORD8 *wr_address[2]; SYS_UWORD16 rd_size_before_call[2]; SYS_UWORD16 rd_size_after_call[2]; SYS_UWORD16 wr_size_before_call[2]; SYS_UWORD16 wr_size_after_call[2]; void (*readOutFunc) (SYS_BOOL cldFromIrq, T_reInstMode *reInstall, SYS_UWORD8 nsource, SYS_UWORD8 *source[], SYS_UWORD16 size[], SYS_UWORD32 state); void (*writeInFunc) (SYS_BOOL cldFromIrq, T_reInstMode *reInstall, SYS_UWORD8 ndest, SYS_UWORD8 *dest[], SYS_UWORD16 size[]); /* * These fields are used to store the state defined in UAF_GetLineState.The * first field is used when UAF_GetLineState and UAF_ReadData are not called. * When one of these functions is called the second field is used. That * avoids to lose events when UAF_GetLineState or UAF_ReadData resets the * first field. */ SYS_UWORD32 state_1; SYS_UWORD32 state_2; SYS_UWORD32 *state; /* * Errors counters. */ SYS_UWORD32 framing_error; SYS_UWORD32 parity_error; SYS_UWORD32 overrun_error; SYS_UWORD32 spurious_interrupts; SYS_UWORD16 max_rx_fifo_level; } t_uart; static t_uart uart_parameters; static const SYS_UWORD32 base_address[NUMBER_OF_FD_UART] = { MEM_UART_IRDA, MEM_UART_MODEM #if (CHIPSET == 12) , MEM_UART_MODEM2 #endif }; /* * DLL (LSB) and DLH (MSB) registers values using the 13 MHz clock. */ static const SYS_UWORD8 dll[] = { 0, /* Auto baud: */ 81, /* 75 baud. */ 40, /* 150 baud. */ 148, /* 300 baud. */ 74, /* 600 baud. */ 165, /* 1200 baud. */ 83, /* 2400 baud. */ 169, /* 4800 baud. */ 113, /* 7200 baud. */ 84, /* 9600 baud. */ 56, /* 14400 baud. */ 42, /* 19200 baud. */ 28, /* 28800 baud. */ 24, /* 33900 baud: not supported. */ 21, /* 38400 baud. */ 14, /* 57600 baud. */ 7, /* 115200 baud. */ 0, /* 203125 baud: not supported. */ 0, /* 406250 baud: not supported. */ 0 /* 812500 baud: not supported. */ }; static const SYS_UWORD8 dlh[] = { 0, /* Auto baud: */ 42, /* 75 baud. */ 21, /* 150 baud. */ 10, /* 300 baud. */ 5, /* 600 baud. */ 2, /* 1200 baud. */ 1, /* 2400 baud. */ 0, /* 4800 baud. */ 0, /* 7200 baud. */ 0, /* 9600 baud. */ 0, /* 14400 baud. */ 0, /* 19200 baud. */ 0, /* 28800 baud. */ 0, /* 33900 baud: not supported. */ 0, /* 38400 baud. */ 0, /* 57600 baud. */ 0, /* 115200 baud. */ 0, /* 203125 baud: not supported. */ 0, /* 406250 baud: not supported. */ 0 /* 812500 baud: not supported. */ }; static const UNSIGNED baudrate_value[] = { 1, 75, 150, 300, 600, 1200, 2400, 4800, 7200, 9600, 14400, 19200, 28800, 0, /* Not supported. */ 38400, 57600, 115200, 0, /* Not supported. */ 0, /* Not supported. */ 0 /* Not supported. */ }; /******************************************************************************* * * get_bytes_in_rx_buffer * * Purpose : Gets the number of bytes in the RX buffer. * * Arguments: In : uart: Pointer on the UART structure. * Out: none * * Returns : The number of bytes in the RX buffer. * ******************************************************************************/ static SYS_UWORD16 get_bytes_in_rx_buffer (t_uart *uart) { SYS_UWORD16 bytes_in_rx_buffer; volatile SYS_UWORD8 *rx_in; rx_in = uart->rx_in; if (uart->rx_out <= rx_in) bytes_in_rx_buffer = (SYS_UWORD16) (rx_in - uart->rx_out); else bytes_in_rx_buffer = (SYS_UWORD16) (rx_in - uart->rx_out + uart->buffer_size + 1); return (bytes_in_rx_buffer); } /******************************************************************************* * * get_bytes_in_tx_buffer * * Purpose : Gets the number of bytes in the TX buffer. * * Arguments: In : uart: Pointer on the UART structure. * Out: none * * Returns : The number of bytes in the TX buffer. * ******************************************************************************/ static SYS_UWORD16 get_bytes_in_tx_buffer (t_uart *uart) { SYS_UWORD16 bytes_in_tx_buffer; volatile SYS_UWORD8 *tx_out; tx_out = uart->tx_out; if (tx_out <= uart->tx_in) bytes_in_tx_buffer = (SYS_UWORD16) (uart->tx_in - tx_out); else bytes_in_tx_buffer = (SYS_UWORD16) (uart->tx_in - tx_out + uart->buffer_size + 1); return (bytes_in_tx_buffer); } /******************************************************************************* * * compute_break_time * * Purpose : Computes a number of TDMA from 3 parameters: * - baudrate, * - bits per character including start bit, stop bits and parity, * - number of characters. * Due to the TDMA value (4.6 ms), a minimal value is sent: 2 TDMA. * * Arguments: In : baudrate * bits_per_char * number_of_chars * Out: none * * Returns : The number of TDMA. * ******************************************************************************/ static UNSIGNED compute_break_time (UNSIGNED baudrate, UNSIGNED bits_per_char, UNSIGNED number_of_chars) { UNSIGNED number_of_tdma; number_of_tdma = CONVERT_TIME_IN_TDMA ( 1000 * bits_per_char * number_of_chars / baudrate); if (number_of_tdma == 0) number_of_tdma = 1; number_of_tdma++; return (number_of_tdma); } /******************************************************************************* * * update_reading_callback * * Purpose : Updates the sizes array and the addresses array and get and builds * the state parameter defined in UAF_GetLineState to call the * readOutFunc function. * * Arguments: In : uart : Pointer on the UART structure. * call_source: 0: application, 1: HISR (Rx or V24), 3: Rx HISR * Out: none * * Returns : none * ******************************************************************************/ static void update_reading_callback (t_uart *uart, SYS_BOOL call_source) { SYS_UWORD32 state; SYS_UWORD8 dtr_level; SYS_UWORD8 fragments_number; SYS_UWORD16 bytes_in_rx_buffer; volatile SYS_UWORD8 *rx_in; /* * Update the sizes array and the addresses array. * A copy of rx_in is used because it may be updated by the interrupt * handler if this function is called from the application. */ rx_in = uart->rx_in; if (uart->rx_out < rx_in) { fragments_number = 1; uart->rd_address[0] = uart->rx_out; uart->rd_size_before_call[0] = (SYS_UWORD16) (rx_in - uart->rx_out); uart->rd_size_after_call[0] = uart->rd_size_before_call[0]; uart->rd_size_before_call[1] = 0; uart->rd_size_after_call[1] = 0; bytes_in_rx_buffer = uart->rd_size_before_call[0]; } else if (rx_in == uart->rx_out) { /* RX buffer empty. */ fragments_number = 1; uart->rd_address[0] = uart->rx_out; uart->rd_size_before_call[0] = 0; uart->rd_size_after_call[0] = 0; uart->rd_size_before_call[1] = 0; uart->rd_size_after_call[1] = 0; bytes_in_rx_buffer = 0; } else { fragments_number = 2; uart->rd_address[0] = uart->rx_out; uart->rd_size_before_call[0] = uart->buffer_size + 1 - (SYS_UWORD16) (uart->rx_out - &(uart->rx_buffer[0])); uart->rd_size_after_call[0] = uart->rd_size_before_call[0]; uart->rd_address[1] = &(uart->rx_buffer[0]); uart->rd_size_before_call[1] = (SYS_UWORD16) (rx_in - &(uart->rx_buffer[0])); uart->rd_size_after_call[1] = uart->rd_size_before_call[1]; bytes_in_rx_buffer = uart->rd_size_before_call[0] + uart->rd_size_before_call[1]; if (!uart->rd_size_before_call[1]) fragments_number = 1; } /* * Build the state parameter defined in UAF_GetLineState. * The field state_2 is used when state_1 is set to 0 to avoid to * lose events detected in the RX interrupt handler. */ #if (UARTFAX_CLASSIC_DTR_DCD || (CHIPSET == 12)) if (call_source == 3) /* Call from Rx HISR */ dtr_level = uart->dtr_level_saved[uart->index_hisr]; else dtr_level = uart->dtr_level; #endif state = uart->state_2; uart->state_2 = 0; uart->state = &(uart->state_2); state |= uart->state_1; uart->state_1 = 0; uart->state = &(uart->state_1); state |= ((((SYS_UWORD32) uart->rts_level) << RTS) | #if (UARTFAX_CLASSIC_DTR_DCD || (CHIPSET == 12)) (((SYS_UWORD32) dtr_level) << DTR) | #endif (((SYS_UWORD32) (uart->tx_stopped_by_application | uart->tx_stopped_by_driver)) << TXSTP) | (((SYS_UWORD32) (uart->rx_stopped_by_application | uart->rx_stopped_by_driver)) << RXSTP) | (((SYS_UWORD32) (uart->buffer_size - bytes_in_rx_buffer)) << RXBLEV)); /* * Fields SA, SB and X are set according to the flow control: * * None RTS/CTS XON/XOFF * SA DTR DTR DTR * SB RTS 0 RTS * X 0 RTS XON:0 XOFF:1 (transmitter) * * DTR is supported on C, D & E-Sample. */ #if (UARTFAX_CLASSIC_DTR_DCD || (CHIPSET == 12)) state |= (((SYS_UWORD32) uart->dtr_level) << SA); #endif if (uart->flow_control_mode != fc_rts) state |= (((SYS_UWORD32) uart->rts_level) << SB); if (uart->flow_control_mode == fc_rts) state |= (((SYS_UWORD32) uart->rts_level) << X); else if ((uart->flow_control_mode == fc_xoff) && (uart->tx_stopped_by_application || uart->tx_stopped_by_driver)) state |= (1 << X); /* * Call the readOutFunc function with these parameters. */ uart->rd_call_setup = rm_notDefined; (*(uart->readOutFunc)) (call_source & 0x01, /* From HISR or application */ &(uart->rd_call_setup), fragments_number, &(uart->rd_address[0]), &(uart->rd_size_after_call[0]), state); } /******************************************************************************* * * update_writing_callback * * Purpose : Updates the sizes array and the addresses array to call the * writeInFunc function. * * Arguments: In : uart : Pointer on the UART structure. * call_source: 0: application, 1: HISR * Out: none * * Returns : none * ******************************************************************************/ static void update_writing_callback (t_uart *uart, SYS_BOOL call_source) { SYS_UWORD8 fragments_number; volatile SYS_UWORD8 *tx_out; /* * Update the array of sizes and the array of addresses. * A copy of tx_out is used because it may be updated by the interrupt * handler if this function is called from the application. */ tx_out = uart->tx_out; if (uart->tx_in < tx_out) { fragments_number = 1; uart->wr_address[0] = uart->tx_in; uart->wr_size_before_call[0] = (SYS_UWORD16) (tx_out - uart->tx_in - 1); uart->wr_size_after_call[0] = uart->wr_size_before_call[0]; uart->wr_size_before_call[1] = 0; uart->wr_size_after_call[1] = 0; } else if (tx_out == &(uart->tx_buffer[0])) { fragments_number = 1; uart->wr_address[0] = uart->tx_in; uart->wr_size_before_call[0] = uart->buffer_size - (SYS_UWORD16) (uart->tx_in - &(uart->tx_buffer[0])); uart->wr_size_after_call[0] = uart->wr_size_before_call[0]; uart->wr_size_before_call[1] = 0; uart->wr_size_after_call[1] = 0; } else { fragments_number = 2; uart->wr_address[0] = uart->tx_in; uart->wr_size_before_call[0] = uart->buffer_size + 1 - (SYS_UWORD16) (uart->tx_in - &(uart->tx_buffer[0])); uart->wr_size_after_call[0] = uart->wr_size_before_call[0]; uart->wr_address[1] = &(uart->tx_buffer[0]); uart->wr_size_before_call[1] = (SYS_UWORD16) (tx_out - &(uart->tx_buffer[0]) - 1); uart->wr_size_after_call[1] = uart->wr_size_before_call[1]; if (!uart->wr_size_before_call[1]) fragments_number = 1; } /* * Call the writeInFunc function with these parameters; */ uart->wr_call_setup = rm_notDefined; (*(uart->writeInFunc)) (call_source, &(uart->wr_call_setup), fragments_number, &(uart->wr_address[0]), &(uart->wr_size_after_call[0])); } /******************************************************************************* * * stop_break * * Purpose : The timer is activated to expire when a time corresponding to the * sending time of 2 characters at least has elapsed. After a break, * no character may be sent during this period. * * Arguments: In : id: parameter not used. * Out: none * * Returns : none * ******************************************************************************/ static VOID stop_break (UNSIGNED id) { t_uart *uart; uart = &uart_parameters; uart->break_to_send = 0; uart->break_in_progress = 0; #if ((CHIPSET != 5) && (CHIPSET != 6)) /* * Disable sleep mode. */ WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP); #endif /* * Unmask Tx interrupt. */ WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) | ETBEI); } /******************************************************************************* * * hisr_start_break * * Purpose : Enables the timer used to control the time without character. * * Arguments: In : none * Out: none * * Returns : none * ******************************************************************************/ static VOID hisr_start_break (VOID) { t_uart *uart; uart = &uart_parameters; (void) NU_Control_Timer (&(uart->break_timer_ctrl_block), NU_DISABLE_TIMER); (void) NU_Reset_Timer (&(uart->break_timer_ctrl_block), stop_break, uart->time_without_character, 0, /* The timer expires once. */ NU_DISABLE_TIMER); (void) NU_Control_Timer (&(uart->break_timer_ctrl_block), NU_ENABLE_TIMER); } /******************************************************************************* * * stop_receiver * * Purpose : Activates DTR or RTS or sends XOFF. * * Arguments: In : uart: Pointer on the UART structure. * Out: none * * Returns : none * ******************************************************************************/ static void stop_receiver (t_uart *uart) { #if ((CHIPSET != 5) && (CHIPSET != 6)) /* * Disable sleep mode. */ WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP); #endif switch (uart->flow_control_mode) { case fc_rts: /* * CTS (RTS on UART side) is deactivated (high). */ WRITE_UART_REGISTER ( uart, MCR, READ_UART_REGISTER (uart, MCR) & ~MRTS); break; case fc_xoff: uart->xon_xoff_to_send = uart->xoff_character; uart->send_xon_xoff = 1; /* * Unmask Tx interrupt. */ WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) | ETBEI); break; } } /******************************************************************************* * * start_receiver * * Purpose : Deactivates DTR or RTS or sends XON. * * Arguments: In : uart: Pointer on the UART structure. * Out: none * * Returns : none * ******************************************************************************/ static void start_receiver (t_uart *uart) { #if ((CHIPSET != 5) && (CHIPSET != 6)) /* * Disable sleep mode. */ WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP); #endif switch (uart->flow_control_mode) { case fc_rts: /* * CTS (RTS on UART side) is activated (low). */ WRITE_UART_REGISTER ( uart, MCR, READ_UART_REGISTER (uart, MCR) | MRTS); break; case fc_xoff: uart->xon_xoff_to_send = uart->xon_character; uart->send_xon_xoff = 1; /* * Unmask Tx interrupt. */ WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) | ETBEI); break; } } /******************************************************************************* * * add_esc_seq_char_in_rx_buffer * * Purpose : Writes one escape sequence character in the RX buffer. * * Arguments: In : uart: Pointer on the UART structure. * Out: none * * Returns : none * ******************************************************************************/ static void add_esc_seq_char_in_rx_buffer (t_uart *uart) { /* * IF the RX buffer is not full, write an escape sequence character in the * RX buffer and check wrap-around. */ if (!RX_BUFFER_FULL (uart)) { *(uart->rx_in++) = uart->esc_seq_character; if (uart->rx_in == &(uart->rx_buffer[0]) + uart->buffer_size + 1) uart->rx_in = &(uart->rx_buffer[0]); } } /******************************************************************************* * * analyze_guard_period_timer_expiration * * Purpose : According to the state of the escape sequence detection, 1 or 2 * escape sequence characters may be written into the TX buffer or * the escape sequence is declared as detected. * If 1 or 2 escape sequence characters have been detected the * guard period must not expire. * If 3 characters have been detected the escape sequence must * expire. * * Arguments: In : id: parameter not used. * Out: none * * Returns : none * ******************************************************************************/ static VOID analyze_guard_period_timer_expiration (UNSIGNED id) { t_uart *uart; SYS_UWORD16 bytes_in_rx_buffer; uart = &uart_parameters; switch (uart->esc_seq_detection_state) { case ONE_CHAR_DETECTED: /* * 1 escape sequence character has been detected. The guard period has * ellapsed. This character is written into the TX buffer. */ add_esc_seq_char_in_rx_buffer (uart); break; case TWO_CHARS_DETECTED: /* * 2 escape sequence characters have been detected. The guard period has * ellapsed. These characters are written into the TX buffer. */ add_esc_seq_char_in_rx_buffer (uart); add_esc_seq_char_in_rx_buffer (uart); break; case THREE_CHARS_DETECTED: /* * 3 escape sequence characters have been detected and the guard period * has ellapsed. The escape sequence is detected. */ uart->esc_seq_received = 1; *(uart->state) |= (1 << ESC); break; } uart->esc_seq_detection_state = NO_ESCAPE_SEQUENCE; /* * If the high watermark is reached, RTS is activated or XOFF is sent * according to the flow control mode. */ bytes_in_rx_buffer = get_bytes_in_rx_buffer (uart); if ((uart->flow_control_mode != fc_none) && (bytes_in_rx_buffer >= RX_HIGH_WATERMARK (uart->buffer_size))) { /* * Check if receipt must be stopped. */ if (!uart->rx_stopped_by_driver) { uart->rx_stopped_by_driver = 1; if (!uart->rx_stopped_by_application) stop_receiver (uart); } } /* * If a reading was suspended or if the callback function is installed, * it is called if one of these conditions is fulfiled: * - the RX threshold level is reached, * - a break has been detected, * - an escape sequence has been detected, */ if ((!uart->rd_call_from_hisr_in_progress) && (uart->reading_suspended || (uart->rd_call_setup == rm_reInstall))) { if ((bytes_in_rx_buffer >= uart->rx_threshold_level) || uart->break_received || uart->esc_seq_received) { uart->rd_call_from_hisr_in_progress = 1; update_reading_callback (uart, 1); /* 1: call from HISR. */ uart->reading_suspended = 0; uart->break_received = 0; uart->esc_seq_received = 0; } } } /******************************************************************************* * * stop_guard_period_timer * * Purpose : Stops the timer used to detect the guard period expiration. * * Arguments: In : uart: Pointer on the UART structure. * Out: none * * Returns : none * ******************************************************************************/ static void stop_guard_period_timer (t_uart *uart) { (void) NU_Control_Timer (&(uart->guard_period_timer_ctrl_block), NU_DISABLE_TIMER); } /******************************************************************************* * * start_guard_period_timer * * Purpose : Starts a timer which expires if the guard period has ellapsed. * * Arguments: In : uart: Pointer on the UART structure. * Out: none * * Returns : none * ******************************************************************************/ static void start_guard_period_timer (t_uart *uart) { (void) NU_Control_Timer (&(uart->guard_period_timer_ctrl_block), NU_DISABLE_TIMER); (void) NU_Reset_Timer (&(uart->guard_period_timer_ctrl_block), analyze_guard_period_timer_expiration, uart->guard_period, 0, /* The timer expires once. */ NU_DISABLE_TIMER); (void) NU_Control_Timer (&(uart->guard_period_timer_ctrl_block), NU_ENABLE_TIMER); } /******************************************************************************* * * detect_escape_sequence * * Purpose : The state machine used to detect an escape sequence is updated * according to the array of bytes to analyse. If the state machine * goes to the initial state due to a break in the sequence * detection, the previous characters are put into the RX buffer. * * Arguments: In : uart: Pointer on the UART structure. * Out: none * * Returns : 0: Break in detection or a sequence has been detected. * 1: A sequence may be detected. * ******************************************************************************/ static int detect_escape_sequence (t_uart *uart) { int detection_result; SYS_UWORD8 *rx_fifo_byte; SYS_UWORD16 bytes_in_rx_buffer; UNSIGNED elapsed_time; detection_result = 0; rx_fifo_byte = uart->rx_buffer_used_by_rx_hisr; if (rx_fifo_byte == &(uart->rx_fifo_byte_1[0])) bytes_in_rx_buffer = uart->bytes_in_rx_buffer_1; else bytes_in_rx_buffer = uart->bytes_in_rx_buffer_2; if (uart->current_time > uart->previous_time) elapsed_time = uart->current_time - uart->previous_time; else elapsed_time = MAX_UNSIGNED_32 - uart->previous_time + uart->current_time; switch (uart->esc_seq_detection_state) { case INITIALIZATION: /* * It is the first character received. It may be the first character * of an escape sequence. The elapsed_time variable is set to the * guard period value to consider this character as the first character * of an escape sequence. */ if (!uart->esc_seq_modified) { elapsed_time = uart->guard_period; uart->esc_seq_detection_state = NO_ESCAPE_SEQUENCE; } /* No break! */ case NO_ESCAPE_SEQUENCE: /* * To go to the next state (one, two or three characters detected): * - a guard period must have elapsed since the last receipt, * - the characters must belong to the escape sequence. */ if ((elapsed_time >= uart->guard_period) && (!uart->esc_seq_modified)) { switch (bytes_in_rx_buffer) { case 1: if (*rx_fifo_byte++ == uart->esc_seq_character) { uart->esc_seq_detection_state = ONE_CHAR_DETECTED; start_guard_period_timer (uart); detection_result = 1; } break; case 2: if ((*rx_fifo_byte++ == uart->esc_seq_character) && (*rx_fifo_byte++ == uart->esc_seq_character)) { uart->esc_seq_detection_state = TWO_CHARS_DETECTED; start_guard_period_timer (uart); detection_result = 1; } break; case 3: if ((*rx_fifo_byte++ == uart->esc_seq_character) && (*rx_fifo_byte++ == uart->esc_seq_character) && (*rx_fifo_byte++ == uart->esc_seq_character)) { uart->esc_seq_detection_state = THREE_CHARS_DETECTED; start_guard_period_timer (uart); detection_result = 1; } break; default: /* * No action. */ break; } } uart->previous_time = uart->current_time; break; case ONE_CHAR_DETECTED: /* * To go to the next state (two or three characters detected): * - the difference between the current time and the previous time * must be less than the guard period, * - the characters must belong to the escape sequence. * Otherwise, an escape sequence character is written in the RX buffer. */ if (!uart->esc_seq_modified) { switch (bytes_in_rx_buffer) { case 1: if (*rx_fifo_byte++ == uart->esc_seq_character) { uart->esc_seq_detection_state = TWO_CHARS_DETECTED; detection_result = 1; } break; case 2: if ((*rx_fifo_byte++ == uart->esc_seq_character) && (*rx_fifo_byte++ == uart->esc_seq_character)) { start_guard_period_timer (uart); /* Reset the timer. */ uart->esc_seq_detection_state = THREE_CHARS_DETECTED; detection_result = 1; } break; default: /* * No action. */ break; } } if (!detection_result) { add_esc_seq_char_in_rx_buffer (uart); uart->previous_time = uart->current_time; uart->esc_seq_detection_state = NO_ESCAPE_SEQUENCE; } break; case TWO_CHARS_DETECTED: /* * To go to the next state (three chars detected): * - the difference between the current time and the previous time * must be less than the guard period, * - the character must belong to the escape sequence. * Otherwise, 2 escape sequence characters are written in the RX buffer. */ if (!uart->esc_seq_modified) { switch (bytes_in_rx_buffer) { case 1: if (*rx_fifo_byte++ == uart->esc_seq_character) { start_guard_period_timer (uart); /* Reset the timer. */ uart->esc_seq_detection_state = THREE_CHARS_DETECTED; detection_result = 1; } break; default: /* * No action. */ break; } } if (!detection_result) { add_esc_seq_char_in_rx_buffer (uart); add_esc_seq_char_in_rx_buffer (uart); uart->previous_time = uart->current_time; uart->esc_seq_detection_state = NO_ESCAPE_SEQUENCE; } break; case THREE_CHARS_DETECTED: /* * An escape sequence is detected if a guard period has elapsed since * the last receipt. Otherwise, 3 escape sequence characters are * written in the RX buffer. */ stop_guard_period_timer (uart); add_esc_seq_char_in_rx_buffer (uart); add_esc_seq_char_in_rx_buffer (uart); add_esc_seq_char_in_rx_buffer (uart); uart->previous_time = uart->current_time; uart->esc_seq_detection_state = NO_ESCAPE_SEQUENCE; break; } return (detection_result); } /******************************************************************************* * * send_break * * Purpose : This function may only called if the TX FIFO is empty. * Null characters are written in the TX FIFO. The number of bytes to * write has been defined with UAF_SetLineState. Enables the break * condition. * * Arguments: In : uart: Pointer on the UART structure. * Out: none * * Returns : Number of bytes sent. * ******************************************************************************/ static SYS_UWORD16 send_break (t_uart *uart) { SYS_UWORD16 bytes_in_tx_fifo; bytes_in_tx_fifo = 0; uart->break_in_progress = 1; #if ((CHIPSET != 5) && (CHIPSET != 6)) /* * Disable sleep mode. */ WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP); #endif WRITE_UART_REGISTER ( uart, LCR, READ_UART_REGISTER (uart, LCR) | BREAK_CONTROL); #if ((CHIPSET != 5) && (CHIPSET != 6)) /* * Re-enable sleep mode. */ /* BELOW LINES WERE COMMENTED TO DISABLE SLEEP MODE IN DRIVER */ /* WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) | IER_SLEEP); */ #endif while (uart->break_length) { WRITE_UART_REGISTER (uart, THR, 0x00); uart->break_length--; bytes_in_tx_fifo++; } return (bytes_in_tx_fifo); } /******************************************************************************* * * build_rx_fifo_array * * Purpose : Reads the RX FIFO to build an array with bytes read. * A byte is written in this array if no error is detected. * * Arguments: In : uart: Pointer on the UART structure. * Out: none * * Returns : The number of bytes in RX FIFO. * ******************************************************************************/ static SYS_UWORD16 build_rx_fifo_array (t_uart *uart) { SYS_UWORD8 status; SYS_UWORD8 *first_byte; SYS_UWORD8 *current_byte; SYS_UWORD16 *bytes_in_rx_buffer; SYS_UWORD16 bytes_received; SYS_UWORD8 cbyte; volatile int x; x = 1; bytes_received = 0; /* * Switch to the other buffer. */ first_byte = uart->rx_buffer_used_by_rx_lisr; if (first_byte == &(uart->rx_fifo_byte_1[0])) { first_byte = &(uart->rx_fifo_byte_2[0]); bytes_in_rx_buffer = &(uart->bytes_in_rx_buffer_2); } else { first_byte = &(uart->rx_fifo_byte_1[0]); bytes_in_rx_buffer = &(uart->bytes_in_rx_buffer_1); } current_byte = first_byte; if (*bytes_in_rx_buffer) { /* The Rx buffer is not empty and is being used by HISR ! */ /* Hence stop the flow control */ stop_receiver (uart); /* * Reset LCR[7] (DLAB) to have access to the RBR, THR and IER registers. */ WRITE_UART_REGISTER (uart, LCR, READ_UART_REGISTER (uart, LCR) & ~DLAB); /* Mask The Rx and interrupt */ WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) & ~(ERBI | EDSSI)); uart->rx_stopped_by_lisr = 1; return (bytes_received); } uart->rx_buffer_used_by_rx_lisr = first_byte; status = READ_UART_REGISTER (uart, LSR); /* * Build an array with the bytes contained in the RX FIFO. */ while (status & DR) { /* While RX FIFO is not empty... */ *current_byte = READ_UART_REGISTER (uart, RHR); /* * Check if a parity error or a framing error is associated with the * received data. If there is an error the byte is not copied into the * bytes array. */ if (status & BYTE_ERROR) { if (status & OE) uart->overrun_error++; if (status & PE) uart->parity_error++; if (status & FE) uart->framing_error++; /* * Check break detection. */ if (status & BI) { uart->break_received = 1; *(uart->state) |= ((1 << BRK) | (MINIMAL_BREAK_LENGTH << BRKLEN)); } } else /* No error */ current_byte++; status = READ_UART_REGISTER (uart, LSR); } bytes_received = (SYS_UWORD16) (current_byte - first_byte); *bytes_in_rx_buffer = bytes_received; /* * Re-switch to the other buffer if no valid character has been received. */ if (!bytes_received) { if (uart->rx_buffer_used_by_rx_lisr == &(uart->rx_fifo_byte_1[0])) uart->rx_buffer_used_by_rx_lisr = &(uart->rx_fifo_byte_2[0]); else uart->rx_buffer_used_by_rx_lisr = &(uart->rx_fifo_byte_1[0]); } if (bytes_received > uart->max_rx_fifo_level) uart->max_rx_fifo_level = bytes_received; return (bytes_received); } /******************************************************************************* * * empty_rx_fifo * * Purpose : Read the RX FIFO. * * Arguments: In : uart: Pointer on the UART structure. * Out: none * * Returns : none * ******************************************************************************/ static void empty_rx_fifo (t_uart *uart) { SYS_UWORD16 bytes_in_rx_fifo; volatile SYS_UWORD8 dummy_byte; bytes_in_rx_fifo = 0; while (READ_UART_REGISTER (uart, LSR) & DR) { dummy_byte = READ_UART_REGISTER (uart, RHR); bytes_in_rx_fifo++; } if (bytes_in_rx_fifo > uart->max_rx_fifo_level) uart->max_rx_fifo_level = bytes_in_rx_fifo; } /******************************************************************************* * * hisr_execute_rx_operations * * Purpose : If an escape sequence is detected or if a break in the detection * has occured RX FIFO bytes are written in the RX buffer. * If the software flow control is used bytes are analyzed to know * if a XON or a XOFF character is received to stop or start the * transmitter. * If a flow control is used and if the high watermark of the RX * buffer is reached the receiver is stopped. * If the RX threshold level is reached the callback mechanism is * activated. * * Arguments: In : none * Out: none * * Returns : none * ******************************************************************************/ static VOID hisr_execute_rx_operations (VOID) { SYS_UWORD16 bytes_free_in_rx_buffer; SYS_UWORD16 wrap_around_counter; SYS_UWORD16 bytes_in_rx_buffer; SYS_UWORD16 bytes_read; SYS_UWORD16 bytes_to_copy; SYS_UWORD8 *current_byte; SYS_UWORD8 xon_xoff_detected; t_uart *uart; uart = &uart_parameters; /* * Since new characters have been received, the sleep timer is reset then * restarted preventing the system to enter deep-sleep for a new period of * time. */ SER_restart_uart_sleep_timer (); uart_sleep_timer_enabled = 1; #if (UARTFAX_CLASSIC_DTR_DCD || (CHIPSET == 12)) uart->index_hisr = (uart->index_hisr + 1) & 0x01; /* 0 or 1 */ #endif xon_xoff_detected = 0; /* * Switch to the other buffer. */ current_byte = uart->rx_buffer_used_by_rx_hisr; if (current_byte == &(uart->rx_fifo_byte_1[0])) { current_byte = &(uart->rx_fifo_byte_2[0]); bytes_read = uart->bytes_in_rx_buffer_2; } else { current_byte = &(uart->rx_fifo_byte_1[0]); bytes_read = uart->bytes_in_rx_buffer_1; } uart->rx_buffer_used_by_rx_hisr = current_byte; /* * All bytes are copied into the RX buffer only if an escape sequence has * been detected or a break in the detection has occured. */ if (!detect_escape_sequence (uart)) { if (uart->rx_out > uart->rx_in) bytes_free_in_rx_buffer = (SYS_UWORD16) (uart->rx_out - uart->rx_in - 1); else bytes_free_in_rx_buffer = (SYS_UWORD16) (uart->buffer_size + uart->rx_out - uart->rx_in); wrap_around_counter = uart->buffer_size + 1 - (SYS_UWORD16) (uart->rx_in - &(uart->rx_buffer[0])); if (uart->flow_control_mode == fc_xoff) { /* * For SW Flow Control, need to further investigate the processing * in order to improve the performance of the driver, and in order * to avoid managing the wrap around of the circular buffer each * time a character is copied. */ while (bytes_read && bytes_free_in_rx_buffer) { /* * If the data received is XON or XOFF, the transmitter is * enabled (XON) or disabled (XOFF). */ if (*current_byte == uart->xoff_character) { uart->tx_stopped_by_driver = 1; xon_xoff_detected = 1; } else if (*current_byte == uart->xon_character) { uart->tx_stopped_by_driver = 0; xon_xoff_detected = 1; #if ((CHIPSET != 5) && (CHIPSET != 6)) /* * Disable sleep mode. */ WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP); #endif /* * Unmask Tx interrupt. */ WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) | ETBEI); } else { *(uart->rx_in++) = *current_byte; wrap_around_counter--; if (!wrap_around_counter) { uart->rx_in = &(uart->rx_buffer[0]); wrap_around_counter = uart->buffer_size + 1; } bytes_free_in_rx_buffer--; } current_byte++; bytes_read--; } } else { /* No Flow Control or HW Flow Control */ /* * Figure out the most restricting condition. */ bytes_to_copy = Min3 (bytes_free_in_rx_buffer, wrap_around_counter, bytes_read); /* * Copy characters into the circular Rx buffer. */ memcpy (uart->rx_in, current_byte, bytes_to_copy); /* * Update first the variables associated to blocking conditions: * if (bytes_read = 0) OR * (bytes_free_in_rx_buffer = 0) => No more characters to copy. */ bytes_free_in_rx_buffer -= bytes_to_copy; bytes_read -= bytes_to_copy; wrap_around_counter -= bytes_to_copy; if (!wrap_around_counter) uart->rx_in = &(uart->rx_buffer[0]); else uart->rx_in += bytes_to_copy; /* * Check if there are still some characters to copy. */ if (bytes_read && bytes_free_in_rx_buffer) { /* * Update the remaining variables and figure out again the * most restricting condition. Since (bytes_read = 0) and * (bytes_free_in_rx_buffer = 0) are blocking conditions, if * we reach that point it means that the wrap around condition * has just occurred and it is not needed to manage it again. */ current_byte += bytes_to_copy; bytes_to_copy = Min (bytes_read, bytes_free_in_rx_buffer); /* * Copy characters into the circular Rx buffer and update * current pointer. */ memcpy (uart->rx_in, current_byte, bytes_to_copy); uart->rx_in += bytes_to_copy; /* * bytes_free_in_rx_buffer not updated since not used anymore. */ bytes_read -= bytes_to_copy; } else { bytes_read = 0; } } /* end if (uart->flow_control_mode == fc_xoff) */ /* * If the high watermark is reached, RTS is activated or XOFF is * sent according to the flow control mode. */ bytes_in_rx_buffer = get_bytes_in_rx_buffer (uart); if ((uart->flow_control_mode != fc_none) && (bytes_in_rx_buffer >= RX_HIGH_WATERMARK (uart->buffer_size))) { /* * Check if receipt must be stopped. */ if (!uart->rx_stopped_by_driver) { uart->rx_stopped_by_driver = 1; if (!uart->rx_stopped_by_application) stop_receiver (uart); } } /* * If a reading was suspended or if the callback function is installed, * it is called if one of these conditions is fulfiled: * - the RX threshold level is reached, * - a break has been detected, */ if ((!uart->rd_call_from_hisr_in_progress) && (uart->reading_suspended || (uart->rd_call_setup == rm_reInstall))) { if ((bytes_in_rx_buffer >= uart->rx_threshold_level) || #if (UARTFAX_CLASSIC_DTR_DCD || (CHIPSET == 12)) uart->dtr_change_detected[uart->index_hisr] || #endif uart->break_received || xon_xoff_detected) { uart->rd_call_from_hisr_in_progress = 1; update_reading_callback (uart, 3); /* 3: call from Rx HISR. */ uart->reading_suspended = 0; uart->break_received = 0; uart->esc_seq_received = 0; #if (UARTFAX_CLASSIC_DTR_DCD || (CHIPSET == 12)) uart->dtr_change_detected[uart->index_hisr] = 0; #endif } } } WRITE_UART_REGISTER (uart, LCR, READ_UART_REGISTER (uart, LCR) & ~DLAB); /* Mask The Rx and Modem status interrupt */ WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) & ~(ERBI | EDSSI)); if ((uart->rx_buffer_used_by_rx_hisr) == &(uart->rx_fifo_byte_1[0])) { uart->bytes_in_rx_buffer_1 = 0; } else { uart->bytes_in_rx_buffer_2 = 0; } WRITE_UART_REGISTER (uart, LCR, READ_UART_REGISTER (uart, LCR) & ~DLAB); /* Unmask The Rx and Modem status interrupt*/ WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) | (ERBI | EDSSI)); if(uart->rx_stopped_by_lisr ) { if (!uart->rx_stopped_by_driver) { uart->rx_stopped_by_lisr = 0; /* * Reset LCR[7] (DLAB) to have access to the RBR, THR and IER registers. */ WRITE_UART_REGISTER (uart, LCR, READ_UART_REGISTER (uart, LCR) & ~DLAB); /* UnMask The Rx interrupt */ WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) | (ERBI | EDSSI)); start_receiver (uart); } } } /******************************************************************************* * * hisr_execute_v24_operations * * Purpose : The user's function is called if all conditions to call it are * fulfiled. * * Arguments: In : none * Out: none * * Returns : none * ******************************************************************************/ static VOID hisr_execute_v24_operations (VOID) { t_uart *uart; uart = &uart_parameters; /* * If a reading was suspended or if the callback function is installed, * it is called. */ if ((!DRIVER_DISABLED (uart)) && (!uart->rd_call_from_hisr_in_progress) && (uart->reading_suspended || (uart->rd_call_setup == rm_reInstall))) { uart->rd_call_from_hisr_in_progress = 1; update_reading_callback (uart, 1); /* 1: call from HISR. */ uart->reading_suspended = 0; uart->break_received = 0; uart->esc_seq_received = 0; } } /******************************************************************************* * * hisr_execute_tx_operations * * Purpose : Writes bytes from the TX buffer to the TX FIFO. * The user's function is called if all conditions to call it are * fulfiled. * * Arguments: In : none * Out: none * * Returns : none * ******************************************************************************/ static VOID hisr_execute_tx_operations (VOID) { SYS_UWORD16 bytes_in_tx_buffer; SYS_UWORD16 bytes_in_tx_fifo; SYS_UWORD16 wrap_around_counter; SYS_UWORD16 bytes_to_write; t_uart *uart; int counter; uart = &uart_parameters; /* * A TX interrupt may have occured during the previous TX HISR. This case * may appear when a HISR having a higher priority has been activated when * the TX HISR was activated. When the next TX HISR is activated, the TX * FIFO may not be empty. Nothing is done until a TX interrupt will occur. * The RX HISR will be activated again and the TX FIFO will be empty. */ if (READ_UART_REGISTER (uart, LSR) & THRE) { bytes_in_tx_fifo = 0; /* * A request to send a XON/XOFF character may have been done by the * RX interrupt handler. The byte can be written because we are sure * that the TX FIFO is not full. */ if (uart->send_xon_xoff) { WRITE_UART_REGISTER (uart, THR, uart->xon_xoff_to_send); uart->send_xon_xoff = 0; bytes_in_tx_fifo++; } if ((!uart->tx_stopped_by_application) && (!uart->tx_stopped_by_driver)) { bytes_in_tx_buffer = get_bytes_in_tx_buffer (uart); wrap_around_counter = uart->buffer_size + 1 - (SYS_UWORD16) (uart->tx_out - &(uart->tx_buffer[0])); /* * Figure out the most restricting condition. */ #if ((CHIPSET == 3) || (CHIPSET == 4) || (CHIPSET == 5) || (CHIPSET == 6)) /* * Loading of only (FIFO_SIZE - 1) characters in the Tx FIFO to * avoid the generation of a spurious Tx FIFO almost empty * interrupt (Ulysse bug report #35). */ bytes_to_write = Min3 (bytes_in_tx_buffer, wrap_around_counter, (FIFO_SIZE - 1 - bytes_in_tx_fifo)); #elif ((CHIPSET == 7) || (CHIPSET == 8) || (CHIPSET == 9) || (CHIPSET == 10) || (CHIPSET == 11) || (CHIPSET == 12)) /* * Bug corrected on Calypso rev. A, rev. B, C035, Ulysse C035, * Calypso Lite & Calypso+. */ bytes_to_write = Min3 (bytes_in_tx_buffer, wrap_around_counter, (FIFO_SIZE - bytes_in_tx_fifo)); #endif /* * Write characters into the Tx FIFO. */ for (counter = 0; counter < bytes_to_write; counter++) WRITE_UART_REGISTER (uart, THR, *(uart->tx_out++)); /* * Update the variables associated to blocking conditions: * if (bytes_in_tx_buffer = 0) OR * (bytes_in_tx_fifo = FIFO_SIZE) => No more characters to copy. */ bytes_in_tx_buffer -= bytes_to_write; bytes_in_tx_fifo += bytes_to_write; wrap_around_counter -= bytes_to_write; if (!wrap_around_counter) uart->tx_out = &(uart->tx_buffer[0]); /* * Check if there are still some characters to write. */ if (bytes_in_tx_buffer && #if ((CHIPSET == 3) || (CHIPSET == 4) || (CHIPSET == 5) || (CHIPSET == 6)) (bytes_in_tx_fifo < (FIFO_SIZE - 1))) { #elif ((CHIPSET == 7) || (CHIPSET == 8) || (CHIPSET == 9) || (CHIPSET == 10) || (CHIPSET == 11) || (CHIPSET == 12)) (bytes_in_tx_fifo < FIFO_SIZE)) { #endif /* * Figure out again the most restricting condition. Since * (bytes_in_tx_buffer = 0) and (bytes_in_tx_fifo = FIFO_SIZE) * are blocking conditions, if we reach that point it means * that the wrap around condition has just occurred and it is * not needed to manage it again. */ #if ((CHIPSET == 3) || (CHIPSET == 4) || (CHIPSET == 5) || (CHIPSET == 6)) bytes_to_write = Min (bytes_in_tx_buffer, (FIFO_SIZE - 1 - bytes_in_tx_fifo)); #elif ((CHIPSET == 7) || (CHIPSET == 8) || (CHIPSET == 9) || (CHIPSET == 10) || (CHIPSET == 11) || (CHIPSET == 12)) bytes_to_write = Min (bytes_in_tx_buffer, (FIFO_SIZE - bytes_in_tx_fifo)); #endif /* * Write characters into the Tx FIFO and update associated * variables. */ for (counter = 0; counter < bytes_to_write; counter++) WRITE_UART_REGISTER (uart, THR, *(uart->tx_out++)); bytes_in_tx_buffer += bytes_to_write; bytes_in_tx_fifo += bytes_to_write; } /* * If a writing was suspended or if the callback function is * installed, it is called if the TX threshold level is reached. */ if ((!DRIVER_DISABLED (uart)) && (!uart->wr_call_from_hisr_in_progress) && (bytes_in_tx_buffer <= uart->tx_threshold_level) && ((uart->wr_call_setup == rm_reInstall) || uart->writing_suspended)) { uart->writing_suspended = 0; uart->wr_call_from_hisr_in_progress = 1; update_writing_callback (uart, 1); /* 1: call from HISR. */ } } /* end if ((!uart->tx_stopped_by_application) && */ /* (!uart->tx_stopped_by_driver)) */ if (bytes_in_tx_fifo) /* * Unmask Tx interrupt. */ WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) | ETBEI); else { if ((!bytes_in_tx_fifo) && (uart->break_to_send)) bytes_in_tx_fifo = send_break (uart); } #if ((CHIPSET != 5) && (CHIPSET != 6)) /* * Re-enable the sleep mode. */ /* BELOW LINES WERE COMMENTED TO DISABLE SLEEP MODE IN DRIVER */ /* WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) | IER_SLEEP); */ #endif } } /******************************************************************************* * * read_rx_fifo * * Purpose : Reads the RX FIFO. If the driver is enabled bytes are written in * an array to be analyzed by the RX HISR. * * Arguments: In : uart: Pointer on the UART structure. * Out: none * * Returns : none * ******************************************************************************/ static void read_rx_fifo (t_uart *uart) { /* * If the driver is disabled the RX FIFO is read to acknoledge the * interrupt else bytes received are written into an array which will be * analyzed from the RX HISR. */ if (DRIVER_DISABLED (uart)) empty_rx_fifo (uart); else if (build_rx_fifo_array (uart)){ (void) NU_Activate_HISR (&(uart->rx_hisr_ctrl_block)); } } /******************************************************************************* * * check_v24_input_lines * * Purpose : Check the V.24 input lines. According to the states of the input * lines and to the flow control mode selected, the transmitter is * enabled or disabled. The reading callback function is called if * it is installed and if all conditions are fulfiled. * * Arguments: In : uart: Pointer on the UART structure. * Out: none * * Returns : none * ******************************************************************************/ static void check_v24_input_lines (t_uart *uart) { SYS_BOOL v24_input_line_changed; volatile SYS_UWORD8 modem_status; modem_status = READ_UART_REGISTER (uart, MSR); v24_input_line_changed = 0; if (modem_status & DELTA_CTS) { v24_input_line_changed = 1; if (modem_status & MCTS) uart->rts_level = 0; else uart->rts_level = 1; } #if (CHIPSET == 12) else if (modem_status & DELTA_DSR) { v24_input_line_changed = 1; if (modem_status & MDSR) { uart->dtr_level = 0; if (uart->flow_control_mode != fc_dtr && uart->baudrate == baudrate_value[FD_BAUD_AUTO]) UAF_SetComPar (UAF_UART_1, FD_BAUD_AUTO, bpc_8, sb_1, pa_none); /* switch back to autobaud */ } else uart->dtr_level = 1; /* * The reading callback function has to be called. But bytes received before * the change of state of DTR must be copied into the RX buffer before to * call it. */ if (READ_UART_REGISTER (uart, LSR) & DR) { /* If Rx FIFO is not empty */ /* * The Rx FIFO will be read to fill one of the two buffers and the Rx * HISR will be activated. */ uart->index_it = (uart->index_it + 1) & 0x01; /* 0 or 1 */ uart->dtr_change_detected[uart->index_it] = 1; uart->dtr_level_saved[uart->index_it] = uart->dtr_level; read_rx_fifo (uart); } else v24_input_line_changed = 1; } #endif /* * When the hardware flow control is selected, if the RS 232 input signal is * deactivated (low), the transmitter is stopped. */ if (uart->flow_control_mode == fc_rts) { if (uart->rts_level) { uart->tx_stopped_by_driver = 1; } else { uart->tx_stopped_by_driver = 0; #ifdef CONFIG_TARGET_GTAMODEM AI_ResetBit(1); #elif defined(CONFIG_TANGO_MODEM) if (AI_Tango_pinmux[0] == 0x82) AI_ResetBit(1); #endif #if ((CHIPSET != 5) && (CHIPSET != 6)) /* * Disable sleep mode. */ WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP); #endif /* * Unmask Tx interrupt. */ WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) | ETBEI); } } if (v24_input_line_changed) (void) NU_Activate_HISR (&(uart->v24_hisr_ctrl_block)); } /******************************************************************************* * * fill_tx_fifo * * Purpose : If the TX buffer is not empty, and if there is no break in * progress, bytes are written into the TX FIFO until the TX FIFO is * full or the TX buffer is empty. Else, if there is a break to send * an all 0s character is written into the TX FIFO and a break is * declared in progress to avoid to fill the TX FIFO on the next * interrupt. * When the TX FIFO is empty and if a break is in progress, the break * length is programmed: all 0s characters are written into the TX * FIFO. The number of bytes has been defined previously with the * UAF_SetLineState function. The break condition is enabled. * When the TX FIFO and the transmitter shift register (TSR) are both * empty and if a break is in progress, the break condition is * disabled. * When bytes are written from the TX buffer to the TX FIFO, the * writing callback function is called if it is installed and if all * conditions are fulfiled. * * Arguments: In : uart: Pointer on the UART structure. * Out: none * * Returns : none * ******************************************************************************/ static void fill_tx_fifo (t_uart *uart) { #if ((CHIPSET != 5) && (CHIPSET != 6)) /* * Disable sleep mode. */ WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP); #endif /* * Mask Tx interrupt. */ WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) & ~ETBEI); /* * If a break is in progress, bytes of the TX buffer are not written into * the TX FIFO. */ if (!uart->break_in_progress) (void) NU_Activate_HISR (&(uart->tx_hisr_ctrl_block)); else { /* * The break HISR is activated and the break condition is cleared. */ WRITE_UART_REGISTER ( uart, LCR, READ_UART_REGISTER (uart, LCR) & ~BREAK_CONTROL); (void) NU_Activate_HISR (&(uart->break_hisr_ctrl_block)); } } /******************************************************************************* * * UAF_Init * * Purpose : Initializes the UART hardware and installs interrupt handlers. * The parameters are set to the default values: * - 19200 baud, * - 8 bits / character, * - no parity, * - 1 stop bit, * - no flow control. * All functionalities of the UART driver are disabled. * * Arguments: In : uartNo: Used UART. * Out: none * * Returns : FD_OK : Successful operation. * FD_NOT_SUPPORTED: Wrong UART number. * FD_INTERNAL_ERR : Internal problem. * ******************************************************************************/ T_FDRET UAF_Init (T_fd_UartId uartNo) { t_uart *uart; volatile SYS_UWORD8 status; /* * Check UART number. * A return is used to simplify the code. * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware * flow control is not supported. * DCD and DTR are not supported on UART Irda on C & D-Sample. * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample. */ if (uartNo != UAF_UART_1) return (FD_NOT_SUPPORTED); uart = &uart_parameters; /* * Create the 3 HISR actived in the RX/TX and V24 interrupt handlers. * A return is used to simplify the code if an error occurs. * All stacks are entirely filled with the pattern 0xFE. */ memset (&(uart->rx_hisr_stack[0]), 0xFE, RX_HISR_STACK_SIZE); if (NU_Create_HISR (&(uart->rx_hisr_ctrl_block), "UAF_Rx", hisr_execute_rx_operations, RX_HISR_PRIORITY, &(uart->rx_hisr_stack[0]), RX_HISR_STACK_SIZE) != NU_SUCCESS) return (FD_INTERNAL_ERR); memset (&(uart->tx_hisr_stack[0]), 0xFE, TX_HISR_STACK_SIZE); if (NU_Create_HISR (&(uart->tx_hisr_ctrl_block), "UAF_Tx", hisr_execute_tx_operations, TX_HISR_PRIORITY, &(uart->tx_hisr_stack[0]), TX_HISR_STACK_SIZE) != NU_SUCCESS) return (FD_INTERNAL_ERR); memset (&(uart->v24_hisr_stack[0]), 0xFE, V24_HISR_STACK_SIZE); if (NU_Create_HISR (&(uart->v24_hisr_ctrl_block), "UAF_V24", hisr_execute_v24_operations, V24_HISR_PRIORITY, &(uart->v24_hisr_stack[0]), V24_HISR_STACK_SIZE) != NU_SUCCESS) return (FD_INTERNAL_ERR); /* * Create the HISR used to send a break. * A return is used to simplify the code if an error occurs. * The stack is entirely filled with the pattern 0xFE. */ memset (&(uart->break_hisr_stack[0]), 0xFE, BREAK_HISR_STACK_SIZE); if (NU_Create_HISR (&(uart->break_hisr_ctrl_block), "UAF_Brk", hisr_start_break, BREAK_HISR_PRIORITY, &(uart->break_hisr_stack[0]), BREAK_HISR_STACK_SIZE) != NU_SUCCESS) return (FD_INTERNAL_ERR); /* * Create a timer used in the break HISR. * A return is used to simplify the code if an error occurs. */ if (NU_Create_Timer (&(uart->break_timer_ctrl_block), "Break", stop_break, 0, /* Parameter supplied to the routine: not used. */ 1, /* This parameter is set when the timer is reset. */ 0, /* The timer expires once. */ NU_DISABLE_TIMER) != NU_SUCCESS) return (FD_INTERNAL_ERR); /* * Create a timer used in the detection of the escape sequence. * A return is used to simplify the code if an error occurs. */ if (NU_Create_Timer (&(uart->guard_period_timer_ctrl_block), "Esc seq", analyze_guard_period_timer_expiration, 0, /* Parameter supplied to the routine: not used. */ 1, /* This parameter is set when the timer is reset. */ 0, /* The timer expires once. */ NU_DISABLE_TIMER) != NU_SUCCESS) return (FD_INTERNAL_ERR); /* * These data are used to send a break. * A character has: 8 data bits + 1 start bit + 1 stop bit = 10 bits. */ uart->baudrate = baudrate_value[FD_BAUD_19200]; uart->autobauding = 0; uart->bits_per_char = 10; /* * UART base address. */ uart->base_address = base_address[uartNo]; /* * Select the current array used to store received bytes. */ uart->rx_buffer_used_by_rx_lisr = &(uart->rx_fifo_byte_2[0]); uart->rx_buffer_used_by_rx_hisr = &(uart->rx_fifo_byte_2[0]); /* * RX and TX buffers. */ uart->buffer_size = FD_MAX_BUFFER_SIZE; uart->rx_threshold_level = 1; uart->tx_threshold_level = 0; uart->rx_in = &(uart->rx_buffer[0]); uart->rx_out = &(uart->rx_buffer[0]); uart->tx_in = &(uart->tx_buffer[0]); uart->tx_out = &(uart->tx_buffer[0]); /* * Escape sequence. */ uart->esc_seq_modified = 0; uart->esc_seq_detection_state = INITIALIZATION; uart->esc_seq_character = DEFAULT_ESC_SEQ_CHARACTER; uart->guard_period = CONVERT_TIME_IN_TDMA ( DEFAULT_GUARD_PERIOD); /* * Flow control. */ uart->flow_control_mode = fc_none; uart->send_xon_xoff = 0; uart->rx_stopped_by_application = 1; uart->rx_stopped_by_driver = 0; uart->rx_stopped_by_lisr = 0; uart->tx_stopped_by_application = 1; uart->tx_stopped_by_driver = 0; /* * Break. */ uart->break_received = 0; uart->break_to_send = 0; uart->break_in_progress = 0; /* * Callback (UAF_ReadData and UAF_WriteData). */ uart->esc_seq_received = 0; uart->reading_suspended = 0; uart->writing_suspended = 0; uart->rd_call_from_hisr_in_progress = 0; uart->wr_call_from_hisr_in_progress = 0; uart->rd_call_setup = rm_noInstall; uart->wr_call_setup = rm_noInstall; /* * State defined in UAF_GetLineState. */ uart->state_1 = 0; uart->state_2 = 0; uart->state = &(uart->state_1); /* * Errors counters. */ uart->framing_error = 0; uart->parity_error = 0; uart->overrun_error = 0; uart->spurious_interrupts = 0; uart->max_rx_fifo_level = 0; /* * Mask all interrupts causes and disable sleep mode and low power mode. */ WRITE_UART_REGISTER (uart, IER, 0x00); /* * Reset UART mode configuration. */ WRITE_UART_REGISTER (uart, MDR1, RESET_DEFAULT_STATE | IR_SLEEP_DISABLED | SIR_TX_WITHOUT_ACREG2 | FRAME_LENGTH_METHOD); /* * FIFO configuration. * EFR[4] = 1 to allow to program FCR[5:4] and MCR[7:5]. */ WRITE_UART_REGISTER (uart, LCR, 0xBF); SET_BIT (uart, EFR, ENHANCED_FEATURE_BIT); /* * Select the word length, the number of stop bits , the parity and set * LCR[7] (DLAB) to allow to program FCR, DLL and DLM. */ WRITE_UART_REGISTER (uart, LCR, WLS_8 | DLAB); /* * Program the trigger levels. * MCR[6] must be set to 1. */ SET_BIT (uart, MCR, TCR_TLR_BIT); WRITE_UART_REGISTER (uart, TCR, 0x0F); WRITE_UART_REGISTER (uart, TLR, RX_FIFO_TRIGGER_LEVEL); RESET_BIT (uart, MCR, TCR_TLR_BIT); /* * Force the generation of THR_IT on TX FIFO empty: SCR[3] = 1. */ WRITE_UART_REGISTER ( uart, SCR, READ_UART_REGISTER (uart, SCR) | TX_EMPTY_CTL_IT); /* * Program the FIFO control register. Bit 0 must be set when other FCR bits * are written to or they are not programmed. * FCR is a write-only register. It will not be modified. */ WRITE_UART_REGISTER (uart, FCR, FIFO_ENABLE | RX_FIFO_RESET | /* self cleared */ TX_FIFO_RESET); /* self cleared */ /* * Program the baud generator. */ WRITE_UART_REGISTER (uart, DLL, dll[FD_BAUD_19200]); WRITE_UART_REGISTER (uart, DLM, dlh[FD_BAUD_19200]); /* * Reset LCR[7] (DLAB) to have access to the RBR, THR and IER registers. */ WRITE_UART_REGISTER (uart, LCR, READ_UART_REGISTER (uart, LCR) & ~DLAB); /* * Select UART mode. */ WRITE_UART_REGISTER (uart, MDR1, UART_MODE | IR_SLEEP_DISABLED | SIR_TX_WITHOUT_ACREG2 | FRAME_LENGTH_METHOD); /* * Read the state of RTS (RTS on RS232, CTS on chipset). */ status = READ_UART_REGISTER (uart, MSR); if (status & MCTS) uart->rts_level = 0; else uart->rts_level = 1; #if UARTFAX_CLASSIC_DTR_DCD /* * On C & D-Sample, 2 I/O are used to control DCD and DTR on UART Modem. * DCD: I/O 2 (output) * DTR: I/O 3 (input) */ #define EXTENDED_MCU_REG (0xFFFEF006) /* Extended MCU register */ #define ASIC_CONFIG_REG (0xFFFEF008) /* Asic Configuration register */ #define IO_DTR (10) /* I/O 3; bit 10 of Asic Configuration register */ #define IO_DCD ( 6) /* I/O 2; bit 6 of Extended MCU register */ /* * Select I/O for DCD and configure it as output. * DCD should start HIGH (not asserted). */ #ifdef CONFIG_TANGO_MODEM if (AI_Tango_pinmux[1] & 0x08) { #endif *((volatile SYS_UWORD16 *) EXTENDED_MCU_REG) &= ~(1 << IO_DCD); AI_ConfigBitAsOutput (ARMIO_DCD); AI_SetBit (ARMIO_DCD); #ifdef CONFIG_TANGO_MODEM } #endif /* * Select I/O for DTR and configure it as input. * An interrupt is used to detect a change of state of DTR. Falling edge * or rising edge is selected according to the state of DTR. */ #ifdef CONFIG_TANGO_MODEM if (AI_Tango_pinmux[1] & 0x80) { #endif *((volatile SYS_UWORD16 *) ASIC_CONFIG_REG) &= ~(1 << IO_DTR); AI_ConfigBitAsInput (ARMIO_DTR); uart->dtr_level = AI_ReadBit (ARMIO_DTR); if (uart->dtr_level) AI_SelectIOForIT (ARMIO_DTR, ARMIO_FALLING_EDGE); else AI_SelectIOForIT (ARMIO_DTR, ARMIO_RISING_EDGE); AI_UnmaskIT (ARMIO_MASKIT_GPIO); #ifdef CONFIG_TANGO_MODEM } else uart->dtr_level = 0; #endif /* * Reset the 2 indexes of the circular buffer of 2 elements. * The circular buffer does not need to be initialized. */ uart->index_it = 0; uart->index_hisr = 0; #elif (CHIPSET == 12) /* * DCD and DTR are directly handled by Calypso+. * Force DCD pin to HIGH */ WRITE_UART_REGISTER (uart, MCR, READ_UART_REGISTER(uart, MCR) & ~MDCD); /* * Read the state of DTR (DTR on RS232, DSR on chipset). */ status = READ_UART_REGISTER (uart, MSR); if (status & MDSR) uart->dtr_level = 0; else uart->dtr_level = 1; /* * Reset the 2 indexes of the circular buffer of 2 elements. * The circular buffer does not need to be initialized. */ uart->index_it = 0; uart->index_hisr = 0; #endif /* BOARD == 8, 9, 40 or 41, CHIPSET == 12 */ /* * Unmask RX interrupt and the modem status interrupt. */ WRITE_UART_REGISTER (uart, IER, ERBI | EDSSI); #if (CHIPSET == 12) /* * Unmask DSR interrupt in order to detect a change of state of DTR. */ ENABLE_DSR_INTERRUPT (uart); #endif return (FD_OK); } /******************************************************************************* * * UAF_Enable * * Purpose : The functionalities of the UART driver are disabled or enabled. * In the deactivated state, all information about the communication * parameters should be stored and recalled if the driver is again * enabled. When the driver is enabled the RX and TX buffers are * cleared. * * Arguments: In : uartNo: Used UART. * : enable: 1: enable the driver * 0: disable the driver * Out: none * * Returns : FD_OK : Successful operation. * FD_NOT_SUPPORTED: Wrong UART number. * FD_INTERNAL_ERR : Internal problem with the hardware. * ******************************************************************************/ T_FDRET UAF_Enable (T_fd_UartId uartNo, SYS_BOOL enable) { t_uart *uart; /* * Check UART number. * A return is used to simplify the code. * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware * flow control is not supported. * DCD and DTR are not supported on UART Irda on C & D-Sample. * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample. */ if (uartNo != UAF_UART_1) return (FD_NOT_SUPPORTED); /* * There is no case where FD_INTERNAL_ERR may be returned. */ uart = &uart_parameters; if (enable) { uart->rx_stopped_by_driver = 0; ENABLE_DRIVER (uart); start_receiver (uart); } else { DISABLE_DRIVER (uart); stop_receiver (uart); uart->tx_in = &(uart->tx_buffer[0]); uart->rx_in = &(uart->rx_buffer[0]); uart->tx_out = uart->tx_in; uart->rx_out = uart->rx_in; } return (FD_OK); } /******************************************************************************* * * UAF_SetComPar * * Purpose : Sets up the communication parameters: baud rate, bits per * character, number of stop bits, parity. * * Arguments: In : uartNo : Used UART. * baudrate: Used baud rate. * bpc : Used bits per character. * sb : Used stop bits. * parity : Used parity. * Out: none * * Returns : FD_OK : Successful operation. * FD_NOT_SUPPORTED: The specified parameters don't fit to the * capabilities of the UART or wrong UART number. * FD_INTERNAL_ERR : Internal problem with the hardware. * ******************************************************************************/ T_FDRET UAF_SetComPar (T_fd_UartId uartNo, T_baudrate baudrate, T_bitsPerCharacter bpc, T_stopBits sb, T_parity parity) { t_uart *uart; volatile SYS_UWORD8 mcr_value; volatile SYS_UWORD8 status; /* * Check UART number. * A return is used to simplify the code. * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware * flow control is not supported. * DCD and DTR are not supported on UART Irda on C & D-Sample. * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample. */ if (uartNo != UAF_UART_1) return (FD_NOT_SUPPORTED); /* * There is no case where FD_INTERNAL_ERR may be returned. * pa_space is not supported. Some baudrates are not supported too. * A return is used to simplify the code. */ if ((!baudrate_value[baudrate]) || (parity == pa_space)) return (FD_NOT_SUPPORTED); uart = &uart_parameters; /* * Mask all interrupts causes and disable sleep mode and low power mode. */ WRITE_UART_REGISTER (uart, IER, 0x00); #ifdef CONFIG_TANGO_MODEM if (AI_Tango_pinmux[1] & 0x80) AI_MaskIT (ARMIO_MASKIT_GPIO); #elif UARTFAX_CLASSIC_DTR_DCD AI_MaskIT (ARMIO_MASKIT_GPIO); #elif (CHIPSET == 12) DISABLE_DSR_INTERRUPT (uart); #endif /* * Reset UART mode configuration. */ WRITE_UART_REGISTER (uart, MDR1, RESET_DEFAULT_STATE | IR_SLEEP_DISABLED | SIR_TX_WITHOUT_ACREG2 | FRAME_LENGTH_METHOD); /* * FIFO configuration. * EFR[4] = 1 to allow to program FCR[5:4] and MCR[7:5]. */ WRITE_UART_REGISTER (uart, LCR, 0xBF); SET_BIT (uart, EFR, ENHANCED_FEATURE_BIT); /* * Select the word length, the number of stop bits , the parity and set * LCR[7] (DLAB) to allow to program FCR, DLL and DLM. */ uart->baudrate = baudrate_value[baudrate]; uart->autobauding = (baudrate == FD_BAUD_AUTO); /* if autobauding enable trigger */ uart->bits_per_char = 1; /* Start bit. */ mcr_value = DLAB; if (bpc == bpc_7) { mcr_value |= WLS_7; uart->bits_per_char += 7; } else { mcr_value |= WLS_8; uart->bits_per_char += 8; } if (sb == sb_2) { mcr_value |= STB; uart->bits_per_char += 2; } else uart->bits_per_char += 1; switch (parity) { case pa_even: mcr_value |= (PEN | EPS); uart->bits_per_char += 1; break; case pa_odd: mcr_value |= PEN; uart->bits_per_char += 1; break; default: /* * There is nothing to do. */ break; } WRITE_UART_REGISTER (uart, LCR, mcr_value); /* * Program the trigger levels. * MCR[6] must be set to 1. */ SET_BIT (uart, MCR, TCR_TLR_BIT); WRITE_UART_REGISTER (uart, TCR, 0x0F); WRITE_UART_REGISTER (uart, TLR, RX_FIFO_TRIGGER_LEVEL); RESET_BIT (uart, MCR, TCR_TLR_BIT); /* * Force the generation of THR_IT on TX FIFO empty: SCR[3] = 1. */ WRITE_UART_REGISTER ( uart, SCR, READ_UART_REGISTER (uart, SCR) | TX_EMPTY_CTL_IT); /* * Program the FIFO control register. Bit 0 must be set when other FCR bits * are written to or they are not programmed. * FCR is a write-only register. It will not be modified. */ WRITE_UART_REGISTER (uart, FCR, FIFO_ENABLE | RX_FIFO_RESET | /* self cleared */ TX_FIFO_RESET); /* self cleared */ /* * Program the baud generator. */ WRITE_UART_REGISTER (uart, DLL, dll[baudrate]); WRITE_UART_REGISTER (uart, DLM, dlh[baudrate]); /* * Reset LCR[7] (DLAB) to have access to the RBR, THR and IER registers. */ WRITE_UART_REGISTER (uart, LCR, READ_UART_REGISTER (uart, LCR) & ~DLAB); /* * Select UART mode. */ WRITE_UART_REGISTER (uart, MDR1, ((baudrate==FD_BAUD_AUTO)? UART_MODE_AUTOBAUDING: UART_MODE) | IR_SLEEP_DISABLED | SIR_TX_WITHOUT_ACREG2 | FRAME_LENGTH_METHOD); /* * Read the state of RTS (RTS on RS232, CTS on chipset). */ status = READ_UART_REGISTER (uart, MSR); if (status & MCTS) uart->rts_level = 0; else uart->rts_level = 1; #if UARTFAX_CLASSIC_DTR_DCD /* * Read the state of DTR and select the edge. */ #ifdef CONFIG_TANGO_MODEM if (AI_Tango_pinmux[1] & 0x80) { #endif uart->dtr_level = AI_ReadBit (ARMIO_DTR); if (uart->dtr_level) AI_SelectIOForIT (ARMIO_DTR, ARMIO_FALLING_EDGE); else AI_SelectIOForIT (ARMIO_DTR, ARMIO_RISING_EDGE); AI_UnmaskIT (ARMIO_MASKIT_GPIO); #ifdef CONFIG_TANGO_MODEM } else uart->dtr_level = 0; #endif #elif (CHIPSET == 12) /* * Read the state of DTR - No need to reload MSR register since its value * is still stored in the "status" local variable. */ if (status & MDSR) uart->dtr_level = 0; else uart->dtr_level = 1; #endif #if ((CHIPSET == 5) || (CHIPSET == 6)) /* * Unmask RX and TX interrupts and the modem status interrupt. */ WRITE_UART_REGISTER (uart, IER, ERBI | ETBEI | EDSSI); #elif (CHIPSET == 12) /* * Unmask RX and TX interrupts and the modem status interrupt... */ WRITE_UART_REGISTER (uart, IER, ERBI | ETBEI | EDSSI); /* * ... Then, unmask DSR interrupt... */ ENABLE_DSR_INTERRUPT (uart); /* * ... And finally allow sleep mode. */ /* BELOW LINES WERE COMMENTED TO DISABLE SLEEP MODE IN DRIVER */ /* WRITE_UART_REGISTER (uart, IER, READ_UART_REGISTER (uart, IER) | IER_SLEEP); */ #else /* * Unmask RX and TX interrupts and the modem status interrupt * and allow sleep mode. */ /* BELOW LINES WERE COMMENTED TO DISABLE SLEEP MODE IN DRIVER */ /* WRITE_UART_REGISTER (uart, IER, ERBI | ETBEI | EDSSI | IER_SLEEP);*/ WRITE_UART_REGISTER (uart, IER, ERBI | ETBEI | EDSSI); #endif return (FD_OK); } /******************************************************************************* * * UAF_SetBuffer * * Purpose : Sets up the size of the circular buffers to be used in the UART * driver. This function may be called only if the UART is disabled * with UAF_Enable. * * Arguments: In : uartNo : Used UART. * bufSize : Specifies the size of the circular buffer. * rxThreshold: Amount of received bytes that leads to a call * to suspended read-out function which is passed * to the function UAF_ReadData. * txThreshold: Amount of bytes in the TX buffer to call the * suspended write-in function which is passed to * the function UAF_WriteData * Out: none * * Returns : FD_OK : Successful operation. * FD_NOT_SUPPORTED: bufSize exceeds the maximal possible * capabilities of the driver or the threshold * values don't correspond to the bufSize or * wrong UART number. * FD_INTERNAL_ERR : Internal problem with the hardware or the * function has been called while the UART is * enabled. * ******************************************************************************/ T_FDRET UAF_SetBuffer (T_fd_UartId uartNo, SYS_UWORD16 bufSize, SYS_UWORD16 rxThreshold, SYS_UWORD16 txThreshold) { T_FDRET result; t_uart *uart; /* * Check UART number. * A return is used to simplify the code. * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware * flow control is not supported. * DCD and DTR are not supported on UART Irda on C & D-Sample. * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample. */ if (uartNo != UAF_UART_1) return (FD_NOT_SUPPORTED); if ((bufSize > FD_MAX_BUFFER_SIZE) || (rxThreshold > FD_MAX_BUFFER_SIZE) || (txThreshold > FD_MAX_BUFFER_SIZE)) result = FD_NOT_SUPPORTED; else { uart = &uart_parameters; if (!DRIVER_DISABLED (uart)) result = FD_INTERNAL_ERR; else if (RX_HIGH_WATERMARK (bufSize) < RX_LOW_WATERMARK (bufSize)) result = FD_NOT_SUPPORTED; else { uart->buffer_size = bufSize; uart->rx_threshold_level = rxThreshold; uart->tx_threshold_level = txThreshold; result = FD_OK; } } return (result); } /******************************************************************************* * * UAF_SetFlowCtrl * * Purpose : Changes the flow control mode of the UART driver. * If a flow control is activated, DTR is activated or XOFF is sent * if the RX buffer is not able to store the received characters else * DTR is deactivated or XON is sent. * * Arguments: In : uartNo: Used UART. * fcMode: flow control mode (none, DTR/DSR, RTS/CTS, XON/XOFF). * XON : ASCII code of the XON character. * XOFF : ASCII code of the XOFF character. * Out: none * * Returns : FD_OK : Successful operation. * FD_NOT_SUPPORTED: The flow control mode is not supported or wrong * UART number. * FD_INTERNAL_ERR : Internal problem with the hardware. * ******************************************************************************/ T_FDRET UAF_SetFlowCtrl (T_fd_UartId uartNo, T_flowCtrlMode fcMode, SYS_UWORD8 XON, SYS_UWORD8 XOFF) { T_FDRET result; t_uart *uart; /* * Check UART number. * A return is used to simplify the code. * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware * flow control is not supported. * DCD and DTR are not supported on UART Irda on C & D-Sample. * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample. */ if (uartNo != UAF_UART_1) return (FD_NOT_SUPPORTED); /* * There is no case where FD_INTERNAL_ERR may be returned. * The DTR/DSR protocol is not supported. */ if (fcMode == fc_dtr) result = FD_NOT_SUPPORTED; else { uart = &uart_parameters; uart->tx_stopped_by_driver = 0; uart->xon_character = XON; uart->xoff_character = XOFF; uart->flow_control_mode = fcMode; #if ((CHIPSET != 5) && (CHIPSET != 6)) /* * Disable sleep mode. */ WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP); #endif WRITE_UART_REGISTER ( uart, MCR, READ_UART_REGISTER (uart, MCR) | MRTS); #if ((CHIPSET != 5) && (CHIPSET != 6)) /* * Re-enable sleep mode. */ /* BELOW LINES WERE COMMENTED TO DISABLE SLEEP MODE IN DRIVER */ /* WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) | IER_SLEEP); */ #endif /* * Openmoko made the change of enabling hardware assisted CTS * flow control in the UART when RTS/CTS flow control is used - * it is a change which we have retained in FreeCalypso - * but they forgot to turn this hw mode off if RTS/CTS flow control * is deselected at the application level. We (FreeCalypso) * are now fixing the latter defect ourselves. */ if (fcMode == fc_rts) { /* begin Openmoko change */ SYS_UWORD8 oldValue; oldValue = READ_UART_REGISTER (uart, LCR); // LCR value to allow acces to EFR WRITE_UART_REGISTER (uart, LCR, 0xBF); // enable hardware assisted CTS SET_BIT (uart, EFR, AUTO_CTS_BIT); WRITE_UART_REGISTER (uart, LCR, oldValue); /* end Openmoko change */ if (uart->rts_level) uart->tx_stopped_by_driver = 1; } else { /* FreeCalypso addition: turn off OM-added Auto-CTS */ SYS_UWORD8 oldValue; oldValue = READ_UART_REGISTER (uart, LCR); // LCR value to allow acces to EFR WRITE_UART_REGISTER (uart, LCR, 0xBF); // disable hardware assisted CTS RESET_BIT (uart, EFR, AUTO_CTS_BIT); WRITE_UART_REGISTER (uart, LCR, oldValue); } /* * If the high watermark is reached, RTS is activated or XOFF is sent * according to the flow control mode. Else, RTS is deactivated or XON * is sent. */ if (fcMode != fc_none) { if (get_bytes_in_rx_buffer (uart) >= RX_HIGH_WATERMARK ( uart->buffer_size)) { uart->rx_stopped_by_driver = 1; stop_receiver (uart); } else if (!DRIVER_DISABLED (uart)) { uart->rx_stopped_by_driver = 0; start_receiver (uart); } } else { uart->rx_stopped_by_driver = 0; uart->tx_stopped_by_driver = 0; } result = FD_OK; } return (result); } /******************************************************************************* * * UAF_SetEscape * * Purpose : To return to the command mode at the ACI while a data connection * is established, an escape sequence has to be detected. * To distinguish between user data and the escape sequence a * defined guard period is necessary before and after this sequence. * * Arguments: In: uartNo : Used UART. * escChar : ASCII character which could appear three times * as an escape sequence. * guardPeriod: Denotes the minimal duration of the rest before * the first and after the last character of the * escape sequence, and the maximal receiving * duration of the whole escape string. This value * is expressed in ms. * Out: none * * Returns : FD_OK : Successful operation. * FD_NOT_SUPPORTED: Wrong UART number. * FD_INTERNAL_ERR : Internal problem with the hardware. * ******************************************************************************/ T_FDRET UAF_SetEscape (T_fd_UartId uartNo, SYS_UWORD8 escChar, SYS_UWORD16 guardPeriod) { t_uart *uart; /* * Check UART number. * A return is used to simplify the code. * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware * flow control is not supported. * DCD and DTR are not supported on UART Irda on C & D-Sample. * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample. */ if (uartNo != UAF_UART_1) return (FD_NOT_SUPPORTED); /* * There is no case where FD_INTERNAL_ERR may be returned. */ uart = &uart_parameters; uart->esc_seq_modified = 1; uart->esc_seq_character = escChar; uart->guard_period = CONVERT_TIME_IN_TDMA ((UNSIGNED) guardPeriod); uart->esc_seq_modified = 0; /* Set to 0 by the RX interrupt handler. */ return (FD_OK); } /******************************************************************************* * * UAF_InpAvail * * Purpose : Returns the number of characters available in the RX buffer of the * driver. If the driver is disabled the function returns 0. * * Arguments: In : uartNo: Used UART. * Out: none * * Returns : >= 0 : The returned value is the amount of data in the * RX buffer. * FD_NOT_SUPPORTED: Wrong UART number. * FD_NOT_READY : The function is called while the callback of the * readOutFunc function is activated and still not * terminated. * FD_INTERNAL_ERR : Internal problem with the hardware. * ******************************************************************************/ T_FDRET UAF_InpAvail (T_fd_UartId uartNo) { T_FDRET result; t_uart *uart; SYS_UWORD16 bytes_read; SYS_UWORD16 bytes_in_rx_buffer; /* * Check UART number. * A return is used to simplify the code. * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware * flow control is not supported. * DCD and DTR are not supported on UART Irda on C & D-Sample. * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample. */ if (uartNo != UAF_UART_1) return (FD_NOT_SUPPORTED); /* * There is no case where FD_INTERNAL_ERR may be returned. */ uart = &uart_parameters; if (uart->rd_call_setup == rm_notDefined) result = FD_NOT_READY; else if (DRIVER_DISABLED (uart)) result = 0; else { bytes_in_rx_buffer = get_bytes_in_rx_buffer (uart); /* * Update reading pointer of the RX buffer if a callback from LISR * has been done. */ if (uart->rd_call_from_hisr_in_progress) { bytes_read = uart->rd_size_before_call[0] - uart->rd_size_after_call[0] + uart->rd_size_before_call[1] - uart->rd_size_after_call[1]; uart->rx_out += bytes_read; if (uart->rx_out >= &(uart->rx_buffer[0]) + uart->buffer_size + 1) uart->rx_out = uart->rx_out - uart->buffer_size - 1; /* * Check if the low watermark is reached to enable the receiver. */ bytes_in_rx_buffer = get_bytes_in_rx_buffer (uart); if ((uart->flow_control_mode != fc_none) && (bytes_in_rx_buffer <= RX_LOW_WATERMARK (uart->buffer_size))) { if ((!uart->rx_stopped_by_application) && uart->rx_stopped_by_driver) start_receiver (uart); uart->rx_stopped_by_driver = 0; } uart->rd_call_from_hisr_in_progress = 0; } result = (T_FDRET) bytes_in_rx_buffer; } return (result); } /******************************************************************************* * * UAF_OutpAvail * * Purpose : Returns the number of free characters in TX buffer of the driver. * If the driver is disabled the function returns 0. * * Arguments: In : uartNo: Used UART. * Out: none * * Returns : >= 0 : The returned value is the amount of data in the * TX buffer. * FD_NOT_SUPPORTED: Wrong UART number. * FD_NOT_READY : The function is called while the callback of the * writeInFunc function is activated and still not * terminated. * FD_INTERNAL_ERR : Internal problem with the hardware. * ******************************************************************************/ T_FDRET UAF_OutpAvail (T_fd_UartId uartNo) { T_FDRET result; t_uart *uart; SYS_UWORD16 bytes_written; /* * Check UART number. * A return is used to simplify the code. * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware * flow control is not supported. * DCD and DTR are not supported on UART Irda on C & D-Sample. * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample. */ if (uartNo != UAF_UART_1) return (FD_NOT_SUPPORTED); /* * There is no case where FD_INTERNAL_ERR may be returned. */ uart = &uart_parameters; if (uart->wr_call_setup == rm_notDefined) result = FD_NOT_READY; else if (DRIVER_DISABLED (uart)) result = 0; else { /* * Update reading pointer of the TX buffer if a callback from LISR * has been done. */ if (uart->wr_call_from_hisr_in_progress) { bytes_written = uart->wr_size_before_call[0] - uart->wr_size_after_call[0] + uart->wr_size_before_call[1] - uart->wr_size_after_call[1]; uart->tx_in += bytes_written; if (uart->tx_in >= &(uart->tx_buffer[0]) + uart->buffer_size + 1) uart->tx_in = uart->tx_in - uart->buffer_size - 1; uart->wr_call_from_hisr_in_progress = 0; /* * if the TX FIFO is empty, unmask TX empty interrupt. */ if (!uart->tx_stopped_by_driver && (READ_UART_REGISTER (uart, LSR) & THRE)) { #if ((CHIPSET != 5) && (CHIPSET != 6)) /* * Disable sleep mode. */ WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP); #endif /* * Unmask Tx interrupt. */ WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) | ETBEI); } } result = (T_FDRET) (uart->buffer_size - get_bytes_in_tx_buffer (uart)); } return (result); } /******************************************************************************* * * UAF_EnterSleep * * Purpose : Checks if UART is ready to enter Deep Sleep. If ready, enables * wake-up interrupt. * * Arguments: In : uartNo: Used UART. * Out: none * * Returns : 0 : Deep Sleep is not possible. * >= 1 : Deep Sleep is possible. * FD_NOT_SUPPORTED: Wrong UART number. * * Warning: Parameters are not verified. * ******************************************************************************/ T_FDRET UAF_EnterSleep (T_fd_UartId uartNo) { t_uart *uart; SYS_BOOL deep_sleep; volatile SYS_UWORD8 status; /* * Check UART number. * A return is used to simplify the code. * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware * flow control is not supported. * DCD and DTR are not supported on UART Irda on C & D-Sample. * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample. */ if (uartNo != UAF_UART_1) return (FD_NOT_SUPPORTED); uart = &uart_parameters; deep_sleep = 0; /* * Check if RX & TX FIFOs are both empty */ status = READ_UART_REGISTER (uart, LSR); if (!(status & DR) && (status & TEMT)) { #if ((CHIPSET != 5) && (CHIPSET != 6)) /* * Disable sleep mode. */ WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP); #endif #if (CHIPSET == 12) /* * Mask DSR interrupt. */ DISABLE_DSR_INTERRUPT (uart); #endif /* * Mask RX, TX and the modem status interrupts. */ WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) & ~(ERBI | ETBEI | EDSSI)); /* * Enable the wake-up interrupt. */ ENABLE_WAKEUP_INTERRUPT (uart); deep_sleep = 1; } return (deep_sleep); } /******************************************************************************* * * UAF_WakeUp * * Purpose : Wakes up UART after Deep Sleep. * * Arguments: In : uartNo: Used UART. * Out: none * * Returns : FD_OK : Successful operation. * FD_NOT_SUPPORTED: Wrong UART number. * * Warning: Parameters are not verified. * ******************************************************************************/ T_FDRET UAF_WakeUp (T_fd_UartId uartNo) { t_uart *uart; /* * Check UART number. * A return is used to simplify the code. * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware * flow control is not supported. * DCD and DTR are not supported on UART Irda on C & D-Sample. * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample. */ if (uartNo != UAF_UART_1) return (FD_NOT_SUPPORTED); uart = &uart_parameters; /* * Disable the wake-up interrupt. */ DISABLE_WAKEUP_INTERRUPT (uart); /* * Unmask RX and modem status interrupts. */ WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) | (ERBI | EDSSI)); #if (CHIPSET == 12) /* * Unmask DSR interrupt. */ ENABLE_DSR_INTERRUPT (uart); #endif #if ((CHIPSET != 5) && (CHIPSET != 6)) /* * Allow sleep mode. */ /* BELOW LINES WERE COMMENTED TO DISABLE SLEEP MODE IN DRIVER */ /* WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) | IER_SLEEP); */ #endif return (FD_OK); } /******************************************************************************* * * UAF_ReadData * * Purpose : To read the received characters out of the RX buffer the address * of a function is passed. If characters are available, the driver * calls this function and pass the address and the amount of * readable characters. Because the RX buffer is circular, the * callback function may be called with more than one address of * buffer fragment. * The readOutFunc function modifies the contents of the size array * to return the driver the number of processed characters. Each * array entry is decremented by the number of bytes read in the * fragment. * If the UAF_ReadData is called while the RX buffer is empty, it * depends on the suspend parameter to suspend the call-back or to * leave without any operation. In the case of suspension, the * return value of UAF_ReadData is UAF_SUSPENDED. A delayed call-back * will be performed if: * - the RX buffer reachs the adjusted threshold (rxThreshold of * UAF_SetBuffer), * - the state of a V.24 input line has changed, * - a break is detected, * - an escape sequence is detected. * If no suspension is necessary the function returns the number of * processed bytes. * * Arguments: In : uartNo : Used UART. * suspend : mode of suspension in case of RX buffer empty. * readOutFunc: Callback function. * cldFromIrq: The driver sets this parameter to 1 * if the callback function is called * from an interrupt service routine. * reInstall : The call-back function sets this * parameter to rm_reInstall if the * driver must call again the callback * function when the RX threshold level * is reached. Else it will be set to * rm_noInstall. Before to call the * readOutFunc function this parameter * is set to rm_notDefined. * nsource : Informed the callback function about * the number of fragments which are * ready to copy from the circular RX * buffer. * source : Array which contains the addresses * of the fragments. * size : Array which contains the sizes of * each fragments. * state : The state parameter is the status * of the V.24 lines and the break / * escape detection. The state * parameter is described in the * specification of UAF_GetLineState. * Out: none * * Returns : >= 0 : Succesful operation. Amount of processed bytes. * FD_NOT_SUPPORTED: Wrong UART number. * FD_SUSPENDED : The callback is suspended until the buffer or * state condition changed. * FD_NOT_READY : The function is called while the callback is * activated and still not terminated. * FD_INTERNAL_ERR : Internal problems with the hardware. * ******************************************************************************/ T_FDRET UAF_ReadData (T_fd_UartId uartNo, T_suspendMode suspend, void (readOutFunc (SYS_BOOL cldFromIrq, T_reInstMode *reInstall, SYS_UWORD8 nsource, SYS_UWORD8 *source[], SYS_UWORD16 size[], SYS_UWORD32 state))) { T_FDRET result; t_uart *uart; SYS_UWORD16 bytes_read; SYS_UWORD16 bytes_in_rx_buffer; /* * Check UART number. * A return is used to simplify the code. * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware * flow control is not supported. * DCD and DTR are not supported on UART Irda on C & D-Sample. * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample. */ if (uartNo != UAF_UART_1) return (FD_NOT_SUPPORTED); /* * There is no case where FD_INTERNAL_ERR may be returned. */ uart = &uart_parameters; if (uart->rd_call_setup == rm_notDefined) result = FD_NOT_READY; else if (get_bytes_in_rx_buffer (uart) || uart->esc_seq_received) { uart->readOutFunc = readOutFunc; update_reading_callback (uart, 0); /* 0: call from application. */ bytes_read = uart->rd_size_before_call[0] - uart->rd_size_after_call[0] + uart->rd_size_before_call[1] - uart->rd_size_after_call[1]; uart->rx_out += bytes_read; if (uart->rx_out >= &(uart->rx_buffer[0]) + uart->buffer_size + 1) uart->rx_out = uart->rx_out - uart->buffer_size - 1; /* * Check if the low watermark is reached to enable the receiver. */ if ((uart->flow_control_mode != fc_none) && (get_bytes_in_rx_buffer (uart) <= RX_LOW_WATERMARK ( uart->buffer_size))) { if ((!uart->rx_stopped_by_application) && uart->rx_stopped_by_driver && (!uart->rx_stopped_by_lisr)) start_receiver (uart); uart->rx_stopped_by_driver = 0; } uart->esc_seq_received = 0; result = (T_FDRET) bytes_read; } else if (suspend == sm_suspend) { uart->readOutFunc = readOutFunc; uart->reading_suspended = 1; result = FD_SUSPENDED; } else { /* * The previous callback function is deinstalled. */ uart->rd_call_setup = rm_noInstall; uart->reading_suspended = 0; result = 0; /* 0 byte read. */ } return (result); } /******************************************************************************* * * UAF_WriteData * * Purpose : To write characters into the TX buffer the address of a function * is passed. If free space is available in the buffer, the driver * calls this function and passes the destination address and the * amount of space. Because the TX buffer is circular, the callback * function may be called with more than one address of buffer * fragment. * The writeInFunc function modifies the contents of the size array * to return the driver the number of processed bytes. Each array * entry is decremented by the number of bytes written in this * fragment. * If the UAF_WriteData function is called while the TX buffer is * full, it depends on the suspend parameter to suspend the * call-back or to leave this function without any operation. In the * case of suspension the returned value of the UAF_WriteData is * UAF_SUSPENDED. A delayed call-back will be performed if the TX * buffer reaches the adjusted threshold (txThreshold of * UAF_SetBuffer). If no suspension is necessary the function returns * the number of processed bytes. * * Arguments: In : uartNo : Used UART. * suspend : mode of suspension in case of TX buffer empty. * writeInFunc: Callback function. * cldFromIrq: The driver sets this parameter to 1 * if the call-back function is called * from an interrupt service routine. * reInstall : The callback function sets this * parameter to rm_reInstall if the * driver must call again the callback * function when the TX threshold level * is reached. Else it will be set to * rm_noInstall. Before to call the * writeInFunc function this parameter * is set to rm_notDefined. * ndest : Informed the callback function about * the number of fragments which are * available in the TX buffer. * dest : Array which contains the addresses * of the fragments. * size : Array which contains the sizes of * each fragments. * Out: none * * Returns : >= 0 : Succesful operation. Amount of processed bytes. * FD_NOT_SUPPORTED: Wrong UART number. * FD_SUSPENDED : The callback is suspended until the buffer * condition changed. * FD_NOT_READY : The function is called while the callback is * activated and still not terminated. * FD_INTERNAL_ERR : Internal problems with the hardware. * ******************************************************************************/ T_FDRET UAF_WriteData (T_fd_UartId uartNo, T_suspendMode suspend, void (writeInFunc (SYS_BOOL cldFromIrq, T_reInstMode *reInstall, SYS_UWORD8 ndest, SYS_UWORD8 *dest[], SYS_UWORD16 size[]))) { T_FDRET result; t_uart *uart; SYS_UWORD16 bytes_written; /* * Check UART number. * A return is used to simplify the code. * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware * flow control is not supported. * DCD and DTR are not supported on UART Irda on C & D-Sample. * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample. */ if (uartNo != UAF_UART_1) return (FD_NOT_SUPPORTED); /* * There is no case where FD_INTERNAL_ERR may be returned. */ uart = &uart_parameters; if (uart->wr_call_setup == rm_notDefined) result = FD_NOT_READY; else if ((!DRIVER_DISABLED (uart)) && (get_bytes_in_tx_buffer (uart) < uart->buffer_size)) { uart->writeInFunc = writeInFunc; update_writing_callback (uart, 0); /* 0: call from application. */ bytes_written = uart->wr_size_before_call[0] - uart->wr_size_after_call[0] + uart->wr_size_before_call[1] - uart->wr_size_after_call[1]; uart->tx_in += bytes_written; if (uart->tx_in >= &(uart->tx_buffer[0]) + uart->buffer_size + 1) uart->tx_in = uart->tx_in - uart->buffer_size - 1; /* If we have been stopped due to high RTS, we have to * wake up application processor by IRQ via IO1 -HW */ #ifdef CONFIG_TARGET_GTAMODEM if (uart->tx_stopped_by_driver) AI_SetBit(1); #elif defined(CONFIG_TANGO_MODEM) if (AI_Tango_pinmux[0] == 0x82 && uart->tx_stopped_by_driver) AI_SetBit(1); #endif /* * If: * - there is no break to send, * - the flow control is not activated, * unmask the TX empty interrupt to be able to send characters. */ if (!uart->break_to_send && !uart->tx_stopped_by_driver) { #if ((CHIPSET != 5) && (CHIPSET != 6)) /* * Disable sleep mode. */ WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP); #endif /* * Unmask Tx interrupt. */ WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) | ETBEI); } result = (T_FDRET) bytes_written; } else if (suspend == sm_suspend) { uart->writeInFunc = writeInFunc; uart->writing_suspended = 1; result = FD_SUSPENDED; } else { /* * The previous callback function is deinstalled. */ uart->wr_call_setup = rm_noInstall; uart->writing_suspended = 0; result = 0; } return (result); } /******************************************************************************* * * UAF_StopRec * * Purpose : If a flow control mode is set, this function tells the terminal * equipment that no more data can be received. * XON/XOFF: XOFF is sent. * DTR/DSR : DTR is desactivated. * RTS/CTS : RTS is deactivated. * * Arguments: In : uartNo: Used UART. * Out: none * * Returns : FD_OK : Successful operation. * FD_NOT_SUPPORTED: Wrong UART number. * FD_INTERNAL_ERR : Internal problem with the hardware. * ******************************************************************************/ T_FDRET UAF_StopRec (T_fd_UartId uartNo) { t_uart *uart; /* * Check UART number. * A return is used to simplify the code. * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware * flow control is not supported. * DCD and DTR are not supported on UART Irda on C & D-Sample. * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample. */ if (uartNo != UAF_UART_1) return (FD_NOT_SUPPORTED); /* * There is no case where FD_INTERNAL_ERR may be returned. */ uart = &uart_parameters; if (uart->flow_control_mode != fc_none) stop_receiver (uart); uart->rx_stopped_by_application = 1; return (FD_OK); } /******************************************************************************* * * UAF_StartRec * * Purpose : If a flow control mode is set, this function tells the terminal * equipment that the receiver is again able to receive more data. * If the buffer has already reached the high water mark the driver * sends the signal only if the buffer drains to a low water mark. * XON/XOFF: XON is sent. * DTR/DSR : DTR is activated. * RTS/CTS : RTS is activated. * * Arguments: In : uartNo: Used UART. * Out: none * * Returns : FD_OK : Successful operation. * FD_NOT_SUPPORTED: Wrong UART number. * FD_INTERNAL_ERR : Internal problem with the hardware. * ******************************************************************************/ T_FDRET UAF_StartRec (T_fd_UartId uartNo) { t_uart *uart; /* * Check UART number. * A return is used to simplify the code. * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware * flow control is not supported. * DCD and DTR are not supported on UART Irda on C & D-Sample. * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample. */ if (uartNo != UAF_UART_1) return (FD_NOT_SUPPORTED); /* * There is no case where FD_INTERNAL_ERR may be returned. */ uart = &uart_parameters; if ((uart->flow_control_mode != fc_none) && (!uart->rx_stopped_by_driver)) start_receiver (uart); uart->rx_stopped_by_application = 0; return (FD_OK); } /******************************************************************************* * * UAF_GetLineState * * Purpose : Returns the state of the V.24 lines, the flow control state and * the result of the break/escape detection process as a bit field. * * Arguments: In : uartNo: Used UART. * Out: state : State of the V.24 lines, the flow control state and * the result of the break/escape sequence detection * process as a bit field. * * Returns : FD_OK : Successful operation. * FD_NOT_SUPPORTED: Wrong UART number. * FD_NOT_READY : The function is called while the callback of * the readOutFunc function is activated and still * not terminated. * FD_INTERNAL_ERR : Internal problem with the hardware. * ******************************************************************************/ T_FDRET UAF_GetLineState (T_fd_UartId uartNo, SYS_UWORD32 *state) { T_FDRET result; t_uart *uart; /* * Check UART number. * A return is used to simplify the code. * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware * flow control is not supported. * DCD and DTR are not supported on UART Irda on C & D-Sample. * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample. */ if (uartNo != UAF_UART_1) return (FD_NOT_SUPPORTED); /* * There is no case where FD_INTERNAL_ERR may be returned. * Signals not supported are reported as 0. */ uart = &uart_parameters; if (uart->rd_call_setup == rm_notDefined) result = FD_NOT_READY; else { /* * The field state_2 is used when state_1 is set to 0 to avoid to * lose events detected in the RX interrupt handler. * Fields BRK and BRKLEN are set when a break is detected. * The field ESC is set when an escape sequence is detected. */ *state = uart->state_2; uart->state_2 = 0; uart->state = &(uart->state_2); *state |= uart->state_1; uart->state_1 = 0; uart->state = &(uart->state_1); *state |= ((((SYS_UWORD32) uart->rts_level) << RTS) | #if (UARTFAX_CLASSIC_DTR_DCD || (CHIPSET == 12)) (((SYS_UWORD32) uart->dtr_level) << DTR) | #endif (((SYS_UWORD32) (uart->tx_stopped_by_application | uart->tx_stopped_by_driver)) << TXSTP) | (((SYS_UWORD32) (uart->rx_stopped_by_application | uart->rx_stopped_by_driver)) << RXSTP) | (((SYS_UWORD32) (uart->buffer_size - get_bytes_in_rx_buffer (uart))) << RXBLEV)); /* * Fields SA, SB and X are set according to the flow control: * * None RTS/CTS XON/XOFF * SA DTR DTR DTR * SB RTS 0 RTS * X 0 RTS XON:0 XOFF:1 (transmitter) * * DTR is supported on C, D & E-Sample. */ #if (UARTFAX_CLASSIC_DTR_DCD || (CHIPSET == 12)) *state |= (((SYS_UWORD32) uart->dtr_level) << SA); #endif if (uart->flow_control_mode != fc_rts) *state |= (((SYS_UWORD32) uart->rts_level) << SB); if (uart->flow_control_mode == fc_rts) *state |= (((SYS_UWORD32) uart->rts_level) << X); else if ((uart->flow_control_mode == fc_xoff) && (uart->tx_stopped_by_application || uart->tx_stopped_by_driver)) *state |= (1 << X); result = FD_OK; } return (result); } /******************************************************************************* * * UAF_SetLineState * * Purpose : Sets the states of the V.24 status lines according to the bit * field of the parameter state. * * Arguments: In : uartNo: Used UART. * state : Bit field. Only the signals which are marked with * the 'set' access can be used to change the state of * the signal. * mask : Bit field with the same structure as state. Each bit * in state corresponds to a bit in mask. Settabled * bits marked by a 1 are manipulated by the driver. * Out: none * * Returns : FD_OK : Successful operation. * FD_NOT_SUPPORTED: Wrong UART number. * FD_INTERNAL_ERR : Internal problem with the hardware. * ******************************************************************************/ T_FDRET UAF_SetLineState (T_fd_UartId uartNo, SYS_UWORD32 state, SYS_UWORD32 mask) { t_uart *uart; UNSIGNED break_length; /* * Check UART number. * A return is used to simplify the code. * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware * flow control is not supported. * DCD and DTR are not supported on UART Irda on C & D-Sample. * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample. */ if (uartNo != UAF_UART_1) return (FD_NOT_SUPPORTED); uart = &uart_parameters; /* * There is no case where FD_INTERNAL_ERR may be returned. * DCD is supported on C, D & E-Sample. The SA field is not supported because * DSR is not supported on all platforms. */ #if (UARTFAX_CLASSIC_DTR_DCD || (CHIPSET == 12)) if (mask & (1 << SA)) #else if ((mask & (1 << SA)) || (mask & (1 << DCD))) #endif return (FD_NOT_SUPPORTED); /* Return used to simplify the code */ /* * Check if a break has to be sent. */ uart->break_length = (UNSIGNED) ((state >> BRKLEN) & 0xFF); if (state & (1 << BRK) && (mask & (1 << BRK))) { if (uart->break_length > FIFO_SIZE) return (FD_NOT_SUPPORTED); /* Return used to simplify the code */ else { uart->time_without_character = compute_break_time (uart->baudrate, uart->bits_per_char, 3); uart->break_to_send = 1; /* * If the TX FIFO is empty the break is send from this function * else the interrupt handler will send the break. */ if (READ_UART_REGISTER (uart, LSR) & TEMT) send_break(uart); } } #if ((CHIPSET != 5) && (CHIPSET != 6)) /* * Disable sleep mode. */ WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) & ~IER_SLEEP); #endif /* * The CTS field is ignored if the X bit in the mask is set. In this case * the X bit controls CTS. */ if (mask & (1 << CTS)) { if (uart->flow_control_mode != fc_rts) { /* * As the RTS/CTS flow control is not selected, the X bit does not * control CTS. CTS needs only to be activated or deactivated * according to the value of the CTS field. */ if (state & (1 << CTS)) WRITE_UART_REGISTER ( uart, MCR, READ_UART_REGISTER (uart, MCR) | MRTS); else WRITE_UART_REGISTER ( uart, MCR, READ_UART_REGISTER (uart, MCR) & ~MRTS); } else if (!(mask & (1 << X))) { /* * The RTS/CTS flow control is selected but the X bit in the mask * is null. Then the CTS bit controls CTS and the receiver must be * stopped or started according to the state of the CTS bit. * The receiver is started only if it was not stopped by the driver * and if it was stopped by the application. */ if (state & (1 << CTS)) { if (!uart->rx_stopped_by_application) { if (!uart->rx_stopped_by_driver) stop_receiver (uart); uart->rx_stopped_by_application = 1; } } else { if ((!uart->rx_stopped_by_driver) && uart->rx_stopped_by_application) start_receiver (uart); uart->rx_stopped_by_application = 0; } } } /* * The DCD field is ignored if the SB bit of the mask is set. */ #if (UARTFAX_CLASSIC_DTR_DCD || (CHIPSET == 12)) if (!(mask & (1 << SB)) && (mask & (1 << DCD))) { if (state & (1 << DCD)) { /* Turn on DCD */ #if (CHIPSET == 12) WRITE_UART_REGISTER (uart, MCR, READ_UART_REGISTER(uart, MCR) | MDCD); #elif defined(CONFIG_TANGO_MODEM) if (AI_Tango_pinmux[1] & 0x08) AI_ResetBit (ARMIO_DCD); #else AI_ResetBit (ARMIO_DCD); #endif } else { /* Turn off DCD */ #if (CHIPSET == 12) WRITE_UART_REGISTER (uart, MCR, READ_UART_REGISTER(uart, MCR) & ~MDCD); #elif defined(CONFIG_TANGO_MODEM) if (AI_Tango_pinmux[1] & 0x08) AI_SetBit (ARMIO_DCD); #else AI_SetBit (ARMIO_DCD); #endif } } #endif /* BOARD 8 or 9 or 40 or 41 or CHIPSET 12 */ /* * Signals are set according to fields SA, SB and X states and flow * control: * * None RTS/CTS XON/XOFF * SA 0 (ns) 0 (ns) 0 (ns) * SB DCD DCD DCD * X ignore CTS XON:0 XOFF:1 (receiver) * * ns: signal not supported. * DCD is supported on C, D & E-Sample. */ #if (UARTFAX_CLASSIC_DTR_DCD || (CHIPSET == 12)) if (mask & (1 << SB)) { if (state & (1 << SB)) { /* Turn on DCD */ #if (CHIPSET == 12) WRITE_UART_REGISTER (uart, MCR, READ_UART_REGISTER(uart, MCR) | MDCD); #elif defined(CONFIG_TANGO_MODEM) if (AI_Tango_pinmux[1] & 0x08) AI_ResetBit (ARMIO_DCD); #else AI_ResetBit (ARMIO_DCD); #endif } else { /* Turn off DCD */ #if (CHIPSET == 12) WRITE_UART_REGISTER (uart, MCR, READ_UART_REGISTER(uart, MCR) & ~MDCD); #elif defined(CONFIG_TANGO_MODEM) if (AI_Tango_pinmux[1] & 0x08) AI_SetBit (ARMIO_DCD); #else AI_SetBit (ARMIO_DCD); #endif } } #endif /* BOARD 8 or 9 or 40 or 41 or CHIPSET 12 */ #ifdef CONFIG_TANGO_MODEM if (mask & (1 << RI) && AI_Tango_pinmux[0] == 0x83) { if (state & (1 << RI)) { /* Turn on RI */ AI_ResetBit(1); } else { /* Turn off RI */ AI_SetBit(1); } } #endif /* Tango modem */ #ifdef CONFIG_TARGET_GTM900 if (mask & (1 << RI)) { if (state & (1 << RI)) { /* Turn on RI */ AI_ResetBit(0); } else { /* Turn off RI */ AI_SetBit(0); } } #endif /* GTM900 modem */ if ((mask & (1 << X)) && (uart->flow_control_mode != fc_none)) { if (state & (1 << X)) { if (!uart->rx_stopped_by_application) { if (!uart->rx_stopped_by_driver) stop_receiver (uart); uart->rx_stopped_by_application = 1; } } else { /* * The receiver is started only if it is not stopped by the driver * and if it is stopped by the application. */ if ((!uart->rx_stopped_by_driver) && uart->rx_stopped_by_application) start_receiver (uart); uart->rx_stopped_by_application = 0; } } #if ((CHIPSET != 5) && (CHIPSET != 6)) /* * Re-enable sleep mode. */ /* BELOW LINES WERE COMMENTED TO DISABLE SLEEP MODE IN DRIVER */ /* WRITE_UART_REGISTER ( uart, IER, READ_UART_REGISTER (uart, IER) | IER_SLEEP); */ #endif return (FD_OK); } /******************************************************************************* * * UAF_InterruptHandler * * Purpose : Interrupt handler. * * Arguments: In : uart_id : origin of interrupt * interrupt_status: source of interrupt * Out: none * * Returns : none * ******************************************************************************/ void UAF_InterruptHandler (T_fd_UartId uart_id, SYS_UWORD8 interrupt_status) { t_uart *uart; /* * uart_id is not used. */ uart = &uart_parameters; uart->current_time = NU_Retrieve_Clock (); /* * Causes of interrupt: * - trigger level reached, * - character time-out indication, * - transmitter holding register empty, * - modem status. */ switch (interrupt_status) { case RX_DATA: #if (UARTFAX_CLASSIC_DTR_DCD || (CHIPSET == 12)) uart->index_it = (uart->index_it + 1) & 0x01; /* 0 or 1 */ uart->dtr_change_detected[uart->index_it] = 0; uart->dtr_level_saved[uart->index_it] = uart->dtr_level; #endif read_rx_fifo (uart); // Disable Autobaud and lock baudrate upon first received character if (uart->autobauding != 0) { /* MSMSMSMS */ SYS_UWORD8 uasr; T_baudrate baudrate; T_bitsPerCharacter bpc; T_parity parity; WRITE_UART_REGISTER (uart, LCR, READ_UART_REGISTER (uart, LCR) | DLAB); uasr = READ_UART_REGISTER (uart, UASR); switch (uasr & 0x1F) { case 0x01: baudrate = FD_BAUD_115200; break; case 0x02: baudrate = FD_BAUD_57600; break; case 0x03: baudrate = FD_BAUD_38400; break; case 0x04: baudrate = FD_BAUD_28800; break; case 0x05: baudrate = FD_BAUD_19200; break; case 0x06: baudrate = FD_BAUD_14400; break; case 0x07: baudrate = FD_BAUD_9600; break; case 0x08: baudrate = FD_BAUD_4800; break; case 0x09: baudrate = FD_BAUD_2400; break; case 0x0A: baudrate = FD_BAUD_1200; break; default: /* no baudrate detected, abort for now */ return; } switch (uasr>>5 & 0x01) { case 0x00: bpc = bpc_7; break; case 0x01: bpc = bpc_8; break; } switch (uasr>>6 & 0x03) { case 0x00: parity = pa_none; break; case 0x01: parity = pa_space; break; case 0x02: parity = pa_even; break; case 0x03: parity = pa_odd; break; } UAF_SetComPar (UAF_UART_1, baudrate, bpc, sb_1, parity); uart->baudrate = baudrate_value[FD_BAUD_AUTO]; /* remember autobauding */ } break; case TX_EMPTY: fill_tx_fifo (uart); break; case MODEM_STATUS: check_v24_input_lines (uart); break; } } /******************************************************************************* * * UAF_CheckXEmpty * * Purpose : Checks the empty condition of the Transmitter. * * Arguments: In : uartNo: Used UART. * Out: none * * Returns : FD_OK : Empty condition OK. * FD_NOT_SUPPORTED: Wrong UART number. * FD_NOT_READY : Empty condition not OK. * FD_INTERNAL_ERR : Internal problem with the hardware. * ******************************************************************************/ T_FDRET UAF_CheckXEmpty (T_fd_UartId uartNo) { T_FDRET result; t_uart *uart; SYS_UWORD8 status; /* * Check UART number. * A return is used to simplify the code. * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware * flow control is not supported. * DCD and DTR are not supported on UART Irda on C & D-Sample. * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample. */ if (uartNo != UAF_UART_1) return (FD_NOT_SUPPORTED); /* * There is no case where FD_INTERNAL_ERR may be returned. */ result = FD_OK; uart = &uart_parameters; status = READ_UART_REGISTER (uart, LSR); /* * Checks if: * - the TX SW Buffer is empty, * - the TX HW FIFO is empty (THRE), * - the Transmitter Shift Register is empty (TEMT). */ if (!(TX_BUFFER_EMPTY (uart)) || !(status & THRE) || !(status & TEMT)) result = FD_NOT_READY; return (result); } #if UARTFAX_CLASSIC_DTR_DCD /******************************************************************************* * * UAF_DTRInterruptHandler * * Purpose : This function is only used on C & D-Sample. On this platform, the * DTR signal is controlled with an I/O. A change of state of this * signal is detected with an interrupt. This function is called when * this interrupt occurs. * * Arguments: In : none * Out: none * * Returns : none * ******************************************************************************/ void UAF_DTRInterruptHandler (void) { t_uart *uart; uart = &uart_parameters; /* * Read the state of DTR and change the edge to detect the next change * of DTR. */ uart->dtr_level = AI_ReadBit (ARMIO_DTR); if (uart->dtr_level) { AI_SelectIOForIT (ARMIO_DTR, ARMIO_FALLING_EDGE); if (uart->flow_control_mode != fc_dtr && uart->baudrate == baudrate_value[FD_BAUD_AUTO]) UAF_SetComPar (UAF_UART_1, FD_BAUD_AUTO, bpc_8, sb_1, pa_none); } else AI_SelectIOForIT (ARMIO_DTR, ARMIO_RISING_EDGE); /* * The reading callback function has to be called. But bytes received before * the change of state of DTR must be copied into the RX buffer before to * call it. */ if (READ_UART_REGISTER (uart, LSR) & DR) { /* If Rx FIFO is not empty */ /* * The Rx FIFO will be read to fill one of the two buffers and the Rx * HISR will be activated. */ uart->index_it = (uart->index_it + 1) & 0x01; /* 0 or 1 */ uart->dtr_change_detected[uart->index_it] = 1; uart->dtr_level_saved[uart->index_it] = uart->dtr_level; read_rx_fifo (uart); } else (void) NU_Activate_HISR (&(uart->v24_hisr_ctrl_block)); } #endif /* BOARD 8 or 9 or 40 or 41 */ #ifdef SERIAL_DYNAMIC_SWITCH /******************************************************************************* * * UAF_Exit * * Purpose : * * Arguments: In : uartNo: Used UART. * Out: none * * Returns : FD_OK : Successful operation. * FD_NOT_SUPPORTED: Wrong UART number. * FD_INTERNAL_ERR : Internal problem. * ******************************************************************************/ T_FDRET UAF_Exit (T_fd_UartId uartNo) { t_uart *uart; /* * Check UART number. * A return is used to simplify the code. * UART IrDA (UAF_UART_0) can't be used for F&D on Ulysse because hardware * flow control is not supported. * DCD and DTR are not supported on UART Irda on C & D-Sample. * DCD and DTR are not supported on UART Irda & Modem2 on E-Sample. */ if (uartNo != UAF_UART_1) return (FD_NOT_SUPPORTED); uart = &uart_parameters; /* * Delete the 3 HISR actived in the RX/TX and V24 interrupt handlers. * A return is used to simplify the code if an error occurs. */ if (NU_Delete_HISR (&(uart->rx_hisr_ctrl_block)) != NU_SUCCESS) return (FD_INTERNAL_ERR); if (NU_Delete_HISR (&(uart->tx_hisr_ctrl_block)) != NU_SUCCESS) return (FD_INTERNAL_ERR); if (NU_Delete_HISR (&(uart->v24_hisr_ctrl_block)) != NU_SUCCESS) return (FD_INTERNAL_ERR); /* * Delete the HISR used to send a break. * A return is used to simplify the code if an error occurs. */ if (NU_Delete_HISR (&(uart->break_hisr_ctrl_block)) != NU_SUCCESS) return (FD_INTERNAL_ERR); /* * Disable and then delete the timer used in the break HISR * A return is used to simplify the code if an error occurs. */ (void) NU_Control_Timer (&(uart->break_timer_ctrl_block), NU_DISABLE_TIMER); if (NU_Delete_Timer (&(uart->break_timer_ctrl_block)) != NU_SUCCESS) return (FD_INTERNAL_ERR); /* * Disable and then delete the timer used in the detection of the escape * sequence. A return is used to simplify the code if an error occurs. */ (void) NU_Control_Timer (&(uart->guard_period_timer_ctrl_block), NU_DISABLE_TIMER); if (NU_Delete_Timer (&(uart->guard_period_timer_ctrl_block)) != NU_SUCCESS) return (FD_INTERNAL_ERR); /* * At that point, all HISRs and Timers have been successfully deleted. */ return (FD_OK); } #endif /* (defined BTEMOBILE && (CHIPSET != 12)) */