Пример #1
0
/* 
 * -------------------------------------------------------------------
 * shutdown ()
 *
 * This routine will shutdown a serial port; interrupts are disabled, and
 * DTR is dropped if the hangup on close termio flag is on.
 * ------------------------------------------------------------------- 
 */
static void shutdown(struct dz_serial *info)
{
	unsigned long flags;
	unsigned short tmp;

	if (!info->is_initialized)
		return;

	save_flags(flags);
	cli();

	dz_stop(info->tty);



	info->cflags &= ~DZ_CREAD;	/* turn off receive enable flag */
	dz_out(info, DZ_LPR, info->cflags);

	if (info->xmit_buf) {	/* free Tx buffer */
		free_page((unsigned long) info->xmit_buf);
		info->xmit_buf = 0;
	}
	if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
		tmp = dz_in(info, DZ_TCR);
		if (tmp & DZ_MODEM_DTR) {
			tmp &= ~DZ_MODEM_DTR;
			dz_out(info, DZ_TCR, tmp);
		}
	}
	if (info->tty)
		set_bit(TTY_IO_ERROR, &info->tty->flags);

	info->is_initialized = 0;
	restore_flags(flags);
}
Пример #2
0
static int __init dz_console_setup(struct console *co, char *options)
{
	struct dz_port *dport = &dz_ports[CONSOLE_LINE];
	int baud = 9600;
	int bits = 8;
	int parity = 'n';
	int flow = 'n';
	int ret;
	unsigned short mask, tmp;

	if (options)
		uart_parse_options(options, &baud, &parity, &bits, &flow);

	dz_reset(dport);

	ret = uart_set_options(&dport->port, co, baud, parity, bits, flow);
	if (ret == 0) {
		mask = 1 << dport->port.line;
		tmp = dz_in(dport, DZ_TCR);	/* read the TX flag */
		if (!(tmp & mask)) {
			tmp |= mask;		/* set the TX flag */
			dz_out(dport, DZ_TCR, tmp);
		}
	}

	return ret;
}
Пример #3
0
/*
 * This routine sends a break character out the serial port.
 */
static void send_break(struct dz_serial *info, int duration)
{
	unsigned long flags;
	unsigned short tmp, mask;

	if (!info->port)
		return;

	mask = 1 << info->line;
	tmp = dz_in(info, DZ_TCR);
	tmp |= mask;

	current->state = TASK_INTERRUPTIBLE;

	save_flags(flags);
	cli();

	dz_out(info, DZ_TCR, tmp);

	schedule_timeout(duration);

	tmp &= ~mask;
	dz_out(info, DZ_TCR, tmp);

	restore_flags(flags);
}
Пример #4
0
/*
 * get_lsr_info - get line status register info
 *
 * Purpose: Let user call ioctl() to get info when the UART physically
 *          is emptied.  On bus types like RS485, the transmitter must
 *          release the bus after transmitting. This must be done when
 *          the transmit shift register is empty, not be done when the
 *          transmit holding register is empty.  This functionality
 *          allows an RS485 driver to be written in user space. 
 */
static unsigned int dz_tx_empty(struct uart_port *uport)
{
	struct dz_port *dport = (struct dz_port *)uport;
	unsigned short status = dz_in(dport, DZ_LPR);

	/* FIXME: this appears to be obviously broken --rmk. */
	return status ? TIOCSER_TEMT : 0;
}
Пример #5
0
Файл: dz.c Проект: ivucica/linux
static void dz_reset(struct dz_port *dport)
{
	dz_out(dport, DZ_CSR, DZ_CLR);
	while (dz_in(dport, DZ_CSR) & DZ_CLR);
	iob();

	/* enable scanning */
	dz_out(dport, DZ_CSR, DZ_MSE);
}
Пример #6
0
Файл: dz.c Проект: ivucica/linux
/*
 * -------------------------------------------------------------------
 * dz_tx_empty() -- get the transmitter empty status
 *
 * Purpose: Let user call ioctl() to get info when the UART physically
 *          is emptied.  On bus types like RS485, the transmitter must
 *          release the bus after transmitting. This must be done when
 *          the transmit shift register is empty, not be done when the
 *          transmit holding register is empty.  This functionality
 *          allows an RS485 driver to be written in user space.
 * -------------------------------------------------------------------
 */
