예제 #1
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);
}
예제 #2
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);
}
예제 #3
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);
}
예제 #4
0
파일: dz.c 프로젝트: OpenHMR/Open-HMR600
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;
}
예제 #5
0
파일: dz.c 프로젝트: ivucica/linux
static void dz_stop_rx(struct uart_port *uport)
{
	struct dz_port *dport = (struct dz_port *)uport;
	unsigned long flags;

	spin_lock_irqsave(&dport->port.lock, flags);
	dport->cflag &= ~DZ_CREAD;
	dz_out(dport, DZ_LPR, dport->cflag | dport->port.line);
	spin_unlock_irqrestore(&dport->port.lock, flags);
}
예제 #6
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;
}
예제 #7
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);

}
예제 #8
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);
}
예제 #9
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);
}
예제 #10
0
파일: dz.c 프로젝트: OpenHMR/Open-HMR600
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
파일: dz.c 프로젝트: OpenHMR/Open-HMR600
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);
}
예제 #12
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);
}
예제 #13
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;
}
예제 #14
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);
	}
}
예제 #15
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);
}
예제 #16
0
파일: dz.c 프로젝트: OpenHMR/Open-HMR600
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);
}
예제 #17
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);
}
예제 #18
0
파일: dz.c 프로젝트: OpenHMR/Open-HMR600
/*
 * -------------------------------------------------------------------
 * 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;
}
예제 #19
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);
}
예제 #20
0
static int __init dz_console_setup(struct console *co, char *options)
{
	int baud = 9600;
	int bits = 8;
	int parity = 'n';
	int cflag = CREAD | HUPCL | CLOCAL;
	char *s;
	unsigned short mask, tmp;

	if (options) {
		baud = simple_strtoul(options, NULL, 10);
		s = options;
		while (*s >= '0' && *s <= '9')
			s++;
		if (*s)
			parity = *s++;
		if (*s)
			bits = *s - '0';
	}
	/*
	 *    Now construct a cflag setting.
	 */
	switch (baud) {
	case 1200:
		cflag |= DZ_B1200;
		break;
	case 2400:
		cflag |= DZ_B2400;
		break;
	case 4800:
		cflag |= DZ_B4800;
		break;
	case 9600:
	default:
		cflag |= DZ_B9600;
		break;
	}
	switch (bits) {
	case 7:
		cflag |= DZ_CS7;
		break;
	default:
	case 8:
		cflag |= DZ_CS8;
		break;
	}
	switch (parity) {
	case 'o':
	case 'O':
		cflag |= DZ_PARODD;
		break;
	case 'e':
	case 'E':
		cflag |= DZ_PARENB;
		break;
	}
	co->cflag = cflag;

	/* TOFIX: force to console line */
	dz_console = &multi[CONSOLE_LINE];
	if ((mips_machtype == MACH_DS23100) || (mips_machtype == MACH_DS5100))
		dz_console->port = KN01_DZ11_BASE;
	else
		dz_console->port = KN02_DZ11_BASE;
	dz_console->line = CONSOLE_LINE;

	dz_out(dz_console, DZ_CSR, DZ_CLR);
	while ((tmp = dz_in(dz_console, DZ_CSR)) & DZ_CLR);

	/* enable scanning */
	dz_out(dz_console, DZ_CSR, DZ_MSE);

	/*  Set up flags... */
	dz_console->cflags = 0;
	dz_console->cflags |= DZ_B9600;
	dz_console->cflags |= DZ_CS8;
	dz_console->cflags |= DZ_PARENB;
	dz_out(dz_console, DZ_LPR, dz_console->cflags);

	mask = 1 << dz_console->line;
	tmp = dz_in(dz_console, DZ_TCR);	/* read the TX flag */
	if (!(tmp & mask)) {
		tmp |= mask;	/* set the TX flag */
		dz_out(dz_console, DZ_TCR, tmp);
	}
	return 0;
}
예제 #21
0
파일: dz.c 프로젝트: ivucica/linux
static void dz_set_termios(struct uart_port *uport, struct ktermios *termios,
			   struct ktermios *old_termios)
{
	struct dz_port *dport = (struct dz_port *)uport;
	unsigned long flags;
	unsigned int cflag, baud;

