static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port) { struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); unsigned long ufstat = rd_regl(port, S3C2410_UFSTAT); unsigned long ufcon = rd_regl(port, S3C2410_UFCON); if (ufcon & S3C2410_UFCON_FIFOMODE) { if ((ufstat & info->tx_fifomask) != 0 || (ufstat & info->tx_fifofull)) return 0; return 1; } return s3c24xx_serial_txempty_nofifo(port); }
static void s3c24xx_serial_rx_enable(struct uart_port *port) { unsigned long flags; unsigned int ucon, ufcon; int count = 10000; spin_lock_irqsave(&port->lock, flags); while (--count && !s3c24xx_serial_txempty_nofifo(port)) udelay(100); ufcon = rd_regl(port, S3C2410_UFCON); ufcon |= S3C2410_UFCON_RESETRX; wr_regl(port, S3C2410_UFCON, ufcon); ucon = rd_regl(port, S3C2410_UCON); ucon |= S3C2410_UCON_RXIRQMODE; wr_regl(port, S3C2410_UCON, ucon); rx_enabled(port) = 1; spin_unlock_irqrestore(&port->lock, flags); }
static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport) { struct uart_port *port = &ourport->port; unsigned int ufcon, ch, flag, ufstat, uerstat; unsigned int fifocnt = 0; int max_count = port->fifosize; while (max_count-- > 0) { /* * Receive all characters known to be in FIFO * before reading FIFO level again */ if (fifocnt == 0) { ufstat = rd_regl(port, S3C2410_UFSTAT); fifocnt = s3c24xx_serial_rx_fifocnt(ourport, ufstat); if (fifocnt == 0) break; } fifocnt--; uerstat = rd_regl(port, S3C2410_UERSTAT); ch = rd_regb(port, S3C2410_URXH); if (port->flags & UPF_CONS_FLOW) { int txe = s3c24xx_serial_txempty_nofifo(port); if (rx_enabled(port)) { if (!txe) { rx_enabled(port) = 0; continue; } } else { if (txe) { ufcon = rd_regl(port, S3C2410_UFCON); ufcon |= S3C2410_UFCON_RESETRX; wr_regl(port, S3C2410_UFCON, ufcon); rx_enabled(port) = 1; return; } continue; } } /* insert the character into the buffer */ flag = TTY_NORMAL; port->icount.rx++; if (unlikely(uerstat & S3C2410_UERSTAT_ANY)) { dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n", ch, uerstat); /* check for break */ if (uerstat & S3C2410_UERSTAT_BREAK) { dbg("break!\n"); port->icount.brk++; if (uart_handle_break(port)) continue; /* Ignore character */ } if (uerstat & S3C2410_UERSTAT_FRAME) port->icount.frame++; if (uerstat & S3C2410_UERSTAT_OVERRUN) port->icount.overrun++; uerstat &= port->read_status_mask; if (uerstat & S3C2410_UERSTAT_BREAK) flag = TTY_BREAK; else if (uerstat & S3C2410_UERSTAT_PARITY) flag = TTY_PARITY; else if (uerstat & (S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_OVERRUN)) flag = TTY_FRAME; } if (uart_handle_sysrq_char(port, ch)) continue; /* Ignore character */ uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN, ch, flag); } tty_flip_buffer_push(&port->state->port); }
static irqreturn_t s3c24xx_serial_rx_chars(int irq, void *dev_id) { struct s3c24xx_uart_port *ourport = dev_id; struct uart_port *port = &ourport->port; struct tty_struct *tty = port->state->port.tty; unsigned int ufcon, ch, flag, ufstat, uerstat; int max_count = 64; while (max_count-- > 0) { ufcon = rd_regl(port, S3C2410_UFCON); ufstat = rd_regl(port, S3C2410_UFSTAT); if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0) break; uerstat = rd_regl(port, S3C2410_UERSTAT); ch = rd_regb(port, S3C2410_URXH); if (port->flags & UPF_CONS_FLOW) { int txe = s3c24xx_serial_txempty_nofifo(port); if (rx_enabled(port)) { if (!txe) { rx_enabled(port) = 0; continue; } } else { if (txe) { ufcon |= S3C2410_UFCON_RESETRX; wr_regl(port, S3C2410_UFCON, ufcon); rx_enabled(port) = 1; goto out; } continue; } } /* insert the character into the buffer */ flag = TTY_NORMAL; port->icount.rx++; if (unlikely(uerstat & S3C2410_UERSTAT_ANY)) { dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n", ch, uerstat); /* check for break */ if (uerstat & S3C2410_UERSTAT_BREAK) { dbg("break!\n"); port->icount.brk++; if (uart_handle_break(port)) goto ignore_char; } if (uerstat & S3C2410_UERSTAT_FRAME) port->icount.frame++; if (uerstat & S3C2410_UERSTAT_OVERRUN) port->icount.overrun++; uerstat &= port->read_status_mask; if (uerstat & S3C2410_UERSTAT_BREAK) flag = TTY_BREAK; else if (uerstat & S3C2410_UERSTAT_PARITY) flag = TTY_PARITY; else if (uerstat & (S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_OVERRUN)) flag = TTY_FRAME; } if (uart_handle_sysrq_char(port, ch)) goto ignore_char; uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN, ch, flag); ignore_char: continue; } tty_flip_buffer_push(tty); out: return IRQ_HANDLED; }
static irqreturn_t s3c24xx_serial_rx_chars(int irq, void *dev_id, struct pt_regs *regs) { struct s3c24xx_uart_port *ourport = dev_id; struct uart_port *port = &ourport->port; struct tty_struct *tty = port->info->tty; unsigned int ufcon, ch, flag, ufstat, uerstat; int max_count = 64; while (max_count-- > 0) { ufcon = rd_regl(port, S3C2410_UFCON); ufstat = rd_regl(port, S3C2410_UFSTAT); if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0) break; if (tty->flip.count >= TTY_FLIPBUF_SIZE) { if (tty->low_latency) tty_flip_buffer_push(tty); /* * If this failed then we will throw away the * bytes but must do so to clear interrupts */ } uerstat = rd_regl(port, S3C2410_UERSTAT); ch = rd_regb(port, S3C2410_URXH); if (port->flags & UPF_CONS_FLOW) { int txe = s3c24xx_serial_txempty_nofifo(port); if (rx_enabled(port)) { if (!txe) { rx_enabled(port) = 0; continue; } } else { if (txe) { ufcon |= S3C2410_UFCON_RESETRX; wr_regl(port, S3C2410_UFCON, ufcon); rx_enabled(port) = 1; goto out; } continue; } } /* insert the character into the buffer */ flag = TTY_NORMAL; port->icount.rx++; if (uerstat & S3C2410_UERSTAT_ANY) { dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n", ch, uerstat); /* check for break */ if (uerstat & S3C2410_UERSTAT_BREAK) { dbg("break!\n"); port->icount.brk++; if (uart_handle_break(port)) goto ignore_char; } if (uerstat & S3C2410_UERSTAT_FRAME) port->icount.frame++; if (uerstat & S3C2410_UERSTAT_OVERRUN) port->icount.overrun++; uerstat &= port->read_status_mask; if (uerstat & S3C2410_UERSTAT_BREAK) flag = TTY_BREAK; else if (uerstat & S3C2410_UERSTAT_PARITY) flag = TTY_PARITY; else if (uerstat & ( S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_OVERRUN)) flag = TTY_FRAME; } if (uart_handle_sysrq_char(port, ch, regs)) goto ignore_char; if ((uerstat & port->ignore_status_mask) == 0) { tty_insert_flip_char(tty, ch, flag); } if ((uerstat & S3C2410_UERSTAT_OVERRUN) && tty->flip.count < TTY_FLIPBUF_SIZE) { /* * Overrun is special, since it's reported * immediately, and doesn't affect the current * character. */ tty_insert_flip_char(tty, 0, TTY_OVERRUN); } ignore_char: continue; } tty_flip_buffer_push(tty); out: return IRQ_HANDLED; }