Esempio n. 1
0
static void handle_rx(struct uart_port *port)
{
	struct tty_port *tport = &port->state->port;

	/*
	 * Handle overrun
	 */
	if ((vt8500_read(port, VT8500_URISR) & RXOVER)) {
		port->icount.overrun++;
		tty_insert_flip_char(tport, 0, TTY_OVERRUN);
	}

	/* and now the main RX loop */
	while (vt8500_read(port, VT8500_URFIDX) & 0x1f00) {
		unsigned int c;
		char flag = TTY_NORMAL;

		c = readw(port->membase + VT8500_RXFIFO) & 0x3ff;

		/* Mask conditions we're ignorning. */
		c &= ~port->read_status_mask;

		if (c & FER) {
			port->icount.frame++;
			flag = TTY_FRAME;
		} else if (c & PER) {
			port->icount.parity++;
			flag = TTY_PARITY;
		}
		port->icount.rx++;

		if (!uart_handle_sysrq_char(port, c))
			tty_insert_flip_char(tport, c, flag);
	}

	spin_unlock(&port->lock);
	tty_flip_buffer_push(tport);
	spin_lock(&port->lock);
}
Esempio n. 2
0
static void tegra_uart_handle_rx_pio(struct tegra_uart_port *tup,
		struct tty_port *tty)
{
	do {
		char flag = TTY_NORMAL;
		unsigned long lsr = 0;
		unsigned char ch;

		lsr = tegra_uart_read(tup, UART_LSR);
		if (!(lsr & UART_LSR_DR))
			break;

		flag = tegra_uart_decode_rx_error(tup, lsr);
		ch = (unsigned char) tegra_uart_read(tup, UART_RX);
		tup->uport.icount.rx++;

		if (!uart_handle_sysrq_char(&tup->uport, ch) && tty)
			tty_insert_flip_char(tty, ch, flag);
	} while (1);

	return;
}
Esempio n. 3
0
static inline void sprd_rx(struct uart_port *port)
{
	struct tty_port *tty = &port->state->port;
	unsigned int ch, flag, lsr, max_count = SPRD_TIMEOUT;

	while ((serial_in(port, SPRD_STS1) & 0x00ff) && max_count--) {
		lsr = serial_in(port, SPRD_LSR);
		ch = serial_in(port, SPRD_RXD);
		flag = TTY_NORMAL;
		port->icount.rx++;

		if (lsr & (SPRD_LSR_BI | SPRD_LSR_PE |
			SPRD_LSR_FE | SPRD_LSR_OE))
			if (handle_lsr_errors(port, &lsr, &flag))
				continue;
		if (uart_handle_sysrq_char(port, ch))
			continue;

		uart_insert_char(port, lsr, SPRD_LSR_OE, ch, flag);
	}

	tty_flip_buffer_push(tty);
}
Esempio n. 4
0
/*
 * Characters received (called from interrupt handler)
 */
static void rk2818_rx_chars(struct uart_port *port)
{
	unsigned int ch, flag;
	while((rk2818_uart_read(port,UART_USR) & UART_RECEIVE_FIFO_NOT_EMPTY) == UART_RECEIVE_FIFO_NOT_EMPTY)
	{
		u32 lsr = rk2818_uart_read(port, UART_LSR);
	    ch = rk2818_uart_read(port,UART_RBR);
	    flag = TTY_NORMAL;
		port->icount.rx++;
		if (lsr & UART_BREAK_INT_BIT) {
			port->icount.brk++;
			if (uart_handle_break(port))
				continue;
		}
		if (uart_handle_sysrq_char(port, ch))
		{
			continue;
		} 
		uart_insert_char(port, 0, 0, ch, flag);
	}
	tty_flip_buffer_push(port->state->port.tty);
	
}
Esempio n. 5
0
static void asc_receive_chars(struct uart_port *port)
{
	struct tty_port *tport = &port->state->port;
	unsigned long status, mode;
	unsigned long c = 0;
	char flag;
	bool ignore_pe = false;

	/*
	 * Datasheet states: If the MODE field selects an 8-bit frame then
	 * this [parity error] bit is undefined. Software should ignore this
	 * bit when reading 8-bit frames.
	 */
	mode = asc_in(port, ASC_CTL) & ASC_CTL_MODE_MSK;
	if (mode == ASC_CTL_MODE_8BIT || mode == ASC_CTL_MODE_8BIT_PAR)
		ignore_pe = true;

	if (irqd_is_wakeup_set(irq_get_irq_data(port->irq)))
		pm_wakeup_event(tport->tty->dev, 0);

	while ((status = asc_in(port, ASC_STA)) & ASC_STA_RBF) {
		c = asc_in(port, ASC_RXBUF) | ASC_RXBUF_DUMMY_RX;
		flag = TTY_NORMAL;
		port->icount.rx++;

		if (status & ASC_STA_OE || c & ASC_RXBUF_FE ||
		    (c & ASC_RXBUF_PE && !ignore_pe)) {

			if (c & ASC_RXBUF_FE) {
				if (c == (ASC_RXBUF_FE | ASC_RXBUF_DUMMY_RX)) {
					port->icount.brk++;
					if (uart_handle_break(port))
						continue;
					c |= ASC_RXBUF_DUMMY_BE;
				} else {
					port->icount.frame++;
				}
			} else if (c & ASC_RXBUF_PE) {
				port->icount.parity++;
			}
			/*
			 * Reading any data from the RX FIFO clears the
			 * overflow error condition.
			 */
			if (status & ASC_STA_OE) {
				port->icount.overrun++;
				c |= ASC_RXBUF_DUMMY_OE;
			}

			c &= port->read_status_mask;

			if (c & ASC_RXBUF_DUMMY_BE)
				flag = TTY_BREAK;
			else if (c & ASC_RXBUF_PE)
				flag = TTY_PARITY;
			else if (c & ASC_RXBUF_FE)
				flag = TTY_FRAME;
		}

		if (uart_handle_sysrq_char(port, c & 0xff))
			continue;

		uart_insert_char(port, c, ASC_RXBUF_DUMMY_OE, c & 0xff, flag);
	}

	/* Tell the rest of the system the news. New characters! */
	tty_flip_buffer_push(tport);
}
Esempio n. 6
0
static _INLINE_ void
receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
{
	struct tty_struct *tty = up->port.info->tty;
	unsigned char ch;
	int max_count = 256;

	do {
		if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
			tty->flip.work.func((void *)tty);
			if (tty->flip.count >= TTY_FLIPBUF_SIZE)
				return; // if TTY_DONT_FLIP is set
		}
		ch = serial_inp(up, UART_RX);
		*tty->flip.char_buf_ptr = ch;
		*tty->flip.flag_buf_ptr = TTY_NORMAL;
		up->port.icount.rx++;

		if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
				       UART_LSR_FE | UART_LSR_OE))) {
			/*
			 * For statistics only
			 */
			if (*status & UART_LSR_BI) {
				*status &= ~(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 (*status & UART_LSR_PE)
				up->port.icount.parity++;
			else if (*status & UART_LSR_FE)
				up->port.icount.frame++;
			if (*status & UART_LSR_OE)
				up->port.icount.overrun++;

			/*
			 * Mask off conditions which should be ingored.
			 */
			*status &= up->port.read_status_mask;

#ifdef CONFIG_SERIAL_AU1X00_CONSOLE
			if (up->port.line == up->port.cons->index) {
				/* Recover the break flag from console xmit */
				*status |= up->lsr_break_flag;
				up->lsr_break_flag = 0;
			}
#endif
			if (*status & UART_LSR_BI) {
				DEBUG_INTR("handling break....");
				*tty->flip.flag_buf_ptr = TTY_BREAK;
			} else if (*status & UART_LSR_PE)
				*tty->flip.flag_buf_ptr = TTY_PARITY;
			else if (*status & UART_LSR_FE)
				*tty->flip.flag_buf_ptr = TTY_FRAME;
		}
		if (uart_handle_sysrq_char(&up->port, ch, regs))
			goto ignore_char;
		if ((*status & up->port.ignore_status_mask) == 0) {
			tty->flip.flag_buf_ptr++;
			tty->flip.char_buf_ptr++;
			tty->flip.count++;
		}
		if ((*status & UART_LSR_OE) &&
		    tty->flip.count < TTY_FLIPBUF_SIZE) {
			/*
			 * Overrun is special, since it's reported
			 * immediately, and doesn't affect the current
			 * character.
			 */
			*tty->flip.flag_buf_ptr = TTY_OVERRUN;
			tty->flip.flag_buf_ptr++;
			tty->flip.char_buf_ptr++;
			tty->flip.count++;
		}
	ignore_char:
		*status = serial_inp(up, UART_LSR);
	} while ((*status & UART_LSR_DR) && (max_count-- > 0));
	spin_unlock(&up->port.lock);
	tty_flip_buffer_push(tty);
	spin_lock(&up->port.lock);
}
Esempio n. 7
0
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;
}
pl010_rx_chars(struct uart_port *port)
#endif
{
	struct tty_struct *tty = port->info->tty;
	unsigned int status, ch, flag, rsr, max_count = 256;

	status = UART_GET_FR(port);
	while (UART_RX_DATA(status) && max_count--) {
		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.
			 */
		}

		ch = UART_GET_CHAR(port);
		flag = TTY_NORMAL;

		port->icount.rx++;

		/*
		 * Note that the error handling code is
		 * out of the main execution path
		 */
		rsr = UART_GET_RSR(port) | UART_DUMMY_RSR_RX;
		if (unlikely(rsr & UART01x_RSR_ANY)) {
			if (rsr & UART01x_RSR_BE) {
				rsr &= ~(UART01x_RSR_FE | UART01x_RSR_PE);
				port->icount.brk++;
				if (uart_handle_break(port))
					goto ignore_char;
			} else if (rsr & UART01x_RSR_PE)
				port->icount.parity++;
			else if (rsr & UART01x_RSR_FE)
				port->icount.frame++;
			if (rsr & UART01x_RSR_OE)
				port->icount.overrun++;

			rsr &= port->read_status_mask;

			if (rsr & UART01x_RSR_BE)
				flag = TTY_BREAK;
			else if (rsr & UART01x_RSR_PE)
				flag = TTY_PARITY;
			else if (rsr & UART01x_RSR_FE)
				flag = TTY_FRAME;
		}

		if (uart_handle_sysrq_char(port, ch, regs))
			goto ignore_char;

		uart_insert_char(port, rsr, UART01x_RSR_OE, ch, flag);

	ignore_char:
		status = UART_GET_FR(port);
	}
	tty_flip_buffer_push(tty);
	return;
}
Esempio n. 9
0
/**
 * cdns_uart_isr - Interrupt handler
 * @irq: Irq number
 * @dev_id: Id of the port
 *
 * Return: IRQHANDLED
 */
static irqreturn_t cdns_uart_isr(int irq, void *dev_id)
{
    struct uart_port *port = (struct uart_port *)dev_id;
    unsigned long flags;
    unsigned int isrstatus, numbytes;
    unsigned int data;
    char status = TTY_NORMAL;

    spin_lock_irqsave(&port->lock, flags);

    /* Read the interrupt status register to determine which
     * interrupt(s) is/are active.
     */
    isrstatus = cdns_uart_readl(CDNS_UART_ISR_OFFSET);

    /*
     * There is no hardware break detection, so we interpret framing
     * error with all-zeros data as a break sequence. Most of the time,
     * there's another non-zero byte at the end of the sequence.
     */
    if (isrstatus & CDNS_UART_IXR_FRAMING) {
        while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) &
                 CDNS_UART_SR_RXEMPTY)) {
            if (!cdns_uart_readl(CDNS_UART_FIFO_OFFSET)) {
                port->read_status_mask |= CDNS_UART_IXR_BRK;
                isrstatus &= ~CDNS_UART_IXR_FRAMING;
            }
        }
        cdns_uart_writel(CDNS_UART_IXR_FRAMING, CDNS_UART_ISR_OFFSET);
    }

    /* drop byte with parity error if IGNPAR specified */
    if (isrstatus & port->ignore_status_mask & CDNS_UART_IXR_PARITY)
        isrstatus &= ~(CDNS_UART_IXR_RXTRIG | CDNS_UART_IXR_TOUT);

    isrstatus &= port->read_status_mask;
    isrstatus &= ~port->ignore_status_mask;

    if ((isrstatus & CDNS_UART_IXR_TOUT) ||
            (isrstatus & CDNS_UART_IXR_RXTRIG)) {
        /* Receive Timeout Interrupt */
        while ((cdns_uart_readl(CDNS_UART_SR_OFFSET) &
                CDNS_UART_SR_RXEMPTY) != CDNS_UART_SR_RXEMPTY) {
            data = cdns_uart_readl(CDNS_UART_FIFO_OFFSET);

            /* Non-NULL byte after BREAK is garbage (99%) */
            if (data && (port->read_status_mask &
                         CDNS_UART_IXR_BRK)) {
                port->read_status_mask &= ~CDNS_UART_IXR_BRK;
                port->icount.brk++;
                if (uart_handle_break(port))
                    continue;
            }

#ifdef SUPPORT_SYSRQ
            /*
             * uart_handle_sysrq_char() doesn't work if
             * spinlocked, for some reason
             */
            if (port->sysrq) {
                spin_unlock(&port->lock);
                if (uart_handle_sysrq_char(port,
                                           (unsigned char)data)) {
                    spin_lock(&port->lock);
                    continue;
                }
                spin_lock(&port->lock);
            }
#endif

            port->icount.rx++;

            if (isrstatus & CDNS_UART_IXR_PARITY) {
                port->icount.parity++;
                status = TTY_PARITY;
            } else if (isrstatus & CDNS_UART_IXR_FRAMING) {
                port->icount.frame++;
                status = TTY_FRAME;
            } else if (isrstatus & CDNS_UART_IXR_OVERRUN) {
                port->icount.overrun++;
            }

            uart_insert_char(port, isrstatus, CDNS_UART_IXR_OVERRUN,
                             data, status);
        }
        spin_unlock(&port->lock);
        tty_flip_buffer_push(&port->state->port);
        spin_lock(&port->lock);
    }

    /* Dispatch an appropriate handler */
    if ((isrstatus & CDNS_UART_IXR_TXEMPTY) == CDNS_UART_IXR_TXEMPTY) {
        if (uart_circ_empty(&port->state->xmit)) {
            cdns_uart_writel(CDNS_UART_IXR_TXEMPTY,
                             CDNS_UART_IDR_OFFSET);
        } else {
            numbytes = port->fifosize;
            /* Break if no more data available in the UART buffer */
            while (numbytes--) {
                if (uart_circ_empty(&port->state->xmit))
                    break;
                /* Get the data from the UART circular buffer
                 * and write it to the cdns_uart's TX_FIFO
                 * register.
                 */
                cdns_uart_writel(
                    port->state->xmit.buf[port->state->xmit.
                                          tail], CDNS_UART_FIFO_OFFSET);

                port->icount.tx++;

                /* Adjust the tail of the UART buffer and wrap
                 * the buffer if it reaches limit.
                 */
                port->state->xmit.tail =
                    (port->state->xmit.tail + 1) &
                    (UART_XMIT_SIZE - 1);
            }

            if (uart_circ_chars_pending(
                        &port->state->xmit) < WAKEUP_CHARS)
                uart_write_wakeup(port);
        }
    }

    cdns_uart_writel(isrstatus, CDNS_UART_ISR_OFFSET);

    /* be sure to release the lock and tty before leaving */
    spin_unlock_irqrestore(&port->lock, flags);

    return IRQ_HANDLED;
}
Esempio n. 10
0
static bool ip22zilog_receive_chars(struct uart_ip22zilog_port *up,
						  struct zilog_channel *channel)
{
	unsigned char ch, flag;
	unsigned int r1;
	bool push = up->port.state != NULL;

	for (;;) {
		ch = readb(&channel->control);
		ZSDELAY();
		if (!(ch & Rx_CH_AV))
			break;

		r1 = read_zsreg(channel, R1);
		if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
			writeb(ERR_RES, &channel->control);
			ZSDELAY();
			ZS_WSYNC(channel);
		}

		ch = readb(&channel->data);
		ZSDELAY();

		ch &= up->parity_mask;

		/* Handle the null char got when BREAK is removed.  */
		if (!ch)
			r1 |= up->tty_break;

		/* A real serial line, record the character and status.  */
		flag = TTY_NORMAL;
		up->port.icount.rx++;
		if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | Rx_SYS | Rx_BRK)) {
			up->tty_break = 0;

			if (r1 & (Rx_SYS | Rx_BRK)) {
				up->port.icount.brk++;
				if (r1 & Rx_SYS)
					continue;
				r1 &= ~(PAR_ERR | CRC_ERR);
			}
			else if (r1 & PAR_ERR)
				up->port.icount.parity++;
			else if (r1 & CRC_ERR)
				up->port.icount.frame++;
			if (r1 & Rx_OVR)
				up->port.icount.overrun++;
			r1 &= up->port.read_status_mask;
			if (r1 & Rx_BRK)
				flag = TTY_BREAK;
			else if (r1 & PAR_ERR)
				flag = TTY_PARITY;
			else if (r1 & CRC_ERR)
				flag = TTY_FRAME;
		}

		if (uart_handle_sysrq_char(&up->port, ch))
			continue;

		if (push)
			uart_insert_char(&up->port, r1, Rx_OVR, ch, flag);
	}
	return push;
}
Esempio n. 11
0
static irqreturn_t imx_rxint(int irq, void *dev_id)
{
	struct imx_port *sport = dev_id;
	unsigned int rx,flg,ignored = 0;
	struct tty_struct *tty = sport->port.state->port.tty;
	unsigned long flags, temp;

	spin_lock_irqsave(&sport->port.lock,flags);

	while (readl(sport->port.membase + USR2) & USR2_RDR) {
		flg = TTY_NORMAL;
		sport->port.icount.rx++;

		rx = readl(sport->port.membase + URXD0);

		temp = readl(sport->port.membase + USR2);
		if (temp & USR2_BRCD) {
			writel(USR2_BRCD, sport->port.membase + USR2);
			if (uart_handle_break(&sport->port))
				continue;
		}

		if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx))
			continue;

		if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) {
			if (rx & URXD_PRERR)
				sport->port.icount.parity++;
			else if (rx & URXD_FRMERR)
				sport->port.icount.frame++;
			if (rx & URXD_OVRRUN)
				sport->port.icount.overrun++;

			if (rx & sport->port.ignore_status_mask) {
				if (++ignored > 100)
					goto out;
				continue;
			}

			rx &= sport->port.read_status_mask;

			if (rx & URXD_PRERR)
				flg = TTY_PARITY;
			else if (rx & URXD_FRMERR)
				flg = TTY_FRAME;
			if (rx & URXD_OVRRUN)
				flg = TTY_OVERRUN;

#ifdef SUPPORT_SYSRQ
			sport->port.sysrq = 0;
#endif
		}

		tty_insert_flip_char(tty, rx, flg);
	}

out:
	spin_unlock_irqrestore(&sport->port.lock,flags);
	tty_flip_buffer_push(tty);
	return IRQ_HANDLED;
}
Esempio n. 12
0
/*
 * read all chars in rx fifo and send them to core
 */
static void bcm_uart_do_rx(struct uart_port *port)
{
	struct tty_struct *tty;
	unsigned int max_count;

	/* limit number of char read in interrupt, should not be
	 * higher than fifo size anyway since we're much faster than
	 * serial port */
	max_count = 32;
	tty = port->state->port.tty;
	do {
		unsigned int iestat, c, cstat;
		char flag;

		/* get overrun/fifo empty information from ier
		 * register */
		iestat = bcm_uart_readl(port, UART_IR_REG);

		if (unlikely(iestat & UART_IR_STAT(UART_IR_RXOVER))) {
			unsigned int val;

			/* fifo reset is required to clear
			 * interrupt */
			val = bcm_uart_readl(port, UART_CTL_REG);
			val |= UART_CTL_RSTRXFIFO_MASK;
			bcm_uart_writel(port, val, UART_CTL_REG);

			port->icount.overrun++;
			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
		}

		if (!(iestat & UART_IR_STAT(UART_IR_RXNOTEMPTY)))
			break;

		cstat = c = bcm_uart_readl(port, UART_FIFO_REG);
		port->icount.rx++;
		flag = TTY_NORMAL;
		c &= 0xff;

		if (unlikely((cstat & UART_FIFO_ANYERR_MASK))) {
			/* do stats first */
			if (cstat & UART_FIFO_BRKDET_MASK) {
				port->icount.brk++;
				if (uart_handle_break(port))
					continue;
			}

			if (cstat & UART_FIFO_PARERR_MASK)
				port->icount.parity++;
			if (cstat & UART_FIFO_FRAMEERR_MASK)
				port->icount.frame++;

			/* update flag wrt read_status_mask */
			cstat &= port->read_status_mask;
			if (cstat & UART_FIFO_BRKDET_MASK)
				flag = TTY_BREAK;
			if (cstat & UART_FIFO_FRAMEERR_MASK)
				flag = TTY_FRAME;
			if (cstat & UART_FIFO_PARERR_MASK)
				flag = TTY_PARITY;
		}

		if (uart_handle_sysrq_char(port, c))
			continue;


		if ((cstat & port->ignore_status_mask) == 0)
			tty_insert_flip_char(tty, c, flag);

	} while (--max_count);

	tty_flip_buffer_push(tty);
}
Esempio n. 13
0
pl011_rx_chars(struct uart_amba_port *uap)
#endif
{
    struct tty_struct *tty = uap->port.info->tty;
    unsigned int status, ch, rsr, max_count = 256;

    status = readw(uap->port.membase + UART01x_FR);
    while ((status & UART01x_FR_RXFE) == 0 && max_count--) {
        if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
            tty->flip.work.func((void *)tty);
            if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
                printk(KERN_WARNING "TTY_DONT_FLIP set\n");
                return;
            }
        }

        ch = readw(uap->port.membase + UART01x_DR);

        *tty->flip.char_buf_ptr = ch;
        *tty->flip.flag_buf_ptr = TTY_NORMAL;
        uap->port.icount.rx++;

        /*
         * Note that the error handling code is
         * out of the main execution path
         */
        rsr = readw(uap->port.membase + UART01x_RSR) | UART_DUMMY_RSR_RX;
        if (rsr & UART01x_RSR_ANY) {
            if (rsr & UART01x_RSR_BE) {
                rsr &= ~(UART01x_RSR_FE | UART01x_RSR_PE);
                uap->port.icount.brk++;
                if (uart_handle_break(&uap->port))
                    goto ignore_char;
            } else if (rsr & UART01x_RSR_PE)
                uap->port.icount.parity++;
            else if (rsr & UART01x_RSR_FE)
                uap->port.icount.frame++;
            if (rsr & UART01x_RSR_OE)
                uap->port.icount.overrun++;

            rsr &= uap->port.read_status_mask;

            if (rsr & UART01x_RSR_BE)
                *tty->flip.flag_buf_ptr = TTY_BREAK;
            else if (rsr & UART01x_RSR_PE)
                *tty->flip.flag_buf_ptr = TTY_PARITY;
            else if (rsr & UART01x_RSR_FE)
                *tty->flip.flag_buf_ptr = TTY_FRAME;
        }

        if (uart_handle_sysrq_char(&uap->port, ch, regs))
            goto ignore_char;

        if ((rsr & uap->port.ignore_status_mask) == 0) {
            tty->flip.flag_buf_ptr++;
            tty->flip.char_buf_ptr++;
            tty->flip.count++;
        }
        if ((rsr & UART01x_RSR_OE) &&
                tty->flip.count < TTY_FLIPBUF_SIZE) {
            /*
             * Overrun is special, since it's reported
             * immediately, and doesn't affect the current
             * character
             */
            *tty->flip.char_buf_ptr++ = 0;
            *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
            tty->flip.count++;
        }
ignore_char:
        status = readw(uap->port.membase + UART01x_FR);
    }
    tty_flip_buffer_push(tty);
    return;
}
Esempio n. 14
0
static irqreturn_t imapx200_serial_rx_chars(int irq, void *dev_id)
{
	struct imapx200_uart_port *ourport = dev_id;
	struct uart_port *port = &ourport->port;
	struct tty_struct *tty = port->state->port.tty;
	unsigned int ch, flag;
	unsigned int usr, rfl, lsr, fcr;
	int max_count = 64;

	while (max_count-- > 0)
	{
		usr = rd_regl(port, IMAPX200_USR);
		rfl = rd_regl(port, IMAPX200_RFL);
		if (imapx200_serial_rx_fifocnt(ourport, usr, rfl) == 0)
			break;

		lsr = rd_regl(port, IMAPX200_LSR);
		ch = rd_regl(port, IMAPX200_RBR);

		if (port->flags & UPF_CONS_FLOW)
		{
			int txe = imapx200_serial_txempty_nofifo(port);

			if (rx_enabled(port))
			{
				if (!txe)
				{
					rx_enabled(port) = 0;
					continue;
				}
			}
			else
			{
				if (txe)
				{
					fcr |= IMAPX200_FCR_RFIFOR_RX_FIFO_RESET | IMAPX200_FCR_FIFOE_FIFO_ENABLE;
					wr_regl(port, IMAPX200_FCR, fcr);
					rx_enabled(port) = 1;
					goto out;
				}
				continue;
			}
		}

		/* insert the character into the buffer */
		flag = TTY_NORMAL;
		port->icount.rx++;

		if (unlikely(lsr & IMAPX200_LSR_ANY))
		{
			dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n", ch, lsr);
			
			/* check for break */
			if (lsr & IMAPX200_LSR_BI_Break_INT)
			{
				dbg("break!\n");
				port->icount.brk++;
				if (uart_handle_break(port))
				    goto ignore_char;
			}

			if (lsr & IMAPX200_LSR_FE_FRAME_ERR)
				port->icount.frame++;
			if (lsr & IMAPX200_LSR_OE_OVERRUN_ERR)
				port->icount.overrun++;

			lsr &= port->read_status_mask;

			if (lsr & IMAPX200_LSR_BI_Break_INT)
				flag = TTY_BREAK;
			else if (lsr & IMAPX200_LSR_PE_PARITY_ERR)
				flag = TTY_PARITY;
			else if (lsr & (IMAPX200_LSR_FE_FRAME_ERR | IMAPX200_LSR_OE_OVERRUN_ERR))
				flag = TTY_FRAME;
		}

		if (uart_handle_sysrq_char(port, ch))
			goto ignore_char;

		uart_insert_char(port, lsr, IMAPX200_LSR_OE_OVERRUN_ERR, ch, flag);

 ignore_char:
		continue;
	}
	tty_flip_buffer_push(tty);

 out:
	return IRQ_HANDLED;
}
Esempio n. 15
0
static void receive_chars(struct uart_sio_port *up, int *status)
{
	struct tty_port *port = &up->port.state->port;
	unsigned char ch;
	unsigned char flag;
	int max_count = 256;

	do {
		ch = sio_in(up, SIORXB);
		flag = TTY_NORMAL;
		up->port.icount.rx++;

		if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
				       UART_LSR_FE | UART_LSR_OE))) {
			/*
			 * For statistics only
			 */
			if (*status & UART_LSR_BI) {
				*status &= ~(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 (*status & UART_LSR_PE)
				up->port.icount.parity++;
			else if (*status & UART_LSR_FE)
				up->port.icount.frame++;
			if (*status & UART_LSR_OE)
				up->port.icount.overrun++;

			/*
			 * Mask off conditions which should be ingored.
			 */
			*status &= up->port.read_status_mask;

			if (*status & UART_LSR_BI) {
				pr_debug("handling break....\n");
				flag = TTY_BREAK;
			} else if (*status & UART_LSR_PE)
				flag = TTY_PARITY;
			else if (*status & UART_LSR_FE)
				flag = TTY_FRAME;
		}
		if (uart_handle_sysrq_char(&up->port, ch))
			goto ignore_char;
		if ((*status & up->port.ignore_status_mask) == 0)
			tty_insert_flip_char(port, ch, flag);

		if (*status & UART_LSR_OE) {
			/*
			 * Overrun is special, since it's reported
			 * immediately, and doesn't affect the current
			 * character.
			 */
			tty_insert_flip_char(port, 0, TTY_OVERRUN);
		}
	ignore_char:
		*status = serial_in(up, UART_LSR);
	} while ((*status & UART_LSR_DR) && (max_count-- > 0));

	spin_unlock(&up->port.lock);
	tty_flip_buffer_push(port);
	spin_lock(&up->port.lock);
}
static void
ip3106_rx_chars(struct ip3106_port *sport, struct pt_regs *regs)
{
	struct tty_struct *tty = sport->port.info->tty;
	unsigned int status, ch, flg, ignored = 0;

	status = FIFO_TO_SM(serial_in(sport, IP3106_FIFO)) |
		 ISTAT_TO_SM(serial_in(sport, IP3106_ISTAT));
	while (status & FIFO_TO_SM(IP3106_UART_FIFO_RXFIFO)) {
		ch = serial_in(sport, IP3106_FIFO);

		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
			goto ignore_char;
		sport->port.icount.rx++;

		flg = TTY_NORMAL;

		/*
		 * note that the error handling code is
		 * out of the main execution path
		 */
		if (status & FIFO_TO_SM(IP3106_UART_FIFO_RXFE |
					IP3106_UART_FIFO_RXPAR))
			goto handle_error;

		if (uart_handle_sysrq_char(&sport->port, ch, regs))
			goto ignore_char;

	error_return:
		tty_insert_flip_char(tty, ch, flg);
	ignore_char:
		serial_out(sport, IP3106_LCR, serial_in(sport, IP3106_LCR) |
				IP3106_UART_LCR_RX_NEXT);
		status = FIFO_TO_SM(serial_in(sport, IP3106_FIFO)) |
			 ISTAT_TO_SM(serial_in(sport, IP3106_ISTAT));
	}
 out:
	tty_flip_buffer_push(tty);
	return;

 handle_error:
	if (status & FIFO_TO_SM(IP3106_UART_FIFO_RXPAR))
		sport->port.icount.parity++;
	else if (status & FIFO_TO_SM(IP3106_UART_FIFO_RXFE))
		sport->port.icount.frame++;
	if (status & ISTAT_TO_SM(IP3106_UART_INT_RXOVRN))
		sport->port.icount.overrun++;

	if (status & sport->port.ignore_status_mask) {
		if (++ignored > 100)
			goto out;
		goto ignore_char;
	}

//	status &= sport->port.read_status_mask;

	if (status & FIFO_TO_SM(IP3106_UART_FIFO_RXPAR))
		flg = TTY_PARITY;
	else if (status & FIFO_TO_SM(IP3106_UART_FIFO_RXFE))
		flg = TTY_FRAME;

	if (status & ISTAT_TO_SM(IP3106_UART_INT_RXOVRN)) {
		/*
		 * overrun does *not* affect the character
		 * we read from the FIFO
		 */
		tty_insert_flip_char(tty, ch, flg);
		ch = 0;
		flg = TTY_OVERRUN;
	}
#ifdef SUPPORT_SYSRQ
	sport->port.sysrq = 0;
#endif
	goto error_return;
}
Esempio n. 17
0
static void
uart00_rx_chars(struct uart_port *port, struct pt_regs *regs)
{
	struct tty_struct *tty = port->info->tty;
	unsigned int status, ch, rds, flg, ignored = 0;

	status = UART_GET_RSR(port);
	while (UART_RX_DATA(status)) {
		/* 
		 * We need to read rds before reading the 
		 * character from the fifo
		 */
		rds = UART_GET_RDS(port);
		ch = UART_GET_CHAR(port);
		port->icount.rx++;

		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
			goto ignore_char;

		flg = TTY_NORMAL;

		/*
		 * Note that the error handling code is
		 * out of the main execution path
		 */
		if (rds & (UART_RDS_BI_MSK |UART_RDS_FE_MSK|
			   UART_RDS_PE_MSK |UART_RDS_PE_MSK))
			goto handle_error;
		if (uart_handle_sysrq_char(port, ch, regs))
			goto ignore_char;

	error_return:
		tty_insert_flip_char(tty, ch, flg);

	ignore_char:
		status = UART_GET_RSR(port);
	}
 out:
	tty_flip_buffer_push(tty);
	return;

 handle_error:
	if (rds & UART_RDS_BI_MSK) {
		status &= ~(UART_RDS_FE_MSK | UART_RDS_PE_MSK);
		port->icount.brk++;
		if (uart_handle_break(port))
			goto ignore_char;
	} else if (rds & UART_RDS_PE_MSK)
		port->icount.parity++;
	else if (rds & UART_RDS_FE_MSK)
		port->icount.frame++;
	if (rds & UART_RDS_OE_MSK)
		port->icount.overrun++;

	if (rds & port->ignore_status_mask) {
		if (++ignored > 100)
			goto out;
		goto ignore_char;
	}
	rds &= port->read_status_mask;

	if (rds & UART_RDS_BI_MSK)
		flg = TTY_BREAK;
	else if (rds & UART_RDS_PE_MSK)
		flg = TTY_PARITY;
	else if (rds & UART_RDS_FE_MSK)
		flg = TTY_FRAME;

	if (rds & UART_RDS_OE_MSK) {
		/*
		 * CHECK: does overrun affect the current character?
		 * ASSUMPTION: it does not.
		 */
		tty_insert_flip_char(tty, ch, flg);
		ch = 0;
		flg = TTY_OVERRUN;
	}
#ifdef SUPPORT_SYSRQ
	port->sysrq = 0;
#endif
	goto error_return;
}
Esempio n. 18
0
static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap,
					    struct pt_regs *regs)
{
	struct tty_struct *tty = NULL;
	unsigned char ch, r1, drop, error;
	int loops = 0;

 retry:
	/* The interrupt can be enabled when the port isn't open, typically
	 * that happens when using one port is open and the other closed (stale
	 * interrupt) or when one port is used as a console.
	 */
	if (!ZS_IS_OPEN(uap)) {
		pmz_debug("pmz: draining input\n");
		/* Port is closed, drain input data */
		for (;;) {
			if ((++loops) > 1000)
				goto flood;
			(void)read_zsreg(uap, R1);
			write_zsreg(uap, R0, ERR_RES);
			(void)read_zsdata(uap);
			ch = read_zsreg(uap, R0);
			if (!(ch & Rx_CH_AV))
				break;
		}
		return NULL;
	}

	/* Sanity check, make sure the old bug is no longer happening */
	if (uap->port.info == NULL || uap->port.info->tty == NULL) {
		WARN_ON(1);
		(void)read_zsdata(uap);
		return NULL;
	}
	tty = uap->port.info->tty;

	while (1) {
		error = 0;
		drop = 0;

		if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
			/* Have to drop the lock here */
			pmz_debug("pmz: flip overflow\n");
			spin_unlock(&uap->port.lock);
			tty->flip.work.func((void *)tty);
			spin_lock(&uap->port.lock);
			if (tty->flip.count >= TTY_FLIPBUF_SIZE)
				drop = 1;
			if (ZS_IS_ASLEEP(uap))
				return NULL;
			if (!ZS_IS_OPEN(uap))
				goto retry;
		}

		r1 = read_zsreg(uap, R1);
		ch = read_zsdata(uap);

		if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
			write_zsreg(uap, R0, ERR_RES);
			zssync(uap);
		}

		ch &= uap->parity_mask;
		if (ch == 0 && uap->prev_status & BRK_ABRT)
			r1 |= BRK_ABRT;

		/* A real serial line, record the character and status.  */
		if (drop)
			goto next_char;

		*tty->flip.char_buf_ptr = ch;
		*tty->flip.flag_buf_ptr = TTY_NORMAL;
		uap->port.icount.rx++;

		if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | BRK_ABRT)) {
			error = 1;
			if (r1 & BRK_ABRT) {
				pmz_debug("pmz: got break !\n");
				r1 &= ~(PAR_ERR | CRC_ERR);
				uap->port.icount.brk++;
				if (uart_handle_break(&uap->port)) {
					pmz_debug("pmz: do handle break !\n");
					goto next_char;
				}
			}
			else if (r1 & PAR_ERR)
				uap->port.icount.parity++;
			else if (r1 & CRC_ERR)
				uap->port.icount.frame++;
			if (r1 & Rx_OVR)
				uap->port.icount.overrun++;
			r1 &= uap->port.read_status_mask;
			if (r1 & BRK_ABRT)
				*tty->flip.flag_buf_ptr = TTY_BREAK;
			else if (r1 & PAR_ERR)
				*tty->flip.flag_buf_ptr = TTY_PARITY;
			else if (r1 & CRC_ERR)
				*tty->flip.flag_buf_ptr = TTY_FRAME;
		}
		if (uart_handle_sysrq_char(&uap->port, ch, regs)) {
			pmz_debug("pmz: sysrq swallowed the char\n");
			goto next_char;
		}

		if (uap->port.ignore_status_mask == 0xff ||
		    (r1 & uap->port.ignore_status_mask) == 0) {
			tty->flip.flag_buf_ptr++;
			tty->flip.char_buf_ptr++;
			tty->flip.count++;
		}
		if ((r1 & Rx_OVR) &&
		    tty->flip.count < TTY_FLIPBUF_SIZE) {
			*tty->flip.flag_buf_ptr = TTY_OVERRUN;
			tty->flip.flag_buf_ptr++;
			tty->flip.char_buf_ptr++;
			tty->flip.count++;
		}
	next_char:
		/* We can get stuck in an infinite loop getting char 0 when the
		 * line is in a wrong HW state, we break that here.
		 * When that happens, I disable the receive side of the driver.
		 * Note that what I've been experiencing is a real irq loop where
		 * I'm getting flooded regardless of the actual port speed.
		 * Something stange is going on with the HW
		 */
		if ((++loops) > 1000)
			goto flood;
		ch = read_zsreg(uap, R0);
		if (!(ch & Rx_CH_AV))
			break;
	}

	return tty;
 flood:
	uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
	write_zsreg(uap, R1, uap->curregs[R1]);
	zssync(uap);
	dev_err(&uap->dev->ofdev.dev, "pmz: rx irq flood !\n");
	return tty;
}
Esempio n. 19
0
static void ip22zilog_receive_chars(struct uart_ip22zilog_port *up,
				   struct zilog_channel *channel)
{
	struct tty_struct *tty = up->port.info->tty;	/* XXX info==NULL? */

	while (1) {
		unsigned char ch, r1, flag;

		r1 = read_zsreg(channel, R1);
		if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
			writeb(ERR_RES, &channel->control);
			ZSDELAY();
			ZS_WSYNC(channel);
		}

		ch = readb(&channel->control);
		ZSDELAY();

		/* This funny hack depends upon BRK_ABRT not interfering
		 * with the other bits we care about in R1.
		 */
		if (ch & BRK_ABRT)
			r1 |= BRK_ABRT;

		ch = readb(&channel->data);
		ZSDELAY();

		ch &= up->parity_mask;

		if (ZS_IS_CONS(up) && (r1 & BRK_ABRT)) {
			/* Wait for BREAK to deassert to avoid potentially
			 * confusing the PROM.
			 */
			while (1) {
				ch = readb(&channel->control);
				ZSDELAY();
				if (!(ch & BRK_ABRT))
					break;
			}
			ip22_do_break();
			return;
		}

