portBASE_TYPE xUARTSendCharacter( unsigned long ulUARTPeripheral, signed char cChar, portTickType xDelay ) { unsigned long ulBase = 0; portBASE_TYPE xReturn = pdFALSE; #if UART_USE_INTERRUPT xQueueHandle xTxQueue = NULL; unsigned char ucStatus = 0; #endif /* UART_USE_INTERRUPT */ switch ( ulUARTPeripheral ) { case 0: ulBase = UART0_BASE; #if UART_USE_INTERRUPT xTxQueue = xUartQueues[0][TX_QUEUE]; #endif break; case 1: ulBase = UART1_BASE; #if UART_USE_INTERRUPT xTxQueue = xUartQueues[1][TX_QUEUE]; #endif break; case 2: ulBase = UART2_BASE; #if UART_USE_INTERRUPT xTxQueue = xUartQueues[2][TX_QUEUE]; #endif break; case 3: ulBase = UART3_BASE; #if UART_USE_INTERRUPT xTxQueue = xUartQueues[3][TX_QUEUE]; #endif break; } if ( 0 != ulBase ) { #if UART_USE_INTERRUPT xReturn = xQueueSend( xTxQueue, &cChar, xDelay ); taskENTER_CRITICAL(); ucStatus = *UARTFR(ulBase); taskEXIT_CRITICAL(); if ( ucStatus & UART_FLAG_TXFE ) { /* Need to kick of the Tx. */ (void)xQueueReceive( xTxQueue, &cChar, 0 ); *UARTDR(ulBase) = cChar; xReturn = pdTRUE; } #else while ( !(*UARTFR(ulBase) & UART_FLAG_TXFE) ); *UARTDR(ulBase) = cChar; xReturn = pdTRUE; #endif /* UART_USE_INTERRUPT */ } return xReturn; }
static irqreturn_t clps711xuart_int_tx(int irq, void *dev_id) { struct uart_port *port = dev_id; struct circ_buf *xmit = &port->state->xmit; int count; if (port->x_char) { clps_writel(port->x_char, UARTDR(port)); port->icount.tx++; port->x_char = 0; return IRQ_HANDLED; } if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { clps711xuart_stop_tx(port); return IRQ_HANDLED; } count = port->fifosize >> 1; do { clps_writel(xmit->buf[xmit->tail], UARTDR(port)); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; if (uart_circ_empty(xmit)) break; } while (--count > 0); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); if (uart_circ_empty(xmit)) clps711xuart_stop_tx(port); return IRQ_HANDLED; }
static irqreturn_t uart_clps711x_int_tx(int irq, void *dev_id) { struct uart_port *port = dev_id; struct clps711x_port *s = dev_get_drvdata(port->dev); struct circ_buf *xmit = &port->state->xmit; if (port->x_char) { clps_writew(port->x_char, UARTDR(port)); port->icount.tx++; port->x_char = 0; return IRQ_HANDLED; } if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { disable_irq_nosync(TX_IRQ(port)); s->tx_enabled[port->line] = 0; return IRQ_HANDLED; } while (!uart_circ_empty(xmit)) { clps_writew(xmit->buf[xmit->tail], UARTDR(port)); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; if (clps_readl(SYSFLG(port) & SYSFLG_UTXFF)) break; } if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); return IRQ_HANDLED; }
static void uart_clps711x_console_putchar(struct uart_port *port, int ch) { while (clps_readl(SYSFLG(port)) & SYSFLG_UTXFF) barrier(); clps_writew(ch, UARTDR(port)); }
static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id, struct pt_regs *regs) { struct uart_port *port = dev_id; struct tty_struct *tty = port->info->tty; unsigned int status, ch, flg, ignored = 0; status = clps_readl(SYSFLG(port)); while (!(status & SYSFLG_URXFE)) { ch = clps_readl(UARTDR(port)); if (tty->flip.count >= TTY_FLIPBUF_SIZE) goto ignore_char; port->icount.rx++; flg = TTY_NORMAL; /* * Note that the error handling code is * out of the main execution path */ if (unlikely(ch & UART_ANY_ERR)) { if (ch & UARTDR_PARERR) port->icount.parity++; else if (ch & UARTDR_FRMERR) port->icount.frame++; if (ch & UARTDR_OVERR) port->icount.overrun++; ch &= port->read_status_mask; if (ch & UARTDR_PARERR) flg = TTY_PARITY; else if (ch & UARTDR_FRMERR) flg = TTY_FRAME; #ifdef SUPPORT_SYSRQ port->sysrq = 0; #endif } if (uart_handle_sysrq_char(port, ch, regs)) goto ignore_char; /* * CHECK: does overrun affect the current character? * ASSUMPTION: it does not. */ uart_insert_char(port, ch, UARTDR_OVERR, ch, flg); ignore_char: status = clps_readl(SYSFLG(port)); } tty_flip_buffer_push(tty); return IRQ_HANDLED; }
static irqreturn_t uart_clps711x_int_rx(int irq, void *dev_id) { struct uart_port *port = dev_id; struct tty_struct *tty = tty_port_tty_get(&port->state->port); unsigned int status, ch, flg; if (!tty) return IRQ_HANDLED; for (;;) { status = clps_readl(SYSFLG(port)); if (status & SYSFLG_URXFE) break; ch = clps_readw(UARTDR(port)); status = ch & (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR); ch &= 0xff; port->icount.rx++; flg = TTY_NORMAL; if (unlikely(status)) { if (status & UARTDR_PARERR) port->icount.parity++; else if (status & UARTDR_FRMERR) port->icount.frame++; else if (status & UARTDR_OVERR) port->icount.overrun++; status &= port->read_status_mask; if (status & UARTDR_PARERR) flg = TTY_PARITY; else if (status & UARTDR_FRMERR) flg = TTY_FRAME; else if (status & UARTDR_OVERR) flg = TTY_OVERRUN; } if (uart_handle_sysrq_char(port, ch)) continue; if (status & port->ignore_status_mask) continue; uart_insert_char(port, status, UARTDR_OVERR, ch, flg); } tty_flip_buffer_push(tty); tty_kref_put(tty); return IRQ_HANDLED; }
/* * Print a string to the serial port trying not to disturb * any possible real use of the port... * * The console_lock must be held when we get here. * * Note that this is called with interrupts already disabled */ static void clps711xuart_console_write(struct console *co, const char *s, unsigned int count) { struct uart_port *port = clps711x_ports + co->index; unsigned int status, syscon; int i; /* * Ensure that the port is enabled. */ syscon = clps_readl(SYSCON(port)); clps_writel(syscon | SYSCON_UARTEN, SYSCON(port)); /* * Now, do each character */ for (i = 0; i < count; i++) { do { status = clps_readl(SYSFLG(port)); } while (status & SYSFLG_UTXFF); clps_writel(s[i], UARTDR(port)); if (s[i] == '\n') { do { status = clps_readl(SYSFLG(port)); } while (status & SYSFLG_UTXFF); clps_writel('\r', UARTDR(port)); } } /* * Finally, wait for transmitter to become empty * and restore the uart state. */ do { status = clps_readl(SYSFLG(port)); } while (status & SYSFLG_UBUSY); clps_writel(syscon, SYSCON(port)); }
portBASE_TYPE xUARTReceiveCharacter( unsigned long ulUARTPeripheral, signed char *pcChar, portTickType xDelay ) { unsigned long ulBase = 0; portBASE_TYPE xReturn = pdFALSE; #if UART_USE_INTERRUPT xQueueHandle xRxQueue = NULL; #endif switch ( ulUARTPeripheral ) { case 0: ulBase = UART0_BASE; #if UART_USE_INTERRUPT xRxQueue = xUartQueues[0][RX_QUEUE]; #endif break; case 1: ulBase = UART1_BASE; #if UART_USE_INTERRUPT xRxQueue = xUartQueues[1][RX_QUEUE]; #endif break; case 2: ulBase = UART2_BASE; #if UART_USE_INTERRUPT xRxQueue = xUartQueues[2][RX_QUEUE]; #endif break; case 3: ulBase = UART3_BASE; #if UART_USE_INTERRUPT xRxQueue = xUartQueues[3][RX_QUEUE]; #endif break; } if ( 0 != ulBase ) { #if UART_USE_INTERRUPT xReturn = xQueueReceive( xRxQueue, pcChar, xDelay ); #else if ( ( *UARTFR(ulBase) & UART_FLAG_RXFE ) == 0 ) { *pcChar = *UARTDR(ulBase); xReturn = pdTRUE; } #endif /* UART_USE_INTERRUPT */ } return xReturn; }
static void clps711xuart_int_tx(int irq, void *dev_id, struct pt_regs *regs) { struct uart_info *info = dev_id; struct uart_port *port = info->port; int count; if (port->x_char) { clps_writel(port->x_char, UARTDR(port)); port->icount.tx++; port->x_char = 0; return; } if (info->xmit.head == info->xmit.tail || info->tty->stopped || info->tty->hw_stopped) { clps711xuart_stop_tx(info->port, 0); return; } count = port->fifosize >> 1; do { clps_writel(info->xmit.buf[info->xmit.tail], UARTDR(port)); info->xmit.tail = (info->xmit.tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; if (info->xmit.head == info->xmit.tail) break; } while (--count > 0); if (CIRC_CNT(info->xmit.head, info->xmit.tail, UART_XMIT_SIZE) < WAKEUP_CHARS) uart_event(info, EVT_WRITE_WAKEUP); if (info->xmit.head == info->xmit.tail) clps711xuart_stop_tx(info->port, 0); }
static void clps711xuart_int_rx(int irq, void *dev_id, struct pt_regs *regs) { struct uart_info *info = dev_id; struct tty_struct *tty = info->tty; unsigned int status, ch, flg, ignored = 0; struct uart_port *port = info->port; status = clps_readl(SYSFLG(port)); while (!(status & SYSFLG_URXFE)) { ch = clps_readl(UARTDR(port)); if (tty->flip.count >= TTY_FLIPBUF_SIZE) goto ignore_char; port->icount.rx++; flg = TTY_NORMAL; /* * Note that the error handling code is * out of the main execution path */ if (ch & UART_ANY_ERR) goto handle_error; if (uart_handle_sysrq_char(info, ch, regs)) goto ignore_char; error_return: *tty->flip.flag_buf_ptr++ = flg; *tty->flip.char_buf_ptr++ = ch; tty->flip.count++; ignore_char: status = clps_readl(SYSFLG(port)); } out: tty_flip_buffer_push(tty); return; handle_error: if (ch & UARTDR_PARERR) port->icount.parity++; else if (ch & UARTDR_FRMERR) port->icount.frame++; if (ch & UARTDR_OVERR) port->icount.overrun++; if (ch & port->ignore_status_mask) { if (++ignored > 100) goto out; goto ignore_char; } ch &= port->read_status_mask; if (ch & UARTDR_PARERR) flg = TTY_PARITY; else if (ch & UARTDR_FRMERR) flg = TTY_FRAME; if (ch & UARTDR_OVERR) { /* * CHECK: does overrun affect the current character? * ASSUMPTION: it does not. */ *tty->flip.flag_buf_ptr++ = flg; *tty->flip.char_buf_ptr++ = ch; tty->flip.count++; if (tty->flip.count >= TTY_FLIPBUF_SIZE) goto ignore_char; ch = 0; flg = TTY_OVERRUN; } #ifdef SUPPORT_SYSRQ info->sysrq = 0; #endif goto error_return; }
void vUARTInterruptHandler( void *pvBaseAddress ) { unsigned long ulBase = (unsigned long)pvBaseAddress; unsigned short usStatus = 0; signed char cTransmitChar = 0; signed char cReceiveChar = 0; portBASE_TYPE xTaskWoken = pdFALSE; xQueueHandle xTxQueue = NULL; xQueueHandle xRxQueue = NULL; unsigned long ulUART = 0; /* Select the UART Queues. */ switch ( ulBase ) { case UART0_BASE: ulUART = 0; break; case UART1_BASE: ulUART = 1; break; case UART2_BASE: ulUART = 2; break; case UART3_BASE: ulUART = 3; break; } xTxQueue = xUartQueues[ulUART][TX_QUEUE]; xRxQueue = xUartQueues[ulUART][RX_QUEUE]; /* Figure out the reason for the interrupt. */ usStatus = *UARTMIS(ulBase); if ( usStatus & UART_INT_STATUS_TX ) { /* Buffer is almost empty, try to refill. */ while ( *UARTFR(ulBase) & UART_FLAG_TXFF ) { if ( pdTRUE == xQueueReceiveFromISR( xTxQueue, &cTransmitChar, &xTaskWoken ) ) { *UARTDR(ulBase) = cTransmitChar; } else { /* Run out of characters to send. */ break; } } } if ( usStatus & UART_INT_STATUS_RX ) { /* Receive Buffer is almost full. */ while ( !( *UARTFR(ulBase) & UART_FLAG_RXFE ) ) { cReceiveChar = *UARTDR(ulBase); if ( pdTRUE != xQueueSendFromISR( xRxQueue, &cReceiveChar, &xTaskWoken ) ) { /* Receive Queue is Full. */ /* Not good as we are going to lose this character. */ break; } } } /* Here we should deal with any errors. */ /* Acknownledge the interrupt. */ *UARTICR(ulBase) = usStatus; /* Finally, switch task if necessary. */ portEND_SWITCHING_ISR(xTaskWoken); }