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; }
/* * 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; /* * Ensure that the port is enabled. */ syscon = clps_readl(SYSCON(port)); clps_writel(syscon | SYSCON_UARTEN, SYSCON(port)); uart_console_write(port, s, count, clps711xuart_console_putchar); /* * 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)); }
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 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 clps711x_flush(struct console_device *cdev) { struct clps711x_uart *s = cdev->dev->priv; while (readl(SYSFLG(s)) & SYSFLG_UBUSY) barrier(); }
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; }
static void clps711x_putc(struct console_device *cdev, char c) { struct clps711x_uart *s = cdev->dev->priv; /* Wait until there is space in the FIFO */ while (readl(SYSFLG(s)) & SYSFLG_UTXFF) barrier(); /* Send the character */ writew(c, s->UARTDR); }
/* * 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)); }
static int clps711x_getc(struct console_device *cdev) { struct clps711x_uart *s = cdev->dev->priv; u16 data; /* Wait until there is data in the FIFO */ while (readl(SYSFLG(s)) & SYSFLG_URXFE) barrier(); data = readw(s->UARTDR); /* Check for an error flag */ if (data & (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR)) return -1; return (int)data; }
static unsigned int clps711xuart_get_mctrl(struct uart_port *port) { unsigned int port_addr; unsigned int result = 0; unsigned int status; port_addr = SYSFLG(port); if (port_addr == SYSFLG1) { status = clps_readl(SYSFLG1); if (status & SYSFLG1_DCD) result |= TIOCM_CAR; if (status & SYSFLG1_DSR) result |= TIOCM_DSR; if (status & SYSFLG1_CTS) result |= TIOCM_CTS; } return result; }
static void uart_clps711x_console_write(struct console *co, const char *c, unsigned n) { struct clps711x_port *s = (struct clps711x_port *)co->data; struct uart_port *port = &s->port[co->index]; u32 syscon; /* Ensure that the port is enabled */ syscon = clps_readl(SYSCON(port)); clps_writel(syscon | SYSCON_UARTEN, SYSCON(port)); uart_console_write(port, c, n, uart_clps711x_console_putchar); /* Wait for transmitter to become empty */ while (clps_readl(SYSFLG(port)) & SYSFLG_UBUSY) barrier(); /* Restore the uart state */ clps_writel(syscon, SYSCON(port)); }
static unsigned int clps711xuart_tx_empty(struct uart_port *port) { unsigned int status = clps_readl(SYSFLG(port)); return status & SYSFLG_UBUSY ? 0 : TIOCSER_TEMT; }
static unsigned int uart_clps711x_tx_empty(struct uart_port *port) { return (clps_readl(SYSFLG(port) & SYSFLG_UBUSY)) ? 0 : TIOCSER_TEMT; }
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; }
static int clps711x_tstc(struct console_device *cdev) { struct clps711x_uart *s = cdev->dev->priv; return !(readl(SYSFLG(s)) & SYSFLG_URXFE); }