📄 uart.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. * * $Id: uart.c,v 1.2.4.3 2004/11/10 22:15:00 joel Exp $ */#include <bsp.h>#include <bsp/irq.h>#include <bsp/uart.h>#include <rtems/libio.h>#include <rtems/bspIo.h>#include <assert.h>/* * Basic 16552 driver */struct uart_data{ unsigned long ioBase; int hwFlow; int baud; BSP_UartBreakCbRec breakCallback;};/* * Initialization of BSP specific data. * The constants are pulled in from a BSP * specific file, whereas all of the code * in this file is generic and makes no * assumptions about addresses, irq vectors * etc... */#define UART_UNSUPP ((unsigned long)(-1))static struct uart_data uart_data[2] = { {#ifdef BSP_UART_IOBASE_COM1 BSP_UART_IOBASE_COM1,#else UART_UNSUPP,#endif }, {#ifdef BSP_UART_IOBASE_COM2 BSP_UART_IOBASE_COM2,#else UART_UNSUPP,#endif },};#define MAX_UARTS (sizeof(uart_data)/sizeof(uart_data[0]))#define SANITY_CHECK(uart) \ assert( MAX_UARTS > (unsigned)(uart) && uart_data[(uart)].ioBase != UART_UNSUPP )/* * Macros to read/wirte register of uart, if configuration is * different just rewrite these macros */ static inline unsigned charuread(int uart, unsigned int reg){ return in_8((unsigned char*)(uart_data[uart].ioBase + reg));}static inline void uwrite(int uart, int reg, unsigned int val){ out_8((unsigned char*)(uart_data[uart].ioBase + reg), val);}#define UARTDEBUG#ifdef UARTDEBUG static voiduartError(int uart, void *termiosPrivate){ unsigned char uartStatus, dummy; BSP_UartBreakCbProc h; uartStatus = uread(uart, LSR); dummy = uread(uart, RBR); 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("********* BREAK INTERRUPT *********\n"); if ((h=uart_data[uart].breakCallback.handler)) h(uart, (dummy<<8)|uartStatus, termiosPrivate, uart_data[uart].breakCallback.private); } if (uartStatus & ERFIFO) printk("********* Error receive Fifo **********\n");}#elseinline void uartError(int uart, void *termiosPrivate){ unsigned char uartStatus,dummy; BSP_UartBreakCbProc h; uartStatus = uread(uart, LSR); dummy = uread(uart, RBR); if ((uartStatus & BI) && (h=uart_data[uart].breakCallback.handler)) h(uart, (dummy<<8)|uartStatus, termiosPrivate, uart_data[uart].breakCallback.private);}#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 */voidBSP_uart_init(int uart, int baud, int hwFlow){ unsigned char tmp; /* Sanity check */ SANITY_CHECK(uart); 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, CHR_8_BITS); /* 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 */ tmp = uread(uart, LSR); tmp = uread(uart, RBR); tmp = uread(uart, MSR); /* Remember state */ uart_data[uart].hwFlow = hwFlow; uart_data[uart].baud = baud; return;}/* * Set baud */voidBSP_uart_set_baud(int uart, int baud){ unsigned char mcr, ier; /* Sanity check */ SANITY_CHECK(uart); /* * 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) { return; } mcr = uread(uart, MCR); ier = uread(uart, IER); BSP_uart_init(uart, baud, 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){ SANITY_CHECK(uart); switch(cmd) { case BSP_UART_INTR_CTRL_DISABLE: uwrite(uart, IER, INTERRUPT_DISABLE); break; case BSP_UART_INTR_CTRL_ENABLE: if(uart_data[uart].hwFlow) { uwrite(uart, IER, (RECEIVE_ENABLE | TRANSMIT_ENABLE | RECEIVER_LINE_ST_ENABLE | MODEM_ENABLE ) ); } else { uwrite(uart, IER, (RECEIVE_ENABLE | TRANSMIT_ENABLE | RECEIVER_LINE_ST_ENABLE ) ); } break; case BSP_UART_INTR_CTRL_TERMIOS: if(uart_data[uart].hwFlow) { uwrite(uart, IER, (RECEIVE_ENABLE | RECEIVER_LINE_ST_ENABLE | MODEM_ENABLE ) ); } else { uwrite(uart, IER, (RECEIVE_ENABLE | RECEIVER_LINE_ST_ENABLE ) ); } break; case BSP_UART_INTR_CTRL_GDB: uwrite(uart, IER, RECEIVE_ENABLE); break; default: assert(0); break; } return;}voidBSP_uart_throttle(int uart){ unsigned int mcr; SANITY_CHECK(uart); if(!uart_data[uart].hwFlow) { /* Should not happen */ assert(0); return; } mcr = uread (uart, MCR); /* RTS down */ mcr &= ~RTS; uwrite(uart, MCR, mcr); return;}voidBSP_uart_unthrottle(int uart){ unsigned int mcr; SANITY_CHECK(uart); 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; SANITY_CHECK(uart); 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 */ SANITY_CHECK(uart); 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); return;}voidBSP_output_char_via_serial(const char val){ BSP_uart_polled_write(BSPConsolePort, val); if (val == '\n') BSP_uart_polled_write(BSPConsolePort,'\r');}/* * Polled mode read function */int BSP_uart_polled_read(int uart){ unsigned char val; SANITY_CHECK(uart); for(;;) { if(uread(uart, LSR) & DR) { break; } } val = uread(uart, RBR); return (int)(val & 0xff);}unsigned BSP_poll_char_via_serial(){ return BSP_uart_polled_read(BSPConsolePort);}static voiduart_noop(const rtems_irq_connect_data *unused){ return;}/* note that the IRQ names contain _ISA_ for legacy * reasons. They can be any interrupt, depending * on the particular BSP... */static intuart_isr_is_on(const rtems_irq_connect_data *irq){ int uart;#if defined(mvme2100) uart = BSP_UART_COM1;#else uart = (irq->name == BSP_ISA_UART_COM1_IRQ) ? BSP_UART_COM1 : BSP_UART_COM2;#endif return uread(uart,IER);}static intdoit(int uart, rtems_irq_hdl handler, int (*p)(const rtems_irq_connect_data*)){ rtems_irq_connect_data d={0};#if defined(mvme2100) d.name = BSP_UART_COM1_IRQ;#else d.name = (uart == BSP_UART_COM1) ? BSP_ISA_UART_COM1_IRQ : BSP_ISA_UART_COM2_IRQ;#endif d.off = d.on = uart_noop; d.isOn = uart_isr_is_on; d.hdl = handler; return p(&d);}intBSP_uart_install_isr(int uart, rtems_irq_hdl handler){ return doit(uart, handler, BSP_install_rtems_irq_handler);} intBSP_uart_remove_isr(int uart, rtems_irq_hdl handler){ return doit(uart, handler, BSP_remove_rtems_irq_handler);}/* ================ Termios support =================*/static volatile int termios_stopped_com[2] = {0,0};static volatile int termios_tx_active_com[2] = {0,0};static void* termios_ttyp_com[2] = {NULL,NULL};static char termios_tx_hold_com[2] = {0,0};static volatile char termios_tx_hold_valid_com[2] = {0,0};/* * Set channel parameters */voidBSP_uart_termios_set(int uart, void *ttyp){ unsigned char val; SANITY_CHECK(uart); if(uart_data[uart].hwFlow) { val = uread(uart, MSR); termios_stopped_com[uart] = (val & CTS) ? 0 : 1; } else { termios_stopped_com[uart] = 0; } termios_tx_active_com[uart] = 0; termios_ttyp_com[uart] = ttyp; termios_tx_hold_com[uart] = 0; termios_tx_hold_valid_com[uart] = 0; return;}intBSP_uart_termios_write_polled(int minor, const char *buf, int len){ int uart=minor; /* could differ, theoretically */ int nwrite; const char *b = buf; assert(buf != NULL); for (nwrite=0 ; nwrite < len ; nwrite++) { BSP_uart_polled_write(uart, *b++); } return nwrite;}intBSP_uart_termios_write_com(int minor, const char *buf, int len){ int uart=minor; /* could differ, theoretically */ assert(buf != NULL); if(len <= 0) { return 0; } /* If the TX buffer is busy - something is royally screwed up */ /* assert((uread(BSP_UART_COM1, LSR) & THRE) != 0); */ if(termios_stopped_com[uart]) { /* CTS low */ termios_tx_hold_com[uart] = *buf; termios_tx_hold_valid_com[uart] = 1; return 0; } /* Write character */ uwrite(uart, THR, *buf & 0xff); /* Enable interrupts if necessary */ if(!termios_tx_active_com[uart] && uart_data[uart].hwFlow) { termios_tx_active_com[uart] = 1; uwrite(uart, IER, (RECEIVE_ENABLE | TRANSMIT_ENABLE | RECEIVER_LINE_ST_ENABLE | MODEM_ENABLE ) ); } else if(!termios_tx_active_com[uart]) { termios_tx_active_com[uart] = 1; uwrite(uart, IER, (RECEIVE_ENABLE | TRANSMIT_ENABLE | RECEIVER_LINE_ST_ENABLE ) ); } return 0;}static voidBSP_uart_termios_isr_com(int uart){ unsigned char buf[40]; unsigned char val; int off, ret, vect; off = 0; for(;;) { vect = uread(uart, IIR) & 0xf; switch(vect) { case MODEM_STATUS : val = uread(uart, MSR); if(uart_data[uart].hwFlow) { if(val & CTS) { /* CTS high */ termios_stopped_com[uart] = 0; if(termios_tx_hold_valid_com[uart]) { termios_tx_hold_valid_com[uart] = 0; BSP_uart_termios_write_com(uart, &termios_tx_hold_com[uart], 1); } } else { /* CTS low */ termios_stopped_com[uart] = 1; } } break; case NO_MORE_INTR : /* No more interrupts */ if(off != 0) { /* Update rx buffer */ rtems_termios_enqueue_raw_characters(termios_ttyp_com[uart], (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. */ ret = rtems_termios_dequeue_characters(termios_ttyp_com[uart], 1); /* If nothing else to send disable interrupts */ if(ret == 0 && uart_data[uart].hwFlow) { uwrite(uart, IER, (RECEIVE_ENABLE | RECEIVER_LINE_ST_ENABLE | MODEM_ENABLE ) ); termios_tx_active_com[uart] = 0; } else if(ret == 0) { uwrite(uart, IER, (RECEIVE_ENABLE | RECEIVER_LINE_ST_ENABLE ) ); termios_tx_active_com[uart] = 0; } break; case RECEIVER_DATA_AVAIL : case CHARACTER_TIMEOUT_INDICATION: /* RX data ready */ assert(off < sizeof(buf)); buf[off++] = uread(uart, RBR); break; case RECEIVER_ERROR: /* RX error: eat character */ uartError(uart, termios_ttyp_com[uart]); break; default: /* Should not happen */ assert(0); return; } }} voidBSP_uart_termios_isr_com1(void){ BSP_uart_termios_isr_com(BSP_UART_COM1);}voidBSP_uart_termios_isr_com2(void){ BSP_uart_termios_isr_com(BSP_UART_COM2);}/* retrieve 'break' handler info */intBSP_uart_get_break_cb(int uart, rtems_libio_ioctl_args_t *arg){BSP_UartBreakCb cb=arg->buffer;unsigned long flags; SANITY_CHECK(uart); rtems_interrupt_disable(flags); *cb = uart_data[uart].breakCallback; rtems_interrupt_enable(flags); arg->ioctl_return=0; return RTEMS_SUCCESSFUL;}/* install 'break' handler */intBSP_uart_set_break_cb(int uart, rtems_libio_ioctl_args_t *arg){BSP_UartBreakCb cb=arg->buffer;unsigned long flags; SANITY_CHECK(uart); rtems_interrupt_disable(flags); uart_data[uart].breakCallback = *cb; rtems_interrupt_enable(flags); arg->ioctl_return=0; return RTEMS_SUCCESSFUL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -