summaryrefslogtreecommitdiff
path: root/drivers/tty/serial/omap-serial.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/serial/omap-serial.c')
-rw-r--r--drivers/tty/serial/omap-serial.c205
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;