	cflag = dport->port.line;

	switch (termios->c_cflag & CSIZE) {
	case CS5:
		cflag |= DZ_CS5;
		break;
	case CS6:
		cflag |= DZ_CS6;
		break;
	case CS7:
		cflag |= DZ_CS7;
		break;
	case CS8:
	default:
		cflag |= DZ_CS8;
	}

	if (termios->c_cflag & CSTOPB)
		cflag |= DZ_CSTOPB;
	if (termios->c_cflag & PARENB)
		cflag |= DZ_PARENB;
	if (termios->c_cflag & PARODD)
		cflag |= DZ_PARODD;

	baud = uart_get_baud_rate(uport, termios, old_termios, 50, 9600);
	switch (baud) {
	case 50:
		cflag |= DZ_B50;
		break;
	case 75:
		cflag |= DZ_B75;
		break;
	case 110:
		cflag |= DZ_B110;
		break;
	case 134:
		cflag |= DZ_B134;
		break;
	case 150:
		cflag |= DZ_B150;
		break;
	case 300:
		cflag |= DZ_B300;
		break;
	case 600:
		cflag |= DZ_B600;
		break;
	case 1200:
		cflag |= DZ_B1200;
		break;
	case 1800:
		cflag |= DZ_B1800;
		break;
	case 2000:
		cflag |= DZ_B2000;
		break;
	case 2400:
		cflag |= DZ_B2400;
		break;
	case 3600:
		cflag |= DZ_B3600;
		break;
	case 4800:
		cflag |= DZ_B4800;
		break;
	case 7200:
		cflag |= DZ_B7200;
		break;
	case 9600:
	default:
		cflag |= DZ_B9600;
	}

	if (termios->c_cflag & CREAD)
		cflag |= DZ_RXENAB;

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

	dz_out(dport, DZ_LPR, cflag | dport->port.line);
	dport->cflag = cflag;

	/* setup accept flag */
	dport->port.read_status_mask = DZ_OERR;
	if (termios->c_iflag & INPCK)
		dport->port.read_status_mask |= DZ_FERR | DZ_PERR;

	/* characters to ignore */
	uport->ignore_status_mask = 0;
	if (termios->c_iflag & IGNPAR)
		dport->port.ignore_status_mask |= DZ_FERR | DZ_PERR;

	spin_unlock_irqrestore(&dport->port.lock, flags);
}
예제 #22
0
/*
 * ------------------------------------------------------------
 * receive_char ()
 *
 * This routine deals with inputs from any lines.
 * ------------------------------------------------------------
 */
static inline void receive_chars(struct dz_serial *info_in)
{

	struct dz_serial *info;
	struct tty_struct *tty = 0;
	struct async_icount *icount;
	int ignore = 0;
	unsigned short status, tmp;
	unsigned char ch;

	/* 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(info_in, DZ_RBUF);
		info = lines[LINE(status)];

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

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

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

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

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

		*tty->flip.char_buf_ptr = ch;
		*tty->flip.flag_buf_ptr = 0;
		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 & info->ignore_status_mask) {
				if (++ignore > 100)
					break;
				goto ignore_char;
			}
			/* mask off the error conditions we want to ignore */
			tmp = status & info->read_status_mask;

			if (tmp & DZ_PERR) {
				*tty->flip.flag_buf_ptr = TTY_PARITY;
#ifdef DEBUG_DZ
				debug_console("PERR\n", 5);
#endif
			} else if (tmp & DZ_FERR) {
				*tty->flip.flag_buf_ptr = TTY_FRAME;
#ifdef DEBUG_DZ
				debug_console("FERR\n", 5);
#endif
			}
			if (tmp & DZ_OERR) {
#ifdef DEBUG_DZ
				debug_console("OERR\n", 5);
#endif
				if (tty->flip.count < TTY_FLIPBUF_SIZE) {
					tty->flip.count++;
					tty->flip.flag_buf_ptr++;
					tty->flip.char_buf_ptr++;
					*tty->flip.flag_buf_ptr = TTY_OVERRUN;
				}
			}
		}
		tty->flip.flag_buf_ptr++;
		tty->flip.char_buf_ptr++;
		tty->flip.count++;
	      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 transmit_chars(struct dz_serial *info)
{
	unsigned char tmp;



	if (info->x_char) {	/* XON/XOFF chars */
		dz_out(info, DZ_TDR, info->x_char);
		info->icount.tx++;
		info->x_char = 0;
		return;
	}
	/* if nothing to do or stopped or hardware stopped */
	if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tty->hw_stopped) {
		dz_stop(info->tty);
		return;
	}
	/*
	 * if something to do ... (rember the dz has no output fifo so we go
	 * one char at a time :-<
	 */
	tmp = (unsigned short) info->xmit_buf[info->xmit_tail++];
	dz_out(info, DZ_TDR, tmp);
	info->xmit_tail = info->xmit_tail & (DZ_XMIT_SIZE - 1);
	info->icount.tx++;

	if (--info->xmit_cnt < WAKEUP_CHARS)
		dz_sched_event(info, DZ_EVENT_WRITE_WAKEUP);


	/* Are we done */
	if (info->xmit_cnt <= 0)
		dz_stop(info->tty);
}
예제 #23
0
/* 
 * -------------------------------------------------------------------
 * change_speed ()
 *
 * set the baud rate.
 * ------------------------------------------------------------------- 
 */