static unsigned int dz_tx_empty(struct uart_port *uport)
{
	struct dz_port *dport = (struct dz_port *)uport;
	unsigned short tmp, mask = 1 << dport->port.line;

	tmp = dz_in(dport, DZ_TCR);
	tmp &= mask;

	return tmp ? 0 : TIOCSER_TEMT;
}
Пример #7
0
/*
 * -------------------------------------------------------------------
 * startup ()
 *
 * various initialization tasks
 * ------------------------------------------------------------------- 
 */
static int startup(struct dz_serial *info)
{
	unsigned long page, flags;
	unsigned short tmp;

	if (info->is_initialized)
		return 0;

	save_flags(flags);
	cli();

	if (!info->port) {
		if (info->tty)
			set_bit(TTY_IO_ERROR, &info->tty->flags);
		restore_flags(flags);
		return -ENODEV;
	}
	if (!info->xmit_buf) {
		page = get_free_page(GFP_KERNEL);
		if (!page) {
			restore_flags(flags);
			return -ENOMEM;
		}
		info->xmit_buf = (unsigned char *) page;
	}
	if (info->tty)
		clear_bit(TTY_IO_ERROR, &info->tty->flags);

	/* enable the interrupt and the scanning */
	tmp = dz_in(info, DZ_CSR);
	tmp |= (DZ_RIE | DZ_TIE | DZ_MSE);
	dz_out(info, DZ_CSR, tmp);

	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;

	/* set up the speed */
	change_speed(info);

	/* clear the line transmitter buffer 
	   I can't figure out why I need to do this - but
	   its necessary - in order for the console portion
	   and the interrupt portion to live happily side by side.
	 */

	/* clear the line transmitter buffer 
	   I can't figure out why I need to do this - but
	   its necessary - in order for the console portion
	   and the interrupt portion to live happily side by side.
	 */

	info->is_initialized = 1;

	restore_flags(flags);
	return 0;
}
Пример #8
0
static void dz_start(struct tty_struct *tty)
{
	struct dz_serial *info = (struct dz_serial *) tty->driver_data;
	unsigned short mask, tmp;

	mask = 1 << info->line;
	tmp = dz_in(info, DZ_TCR);	/* read the TX flag */

	tmp |= mask;		/* set the TX flag */
	dz_out(info, DZ_TCR, tmp);

}
Пример #9
0
Файл: dz.c Проект: ivucica/linux
static void dz_start_tx(struct uart_port *uport)
{
	struct dz_port *dport = (struct dz_port *)uport;
	unsigned short tmp, mask = 1 << dport->port.line;
	unsigned long flags;

	spin_lock_irqsave(&dport->port.lock, flags);
	tmp = dz_in(dport, DZ_TCR);	/* read the TX flag */
	tmp |= mask;			/* set the TX flag */
	dz_out(dport, DZ_TCR, tmp);
	spin_unlock_irqrestore(&dport->port.lock, flags);
}
Пример #10
0
static void dz_set_mctrl(struct uart_port *uport, unsigned int mctrl)
{
	struct dz_port *dport = (struct dz_port *)uport;
	unsigned short tmp;

	if (dport->port.line == DZ_MODEM) {
		tmp = dz_in(dport, DZ_TCR);
		if (mctrl & TIOCM_DTR)
			tmp &= ~DZ_MODEM_DTR;
		else
			tmp |= DZ_MODEM_DTR;
		dz_out(dport, DZ_TCR, tmp);
	}
}
Пример #11
0
/*
 * ------------------------------------------------------------
 * check_modem_status ()
 *
 * Only valid for the MODEM line duh !
 * ------------------------------------------------------------
 */
