Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 83485f82 authored by Atsushi Nemoto's avatar Atsushi Nemoto Committed by Linus Torvalds
Browse files

[PATCH] serial: serial_txx9 driver update



Update the serial_txx9 driver.

 * More strict check in verify_port.  Cleanup.
 * Do not insert a char caused previous overrun.
 * Fix some spin_locks.
 * Do not call uart_add_one_port for absent ports.

Also, this patch removes a BROKEN tag from Kconfig.  This driver has been
marked as BROKEN by removal of uart_register_port, but it has been solved
already on Sep 2005.

Signed-off-by: default avatarAtsushi Nemoto <anemo@mba.ocn.ne.jp>
Cc: Russell King <rmk@arm.linux.org.uk>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 4024ce5e
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -866,7 +866,7 @@ config SERIAL_M32R_PLDSIO

config SERIAL_TXX9
	bool "TMPTX39XX/49XX SIO support"
	depends HAS_TXX9_SERIAL && BROKEN
	depends HAS_TXX9_SERIAL
	select SERIAL_CORE
	default y

+41 −36
Original line number Diff line number Diff line
@@ -33,6 +33,10 @@
 *	1.02	Cleanup. (import 8250.c changes)
 *	1.03	Fix low-latency mode. (import 8250.c changes)
 *	1.04	Remove usage of deprecated functions, cleanup.
 *	1.05	More strict check in verify_port.  Cleanup.
 *	1.06	Do not insert a char caused previous overrun.
 *		Fix some spin_locks.
 *		Do not call uart_add_one_port for absent ports.
 */
#include <linux/config.h>

@@ -57,7 +61,7 @@
#include <asm/io.h>
#include <asm/irq.h>

static char *serial_version = "1.04";
static char *serial_version = "1.06";
static char *serial_name = "TX39/49 Serial driver";

#define PASS_LIMIT	256
@@ -94,6 +98,8 @@ static char *serial_name = "TX39/49 Serial driver";
#define UART_NR  4
#endif

#define HIGH_BITS_OFFSET	((sizeof(long)-sizeof(int))*8)