static void change_speed(struct dz_serial *info)
{
	unsigned long flags;
	unsigned cflag;
	int baud;

	if (!info->tty || !info->tty->termios)
		return;

	save_flags(flags);
	cli();

	info->cflags = info->line;

	cflag = info->tty->termios->c_cflag;

	switch (cflag & CSIZE) {
	case CS5:
		info->cflags |= DZ_CS5;
		break;
	case CS6:
		info->cflags |= DZ_CS6;
		break;
	case CS7:
		info->cflags |= DZ_CS7;
		break;
	case CS8:
	default:
		info->cflags |= DZ_CS8;
	}

	if (cflag & CSTOPB)
		info->cflags |= DZ_CSTOPB;
	if (cflag & PARENB)
		info->cflags |= DZ_PARENB;
	if (cflag & PARODD)
		info->cflags |= DZ_PARODD;

	baud = tty_get_baud_rate(info->tty);
	switch (baud) {
	case 50:
		info->cflags |= DZ_B50;
		break;
	case 75:
		info->cflags |= DZ_B75;
		break;
	case 110:
		info->cflags |= DZ_B110;
		break;
	case 134:
		info->cflags |= DZ_B134;
		break;
	case 150:
		info->cflags |= DZ_B150;
		break;
	case 300:
		info->cflags |= DZ_B300;
		break;
	case 600:
		info->cflags |= DZ_B600;
		break;
	case 1200:
		info->cflags |= DZ_B1200;
		break;
	case 1800:
		info->cflags |= DZ_B1800;
		break;
	case 2000:
		info->cflags |= DZ_B2000;
		break;
	case 2400:
		info->cflags |= DZ_B2400;
		break;
	case 3600:
		info->cflags |= DZ_B3600;
		break;
	case 4800:
		info->cflags |= DZ_B4800;
		break;
	case 7200:
		info->cflags |= DZ_B7200;
		break;
	case 9600:
	default:
		info->cflags |= DZ_B9600;
	}

	info->cflags |= DZ_RXENAB;
	dz_out(info, DZ_LPR, info->cflags);

	/* setup accept flag */
	info->read_status_mask = DZ_OERR;
	if (I_INPCK(info->tty))
		info->read_status_mask |= (DZ_FERR | DZ_PERR);

	/* characters to ignore */
	info->ignore_status_mask = 0;
	if (I_IGNPAR(info->tty))
		info->ignore_status_mask |= (DZ_FERR | DZ_PERR);

	restore_flags(flags);
}
예제 #24
0
파일: dz.c 프로젝트: OpenHMR/Open-HMR600
/*
 * ------------------------------------------------------------
 * 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++;
}
예제 #25
0
int __init dz_init(void)
{
	int i;
	long flags;
	struct dz_serial *info;

	/* Setup base handler, and timer table. */
	init_bh(SERIAL_BH, do_serial_bh);

	show_serial_version();

	memset(&serial_driver, 0, sizeof(struct tty_driver));
	serial_driver.magic = TTY_DRIVER_MAGIC;