static inline void check_modem_status(struct dz_serial *info)
{
	unsigned short status;

	/* if not ne modem line just return */
	if (info->line != DZ_MODEM)
		return;

	status = dz_in(info, DZ_MSR);

	/* it's easy, since DSR2 is the only bit in the register */
	if (status)
		info->icount.dsr++;
}
Пример #12
0
static unsigned int dz_get_mctrl(struct uart_port *uport)
{
	struct dz_port *dport = (struct dz_port *)uport;
	unsigned int mctrl = TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;

	if (dport->port.line == DZ_MODEM) {
		/*
		 * CHECKME: This is a guess from the other code... --rmk
		 */
		if (dz_in(dport, DZ_MSR) & DZ_MODEM_DSR)
			mctrl &= ~TIOCM_DSR;
	}

	return mctrl;
}
Пример #13
0
/*
 * ------------------------------------------------------------
 * dz_interrupt ()
 *
 * this is the main interrupt routine for the DZ chip.
 * It deals with the multiple ports.
 * ------------------------------------------------------------
 */
static void dz_interrupt(int irq, void *dev, struct pt_regs *regs)
{
	struct dz_serial *info;
	unsigned short status;

	/* get the reason why we just got an irq */
	status = dz_in((struct dz_serial *) dev, DZ_CSR);
	info = lines[LINE(status)];	/* re-arrange info the proper port */

	if (status & DZ_RDONE)
		receive_chars(info);	/* the receive function */

	if (status & DZ_TRDY)
		transmit_chars(info);
}
Пример #14
0
static void dz_break_ctl(struct uart_port *uport, int break_state)
{
	struct dz_port *dport = (struct dz_port *)uport;
	unsigned long flags;
	unsigned short tmp, mask = 1 << uport->line;

	spin_lock_irqsave(&uport->lock, flags);
	tmp = dz_in(dport, DZ_TCR);
	if (break_state)
		tmp |= mask;
	else
		tmp &= ~mask;
	dz_out(dport, DZ_TCR, tmp);
	spin_unlock_irqrestore(&uport->lock, flags);
}
Пример #15
0
Файл: dz.c Проект: ivucica/linux
/*
 * -------------------------------------------------------------------
 * dz_console_putchar() -- transmit a character
 *
 * Polled transmission.  This is tricky.  We need to mask transmit
 * interrupts so that they do not interfere, enable the transmitter
 * for the line requested and then wait till the transmit scanner
 * requests data for this line.  But it may request data for another
 * line first, in which case we have to disable its transmitter and
 * repeat waiting till our line pops up.  Only then the character may
 * be transmitted.  Finally, the state of the transmitter mask is
 * restored.  Welcome to the world of PDP-11!
 * -------------------------------------------------------------------
 */
static void dz_console_putchar(struct uart_port *uport, int ch)
{
	struct dz_port *dport = (struct dz_port *)uport;
	unsigned long flags;
	unsigned short csr, tcr, trdy, mask;
	int loops = 10000;

	spin_lock_irqsave(&dport->port.lock, flags);
	csr = dz_in(dport, DZ_CSR);
	dz_out(dport, DZ_CSR, csr & ~DZ_TIE);
	tcr = dz_in(dport, DZ_TCR);
	tcr |= 1 << dport->port.line;
	mask = tcr;
	dz_out(dport, DZ_TCR, mask);
	iob();
	spin_unlock_irqrestore(&dport->port.lock, flags);

	while (loops--) {
		trdy = dz_in(dport, DZ_CSR);
		if (!(trdy & DZ_TRDY))
			continue;
		trdy = (trdy & DZ_TLINE) >> 8;
		if (trdy == dport->port.line)
			break;
		mask &= ~(1 << trdy);
		dz_out(dport, DZ_TCR, mask);
		iob();
		udelay(2);
	}

	if (loops)				/* Cannot send otherwise. */
		dz_out(dport, DZ_TDR, ch);

	dz_out(dport, DZ_TCR, tcr);
	dz_out(dport, DZ_CSR, csr);
}
Пример #16
0
Файл: dz.c Проект: ivucica/linux
static unsigned int dz_get_mctrl(struct uart_port *uport)
{
	/*
	 * FIXME: Handle the 3100/5000 as appropriate. --macro
	 */
	struct dz_port *dport = (struct dz_port *)uport;
	unsigned int mctrl = TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;

	if (dport->port.line == DZ_MODEM) {
		if (dz_in(dport, DZ_MSR) & DZ_MODEM_DSR)
			mctrl &= ~TIOCM_DSR;
	}

	return mctrl;
}
Пример #17
0
static void dz_stop(struct tty_struct *tty)
{
	struct dz_serial *info;
	unsigned short mask, tmp;

	if (tty == 0)
		return;

	info = (struct dz_serial *) tty->driver_data;

	mask = 1 << info->line;
	tmp = dz_in(info, DZ_TCR);	/* read the TX flag */

	tmp &= ~mask;		/* clear the TX flag */
	dz_out(info, DZ_TCR, tmp);
}
Пример #18
0
Файл: dz.c Проект: ivucica/linux
/*
 * ------------------------------------------------------------
 * dz_interrupt ()
 *
 * this is the main interrupt routine for the DZ chip.
 * It deals with the multiple ports.
 * ------------------------------------------------------------
 */
static irqreturn_t dz_interrupt(int irq, void *dev)
{
	struct dz_port *dport = (struct dz_port *)dev;
	unsigned short status;

	/* get the reason why we just got an irq */
	status = dz_in(dport, DZ_CSR);

	if ((status & (DZ_RDONE | DZ_RIE)) == (DZ_RDONE | DZ_RIE))
		dz_receive_chars(dport, regs);

	if ((status & (DZ_TRDY | DZ_TIE)) == (DZ_TRDY | DZ_TIE))
		dz_transmit_chars(dport);

	return IRQ_HANDLED;
}
Пример #19
0
Файл: dz.c Проект: ivucica/linux
/*
 * -------------------------------------------------------------------
 * startup ()
 *
 * various initialization tasks
 * -------------------------------------------------------------------
 */
static int dz_startup(struct uart_port *uport)
{
	struct dz_port *dport = (struct dz_port *)uport;
	unsigned long flags;
	unsigned short tmp;

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

	/* enable the interrupt and the scanning */
	tmp = dz_in(dport, DZ_CSR);
	tmp |= DZ_RIE | DZ_TIE | DZ_MSE;
	dz_out(dport, DZ_CSR, tmp);

	spin_unlock_irqrestore(&dport->port.lock, flags);

	return 0;
}
Пример #20
0
Файл: dz.c Проект: ivucica/linux
static void dz_set_mctrl(struct uart_port *uport, unsigned int mctrl)
{
	/*
	 * FIXME: Handle the 3100/5000 as appropriate. --macro
	 */
	struct dz_port *dport = (struct dz_port *)uport;
	unsigned short tmp;

	if (dport->port.line == DZ_MODEM) {
		tmp = dz_in(dport, DZ_TCR);
		if (mctrl & TIOCM_DTR)
			tmp &= ~DZ_MODEM_DTR;
		else
			tmp |= DZ_MODEM_DTR;
		dz_out(dport, DZ_TCR, tmp);
	}
}
Пример #21
0
Файл: dz.c Проект: ivucica/linux
static void dz_break_ctl(struct uart_port *uport, int break_state)
{
	/*
	 * FIXME: Can't access BREAK bits in TDR easily;
	 * reuse the code for polled TX. --macro
	 */
	struct dz_port *dport = (struct dz_port *)uport;
	unsigned long flags;
	unsigned short tmp, mask = 1 << dport->port.line;

	spin_lock_irqsave(&uport->lock, flags);
	tmp = dz_in(dport, DZ_TCR);
	if (break_state)
		tmp |= mask;
	else
		tmp &= ~mask;
	dz_out(dport, DZ_TCR, tmp);
	spin_unlock_irqrestore(&uport->lock, flags);
}
Пример #22
0
/*
 * ------------------------------------------------------------
 * dz_interrupt ()
 *
 * this is the main interrupt routine for the DZ chip.
 * It deals with the multiple ports.
 * ------------------------------------------------------------
 */
static irqreturn_t dz_interrupt(int irq, void *dev, struct pt_regs *regs)
{
	struct dz_port *dport;
	unsigned short status;

	/* get the reason why we just got an irq */
	status = dz_in((struct dz_port *)dev, DZ_CSR);
	dport = &dz_ports[LINE(status)];

	if (status & DZ_RDONE)
		dz_receive_chars(dport);

	if (status & DZ_TRDY)
		dz_transmit_chars(dport);

	/* FIXME: what about check modem status??? --rmk */

	return IRQ_HANDLED;
}
Пример #23
0
Файл: dz.c Проект: ivucica/linux
/*
 * ------------------------------------------------------------
 * check_modem_status()
 *
 * DS 3100 & 5100: Only valid for the MODEM line, duh!
 * DS 5000/200: Valid for the MODEM and PRINTER line.
 * ------------------------------------------------------------
 */
static inline void check_modem_status(struct dz_port *dport)
{
	/*
	 * FIXME:
	 * 1. No status change interrupt; use a timer.
	 * 2. Handle the 3100/5000 as appropriate. --macro
	 */
	unsigned short status;

	/* If not the modem line just return.  */
	if (dport->port.line != DZ_MODEM)
		return;

	status = dz_in(dport, DZ_MSR);

	/* it's easy, since DSR2 is the only bit in the register */
	if (status)
		dport->port.icount.dsr++;
}
Пример #24
0
static void dz_console_put_char(struct dz_port *dport, unsigned char ch)
{
	unsigned long flags;
	int loops = 2500;
	unsigned short tmp = ch;
	/* this code sends stuff out to serial device - spinning its
	   wheels and waiting. */

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

	/* spin our wheels */
	while (((dz_in(dport, DZ_CSR) & DZ_TRDY) != DZ_TRDY) && loops--)
		/* FIXME: cpu_relax, udelay? --rmk */
		;

	/* Actually transmit the character. */
	dz_out(dport, DZ_TDR, tmp);

	spin_unlock_irqrestore(&dport->port.lock, flags);
}
Пример #25
0
Файл: dz.c Проект: ivucica/linux
/*
 * ------------------------------------------------------------
 * transmit_char ()
 *
 * This routine deals with outputs to any lines.
 * ------------------------------------------------------------
 */
static inline void dz_transmit_chars(struct dz_port *dport_in)
{
	struct dz_port *dport;
	struct circ_buf *xmit;
	unsigned short status;
	unsigned char tmp;

	status = dz_in(dport_in, DZ_CSR);
	dport = &dz_ports[LINE(status)];
	xmit = &dport->port.info->xmit;

	if (dport->port.x_char) {		/* XON/XOFF chars */
		dz_out(dport, DZ_TDR, dport->port.x_char);
		dport->port.icount.tx++;
		dport->port.x_char = 0;
		return;
	}
	/* If nothing to do or stopped or hardware stopped. */
	if (uart_circ_empty(xmit) || uart_tx_stopped(&dport->port)) {
		dz_stop_tx(&dport->port);
		return;
	}

	/*
	 * If something to do... (remember the dz has no output fifo,
	 * so we go one char at a time) :-<
	 */
	tmp = xmit->buf[xmit->tail];
	xmit->tail = (xmit->tail + 1) & (DZ_XMIT_SIZE - 1);
	dz_out(dport, DZ_TDR, tmp);
	dport->port.icount.tx++;

	if (uart_circ_chars_pending(xmit) < DZ_WAKEUP_CHARS)
		uart_write_wakeup(&dport->port);

	/* Are we are done. */
	if (uart_circ_empty(xmit))
		dz_stop_tx(&dport->port);
}
Пример #26
0
static void dz_console_put_char(unsigned char ch)
{
	unsigned long flags;
	int loops = 2500;
	unsigned short tmp = ch;
	/* this code sends stuff out to serial device - spinning its
	   wheels and waiting. */

	/* force the issue - point it at lines[3] */
	dz_console = &multi[CONSOLE_LINE];

	save_flags(flags);
	cli();


	/* spin our wheels */
	while (((dz_in(dz_console, DZ_CSR) & DZ_TRDY) != DZ_TRDY) && loops--);

	/* Actually transmit the character. */
	dz_out(dz_console, DZ_TDR, tmp);

	restore_flags(flags);
}
Пример #27
0
/*
 * -------------------------------------------------------------------
 * startup ()
 *
 * various initialization tasks
 * ------------------------------------------------------------------- 
 */