struct uart_txx9_port {
	struct uart_port	port;

@@ -210,7 +216,7 @@ static inline unsigned int sio_in(struct uart_txx9_port *up, int offset)
{
	switch (up->port.iotype) {
	default:
		return *(volatile u32 *)(up->port.membase + offset);
		return __raw_readl(up->port.membase + offset);
	case UPIO_PORT:
		return inl(up->port.iobase + offset);
	}
@@ -221,7 +227,7 @@ sio_out(struct uart_txx9_port *up, int offset, int value)
{
	switch (up->port.iotype) {
	default:
		*(volatile u32 *)(up->port.membase + offset) = value;
		__raw_writel(value, up->port.membase + offset);
		break;
	case UPIO_PORT:
		outl(value, up->port.iobase + offset);
@@ -259,34 +265,19 @@ sio_quot_set(struct uart_txx9_port *up, int quot)
static void serial_txx9_stop_tx(struct uart_port *port)
{
	struct uart_txx9_port *up = (struct uart_txx9_port *)port;
	unsigned long flags;

	spin_lock_irqsave(&up->port.lock, flags);
	sio_mask(up, TXX9_SIDICR, TXX9_SIDICR_TIE);
	spin_unlock_irqrestore(&up->port.lock, flags);
}

static void serial_txx9_start_tx(struct uart_port *port)
{
	struct uart_txx9_port *up = (struct uart_txx9_port *)port;
	unsigned long flags;

	spin_lock_irqsave(&up->port.lock, flags);
	sio_set(up, TXX9_SIDICR, TXX9_SIDICR_TIE);
	spin_unlock_irqrestore(&up->port.lock, flags);
}

static void serial_txx9_stop_rx(struct uart_port *port)
{
	struct uart_txx9_port *up = (struct uart_txx9_port *)port;
	unsigned long flags;

	spin_lock_irqsave(&up->port.lock, flags);
	up->port.read_status_mask &= ~TXX9_SIDISR_RDIS;
#if 0
	sio_mask(up, TXX9_SIDICR, TXX9_SIDICR_RIE);
#endif
	spin_unlock_irqrestore(&up->port.lock, flags);
}

static void serial_txx9_enable_ms(struct uart_port *port)
@@ -302,12 +293,16 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status, struct pt_regs *r
	unsigned int disr = *status;
	int max_count = 256;
	char flag;
	unsigned int next_ignore_status_mask;

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

		/* mask out RFDN_MASK bit added by previous overrun */
		next_ignore_status_mask =
			up->port.ignore_status_mask & ~TXX9_SIDISR_RFDN_MASK;
		if (unlikely(disr & (TXX9_SIDISR_UBRK | TXX9_SIDISR_UPER |
				     TXX9_SIDISR_UFER | TXX9_SIDISR_UOER))) {
			/*
@@ -328,8 +323,17 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status, struct pt_regs *r
				up->port.icount.parity++;
			else if (disr & TXX9_SIDISR_UFER)
				up->port.icount.frame++;
			if (disr & TXX9_SIDISR_UOER)
			if (disr & TXX9_SIDISR_UOER) {
				up->port.icount.overrun++;
				/*
				 * The receiver read buffer still hold
				 * a char which caused overrun.
				 * Ignore next char by adding RFDN_MASK
				 * to ignore_status_mask temporarily.
				 */
				next_ignore_status_mask |=
					TXX9_SIDISR_RFDN_MASK;
			}

			/*
			 * Mask off conditions which should be ingored.
@@ -349,6 +353,7 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status, struct pt_regs *r
		uart_insert_char(&up->port, disr, TXX9_SIDISR_UOER, ch, flag);

	ignore_char:
		up->port.ignore_status_mask = next_ignore_status_mask;
		disr = sio_in(up, TXX9_SIDISR);
	} while (!(disr & TXX9_SIDISR_UVALID) && (max_count-- > 0));
	spin_unlock(&up->port.lock);
@@ -450,14 +455,11 @@ static unsigned int serial_txx9_get_mctrl(struct uart_port *port)
static void serial_txx9_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
	struct uart_txx9_port *up = (struct uart_txx9_port *)port;
	unsigned long flags;

	spin_lock_irqsave(&up->port.lock, flags);
	if (mctrl & TIOCM_RTS)
		sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC);
	else
		sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC);
	spin_unlock_irqrestore(&up->port.lock, flags);
}

static void serial_txx9_break_ctl(struct uart_port *port, int break_state)
@@ -784,8 +786,14 @@ static void serial_txx9_config_port(struct uart_port *port, int uflags)
static int
serial_txx9_verify_port(struct uart_port *port, struct serial_struct *ser)
{
	if (ser->irq < 0 ||
	    ser->baud_base < 9600 || ser->type != PORT_TXX9)
	unsigned long new_port = ser->port;
	if (HIGH_BITS_OFFSET)
		new_port += (unsigned long)ser->port_high << HIGH_BITS_OFFSET;
	if (ser->type != port->type ||
	    ser->irq != port->irq ||
	    ser->io_type != port->iotype ||
	    new_port != port->iobase ||
	    (unsigned long)ser->iomem_base != port->mapbase)
		return -EINVAL;
	return 0;
}
@@ -827,6 +835,7 @@ static void __init serial_txx9_register_ports(struct uart_driver *drv)

		up->port.line = i;
		up->port.ops = &serial_txx9_pops;
		if (up->port.iobase || up->port.mapbase)
			uart_add_one_port(drv, &up->port);
	}
}
@@ -926,11 +935,6 @@ static int serial_txx9_console_setup(struct console *co, char *options)
	if (!port->ops)
		return -ENODEV;

	/*
	 * Temporary fix.
	 */
	spin_lock_init(&port->lock);

	/*
	 *	Disable UART interrupts, set DTR and RTS high
	 *	and set speed.
@@ -1041,11 +1045,10 @@ static int __devinit serial_txx9_register_port(struct uart_port *port)
	mutex_lock(&serial_txx9_mutex);
	for (i = 0; i < UART_NR; i++) {
		uart = &serial_txx9_ports[i];
		if (uart->port.type == PORT_UNKNOWN)
		if (!(uart->port.iobase || uart->port.mapbase))
			break;
	}
	if (i < UART_NR) {
		uart_remove_one_port(&serial_txx9_reg, &uart->port);
		uart->port.iobase = port->iobase;
		uart->port.membase = port->membase;
		uart->port.irq      = port->irq;
@@ -1080,9 +1083,8 @@ static void __devexit serial_txx9_unregister_port(int line)
	uart->port.type = PORT_UNKNOWN;
	uart->port.iobase = 0;
	uart->port.mapbase = 0;
	uart->port.membase = 0;
	uart->port.membase = NULL;
	uart->port.dev = NULL;
	uart_add_one_port(&serial_txx9_reg, &uart->port);
	mutex_unlock(&serial_txx9_mutex);
}

@@ -1198,8 +1200,11 @@ static void __exit serial_txx9_exit(void)
#ifdef ENABLE_SERIAL_TXX9_PCI
	pci_unregister_driver(&serial_txx9_pci_driver);
#endif
	for (i = 0; i < UART_NR; i++)
		uart_remove_one_port(&serial_txx9_reg, &serial_txx9_ports[i].port);
	for (i = 0; i < UART_NR; i++) {
		struct uart_txx9_port *up = &serial_txx9_ports[i];
		if (up->port.iobase || up->port.mapbase)
			uart_remove_one_port(&serial_txx9_reg, &up->port);
	}

	uart_unregister_driver(&serial_txx9_reg);
}