diff options
Diffstat (limited to 'bsps/i386/pc386/console/uart.c')
-rw-r--r-- | bsps/i386/pc386/console/uart.c | 959 |
1 files changed, 959 insertions, 0 deletions
diff --git a/bsps/i386/pc386/console/uart.c b/bsps/i386/pc386/console/uart.c new file mode 100644 index 0000000000..5d2dd64854 --- /dev/null +++ b/bsps/i386/pc386/console/uart.c @@ -0,0 +1,959 @@ +/* + * 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 */ |