		/* A real serial line, record the character and status.  */
		flag = TTY_NORMAL;
		up->port.icount.rx++;
		if (r1 & (BRK_ABRT | PAR_ERR | Rx_OVR | CRC_ERR)) {
			if (r1 & BRK_ABRT) {
				r1 &= ~(PAR_ERR | CRC_ERR);
				up->port.icount.brk++;
				if (uart_handle_break(&up->port))
					goto next_char;
			}
			else if (r1 & PAR_ERR)
				up->port.icount.parity++;
			else if (r1 & CRC_ERR)
				up->port.icount.frame++;
			if (r1 & Rx_OVR)
				up->port.icount.overrun++;
			r1 &= up->port.read_status_mask;
			if (r1 & BRK_ABRT)
				flag = TTY_BREAK;
			else if (r1 & PAR_ERR)
				flag = TTY_PARITY;
			else if (r1 & CRC_ERR)
				flag = TTY_FRAME;
		}
		if (uart_handle_sysrq_char(&up->port, ch))
			goto next_char;

		if (up->port.ignore_status_mask == 0xff ||
		    (r1 & up->port.ignore_status_mask) == 0)
		    	tty_insert_flip_char(tty, ch, flag);

		if (r1 & Rx_OVR)
			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
	next_char:
		ch = readb(&channel->control);
		ZSDELAY();
		if (!(ch & Rx_CH_AV))
			break;
	}

	tty_flip_buffer_push(tty);
}
Esempio n. 20
0
static inline void receive_chars(struct uart_omap_port *up, int *status)
{
	struct tty_struct *tty = up->port.state->port.tty;
	unsigned int flag;
	unsigned char ch, lsr = *status;
	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);
}
Esempio n. 21
0
static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap)
{
	struct tty_struct *tty = NULL;
	unsigned char ch, r1, drop, error, flag;
	int loops = 0;

	/* The interrupt can be enabled when the port isn't open, typically
	 * that happens when using one port is open and the other closed (stale
	 * interrupt) or when one port is used as a console.
	 */
	if (!ZS_IS_OPEN(uap)) {
		pmz_debug("pmz: draining input\n");
		/* Port is closed, drain input data */
		for (;;) {
			if ((++loops) > 1000)
				goto flood;
			(void)read_zsreg(uap, R1);
			write_zsreg(uap, R0, ERR_RES);
			(void)read_zsdata(uap);
			ch = read_zsreg(uap, R0);
			if (!(ch & Rx_CH_AV))
				break;
		}
		return NULL;
	}

	/* Sanity check, make sure the old bug is no longer happening */
	if (uap->port.info == NULL || uap->port.info->tty == NULL) {
		WARN_ON(1);
		(void)read_zsdata(uap);
		return NULL;
	}
	tty = uap->port.info->tty;

	while (1) {
		error = 0;
		drop = 0;

		r1 = read_zsreg(uap, R1);
		ch = read_zsdata(uap);

		if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
			write_zsreg(uap, R0, ERR_RES);
			zssync(uap);
		}

		ch &= uap->parity_mask;
		if (ch == 0 && uap->flags & PMACZILOG_FLAG_BREAK) {
			uap->flags &= ~PMACZILOG_FLAG_BREAK;
		}

#if defined(CONFIG_MAGIC_SYSRQ) && defined(CONFIG_SERIAL_CORE_CONSOLE)
#ifdef USE_CTRL_O_SYSRQ
		/* Handle the SysRq ^O Hack */
		if (ch == '\x0f') {
			uap->port.sysrq = jiffies + HZ*5;
			goto next_char;
		}
#endif /* USE_CTRL_O_SYSRQ */
		if (uap->port.sysrq) {
			int swallow;
			spin_unlock(&uap->port.lock);
			swallow = uart_handle_sysrq_char(&uap->port, ch);
			spin_lock(&uap->port.lock);
			if (swallow)
				goto next_char;
 		}
#endif /* CONFIG_MAGIC_SYSRQ && CONFIG_SERIAL_CORE_CONSOLE */

		/* A real serial line, record the character and status.  */
		if (drop)
			goto next_char;

		flag = TTY_NORMAL;
		uap->port.icount.rx++;

		if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | BRK_ABRT)) {
			error = 1;
			if (r1 & BRK_ABRT) {
				pmz_debug("pmz: got break !\n");
				r1 &= ~(PAR_ERR | CRC_ERR);
				uap->port.icount.brk++;
				if (uart_handle_break(&uap->port))
					goto next_char;
			}
			else if (r1 & PAR_ERR)
				uap->port.icount.parity++;
			else if (r1 & CRC_ERR)
				uap->port.icount.frame++;
			if (r1 & Rx_OVR)
				uap->port.icount.overrun++;
			r1 &= uap->port.read_status_mask;
			if (r1 & BRK_ABRT)
				flag = TTY_BREAK;
			else if (r1 & PAR_ERR)
				flag = TTY_PARITY;
			else if (r1 & CRC_ERR)
				flag = TTY_FRAME;
		}

		if (uap->port.ignore_status_mask == 0xff ||
		    (r1 & uap->port.ignore_status_mask) == 0) {
		    	tty_insert_flip_char(tty, ch, flag);
		}
		if (r1 & Rx_OVR)
			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
	next_char:
		/* We can get stuck in an infinite loop getting char 0 when the
		 * line is in a wrong HW state, we break that here.
		 * When that happens, I disable the receive side of the driver.
		 * Note that what I've been experiencing is a real irq loop where
		 * I'm getting flooded regardless of the actual port speed.
		 * Something stange is going on with the HW
		 */
		if ((++loops) > 1000)
			goto flood;
		ch = read_zsreg(uap, R0);
		if (!(ch & Rx_CH_AV))
			break;
	}

	return tty;
 flood:
	uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
	write_zsreg(uap, R1, uap->curregs[R1]);
	zssync(uap);
	dev_err(&uap->dev->ofdev.dev, "pmz: rx irq flood !\n");
	return tty;
}
Esempio n. 22
0
/*
 * Receive characters
 */
static void cpm_uart_int_rx(struct uart_port *port)
{
	int i;
	unsigned char ch, *cp;
	struct tty_struct *tty = port->info->tty;
	struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
	volatile cbd_t *bdp;
	u16 status;
	unsigned int flg;

	pr_debug("CPM uart[%d]:RX INT\n", port->line);

	/* Just loop through the closed BDs and copy the characters into
	 * the buffer.
	 */
	bdp = pinfo->rx_cur;
	for (;;) {
		/* get status */
		status = bdp->cbd_sc;
		/* If this one is empty, return happy */
		if (status & BD_SC_EMPTY)
			break;

		/* get number of characters, and check spce in flip-buffer */
		i = bdp->cbd_datlen;

		/* If we have not enough room in tty flip buffer, then we try
		 * later, which will be the next rx-interrupt or a timeout
		 */
		if(tty_buffer_request_room(tty, i) < i) {
			printk(KERN_WARNING "No room in flip buffer\n");
			return;
		}

		/* get pointer */
		cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);

		/* loop through the buffer */
		while (i-- > 0) {
			ch = *cp++;
			port->icount.rx++;
			flg = TTY_NORMAL;

			if (status &
			    (BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV))
				goto handle_error;
			if (uart_handle_sysrq_char(port, ch))
				continue;

		      error_return:
			tty_insert_flip_char(tty, ch, flg);

		}		/* End while (i--) */

		/* This BD is ready to be used again. Clear status. get next */
		bdp->cbd_sc &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV | BD_SC_ID);
		bdp->cbd_sc |= BD_SC_EMPTY;

		if (bdp->cbd_sc & BD_SC_WRAP)
			bdp = pinfo->rx_bd_base;
		else
			bdp++;

	} /* End for (;;) */

	/* Write back buffer pointer */
	pinfo->rx_cur = (volatile cbd_t *) bdp;

	/* activate BH processing */
	tty_flip_buffer_push(tty);

	return;

	/* Error processing */

      handle_error:
	/* Statistics */
	if (status & BD_SC_BR)
		port->icount.brk++;
	if (status & BD_SC_PR)
		port->icount.parity++;
	if (status & BD_SC_FR)
		port->icount.frame++;
	if (status & BD_SC_OV)
		port->icount.overrun++;

	/* Mask out ignored conditions */
	status &= port->read_status_mask;

	/* Handle the remaining ones */
	if (status & BD_SC_BR)
		flg = TTY_BREAK;
	else if (status & BD_SC_PR)
		flg = TTY_PARITY;
	else if (status & BD_SC_FR)
		flg = TTY_FRAME;

	/* overrun does not affect the current character ! */
	if (status & BD_SC_OV) {
		ch = 0;
		flg = TTY_OVERRUN;
		/* We skip this buffer */
		/* CHECK: Is really nothing senseful there */
		/* ASSUMPTION: it contains nothing valid */
		i = 0;
	}
