diff options
Diffstat (limited to 'drivers/tty')
-rw-r--r-- | drivers/tty/serial/omap-serial.c | 205 |
1 files changed, 101 insertions, 104 deletions
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index d5a08cb..9c0a4ae 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -196,74 +196,6 @@ static void serial_omap_stop_rx(struct uart_port *port) pm_runtime_put_autosuspend(up->dev); } -static inline void receive_chars(struct uart_omap_port *up, - unsigned int *status) -{ - struct tty_struct *tty = up->port.state->port.tty; - unsigned int flag, lsr = *status; - unsigned char ch = 0; - int max_count = 256; - - do { - if (likely(lsr & UART_LSR_DR)) - ch = serial_in(up, UART_RX); - flag = TTY_NORMAL; - up->port.icount.rx++; - - if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) { - /* - * For statistics only - */ - if (lsr & UART_LSR_BI) { - lsr &= ~(UART_LSR_FE | UART_LSR_PE); - up->port.icount.brk++; - /* - * We do the SysRQ and SAK checking - * here because otherwise the break - * may get masked by ignore_status_mask - * or read_status_mask. - */ - if (uart_handle_break(&up->port)) - goto ignore_char; - } else if (lsr & UART_LSR_PE) { - up->port.icount.parity++; - } else if (lsr & UART_LSR_FE) { - up->port.icount.frame++; - } - - if (lsr & UART_LSR_OE) - up->port.icount.overrun++; - - /* - * Mask off conditions which should be ignored. - */ - lsr &= up->port.read_status_mask; - -#ifdef CONFIG_SERIAL_OMAP_CONSOLE - if (up->port.line == up->port.cons->index) { - /* Recover the break flag from console xmit */ - lsr |= up->lsr_break_flag; - } -#endif - if (lsr & UART_LSR_BI) - flag = TTY_BREAK; - else if (lsr & UART_LSR_PE) - flag = TTY_PARITY; - else if (lsr & UART_LSR_FE) - flag = TTY_FRAME; - } - - if (uart_handle_sysrq_char(&up->port, ch)) - goto ignore_char; - uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag); -ignore_char: - lsr = serial_in(up, UART_LSR); - } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0)); - spin_unlock(&up->port.lock); - tty_flip_buffer_push(tty); - spin_lock(&up->port.lock); -} - static void transmit_chars(struct uart_omap_port *up) { struct circ_buf *xmit = &up->port.state->xmit; @@ -342,6 +274,68 @@ static unsigned int check_modem_status(struct uart_omap_port *up) return status; } +static void serial_omap_rlsi(struct uart_omap_port *up, unsigned int lsr) +{ + unsigned int flag; + + up->port.icount.rx++; + flag = TTY_NORMAL; + + if (lsr & UART_LSR_BI) { + flag = TTY_BREAK; + lsr &= ~(UART_LSR_FE | UART_LSR_PE); + up->port.icount.brk++; + /* + * We do the SysRQ and SAK checking + * here because otherwise the break + * may get masked by ignore_status_mask + * or read_status_mask. + */ + if (uart_handle_break(&up->port)) + return; + + } + + if (lsr & UART_LSR_PE) { + flag = TTY_PARITY; + up->port.icount.parity++; + } + + if (lsr & UART_LSR_FE) { + flag = TTY_FRAME; + up->port.icount.frame++; + } + + if (lsr & UART_LSR_OE) + up->port.icount.overrun++; + +#ifdef CONFIG_SERIAL_OMAP_CONSOLE + if (up->port.line == up->port.cons->index) { + /* Recover the break flag from console xmit */ + lsr |= up->lsr_break_flag; + } +#endif + uart_insert_char(&up->port, lsr, UART_LSR_OE, 0, flag); +} + +static void serial_omap_rdi(struct uart_omap_port *up, unsigned int lsr) +{ + unsigned char ch = 0; + unsigned int flag; + + if (!(lsr & UART_LSR_DR)) + return; + + ch = serial_in(up, UART_RX); + flag = TTY_NORMAL; + up->port.icount.rx++; + + if (uart_handle_sysrq_char(&up->port, ch)) + return; + + uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag); +} + /** * serial_omap_irq() - This handles the interrupt from one port * @irq: uart port irq number @@ -350,54 +344,57 @@ static unsigned int check_modem_status(struct uart_omap_port *up) static inline irqreturn_t serial_omap_irq(int irq, void *dev_id) { struct uart_omap_port *up = dev_id; + struct tty_struct *tty = up->port.state->port.tty; unsigned int iir, lsr; unsigned int type; unsigned long flags; irqreturn_t ret = IRQ_NONE; + int max_count = 256; spin_lock_irqsave(&up->port.lock, flags); pm_runtime_get_sync(up->dev); - iir = serial_in(up, UART_IIR); -again: - if (iir & UART_IIR_NO_INT) - goto out; - ret = IRQ_HANDLED; - lsr = serial_in(up, UART_LSR); + do { + iir = serial_in(up, UART_IIR); + if (iir & UART_IIR_NO_INT) + break; - /* extract IRQ type from IIR register */ - type = iir & 0x3e; + ret = IRQ_HANDLED; + lsr = serial_in(up, UART_LSR); - switch (type) { - case UART_IIR_MSI: - check_modem_status(up); - break; - case UART_IIR_THRI: - if (lsr & UART_LSR_THRE) - transmit_chars(up); - break; - case UART_IIR_RDI: - if (lsr & UART_LSR_DR) - receive_chars(up, &lsr); - break; - case UART_IIR_RLSI: - if (lsr & UART_LSR_BRK_ERROR_BITS) - receive_chars(up, &lsr); - break; - case UART_IIR_RX_TIMEOUT: - receive_chars(up, &lsr); - break; - case UART_IIR_CTS_RTS_DSR: - iir = serial_in(up, UART_IIR); - goto again; - case UART_IIR_XOFF: - /* FALLTHROUGH */ - default: - break; - } + /* extract IRQ type from IIR register */ + type = iir & 0x3e; + + switch (type) { + case UART_IIR_MSI: + check_modem_status(up); + break; + case UART_IIR_THRI: + if (lsr & UART_LSR_THRE) + transmit_chars(up); + break; + case UART_IIR_RX_TIMEOUT: + /* FALLTHROUGH */ + case UART_IIR_RDI: + serial_omap_rdi(up, lsr); + break; + case UART_IIR_RLSI: + serial_omap_rlsi(up, lsr); + break; + case UART_IIR_CTS_RTS_DSR: + /* simply try again */ + break; + case UART_IIR_XOFF: + /* FALLTHROUGH */ + default: + break; + } + } while (!(iir & UART_IIR_NO_INT) && max_count--); -out: spin_unlock_irqrestore(&up->port.lock, flags); + + tty_flip_buffer_push(tty); + pm_runtime_mark_last_busy(up->dev); pm_runtime_put_autosuspend(up->dev); up->port_activity = jiffies; |