forked from Imagelibrary/rtems
960 lines
23 KiB
C
960 lines
23 KiB
C
/*
|
|
* This software is Copyright (C) 1998 by T.sqware - all rights limited
|
|
* It is provided in to the public domain "as is", can be freely modified
|
|
* as far as this copyight notice is kept unchanged, but does not imply
|
|
* an endorsement by T.sqware of the product in which it is included.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <bsp.h>
|
|
#include <bsp/irq.h>
|
|
#include <uart.h>
|
|
#include <rtems/libio.h>
|
|
#include <rtems/termiostypes.h>
|
|
#include <termios.h>
|
|
#include <assert.h>
|
|
|
|
/*
|
|
* Basic 16552 driver
|
|
*/
|
|
|
|
struct uart_data
|
|
{
|
|
int ioMode;
|
|
int hwFlow;
|
|
unsigned int ier;
|
|
unsigned long baud;
|
|
unsigned long databits;
|
|
unsigned long parity;
|
|
unsigned long stopbits;
|
|
};
|
|
|
|
static struct uart_data uart_data[2];
|
|
|
|
/*
|
|
* Macros to read/write register of uart, if configuration is
|
|
* different just rewrite these macros
|
|
*/
|
|
|
|
static inline unsigned char
|
|
uread(int uart, unsigned int reg)
|
|
{
|
|
register unsigned char val;
|
|
|
|
if (uart == 0) {
|
|
inport_byte(COM1_BASE_IO+reg, val);
|
|
} else {
|
|
inport_byte(COM2_BASE_IO+reg, val);
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
static inline void
|
|
uwrite(int uart, int reg, unsigned int val)
|
|
{
|
|
if (uart == 0) {
|
|
outport_byte(COM1_BASE_IO+reg, val);
|
|
} else {
|
|
outport_byte(COM2_BASE_IO+reg, val);
|
|
}
|
|
}
|
|
|
|
static void
|
|
uartError(int uart)
|
|
{
|
|
unsigned char uartStatus, dummy;
|
|
|
|
uartStatus = uread(uart, LSR);
|
|
(void) uartStatus; /* avoid set but not used warning */
|
|
dummy = uread(uart, RBR);
|
|
(void) dummy; /* avoid set but not used warning */
|
|
|
|
#ifdef UARTDEBUG
|
|
if (uartStatus & OE)
|
|
printk("********* Over run Error **********\n");
|
|
if (uartStatus & PE)
|
|
printk("********* Parity Error **********\n");
|
|
if (uartStatus & FE)
|
|
printk("********* Framing Error **********\n");
|
|
if (uartStatus & BI)
|
|
printk("********* Parity Error **********\n");
|
|
if (uartStatus & ERFIFO)
|
|
printk("********* Error receive Fifo **********\n");
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Uart initialization, it is hardcoded to 8 bit, no parity,
|
|
* one stop bit, FIFO, things to be changed
|
|
* are baud rate and nad hw flow control,
|
|
* and longest rx fifo setting
|
|
*/
|
|
void
|
|
BSP_uart_init
|
|
(
|
|
int uart,
|
|
unsigned long baud,
|
|
unsigned long databits,
|
|
unsigned long parity,
|
|
unsigned long stopbits,
|
|
int hwFlow
|
|
)
|
|
{
|
|
/* Sanity check */
|
|
assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
|
|
|
|
switch(baud)
|
|
{
|
|
case 50:
|
|
case 75:
|
|
case 110:
|
|
case 134:
|
|
case 300:
|
|
case 600:
|
|
case 1200:
|
|
case 2400:
|
|
case 9600:
|
|
case 19200:
|
|
case 38400:
|
|
case 57600:
|
|
case 115200:
|
|
break;
|
|
default:
|
|
assert(0);
|
|
return;
|
|
}
|
|
|
|
/* Set DLAB bit to 1 */
|
|
uwrite(uart, LCR, DLAB);
|
|
|
|
/* Set baud rate */
|
|
uwrite(uart, DLL, (BSPBaseBaud/baud) & 0xff);
|
|
uwrite(uart, DLM, ((BSPBaseBaud/baud) >> 8) & 0xff);
|
|
|
|
/* 8-bit, no parity , 1 stop */
|
|
uwrite(uart, LCR, databits | parity | stopbits);
|
|
|
|
/* Set DTR, RTS and OUT2 high */
|
|
uwrite(uart, MCR, DTR | RTS | OUT_2);
|
|
|
|
/* Enable FIFO */
|
|
uwrite(uart, FCR, FIFO_EN | XMIT_RESET | RCV_RESET | RECEIVE_FIFO_TRIGGER12);
|
|
|
|
/* Disable Interrupts */
|
|
uwrite(uart, IER, 0);
|
|
|
|
/* Read status to clear them */
|
|
uread(uart, LSR);
|
|
uread(uart, RBR);
|
|
uread(uart, MSR);
|
|
|
|
/* Remember state */
|
|
uart_data[uart].baud = baud;
|
|
uart_data[uart].databits = databits;
|
|
uart_data[uart].parity = parity;
|
|
uart_data[uart].stopbits = stopbits;
|
|
uart_data[uart].hwFlow = hwFlow;
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Set baud
|
|
*/
|
|
|
|
void
|
|
BSP_uart_set_baud(
|
|
int uart,
|
|
unsigned long baud
|
|
)
|
|
{
|
|
/* Sanity check */
|
|
assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
|
|
|
|
BSP_uart_set_attributes( uart, baud, uart_data[uart].databits,
|
|
uart_data[uart].parity, uart_data[uart].stopbits );
|
|
}
|
|
|
|
/*
|
|
* Set all attributes
|
|
*/
|
|
|
|
void
|
|
BSP_uart_set_attributes
|
|
(
|
|
int uart,
|
|
unsigned long baud,
|
|
unsigned long databits,
|
|
unsigned long parity,
|
|
unsigned long stopbits
|
|
)
|
|
{
|
|
unsigned char mcr, ier;
|
|
|
|
/* Sanity check */
|
|
assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
|
|
|
|
/*
|
|
* This function may be called whenever TERMIOS parameters
|
|
* are changed, so we have to make sure that baud change is
|
|
* indeed required
|
|
*/
|
|
|
|
if( (baud == uart_data[uart].baud) &&
|
|
(databits == uart_data[uart].databits) &&
|
|
(parity == uart_data[uart].parity) &&
|
|
(stopbits == uart_data[uart].stopbits) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
mcr = uread(uart, MCR);
|
|
ier = uread(uart, IER);
|
|
|
|
BSP_uart_init(uart, baud, databits, parity, stopbits, uart_data[uart].hwFlow);
|
|
|
|
uwrite(uart, MCR, mcr);
|
|
uwrite(uart, IER, ier);
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Enable/disable interrupts
|
|
*/
|
|
void
|
|
BSP_uart_intr_ctrl(int uart, int cmd)
|
|
{
|
|
int iStatus = (int)INTERRUPT_DISABLE;
|
|
|
|
assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
|
|
|
|
switch(cmd)
|
|
{
|
|
case BSP_UART_INTR_CTRL_ENABLE:
|
|
iStatus |= (RECEIVE_ENABLE | RECEIVER_LINE_ST_ENABLE | TRANSMIT_ENABLE);
|
|
if ( uart_data[uart].hwFlow ) {
|
|
iStatus |= MODEM_ENABLE;
|
|
}
|
|
break;
|
|
case BSP_UART_INTR_CTRL_TERMIOS:
|
|
iStatus |= (RECEIVE_ENABLE | RECEIVER_LINE_ST_ENABLE);
|
|
if ( uart_data[uart].hwFlow ) {
|
|
iStatus |= MODEM_ENABLE;
|
|
}
|
|
break;
|
|
case BSP_UART_INTR_CTRL_GDB:
|
|
iStatus |= RECEIVE_ENABLE;
|
|
break;
|
|
}
|
|
|
|
uart_data[uart].ier = iStatus;
|
|
uwrite(uart, IER, iStatus);
|
|
|
|
return;
|
|
}
|
|
|
|
void
|
|
BSP_uart_throttle(int uart)
|
|
{
|
|
unsigned int mcr;
|
|
|
|
assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
|
|
|
|
if(!uart_data[uart].hwFlow)
|
|
{
|
|
/* Should not happen */
|
|
assert(0);
|
|
return;
|
|
}
|
|
mcr = uread (uart, MCR);
|
|
/* RTS down */
|
|
mcr &= ~RTS;
|
|
uwrite(uart, MCR, mcr);
|
|
|
|
return;
|
|
}
|
|
|
|
void
|
|
BSP_uart_unthrottle(int uart)
|
|
{
|
|
unsigned int mcr;
|
|
|
|
assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
|
|
|
|
if(!uart_data[uart].hwFlow)
|
|
{
|
|
/* Should not happen */
|
|
assert(0);
|
|
return;
|
|
}
|
|
mcr = uread (uart, MCR);
|
|
/* RTS up */
|
|
mcr |= RTS;
|
|
uwrite(uart, MCR, mcr);
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Status function, -1 if error
|
|
* detected, 0 if no received chars available,
|
|
* 1 if received char available, 2 if break
|
|
* is detected, it will eat break and error
|
|
* chars. It ignores overruns - we cannot do
|
|
* anything about - it execpt count statistics
|
|
* and we are not counting it.
|
|
*/
|
|
int
|
|
BSP_uart_polled_status(int uart)
|
|
{
|
|
unsigned char val;
|
|
|
|
assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
|
|
|
|
val = uread(uart, LSR);
|
|
|
|
if(val & BI)
|
|
{
|
|
/* BREAK found, eat character */
|
|
uread(uart, RBR);
|
|
return BSP_UART_STATUS_BREAK;
|
|
}
|
|
|
|
if((val & (DR | OE | FE)) == 1)
|
|
{
|
|
/* No error, character present */
|
|
return BSP_UART_STATUS_CHAR;
|
|
}
|
|
|
|
if((val & (DR | OE | FE)) == 0)
|
|
{
|
|
/* Nothing */
|
|
return BSP_UART_STATUS_NOCHAR;
|
|
}
|
|
|
|
/*
|
|
* Framing or parity error
|
|
* eat character
|
|
*/
|
|
uread(uart, RBR);
|
|
|
|
return BSP_UART_STATUS_ERROR;
|
|
}
|
|
|
|
/*
|
|
* Polled mode write function
|
|
*/
|
|
void
|
|
BSP_uart_polled_write(int uart, int val)
|
|
{
|
|
unsigned char val1;
|
|
|
|
/* Sanity check */
|
|
assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
|
|
|
|
for(;;)
|
|
{
|
|
if((val1=uread(uart, LSR)) & THRE)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(uart_data[uart].hwFlow)
|
|
{
|
|
for(;;)
|
|
{
|
|
if(uread(uart, MSR) & CTS)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
uwrite(uart, THR, val & 0xff);
|
|
|
|
/*
|
|
* Wait for character to be transmitted.
|
|
* This ensures that printk and printf play nicely together
|
|
* when using the same serial port.
|
|
* Yes, there's a performance hit here, but if we're doing
|
|
* polled writes to a serial port we're probably not that
|
|
* interested in efficiency anyway.....
|
|
*/
|
|
for(;;)
|
|
{
|
|
if((val1=uread(uart, LSR)) & THRE)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void
|
|
BSP_output_char_via_serial(char val)
|
|
{
|
|
BSP_uart_polled_write(BSPConsolePort, val);
|
|
}
|
|
|
|
/*
|
|
* Polled mode read function
|
|
*/
|
|
int
|
|
BSP_uart_polled_read(int uart)
|
|
{
|
|
unsigned char val;
|
|
|
|
assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
|
|
|
|
for(;;)
|
|
{
|
|
if(uread(uart, LSR) & DR)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
val = uread(uart, RBR);
|
|
|
|
return (int)(val & 0xff);
|
|
}
|
|
|
|
int
|
|
BSP_poll_char_via_serial(void)
|
|
{
|
|
return BSP_uart_polled_read(BSPConsolePort);
|
|
}
|
|
|
|
/* ================ Termios support =================*/
|
|
|
|
static volatile int termios_stopped_com1 = 0;
|
|
static volatile int termios_tx_active_com1 = 0;
|
|
static void* termios_ttyp_com1 = NULL;
|
|
static char termios_tx_hold_com1 = 0;
|
|
static volatile char termios_tx_hold_valid_com1 = 0;
|
|
|
|
static volatile int termios_stopped_com2 = 0;
|
|
static volatile int termios_tx_active_com2 = 0;
|
|
static void* termios_ttyp_com2 = NULL;
|
|
static char termios_tx_hold_com2 = 0;
|
|
static volatile char termios_tx_hold_valid_com2 = 0;
|
|
|
|
static void ( *driver_input_handler_com1 )( void *, char *, int ) = 0;
|
|
static void ( *driver_input_handler_com2 )( void *, char *, int ) = 0;
|
|
|
|
/*
|
|
* Set channel parameters
|
|
*/
|
|
void
|
|
BSP_uart_termios_set(int uart, void *ttyp)
|
|
{
|
|
struct rtems_termios_tty *p = (struct rtems_termios_tty *)ttyp;
|
|
unsigned char val;
|
|
assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
|
|
|
|
if(uart == BSP_UART_COM1)
|
|
{
|
|
uart_data[uart].ioMode = p->device.outputUsesInterrupts;
|
|
if(uart_data[uart].hwFlow)
|
|
{
|
|
val = uread(uart, MSR);
|
|
|
|
termios_stopped_com1 = (val & CTS) ? 0 : 1;
|
|
}
|
|
else
|
|
{
|
|
termios_stopped_com1 = 0;
|
|
}
|
|
termios_tx_active_com1 = 0;
|
|
termios_ttyp_com1 = ttyp;
|
|
termios_tx_hold_com1 = 0;
|
|
termios_tx_hold_valid_com1 = 0;
|
|
}
|
|
else
|
|
{
|
|
uart_data[uart].ioMode = p->device.outputUsesInterrupts;
|
|
if(uart_data[uart].hwFlow)
|
|
{
|
|
val = uread(uart, MSR);
|
|
|
|
termios_stopped_com2 = (val & CTS) ? 0 : 1;
|
|
}
|
|
else
|
|
{
|
|
termios_stopped_com2 = 0;
|
|
}
|
|
termios_tx_active_com2 = 0;
|
|
termios_ttyp_com2 = ttyp;
|
|
termios_tx_hold_com2 = 0;
|
|
termios_tx_hold_valid_com2 = 0;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
int
|
|
BSP_uart_termios_read_com1(int uart)
|
|
{
|
|
int off = (int)0;
|
|
char buf[40];
|
|
|
|
/* read bytes */
|
|
while (( off < sizeof(buf) ) && ( uread(BSP_UART_COM1, LSR) & DR )) {
|
|
buf[off++] = uread(BSP_UART_COM1, RBR);
|
|
}
|
|
|
|
/* write out data */
|
|
if ( off > 0 ) {
|
|
rtems_termios_enqueue_raw_characters(termios_ttyp_com1, buf, off);
|
|
}
|
|
|
|
/* enable receive interrupts */
|
|
uart_data[BSP_UART_COM1].ier |= (RECEIVE_ENABLE | RECEIVER_LINE_ST_ENABLE);
|
|
uwrite(BSP_UART_COM1, IER, uart_data[BSP_UART_COM1].ier);
|
|
|
|
return ( EOF );
|
|
}
|
|
|
|
int
|
|
BSP_uart_termios_read_com2(int uart)
|
|
{
|
|
int off = (int)0;
|
|
char buf[40];
|
|
|
|
/* read current byte */
|
|
while (( off < sizeof(buf) ) && ( uread(BSP_UART_COM2, LSR) & DR )) {
|
|
buf[off++] = uread(BSP_UART_COM2, RBR);
|
|
}
|
|
|
|
/* write out data */
|
|
if ( off > 0 ) {
|
|
rtems_termios_enqueue_raw_characters(termios_ttyp_com2, buf, off);
|
|
}
|
|
|
|
/* enable receive interrupts */
|
|
uart_data[BSP_UART_COM2].ier |= (RECEIVE_ENABLE | RECEIVER_LINE_ST_ENABLE);
|
|
uwrite(BSP_UART_COM2, IER, uart_data[BSP_UART_COM2].ier);
|
|
|
|
return ( EOF );
|
|
}
|
|
|
|
ssize_t
|
|
BSP_uart_termios_write_com1(int minor, const char *buf, size_t len)
|
|
{
|
|
if(len <= 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
assert(buf != NULL);
|
|
|
|
/* If there TX buffer is busy - something is royally screwed up */
|
|
assert((uread(BSP_UART_COM1, LSR) & THRE) != 0);
|
|
|
|
if(termios_stopped_com1)
|
|
{
|
|
/* CTS low */
|
|
termios_tx_hold_com1 = *buf;
|
|
termios_tx_hold_valid_com1 = 1;
|
|
return 0;
|
|
}
|
|
|
|
/* Write character */
|
|
uwrite(BSP_UART_COM1, THR, *buf & 0xff);
|
|
|
|
/* Enable interrupts if necessary */
|
|
if ( !termios_tx_active_com1 ) {
|
|
termios_tx_active_com1 = 1;
|
|
uart_data[BSP_UART_COM1].ier |= TRANSMIT_ENABLE;
|
|
uwrite(BSP_UART_COM1, IER, uart_data[BSP_UART_COM1].ier);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
ssize_t
|
|
BSP_uart_termios_write_com2(int minor, const char *buf, size_t len)
|
|
{
|
|
if(len <= 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
assert(buf != NULL);
|
|
|
|
/* If there TX buffer is busy - something is royally screwed up */
|
|
assert((uread(BSP_UART_COM2, LSR) & THRE) != 0);
|
|
|
|
if(termios_stopped_com2)
|
|
{
|
|
/* CTS low */
|
|
termios_tx_hold_com2 = *buf;
|
|
termios_tx_hold_valid_com2 = 1;
|
|
return 0;
|
|
}
|
|
|
|
/* Write character */
|
|
uwrite(BSP_UART_COM2, THR, *buf & 0xff);
|
|
|
|
/* Enable interrupts if necessary */
|
|
if ( !termios_tx_active_com2 ) {
|
|
termios_tx_active_com2 = 1;
|
|
uart_data[BSP_UART_COM2].ier |= TRANSMIT_ENABLE;
|
|
uwrite(BSP_UART_COM2, IER, uart_data[BSP_UART_COM2].ier);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
BSP_uart_termios_isr_com1(void *ignored)
|
|
{
|
|
unsigned char buf[40];
|
|
unsigned char val;
|
|
int off, ret, vect;
|
|
|
|
off = 0;
|
|
|
|
for(;;)
|
|
{
|
|
vect = uread(BSP_UART_COM1, IIR) & 0xf;
|
|
|
|
switch(vect)
|
|
{
|
|
case MODEM_STATUS :
|
|
val = uread(BSP_UART_COM1, MSR);
|
|
if(uart_data[BSP_UART_COM1].hwFlow)
|
|
{
|
|
if(val & CTS)
|
|
{
|
|
/* CTS high */
|
|
termios_stopped_com1 = 0;
|
|
if(termios_tx_hold_valid_com1)
|
|
{
|
|
termios_tx_hold_valid_com1 = 0;
|
|
BSP_uart_termios_write_com1(0, &termios_tx_hold_com1,
|
|
1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* CTS low */
|
|
termios_stopped_com1 = 1;
|
|
}
|
|
}
|
|
break;
|
|
case NO_MORE_INTR :
|
|
/* No more interrupts */
|
|
if(off != 0)
|
|
{
|
|
/* Update rx buffer */
|
|
if( driver_input_handler_com1 )
|
|
{
|
|
driver_input_handler_com1( termios_ttyp_com1, (char *)buf, off );
|
|
}
|
|
else
|
|
{
|
|
/* Update rx buffer */
|
|
rtems_termios_enqueue_raw_characters(termios_ttyp_com1, (char *)buf, off );
|
|
}
|
|
}
|
|
return;
|
|
case TRANSMITTER_HODING_REGISTER_EMPTY :
|
|
/*
|
|
* TX holding empty: we have to disable these interrupts
|
|
* if there is nothing more to send.
|
|
*/
|
|
|
|
/* If nothing else to send disable interrupts */
|
|
ret = rtems_termios_dequeue_characters(termios_ttyp_com1, 1);
|
|
if ( ret == 0 ) {
|
|
termios_tx_active_com1 = 0;
|
|
uart_data[BSP_UART_COM1].ier &= ~(TRANSMIT_ENABLE);
|
|
uwrite(BSP_UART_COM1, IER, uart_data[BSP_UART_COM1].ier);
|
|
}
|
|
break;
|
|
case RECEIVER_DATA_AVAIL :
|
|
case CHARACTER_TIMEOUT_INDICATION:
|
|
if ( uart_data[BSP_UART_COM1].ioMode == TERMIOS_TASK_DRIVEN ) {
|
|
/* ensure interrupts are enabled */
|
|
if ( uart_data[BSP_UART_COM1].ier & RECEIVE_ENABLE ) {
|
|
/* disable interrupts and notify termios */
|
|
uart_data[BSP_UART_COM1].ier &= ~(RECEIVE_ENABLE | RECEIVER_LINE_ST_ENABLE);
|
|
uwrite(BSP_UART_COM1, IER, uart_data[BSP_UART_COM1].ier);
|
|
rtems_termios_rxirq_occured(termios_ttyp_com1);
|
|
}
|
|
}
|
|
else {
|
|
/* RX data ready */
|
|
assert(off < sizeof(buf));
|
|
buf[off++] = uread(BSP_UART_COM1, RBR);
|
|
}
|
|
break;
|
|
case RECEIVER_ERROR:
|
|
/* RX error: eat character */
|
|
uartError(BSP_UART_COM1);
|
|
break;
|
|
default:
|
|
/* Should not happen */
|
|
assert(0);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
BSP_uart_termios_isr_com2(void *ignored)
|
|
{
|
|
unsigned char buf[40];
|
|
unsigned char val;
|
|
int off, ret, vect;
|
|
|
|
off = 0;
|
|
|
|
for(;;)
|
|
{
|
|
vect = uread(BSP_UART_COM2, IIR) & 0xf;
|
|
|
|
switch(vect)
|
|
{
|
|
case MODEM_STATUS :
|
|
val = uread(BSP_UART_COM2, MSR);
|
|
if(uart_data[BSP_UART_COM2].hwFlow)
|
|
{
|
|
if(val & CTS)
|
|
{
|
|
/* CTS high */
|
|
termios_stopped_com2 = 0;
|
|
if(termios_tx_hold_valid_com2)
|
|
{
|
|
termios_tx_hold_valid_com2 = 0;
|
|
BSP_uart_termios_write_com2(0, &termios_tx_hold_com2,
|
|
1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* CTS low */
|
|
termios_stopped_com2 = 1;
|
|
}
|
|
}
|
|
break;
|
|
case NO_MORE_INTR :
|
|
/* No more interrupts */
|
|
if(off != 0)
|
|
{
|
|
/* Update rx buffer */
|
|
if( driver_input_handler_com2 )
|
|
{
|
|
driver_input_handler_com2( termios_ttyp_com2, (char *)buf, off );
|
|
}
|
|
else
|
|
{
|
|
rtems_termios_enqueue_raw_characters(termios_ttyp_com2, (char *)buf, off);
|
|
}
|
|
}
|
|
return;
|
|
case TRANSMITTER_HODING_REGISTER_EMPTY :
|
|
/*
|
|
* TX holding empty: we have to disable these interrupts
|
|
* if there is nothing more to send.
|
|
*/
|
|
|
|
/* If nothing else to send disable interrupts */
|
|
ret = rtems_termios_dequeue_characters(termios_ttyp_com2, 1);
|
|
if ( ret == 0 ) {
|
|
termios_tx_active_com2 = 0;
|
|
uart_data[BSP_UART_COM2].ier &= ~(TRANSMIT_ENABLE);
|
|
uwrite(BSP_UART_COM2, IER, uart_data[BSP_UART_COM2].ier);
|
|
}
|
|
break;
|
|
case RECEIVER_DATA_AVAIL :
|
|
case CHARACTER_TIMEOUT_INDICATION:
|
|
if ( uart_data[BSP_UART_COM2].ioMode == TERMIOS_TASK_DRIVEN ) {
|
|
/* ensure interrupts are enabled */
|
|
if ( uart_data[BSP_UART_COM2].ier & RECEIVE_ENABLE ) {
|
|
/* disable interrupts and notify termios */
|
|
uart_data[BSP_UART_COM2].ier &= ~(RECEIVE_ENABLE | RECEIVER_LINE_ST_ENABLE);
|
|
uwrite(BSP_UART_COM2, IER, uart_data[BSP_UART_COM2].ier);
|
|
rtems_termios_rxirq_occured(termios_ttyp_com2);
|
|
}
|
|
}
|
|
else {
|
|
/* RX data ready */
|
|
assert(off < sizeof(buf));
|
|
buf[off++] = uread(BSP_UART_COM2, RBR);
|
|
}
|
|
break;
|
|
case RECEIVER_ERROR:
|
|
/* RX error: eat character */
|
|
uartError(BSP_UART_COM2);
|
|
break;
|
|
default:
|
|
/* Should not happen */
|
|
assert(0);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ================= GDB support ===================*/
|
|
int BSP_uart_dbgisr_com_regsav[4] RTEMS_UNUSED;
|
|
|
|
/*
|
|
* Interrupt service routine for COM1 - all,
|
|
* it does it check whether ^C is received
|
|
* if yes it will flip TF bit before returning
|
|
* Note: it should be installed as raw interrupt
|
|
* handler
|
|
*/
|
|
|
|
__asm__ (".p2align 4");
|
|
__asm__ (".text");
|
|
__asm__ (".globl BSP_uart_dbgisr_com1");
|
|
__asm__ ("BSP_uart_dbgisr_com1:");
|
|
__asm__ (" movl %eax, BSP_uart_dbgisr_com_regsav"); /* Save eax */
|
|
__asm__ (" movl %ebx, BSP_uart_dbgisr_com_regsav + 4"); /* Save ebx */
|
|
__asm__ (" movl %edx, BSP_uart_dbgisr_com_regsav + 8"); /* Save edx */
|
|
|
|
__asm__ (" movl $0, %ebx"); /* Clear flag */
|
|
|
|
/*
|
|
* We know that only receive related interrupts
|
|
* are available, eat chars
|
|
*/
|
|
__asm__ ("uart_dbgisr_com1_1:");
|
|
__asm__ (" movw $0x3FD, %dx");
|
|
__asm__ (" inb %dx, %al"); /* Read LSR */
|
|
__asm__ (" andb $1, %al");
|
|
__asm__ (" cmpb $0, %al");
|
|
__asm__ (" je uart_dbgisr_com1_2");
|
|
__asm__ (" movw $0x3F8, %dx");
|
|
__asm__ (" inb %dx, %al"); /* Get input character */
|
|
__asm__ (" cmpb $3, %al");
|
|
__asm__ (" jne uart_dbgisr_com1_1");
|
|
|
|
/* ^C received, set flag */
|
|
__asm__ (" movl $1, %ebx");
|
|
__asm__ (" jmp uart_dbgisr_com1_1");
|
|
|
|
/* All chars read */
|
|
__asm__ ("uart_dbgisr_com1_2:");
|
|
|
|
/* If flag is set we have to tweak TF */
|
|
__asm__ (" cmpl $0, %ebx");
|
|
__asm__ (" je uart_dbgisr_com1_3");
|
|
|
|
/* Flag is set */
|
|
__asm__ (" movl BSP_uart_dbgisr_com_regsav+4, %ebx"); /* Restore ebx */
|
|
__asm__ (" movl BSP_uart_dbgisr_com_regsav+8, %edx"); /* Restore edx */
|
|
|
|
/* Set TF bit */
|
|
__asm__ (" popl %eax"); /* Pop eip */
|
|
__asm__ (" movl %eax, BSP_uart_dbgisr_com_regsav + 4"); /* Save it */
|
|
__asm__ (" popl %eax"); /* Pop cs */
|
|
__asm__ (" movl %eax, BSP_uart_dbgisr_com_regsav + 8"); /* Save it */
|
|
__asm__ (" popl %eax"); /* Pop flags */
|
|
__asm__ (" orl $0x100, %eax"); /* Modify it */
|
|
__asm__ (" pushl %eax"); /* Push it back */
|
|
__asm__ (" movl BSP_uart_dbgisr_com_regsav+8, %eax"); /* Put back cs */
|
|
__asm__ (" pushl %eax");
|
|
__asm__ (" movl BSP_uart_dbgisr_com_regsav+4, %eax"); /* Put back eip */
|
|
__asm__ (" pushl %eax");
|
|
|
|
/* Acknowledge IRQ */
|
|
__asm__ (" movb $0x20, %al");
|
|
__asm__ (" outb %al, $0x20");
|
|
__asm__ (" movl BSP_uart_dbgisr_com_regsav, %eax"); /* Restore eax */
|
|
__asm__ (" iret"); /* Done */
|
|
|
|
/* Flag is not set */
|
|
__asm__ ("uart_dbgisr_com1_3:");
|
|
__asm__ (" movl BSP_uart_dbgisr_com_regsav+4, %ebx"); /* Restore ebx */
|
|
__asm__ (" movl BSP_uart_dbgisr_com_regsav+8, %edx"); /* Restore edx */
|
|
|
|
/* Acknowledge irq */
|
|
__asm__ (" movb $0x20, %al");
|
|
__asm__ (" outb %al, $0x20");
|
|
__asm__ (" movl BSP_uart_dbgisr_com_regsav, %eax"); /* Restore eax */
|
|
__asm__ (" iret"); /* Done */
|
|
|
|
/*
|
|
* Interrupt service routine for COM2 - all,
|
|
* it does it check whether ^C is received
|
|
* if yes it will flip TF bit before returning
|
|
* Note: it has to be installed as raw interrupt
|
|
* handler
|
|
*/
|
|
__asm__ (".p2align 4");
|
|
__asm__ (".text");
|
|
__asm__ (".globl BSP_uart_dbgisr_com2");
|
|
__asm__ ("BSP_uart_dbgisr_com2:");
|
|
__asm__ (" movl %eax, BSP_uart_dbgisr_com_regsav"); /* Save eax */
|
|
__asm__ (" movl %ebx, BSP_uart_dbgisr_com_regsav + 4"); /* Save ebx */
|
|
__asm__ (" movl %edx, BSP_uart_dbgisr_com_regsav + 8"); /* Save edx */
|
|
|
|
__asm__ (" movl $0, %ebx"); /* Clear flag */
|
|
|
|
/*
|
|
* We know that only receive related interrupts
|
|
* are available, eat chars
|
|
*/
|
|
__asm__ ("uart_dbgisr_com2_1:");
|
|
__asm__ (" movw $0x2FD, %dx");
|
|
__asm__ (" inb %dx, %al"); /* Read LSR */
|
|
__asm__ (" andb $1, %al");
|
|
__asm__ (" cmpb $0, %al");
|
|
__asm__ (" je uart_dbgisr_com2_2");
|
|
__asm__ (" movw $0x2F8, %dx");
|
|
__asm__ (" inb %dx, %al"); /* Get input character */
|
|
__asm__ (" cmpb $3, %al");
|
|
__asm__ (" jne uart_dbgisr_com2_1");
|
|
|
|
/* ^C received, set flag */
|
|
__asm__ (" movl $1, %ebx");
|
|
__asm__ (" jmp uart_dbgisr_com2_1");
|
|
|
|
/* All chars read */
|
|
__asm__ ("uart_dbgisr_com2_2:");
|
|
|
|
/* If flag is set we have to tweak TF */
|
|
__asm__ (" cmpl $0, %ebx");
|
|
__asm__ (" je uart_dbgisr_com2_3");
|
|
|
|
/* Flag is set */
|
|
__asm__ (" movl BSP_uart_dbgisr_com_regsav+4, %ebx"); /* Restore ebx */
|
|
__asm__ (" movl BSP_uart_dbgisr_com_regsav+8, %edx"); /* Restore edx */
|
|
|
|
/* Set TF bit */
|
|
__asm__ (" popl %eax"); /* Pop eip */
|
|
__asm__ (" movl %eax, BSP_uart_dbgisr_com_regsav + 4"); /* Save it */
|
|
__asm__ (" popl %eax"); /* Pop cs */
|
|
__asm__ (" movl %eax, BSP_uart_dbgisr_com_regsav + 8"); /* Save it */
|
|
__asm__ (" popl %eax"); /* Pop flags */
|
|
__asm__ (" orl $0x100, %eax"); /* Modify it */
|
|
__asm__ (" pushl %eax"); /* Push it back */
|
|
__asm__ (" movl BSP_uart_dbgisr_com_regsav+8, %eax"); /* Put back cs */
|
|
__asm__ (" pushl %eax");
|
|
__asm__ (" movl BSP_uart_dbgisr_com_regsav+4, %eax"); /* Put back eip */
|
|
__asm__ (" pushl %eax");
|
|
|
|
/* Acknowledge IRQ */
|
|
__asm__ (" movb $0x20, %al");
|
|
__asm__ (" outb %al, $0x20");
|
|
__asm__ (" movl BSP_uart_dbgisr_com_regsav, %eax"); /* Restore eax */
|
|
__asm__ (" iret"); /* Done */
|
|
|
|
/* Flag is not set */
|
|
__asm__ ("uart_dbgisr_com2_3:");
|
|
__asm__ (" movl BSP_uart_dbgisr_com_regsav+4, %ebx"); /* Restore ebx */
|
|
__asm__ (" movl BSP_uart_dbgisr_com_regsav+8, %edx"); /* Restore edx */
|
|
|
|
/* Acknowledge irq */
|
|
__asm__ (" movb $0x20, %al");
|
|
__asm__ (" outb %al, $0x20");
|
|
__asm__ (" movl BSP_uart_dbgisr_com_regsav, %eax"); /* Restore eax */
|
|
__asm__ (" iret"); /* Done */
|