#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
	serial_driver.name = "ttyS";
#else
	serial_driver.name = "tts/%d";
#endif
	serial_driver.major = TTY_MAJOR;
	serial_driver.minor_start = 64;
	serial_driver.num = DZ_NB_PORT;
	serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
	serial_driver.subtype = SERIAL_TYPE_NORMAL;
	serial_driver.init_termios = tty_std_termios;

	serial_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL |
	                                     CLOCAL;
	serial_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
	serial_driver.refcount = &serial_refcount;
	serial_driver.table = serial_table;
	serial_driver.termios = serial_termios;
	serial_driver.termios_locked = serial_termios_locked;

	serial_driver.open = dz_open;
	serial_driver.close = dz_close;
	serial_driver.write = dz_write;
	serial_driver.flush_chars = dz_flush_chars;
	serial_driver.write_room = dz_write_room;
	serial_driver.chars_in_buffer = dz_chars_in_buffer;
	serial_driver.flush_buffer = dz_flush_buffer;
	serial_driver.ioctl = dz_ioctl;
	serial_driver.throttle = dz_throttle;
	serial_driver.unthrottle = dz_unthrottle;
	serial_driver.send_xchar = dz_send_xchar;
	serial_driver.set_termios = dz_set_termios;
	serial_driver.stop = dz_stop;
	serial_driver.start = dz_start;
	serial_driver.hangup = dz_hangup;

	/*
	 * The callout device is just like normal device except for
	 * major number and the subtype code.
	 */
	callout_driver = serial_driver;
#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
	callout_driver.name = "cua";
#else
	callout_driver.name = "cua/%d";
#endif
	callout_driver.major = TTYAUX_MAJOR;
	callout_driver.subtype = SERIAL_TYPE_CALLOUT;

	if (tty_register_driver(&serial_driver))
		panic("Couldn't register serial driver");
	if (tty_register_driver(&callout_driver))
		panic("Couldn't register callout driver");
	save_flags(flags);
	cli();

	for (i = 0; i < DZ_NB_PORT; i++) {
		info = &multi[i];
		lines[i] = info;
		info->magic = SERIAL_MAGIC;

		if (mips_machtype == MACH_DS23100 ||
		    mips_machtype == MACH_DS5100)
			info->port = (unsigned long) KN01_DZ11_BASE;
		else
			info->port = (unsigned long) KN02_DZ11_BASE;

		info->line = i;
		info->tty = 0;
		info->close_delay = 50;
		info->closing_wait = 3000;
		info->x_char = 0;
		info->event = 0;
		info->count = 0;
		info->blocked_open = 0;
		info->tqueue.routine = do_softint;
		info->tqueue.data = info;
		info->tqueue_hangup.routine = do_serial_hangup;
		info->tqueue_hangup.data = info;
		info->callout_termios = callout_driver.init_termios;
		info->normal_termios = serial_driver.init_termios;
		init_waitqueue_head(&info->open_wait);
		init_waitqueue_head(&info->close_wait);

		/*
		 * If we are pointing to address zero then punt - not correctly
		 * set up in setup.c to handle this.
		 */
		if (!info->port)
			return 0;

		printk("ttyS%02d at 0x%08x (irq = %d)\n", info->line,
		       info->port, dec_interrupt[DEC_IRQ_DZ11]);

		tty_register_devfs(&serial_driver, 0,
				 serial_driver.minor_start + info->line);
		tty_register_devfs(&callout_driver, 0,
				callout_driver.minor_start + info->line);
	}

	/* reset the chip */
#ifndef CONFIG_SERIAL_DEC_CONSOLE
	dz_out(info, DZ_CSR, DZ_CLR);
	while (dz_in(info, DZ_CSR) & DZ_CLR);
	iob();

	/* enable scanning */
	dz_out(info, DZ_CSR, DZ_MSE);
#endif

	/* order matters here... the trick is that flags
	   is updated... in request_irq - to immediatedly obliterate
	   it is unwise. */
	restore_flags(flags);


	if (request_irq(dec_interrupt[DEC_IRQ_DZ11], dz_interrupt,
			SA_INTERRUPT, "DZ", lines[0]))
		panic("Unable to register DZ interrupt");

	return 0;
}