static int dz_startup(struct uart_port *uport)
{
	struct dz_port *dport = (struct dz_port *)uport;
	unsigned long flags;
	unsigned short tmp;

	/* The dz lines for the mouse/keyboard must be
	 * opened using their respective drivers.
	 */
	if ((dport->port.line == DZ_KEYBOARD) ||
	    (dport->port.line == DZ_MOUSE))
		return -ENODEV;

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

	/* enable the interrupt and the scanning */
	tmp = dz_in(dport, DZ_CSR);
	tmp |= DZ_RIE | DZ_TIE | DZ_MSE;
	dz_out(dport, DZ_CSR, tmp);

	spin_unlock_irqrestore(&dport->port.lock, flags);

	return 0;
}
Пример #28
0
/*
 * get_lsr_info - get line status register info
 *
 * Purpose: Let user call ioctl() to get info when the UART physically
 *          is emptied.  On bus types like RS485, the transmitter must
 *          release the bus after transmitting. This must be done when
 *          the transmit shift register is empty, not be done when the
 *          transmit holding register is empty.  This functionality
 *          allows an RS485 driver to be written in user space. 
 */
static int get_lsr_info(struct dz_serial *info, unsigned int *value)
{
	unsigned short status = dz_in(info, DZ_LPR);

	return put_user(status, value);
}
Пример #29
0
Файл: dz.c Проект: ivucica/linux
/*
 * ------------------------------------------------------------
 * receive_char ()
 *
 * This routine deals with inputs from any lines.
 * ------------------------------------------------------------
 */
static inline void dz_receive_chars(struct dz_port *dport_in,
				    struct pt_regs *regs)
{
	struct dz_port *dport;
	struct tty_struct *tty = NULL;
	struct uart_icount *icount;
	int lines_rx[DZ_NB_PORT] = { [0 ... DZ_NB_PORT - 1] = 0 };
	unsigned short status;
	unsigned char ch, flag;
	int i;

	while ((status = dz_in(dport_in, DZ_RBUF)) & DZ_DVAL) {
		dport = &dz_ports[LINE(status)];
		tty = dport->port.info->tty;	/* point to the proper dev */

		ch = UCHAR(status);		/* grab the char */

		icount = &dport->port.icount;
		icount->rx++;

		flag = TTY_NORMAL;
		if (status & DZ_FERR) {		/* frame error */
			/*
			 * There is no separate BREAK status bit, so
			 * treat framing errors as BREAKs for Magic SysRq
			 * and SAK; normally, otherwise.
			 */
			if (uart_handle_break(&dport->port))
				continue;
			if (dport->port.flags & UPF_SAK)
				flag = TTY_BREAK;
			else
				flag = TTY_FRAME;
		} else if (status & DZ_OERR)	/* overrun error */
			flag = TTY_OVERRUN;
		else if (status & DZ_PERR)	/* parity error */
			flag = TTY_PARITY;

		/* keep track of the statistics */
		switch (flag) {
		case TTY_FRAME:
			icount->frame++;
			break;
		case TTY_PARITY:
			icount->parity++;
			break;
		case TTY_OVERRUN:
			icount->overrun++;
			break;
		case TTY_BREAK:
			icount->brk++;
			break;
		default:
			break;
		}

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

		if ((status & dport->port.ignore_status_mask) == 0) {
			uart_insert_char(&dport->port,
					 status, DZ_OERR, ch, flag);
			lines_rx[LINE(status)] = 1;
		}
	}
	for (i = 0; i < DZ_NB_PORT; i++)
		if (lines_rx[i])
			tty_flip_buffer_push(dz_ports[i].port.info->tty);
}
Пример #30
0
/*
 * ------------------------------------------------------------
 * receive_char ()
 *
 * This routine deals with inputs from any lines.
 * ------------------------------------------------------------
 */