#ifdef SUPPORT_SYSRQ
	port->sysrq = 0;
#endif
	goto error_return;
}
Esempio n. 23
0
static inline void receive_chars(struct uart_hsu_port *up, int *status)
{
	struct tty_struct *tty = up->port.state->port.tty;
	unsigned int ch, flag;
	unsigned int max_count = 256;

	if (!tty)
		return;

	do {
		ch = serial_in(up, UART_RX);
		flag = TTY_NORMAL;
		up->port.icount.rx++;

		if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
				       UART_LSR_FE | UART_LSR_OE))) {

			dev_warn(up->dev, "We really rush into ERR/BI case"
				"status = 0x%02x", *status);
			/* For statistics only */
			if (*status & UART_LSR_BI) {
				*status &= ~(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 (*status & UART_LSR_PE)
				up->port.icount.parity++;
			else if (*status & UART_LSR_FE)
				up->port.icount.frame++;
			if (*status & UART_LSR_OE)
				up->port.icount.overrun++;

			/* Mask off conditions which should be ignored. */
			*status &= up->port.read_status_mask;

#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE
			if (up->port.cons &&
				up->port.cons->index == up->port.line) {
				/* Recover the break flag from console xmit */
				*status |= up->lsr_break_flag;
				up->lsr_break_flag = 0;
			}
#endif
			if (*status & UART_LSR_BI) {
				flag = TTY_BREAK;
			} else if (*status & UART_LSR_PE)
				flag = TTY_PARITY;
			else if (*status & UART_LSR_FE)
				flag = TTY_FRAME;
		}

		if (uart_handle_sysrq_char(&up->port, ch))
			goto ignore_char;

		uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag);
	ignore_char:
		*status = serial_in(up, UART_LSR);
	} while ((*status & UART_LSR_DR) && max_count--);
	tty_flip_buffer_push(tty);
}
Esempio n. 24
0
static inline void sci_receive_chars(struct uart_port *port)
{
	struct sci_port *sci_port = (struct sci_port *)port;
	struct tty_struct *tty = port->info->port.tty;
	int i, count, copied = 0;
	unsigned short status;
	unsigned char flag;

	status = sci_in(port, SCxSR);
	if (!(status & SCxSR_RDxF(port)))
		return;

	while (1) {
		if (port->type == PORT_SCIF)
			count = scif_rxroom(port);
		else
			count = sci_rxroom(port);

		/* Don't copy more bytes than there is room for in the buffer */
		count = tty_buffer_request_room(tty, count);

		/* If for any reason we can't copy more data, we're done! */
		if (count == 0)
			break;

		if (port->type == PORT_SCI) {
			char c = sci_in(port, SCxRDR);
			if (uart_handle_sysrq_char(port, c) || sci_port->break_flag)
				count = 0;
			else {
				tty_insert_flip_char(tty, c, TTY_NORMAL);
			}
		} else {
			for (i=0; i<count; i++) {
				char c = sci_in(port, SCxRDR);
				status = sci_in(port, SCxSR);
#if defined(CONFIG_CPU_SH3)
				/* Skip "chars" during break */
				if (sci_port->break_flag) {
					if ((c == 0) &&
					    (status & SCxSR_FER(port))) {
						count--; i--;
						continue;
					}

					/* Nonzero => end-of-break */
					pr_debug("scif: debounce<%02x>\n", c);
					sci_port->break_flag = 0;

					if (STEPFN(c)) {
						count--; i--;
						continue;
					}
				}
#endif /* CONFIG_CPU_SH3 */
				if (uart_handle_sysrq_char(port, c)) {
					count--; i--;
					continue;
				}

				/* Store data and status */
				if (status&SCxSR_FER(port)) {
					flag = TTY_FRAME;
					pr_debug("sci: frame error\n");
				} else if (status&SCxSR_PER(port)) {
					flag = TTY_PARITY;
					pr_debug("sci: parity error\n");
				} else
					flag = TTY_NORMAL;
				tty_insert_flip_char(tty, c, flag);
			}
		}

		sci_in(port, SCxSR); /* dummy read */
		sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));

		copied += count;
		port->icount.rx += count;
	}

	if (copied) {
		/* Tell the rest of the system the news. New characters! */
		tty_flip_buffer_push(tty);
	} else {
		sci_in(port, SCxSR); /* dummy read */
		sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
	}
}
void stmp_appuart_rx(struct stmp_appuart_port *s, u8 *rx_buffer, int count)
{
	u8 c;
	int flag;
	struct tty_struct *tty = s->port.info->port.tty;
	u32 stat;

	spin_lock(&s->lock);
	stat = HW_UARTAPP_STAT_RD_NB(s->mem);

	if (count < 0) {
		count = HW_UARTAPP_STAT_RD_NB(s->mem) & BM_UARTAPP_STAT_RXCOUNT;
		dev_dbg(s->dev, "count = %d\n", count);
	}

	for (;;) {
		if (!rx_buffer) {
			if (stat & BM_UARTAPP_STAT_RXFE)
				break;
			c = HW_UARTAPP_DATA_RD_NB(s->mem) & 0xFF;
		} else {
			if (count-- <= 0)
				break;
			c = *rx_buffer++;
			dev_dbg(s->dev, "Received: %x(%c)\n", c, chr(c));
		}

		flag = TTY_NORMAL;
		if (stat & BM_UARTAPP_STAT_BERR) {
			stat &= ~BM_UARTAPP_STAT_BERR;
			s->port.icount.brk++;
			if (uart_handle_break(&s->port))
				goto ignore;
			flag = TTY_BREAK;
		} else if (stat & BM_UARTAPP_STAT_PERR) {
			stat &= ~BM_UARTAPP_STAT_PERR;
				s->port.icount.parity++;
				flag = TTY_PARITY;
		} else if (stat & BM_UARTAPP_STAT_FERR) {
			stat &= ~BM_UARTAPP_STAT_FERR;
			s->port.icount.frame++;
			flag = TTY_FRAME;
		}

		if (stat & BM_UARTAPP_STAT_OERR)
			s->port.icount.overrun++;

		if (uart_handle_sysrq_char(&s->port, c))
			goto ignore;

		uart_insert_char(&s->port, stat,
			BM_UARTAPP_STAT_OERR, c, flag);
ignore:
		if (pio_mode) {
			HW_UARTAPP_STAT_WR_NB(s->mem, stat);
			stat = HW_UARTAPP_STAT_RD_NB(s->mem);
		}
	}

	HW_UARTAPP_STAT_WR_NB(s->mem, stat);
	tty_flip_buffer_push(tty);
	spin_unlock(&s->lock);
}
Esempio n. 26
0
static void pnx8xxx_rx_chars(struct pnx8xxx_port *sport)
{
	struct tty_struct *tty = sport->port.state->port.tty;
	unsigned int status, ch, flg;

	status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) |
		 ISTAT_TO_SM(serial_in(sport, PNX8XXX_ISTAT));
	while (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFIFO)) {
		ch = serial_in(sport, PNX8XXX_FIFO) & 0xff;

		sport->port.icount.rx++;

		flg = TTY_NORMAL;

		/*
		 * note that the error handling code is
		 * out of the main execution path
		 */
		if (status & (FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE |
					PNX8XXX_UART_FIFO_RXPAR |
					PNX8XXX_UART_FIFO_RXBRK) |
			      ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN))) {
			if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXBRK)) {
				status &= ~(FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) |
					FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR));
				sport->port.icount.brk++;
				if (uart_handle_break(&sport->port))
					goto ignore_char;
			} else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR))
				sport->port.icount.parity++;
			else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE))
				sport->port.icount.frame++;
			if (status & ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN))
				sport->port.icount.overrun++;

			status &= sport->port.read_status_mask;

			if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR))
				flg = TTY_PARITY;
			else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE))
				flg = TTY_FRAME;