static inline void dz_receive_chars(struct dz_port *dport)
{
	struct tty_struct *tty = NULL;
	struct uart_icount *icount;
	int ignore = 0;
	unsigned short status, tmp;
	unsigned char ch, flag;

	/* this code is going to be a problem...
	   the call to tty_flip_buffer is going to need
	   to be rethought...
	 */
	do {
		status = dz_in(dport, DZ_RBUF);

		/* punt so we don't get duplicate characters */
		if (!(status & DZ_DVAL))
			goto ignore_char;


		ch = UCHAR(status);	/* grab the char */
		flag = TTY_NORMAL;

#if 0
		if (info->is_console) {
			if (ch == 0)
				return;		/* it's a break ... */
		}
#endif

		tty = dport->port.info->tty;/* now tty points to the proper dev */
		icount = &dport->port.icount;

		if (!tty)
			break;
		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
			break;

		icount->rx++;

		/* keep track of the statistics */
		if (status & (DZ_OERR | DZ_FERR | DZ_PERR)) {
			if (status & DZ_PERR)	/* parity error */
				icount->parity++;
			else if (status & DZ_FERR)	/* frame error */
				icount->frame++;
			if (status & DZ_OERR)	/* overrun error */
				icount->overrun++;

			/*  check to see if we should ignore the character
			   and mask off conditions that should be ignored
			 */

			if (status & dport->port.ignore_status_mask) {
				if (++ignore > 100)
					break;
				goto ignore_char;
			}
			/* mask off the error conditions we want to ignore */
			tmp = status & dport->port.read_status_mask;

			if (tmp & DZ_PERR) {
				flag = TTY_PARITY;
#ifdef DEBUG_DZ
				debug_console("PERR\n", 5);
#endif
			} else if (tmp & DZ_FERR) {
				flag = TTY_FRAME;
#ifdef DEBUG_DZ
				debug_console("FERR\n", 5);
#endif
			}
			if (tmp & DZ_OERR) {
#ifdef DEBUG_DZ
				debug_console("OERR\n", 5);
#endif
				tty_insert_flip_char(tty, ch, flag);
				ch = 0;
				flag = TTY_OVERRUN;
			}
		}
		tty_insert_flip_char(tty, ch, flag);
	      ignore_char:
	} while (status & DZ_DVAL);

	if (tty)
		tty_flip_buffer_push(tty);
}

/*
 * ------------------------------------------------------------
 * transmit_char ()
 *
 * This routine deals with outputs to any lines.
 * ------------------------------------------------------------
 */
static inline void dz_transmit_chars(struct dz_port *dport)
{
	struct circ_buf *xmit = &dport->port.info->xmit;
	unsigned char tmp;

	if (dport->port.x_char) {	/* XON/XOFF chars */
		dz_out(dport, DZ_TDR, dport->port.x_char);
		dport->port.icount.tx++;
		dport->port.x_char = 0;
		return;
	}
	/* if nothing to do or stopped or hardware stopped */
	if (uart_circ_empty(xmit) || uart_tx_stopped(&dport->port)) {
		dz_stop_tx(&dport->port, 0);
		return;
	}

	/*
	 * if something to do ... (rember the dz has no output fifo so we go
	 * one char at a time :-<
	 */
	tmp = xmit->buf[xmit->tail];
	xmit->tail = (xmit->tail + 1) & (DZ_XMIT_SIZE - 1);
	dz_out(dport, DZ_TDR, tmp);
	dport->port.icount.tx++;

	if (uart_circ_chars_pending(xmit) < DZ_WAKEUP_CHARS)
		uart_write_wakeup(&dport->port);

	/* Are we done */
	if (uart_circ_empty(xmit))
		dz_stop_tx(&dport->port, 0);
}

/*
 * ------------------------------------------------------------
 * check_modem_status ()
 *
 * Only valid for the MODEM line duh !
 * ------------------------------------------------------------
 */
static inline void check_modem_status(struct dz_port *dport)
{
	unsigned short status;

	/* if not ne modem line just return */
	if (dport->port.line != DZ_MODEM)
		return;

	status = dz_in(dport, DZ_MSR);

	/* it's easy, since DSR2 is the only bit in the register */
	if (status)
		dport->port.icount.dsr++;
}