#ifdef SUPPORT_SYSRQ
			sport->port.sysrq = 0;
#endif
		}

		if (uart_handle_sysrq_char(&sport->port, ch))
			goto ignore_char;

		uart_insert_char(&sport->port, status,
				ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN), ch, flg);

	ignore_char:
		serial_out(sport, PNX8XXX_LCR, serial_in(sport, PNX8XXX_LCR) |
				PNX8XXX_UART_LCR_RX_NEXT);
		status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) |
			 ISTAT_TO_SM(serial_in(sport, PNX8XXX_ISTAT));
	}
	tty_flip_buffer_push(tty);
}
Esempio n. 27
0
static int
plser_rx_chars(struct uart_info *info, struct pt_regs *regs)
{
	struct tty_struct *tty = info->tty;
	unsigned int status, ch, flg, ignored = 0;
	struct uart_port *port = info->port;
    int rc = 0;

	status = plser_readb(port, SER_STATUS);
	while (status & ST_RX_READY) {
		if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
            tty->flip.tqueue.routine((void *)tty);
            if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
                rc = 1;
                break;
            }
        }

		ch = plser_readb(port, SER_DATA);
		port->icount.rx++;
		flg = TTY_NORMAL;

		/*
		 * note that the error handling code is
		 * out of the main execution path
		 */
		if (status & (ST_PARITY|ST_FRAME|ST_OVERRUN)) {
        	if (status & ST_PARITY)
		        port->icount.parity++;
	        else if (status & ST_FRAME)
		        port->icount.frame++;
	        if (status & ST_OVERRUN)
		        port->icount.overrun++;

	        if (status & port->ignore_status_mask) {
		        if (++ignored > 100) {
                    rc = 1;
			        break;
                }
            }
            goto ignore_char;

	        status &= port->read_status_mask;

	        if (status & ST_PARITY)
		        flg = TTY_PARITY;
	        else if (status & ST_FRAME)
		        flg = TTY_FRAME;

        	if (status & ST_OVERRUN) {
        		/*
		         * overrun does *not* affect the character
		         * we read from the FIFO
		         */
		        *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
        }

		if (uart_handle_sysrq_char(info, ch, regs))
			goto ignore_char;

        *tty->flip.flag_buf_ptr++ = flg;
		*tty->flip.char_buf_ptr++ = ch;
		tty->flip.count++;

	ignore_char:
		status = plser_readb(port, SER_STATUS);
	}

	tty_flip_buffer_push(tty);
	return rc;

}
Esempio n. 28
0
static inline void receive_chars(struct uart_pxa_port *up, int *status)
{
	unsigned int ch, flag;
	int max_count = 256;

	do {
		/* work around Errata #20 according to
		 * Intel(R) PXA27x Processor Family
		 * Specification Update (May 2005)
		 *
		 * Step 2
		 * Disable the Reciever Time Out Interrupt via IER[RTOEI]
		 */
		up->ier &= ~UART_IER_RTOIE;
		serial_out(up, UART_IER, up->ier);

		ch = serial_in(up, UART_RX);
		flag = TTY_NORMAL;
		up->port.icount.rx++;

		if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
				       UART_LSR_FE | UART_LSR_OE))) {
			/*
			 * For statistics only
			 */
			if (*status & UART_LSR_BI) {
				*status &= ~(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 (*status & UART_LSR_PE)
				up->port.icount.parity++;
			else if (*status & UART_LSR_FE)
				up->port.icount.frame++;
			if (*status & UART_LSR_OE)
				up->port.icount.overrun++;

			/*
			 * Mask off conditions which should be ignored.
			 */
			*status &= up->port.read_status_mask;

#ifdef CONFIG_SERIAL_PXA_CONSOLE
			if (up->port.line == up->port.cons->index) {
				/* Recover the break flag from console xmit */
				*status |= up->lsr_break_flag;
				up->lsr_break_flag = 0;
			}
#endif
			if (*status & UART_LSR_BI) {
				flag = TTY_BREAK;
			} else if (*status & UART_LSR_PE)
				flag = TTY_PARITY;
			else if (*status & UART_LSR_FE)
				flag = TTY_FRAME;
		}

		if (uart_handle_sysrq_char(&up->port, ch))
			goto ignore_char;

		uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag);

	ignore_char:
		*status = serial_in(up, UART_LSR);
	} while ((*status & UART_LSR_DR) && (max_count-- > 0));
	tty_flip_buffer_push(&up->port.state->port);

	/* work around Errata #20 according to
	 * Intel(R) PXA27x Processor Family
	 * Specification Update (May 2005)
	 *
	 * Step 6:
	 * No more data in FIFO: Re-enable RTO interrupt via IER[RTOIE]
	 */
	up->ier |= UART_IER_RTOIE;
	serial_out(up, UART_IER, up->ier);
}
Esempio n. 29
0
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);
}
Esempio n. 30
0
static unsigned int sw_uart_handle_rx(struct sw_uart_port *sw_uport, unsigned int lsr)
{
	struct tty_struct *tty = sw_uport->port.state->port.tty;
	unsigned char ch = 0;
	int max_count = 256;
	char flag;

	do {
		if (likely(lsr & SW_UART_LSR_DR)) {
			ch = serial_in(&sw_uport->port, SW_UART_RBR);
#ifdef CONFIG_SW_UART_DUMP_DATA
			sw_uport->dump_buff[sw_uport->dump_len++] = ch;
#endif
		}

		flag = TTY_NORMAL;
		sw_uport->port.icount.rx++;

		if (unlikely(lsr & SW_UART_LSR_BRK_ERROR_BITS)) {
			/*
			 * For statistics only
			 */
			if (lsr & SW_UART_LSR_BI) {
				lsr &= ~(SW_UART_LSR_FE | SW_UART_LSR_PE);
				sw_uport->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(&sw_uport->port))
					goto ignore_char;
			} else if (lsr & SW_UART_LSR_PE)
				sw_uport->port.icount.parity++;
			else if (lsr & SW_UART_LSR_FE)
				sw_uport->port.icount.frame++;
			if (lsr & SW_UART_LSR_OE)
				sw_uport->port.icount.overrun++;

			/*
			 * Mask off conditions which should be ignored.
			 */
			lsr &= sw_uport->port.read_status_mask;
#ifdef CONFIG_SERIAL_SUNXI_CONSOLE
			if (sw_is_console_port(&sw_uport->port)) {
				/* Recover the break flag from console xmit */
				lsr |= sw_uport->lsr_break_flag;
			}
#endif
			if (lsr & SW_UART_LSR_BI)
				flag = TTY_BREAK;
			else if (lsr & SW_UART_LSR_PE)
				flag = TTY_PARITY;
			else if (lsr & SW_UART_LSR_FE)
				flag = TTY_FRAME;
		}
		if (uart_handle_sysrq_char(&sw_uport->port, ch))
			goto ignore_char;
		uart_insert_char(&sw_uport->port, lsr, SW_UART_LSR_OE, ch, flag);
ignore_char:
		lsr = serial_in(&sw_uport->port, SW_UART_LSR);
	} while ((lsr & (SW_UART_LSR_DR | SW_UART_LSR_BI)) && (max_count-- > 0));

	SERIAL_DUMP(sw_uport, "Rx");
	spin_unlock(&sw_uport->port.lock);
	tty_flip_buffer_push(tty);
	spin_lock(&sw_uport->port.lock);

	return lsr;
}