summaryrefslogtreecommitdiff
path: root/drivers/serial
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/serial')
-rw-r--r--drivers/serial/8250.c23
-rw-r--r--drivers/serial/8250_acorn.c3
-rw-r--r--drivers/serial/Kconfig32
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/amba-pl010.c3
-rw-r--r--drivers/serial/amba-pl011.c3
-rw-r--r--drivers/serial/bfin_5xx.c125
-rw-r--r--drivers/serial/cpm_uart/cpm_uart.h2
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_core.c15
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm1.c6
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm2.c6
-rw-r--r--drivers/serial/icom.c56
-rw-r--r--drivers/serial/jsm/jsm_neo.c7
-rw-r--r--drivers/serial/jsm/jsm_tty.c1
-rw-r--r--drivers/serial/mpc52xx_uart.c7
-rw-r--r--drivers/serial/of_serial.c4
-rw-r--r--drivers/serial/pmac_zilog.c8
-rw-r--r--drivers/serial/s3c2410.c6
-rw-r--r--drivers/serial/serial_ks8695.c657
-rw-r--r--drivers/serial/serial_txx9.c32
-rw-r--r--drivers/serial/suncore.c6
-rw-r--r--drivers/serial/sunhv.c280
-rw-r--r--drivers/serial/sunzilog.c142
-rw-r--r--drivers/serial/sunzilog.h19
24 files changed, 1192 insertions, 252 deletions
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index c9832d963f1e..c84dab083a85 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -894,7 +894,7 @@ static void autoconfig_16550a(struct uart_8250_port *up)
quot = serial_dl_read(up);
quot <<= 3;
- status1 = serial_in(up, 0x04); /* EXCR1 */
+ status1 = serial_in(up, 0x04); /* EXCR2 */
status1 &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
status1 |= 0x10; /* 1.625 divisor for baud_base --> 921600 */
serial_outp(up, 0x04, status1);
@@ -994,7 +994,6 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
* be frobbing the chips IRQ enable register to see if it exists.
*/
spin_lock_irqsave(&up->port.lock, flags);
-// save_flags(flags); cli();
up->capabilities = 0;
up->bugs = 0;
@@ -1151,7 +1150,6 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
out:
spin_unlock_irqrestore(&up->port.lock, flags);
-// restore_flags(flags);
DEBUG_AUTOCONF("type=%s\n", uart_config[up->port.type].name);
}
@@ -2619,7 +2617,22 @@ void serial8250_suspend_port(int line)
*/
void serial8250_resume_port(int line)
{
- uart_resume_port(&serial8250_reg, &serial8250_ports[line].port);
+ struct uart_8250_port *up = &serial8250_ports[line];
+
+ if (up->capabilities & UART_NATSEMI) {
+ unsigned char tmp;
+
+ /* Ensure it's still in high speed mode */
+ serial_outp(up, UART_LCR, 0xE0);
+
+ tmp = serial_in(up, 0x04); /* EXCR2 */
+ tmp &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
+ tmp |= 0x10; /* 1.625 divisor for baud_base --> 921600 */
+ serial_outp(up, 0x04, tmp);
+
+ serial_outp(up, UART_LCR, 0);
+ }
+ uart_resume_port(&serial8250_reg, &up->port);
}
/*
@@ -2696,7 +2709,7 @@ static int serial8250_resume(struct platform_device *dev)
struct uart_8250_port *up = &serial8250_ports[i];
if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
- uart_resume_port(&serial8250_reg, &up->port);
+ serial8250_resume_port(i);
}
return 0;
diff --git a/drivers/serial/8250_acorn.c b/drivers/serial/8250_acorn.c
index 562ba745a044..b0ce8c56f1a4 100644
--- a/drivers/serial/8250_acorn.c
+++ b/drivers/serial/8250_acorn.c
@@ -54,7 +54,7 @@ serial_card_probe(struct expansion_card *ec, const struct ecard_id *id)
info->num_ports = type->num_ports;
bus_addr = ecard_resource_start(ec, type->type);
- info->vaddr = ioremap(bus_addr, ecard_resource_len(ec, type->type));
+ info->vaddr = ecardm_iomap(ec, type->type, 0, 0);
if (!info->vaddr) {
kfree(info);
return -ENOMEM;
@@ -91,7 +91,6 @@ static void __devexit serial_card_remove(struct expansion_card *ec)
if (info->ports[i] > 0)
serial8250_unregister_port(info->ports[i]);
- iounmap(info->vaddr);
kfree(info);
}
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 924e9bd757f0..315ea9916456 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -5,6 +5,7 @@
#
menu "Serial drivers"
+ depends on HAS_IOMEM
#
# The new 8250/16550 serial drivers
@@ -73,17 +74,21 @@ config SERIAL_8250_PCI
depends on SERIAL_8250 && PCI
default SERIAL_8250
help
- This builds standard PCI serial support. You may be able to
- disable this feature if you only need legacy serial support.
- Saves about 9K.
+ Say Y here if you have PCI serial ports.
+
+ To compile this driver as a module, choose M here: the module
+ will be called 8250_pci.
config SERIAL_8250_PNP
tristate "8250/16550 PNP device support" if EMBEDDED
depends on SERIAL_8250 && PNP
default SERIAL_8250
help
- This builds standard PNP serial support. You may be able to
- disable this feature if you only need legacy serial support.
+ Say Y here if you have serial ports described by PNPBIOS or ACPI.
+ These are typically ports built into the system board.
+
+ To compile this driver as a module, choose M here: the module
+ will be called 8250_pnp.
config SERIAL_8250_HP300
tristate
@@ -354,6 +359,23 @@ config SERIAL_ATMEL_TTYAT
Say Y if you have an external 8250/16C550 UART. If unsure, say N.
+config SERIAL_KS8695
+ bool "Micrel KS8695 (Centaur) serial port support"
+ depends on ARCH_KS8695
+ select SERIAL_CORE
+ help
+ This selects the Micrel Centaur KS8695 UART. Say Y here.
+
+config SERIAL_KS8695_CONSOLE
+ bool "Support for console on KS8695 (Centaur) serial port"
+ depends on SERIAL_KS8695=y
+ select SERIAL_CORE_CONSOLE
+ help
+ Say Y here if you wish to use a KS8695 (Centaur) UART as the
+ system console (the system console is the device which
+ receives all kernel messages and warnings and which allows
+ logins in single user mode).
+
config SERIAL_CLPS711X
tristate "CLPS711X serial port support"
depends on ARM && ARCH_CLPS711X
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 4959bcb8d1ef..08ad0d978183 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -61,3 +61,4 @@ obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o
obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
+obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c
index 1a9a24b82636..00d1255e4c12 100644
--- a/drivers/serial/amba-pl010.c
+++ b/drivers/serial/amba-pl010.c
@@ -167,8 +167,9 @@ static void pl010_rx_chars(struct uart_amba_port *uap)
ignore_char:
status = readb(uap->port.membase + UART01x_FR);
}
+ spin_unlock(&port->lock);
tty_flip_buffer_push(tty);
- return;
+ spin_lock(&port->lock);
}
static void pl010_tx_chars(struct uart_amba_port *uap)
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
index 44639e71372a..954073c6ce3a 100644
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -153,8 +153,9 @@ static void pl011_rx_chars(struct uart_amba_port *uap)
ignore_char:
status = readw(uap->port.membase + UART01x_FR);
}
+ spin_unlock(&uap->port.lock);
tty_flip_buffer_push(tty);
- return;
+ spin_lock(&uap->port.lock);
}
static void pl011_tx_chars(struct uart_amba_port *uap)
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index 408390f93db9..787dc7168f3e 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -6,8 +6,6 @@
* Created:
* Description: Driver for blackfin 5xx serial ports
*
- * Rev: $Id: bfin_5xx.c,v 1.19 2006/09/24 02:33:53 aubrey Exp $
- *
* Modified:
* Copyright 2006 Analog Devices Inc.
*
@@ -152,7 +150,7 @@ static void local_put_char(struct bfin_serial_port *uart, char ch)
static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
{
- struct tty_struct *tty = uart->port.info?uart->port.info->tty:0;
+ struct tty_struct *tty = uart->port.info->tty;
unsigned int status, ch, flg;
#ifdef BF533_FAMILY
static int in_break = 0;
@@ -173,8 +171,10 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
if (ch != 0) {
in_break = 0;
ch = UART_GET_CHAR(uart);
- }
- return;
+ if (bfin_revid() < 5)
+ return;
+ } else
+ return;
}
#endif
@@ -185,27 +185,32 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
uart->port.icount.brk++;
if (uart_handle_break(&uart->port))
goto ignore_char;
- flg = TTY_BREAK;
- } else if (status & PE) {
- flg = TTY_PARITY;
+ }
+ if (status & PE)
uart->port.icount.parity++;
- } else if (status & OE) {
- flg = TTY_OVERRUN;
+ if (status & OE)
uart->port.icount.overrun++;
- } else if (status & FE) {
- flg = TTY_FRAME;
+ if (status & FE)
uart->port.icount.frame++;
- } else
+
+ status &= uart->port.read_status_mask;
+
+ if (status & BI)
+ flg = TTY_BREAK;
+ else if (status & PE)
+ flg = TTY_PARITY;
+ else if (status & FE)
+ flg = TTY_FRAME;
+ else
flg = TTY_NORMAL;
if (uart_handle_sysrq_char(&uart->port, ch))
goto ignore_char;
- if (tty)
- uart_insert_char(&uart->port, status, 2, ch, flg);
-ignore_char:
- if (tty)
- tty_flip_buffer_push(tty);
+ uart_insert_char(&uart->port, status, OE, ch, flg);
+
+ ignore_char:
+ tty_flip_buffer_push(tty);
}
static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
@@ -240,24 +245,29 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
bfin_serial_stop_tx(&uart->port);
}
-static irqreturn_t bfin_serial_int(int irq, void *dev_id)
+static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id)
{
struct bfin_serial_port *uart = dev_id;
- unsigned short status;
spin_lock(&uart->port.lock);
- status = UART_GET_IIR(uart);
- do {
- if ((status & IIR_STATUS) == IIR_TX_READY)
- bfin_serial_tx_chars(uart);
- if ((status & IIR_STATUS) == IIR_RX_READY)
- bfin_serial_rx_chars(uart);
- status = UART_GET_IIR(uart);
- } while (status & (IIR_TX_READY | IIR_RX_READY));
+ while ((UART_GET_IIR(uart) & IIR_STATUS) == IIR_RX_READY)
+ bfin_serial_rx_chars(uart);
spin_unlock(&uart->port.lock);
return IRQ_HANDLED;
}
+static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id)
+{
+ struct bfin_serial_port *uart = dev_id;
+
+ spin_lock(&uart->port.lock);
+ while ((UART_GET_IIR(uart) & IIR_STATUS) == IIR_TX_READY)
+ bfin_serial_tx_chars(uart);
+ spin_unlock(&uart->port.lock);
+ return IRQ_HANDLED;
+}
+
+
static void bfin_serial_do_work(struct work_struct *work)
{
struct bfin_serial_port *uart = container_of(work, struct bfin_serial_port, cts_workqueue);
@@ -319,7 +329,7 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
spin_unlock_irqrestore(&uart->port.lock, flags);
}
-static void bfin_serial_dma_rx_chars(struct bfin_serial_port * uart)
+static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
{
struct tty_struct *tty = uart->port.info->tty;
int i, flg, status;
@@ -331,25 +341,32 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port * uart)
uart->port.icount.brk++;
if (uart_handle_break(&uart->port))
goto dma_ignore_char;
- flg = TTY_BREAK;
- } else if (status & PE) {
- flg = TTY_PARITY;
+ }
+ if (status & PE)
uart->port.icount.parity++;
- } else if (status & OE) {
- flg = TTY_OVERRUN;
+ if (status & OE)
uart->port.icount.overrun++;
- } else if (status & FE) {
- flg = TTY_FRAME;
+ if (status & FE)
uart->port.icount.frame++;
- } else
+
+ status &= uart->port.read_status_mask;
+
+ if (status & BI)
+ flg = TTY_BREAK;
+ else if (status & PE)
+ flg = TTY_PARITY;
+ else if (status & FE)
+ flg = TTY_FRAME;
+ else
flg = TTY_NORMAL;
for (i = uart->rx_dma_buf.head; i < uart->rx_dma_buf.tail; i++) {
if (uart_handle_sysrq_char(&uart->port, uart->rx_dma_buf.buf[i]))
goto dma_ignore_char;
- uart_insert_char(&uart->port, status, 2, uart->rx_dma_buf.buf[i], flg);
+ uart_insert_char(&uart->port, status, OE, uart->rx_dma_buf.buf[i], flg);
}
-dma_ignore_char:
+
+ dma_ignore_char:
tty_flip_buffer_push(tty);
}
@@ -545,14 +562,14 @@ static int bfin_serial_startup(struct uart_port *port)
add_timer(&(uart->rx_dma_timer));
#else
if (request_irq
- (uart->port.irq, bfin_serial_int, IRQF_DISABLED,
+ (uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED,
"BFIN_UART_RX", uart)) {
printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n");
return -EBUSY;
}
if (request_irq
- (uart->port.irq+1, bfin_serial_int, IRQF_DISABLED,
+ (uart->port.irq+1, bfin_serial_tx_int, IRQF_DISABLED,
"BFIN_UART_TX", uart)) {
printk(KERN_NOTICE "Unable to attach BlackFin UART TX interrupt\n");
free_irq(uart->port.irq, uart);
@@ -614,13 +631,27 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
lcr |= EPS;
}
- /* These controls are not implemented for this port */
- termios->c_iflag |= INPCK | BRKINT | PARMRK;
- termios->c_iflag &= ~(IGNPAR | IGNBRK);
+ port->read_status_mask = OE;
+ if (termios->c_iflag & INPCK)
+ port->read_status_mask |= (FE | PE);
+ if (termios->c_iflag & (BRKINT | PARMRK))
+ port->read_status_mask |= BI;
- /* These controls are not implemented for this port */
- termios->c_iflag |= INPCK | BRKINT | PARMRK;
- termios->c_iflag &= ~(IGNPAR | IGNBRK);
+ /*
+ * Characters to ignore
+ */
+ port->ignore_status_mask = 0;
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |= FE | PE;
+ if (termios->c_iflag & IGNBRK) {
+ port->ignore_status_mask |= BI;
+ /*
+ * If we're ignoring parity and break indicators,
+ * ignore overruns too (for real raw support).
+ */
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |= OE;
+ }
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h
index 69715e556506..a8f894c78194 100644
--- a/drivers/serial/cpm_uart/cpm_uart.h
+++ b/drivers/serial/cpm_uart/cpm_uart.h
@@ -88,7 +88,7 @@ extern struct uart_cpm_port cpm_uart_ports[UART_NR];
/* these are located in their respective files */
void cpm_line_cr_cmd(int line, int cmd);
-int __init cpm_uart_init_portdesc(void);
+int cpm_uart_init_portdesc(void);
int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con);
void cpm_uart_freebuf(struct uart_cpm_port *pinfo);
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index 7a3b97fdf8d1..b63ff8dd7304 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -482,7 +482,8 @@ static void cpm_uart_shutdown(struct uart_port *port)
}
static void cpm_uart_set_termios(struct uart_port *port,
- struct termios *termios, struct termios *old)
+ struct ktermios *termios,
+ struct ktermios *old)
{
int baud;
unsigned long flags;
@@ -934,7 +935,7 @@ struct uart_cpm_port cpm_uart_ports[UART_NR] = {
.irq = SMC1_IRQ,
.ops = &cpm_uart_pops,
.iotype = UPIO_MEM,
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(cpm_uart_ports[UART_SMC1].port.lock),
},
.flags = FLAG_SMC,
.tx_nrfifos = TX_NUM_FIFO,
@@ -948,7 +949,7 @@ struct uart_cpm_port cpm_uart_ports[UART_NR] = {
.irq = SMC2_IRQ,
.ops = &cpm_uart_pops,
.iotype = UPIO_MEM,
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(cpm_uart_ports[UART_SMC2].port.lock),
},
.flags = FLAG_SMC,
.tx_nrfifos = TX_NUM_FIFO,
@@ -965,7 +966,7 @@ struct uart_cpm_port cpm_uart_ports[UART_NR] = {
.irq = SCC1_IRQ,
.ops = &cpm_uart_pops,
.iotype = UPIO_MEM,
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(cpm_uart_ports[UART_SCC1].port.lock),
},
.tx_nrfifos = TX_NUM_FIFO,
.tx_fifosize = TX_BUF_SIZE,
@@ -979,7 +980,7 @@ struct uart_cpm_port cpm_uart_ports[UART_NR] = {
.irq = SCC2_IRQ,
.ops = &cpm_uart_pops,
.iotype = UPIO_MEM,
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(cpm_uart_ports[UART_SCC2].port.lock),
},
.tx_nrfifos = TX_NUM_FIFO,
.tx_fifosize = TX_BUF_SIZE,
@@ -993,7 +994,7 @@ struct uart_cpm_port cpm_uart_ports[UART_NR] = {
.irq = SCC3_IRQ,
.ops = &cpm_uart_pops,
.iotype = UPIO_MEM,
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(cpm_uart_ports[UART_SCC3].port.lock),
},
.tx_nrfifos = TX_NUM_FIFO,
.tx_fifosize = TX_BUF_SIZE,
@@ -1007,7 +1008,7 @@ struct uart_cpm_port cpm_uart_ports[UART_NR] = {
.irq = SCC4_IRQ,
.ops = &cpm_uart_pops,
.iotype = UPIO_MEM,
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(cpm_uart_ports[UART_SCC4].port.lock),
},
.tx_nrfifos = TX_NUM_FIFO,
.tx_fifosize = TX_BUF_SIZE,
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
index 925fb607d8c4..8c6324ed0202 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
@@ -125,7 +125,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
{
int dpmemsz, memsz;
u8 *dp_mem;
- uint dp_offset;
+ unsigned long dp_offset;
u8 *mem_addr;
dma_addr_t dma_addr = 0;
@@ -133,7 +133,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos);
dp_offset = cpm_dpalloc(dpmemsz, 8);
- if (IS_DPERR(dp_offset)) {
+ if (IS_ERR_VALUE(dp_offset)) {
printk(KERN_ERR
"cpm_uart_cpm1.c: could not allocate buffer descriptors\n");
return -ENOMEM;
@@ -185,7 +185,7 @@ void cpm_uart_freebuf(struct uart_cpm_port *pinfo)
}
/* Setup any dynamic params in the uart desc */
-int __init cpm_uart_init_portdesc(void)
+int cpm_uart_init_portdesc(void)
{
pr_debug("CPM uart[-]:init portdesc\n");
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
index fa455996ad8f..7b61d805ebe9 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
@@ -222,7 +222,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
{
int dpmemsz, memsz;
u8 *dp_mem;
- uint dp_offset;
+ unsigned long dp_offset;
u8 *mem_addr;
dma_addr_t dma_addr = 0;
@@ -230,7 +230,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos);
dp_offset = cpm_dpalloc(dpmemsz, 8);
- if (IS_DPERR(dp_offset)) {
+ if (IS_ERR_VALUE(dp_offset)) {
printk(KERN_ERR
"cpm_uart_cpm.c: could not allocate buffer descriptors\n");
return -ENOMEM;
@@ -282,7 +282,7 @@ void cpm_uart_freebuf(struct uart_cpm_port *pinfo)
}
/* Setup any dynamic params in the uart desc */
-int __init cpm_uart_init_portdesc(void)
+int cpm_uart_init_portdesc(void)
{
#if defined(CONFIG_SERIAL_CPM_SMC1) || defined(CONFIG_SERIAL_CPM_SMC2)
u16 *addr;
diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c
index 246c5572667b..9d3105b64a7a 100644
--- a/drivers/serial/icom.c
+++ b/drivers/serial/icom.c
@@ -47,7 +47,6 @@
#include <linux/pci.h>
#include <linux/vmalloc.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/spinlock.h>
#include <linux/kobject.h>
#include <linux/firmware.h>
@@ -70,33 +69,40 @@
static const struct pci_device_id icom_pci_table[] = {
{
- .vendor = PCI_VENDOR_ID_IBM,
- .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_1,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = ADAPTER_V1,
- },
+ .vendor = PCI_VENDOR_ID_IBM,
+ .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_1,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = ADAPTER_V1,
+ },
{
- .vendor = PCI_VENDOR_ID_IBM,
- .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
- .subvendor = PCI_VENDOR_ID_IBM,
- .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_TWO_PORTS_RVX,
- .driver_data = ADAPTER_V2,
- },
+ .vendor = PCI_VENDOR_ID_IBM,
+ .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
+ .subvendor = PCI_VENDOR_ID_IBM,
+ .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_TWO_PORTS_RVX,
+ .driver_data = ADAPTER_V2,
+ },
{
- .vendor = PCI_VENDOR_ID_IBM,
- .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
- .subvendor = PCI_VENDOR_ID_IBM,
- .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM,
- .driver_data = ADAPTER_V2,
- },
+ .vendor = PCI_VENDOR_ID_IBM,
+ .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
+ .subvendor = PCI_VENDOR_ID_IBM,
+ .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM,
+ .driver_data = ADAPTER_V2,
+ },
{
- .vendor = PCI_VENDOR_ID_IBM,
- .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
- .subvendor = PCI_VENDOR_ID_IBM,
- .subdevice = PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL,
- .driver_data = ADAPTER_V2,
- },
+ .vendor = PCI_VENDOR_ID_IBM,
+ .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
+ .subvendor = PCI_VENDOR_ID_IBM,
+ .subdevice = PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL,
+ .driver_data = ADAPTER_V2,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_IBM,
+ .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
+ .subvendor = PCI_VENDOR_ID_IBM,
+ .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM_PCIE,
+ .driver_data = ADAPTER_V2,
+ },
{}
};
diff --git a/drivers/serial/jsm/jsm_neo.c b/drivers/serial/jsm/jsm_neo.c
index 8be8da37f629..b2d6f5b1a7c2 100644
--- a/drivers/serial/jsm/jsm_neo.c
+++ b/drivers/serial/jsm/jsm_neo.c
@@ -581,8 +581,13 @@ static void neo_parse_modem(struct jsm_channel *ch, u8 signals)
return;
/* Scrub off lower bits. They signify delta's, which I don't care about */
- msignals &= 0xf0;
+ /* Keep DDCD and DDSR though */
+ msignals &= 0xf8;
+ if (msignals & UART_MSR_DDCD)
+ uart_handle_dcd_change(&ch->uart_port, msignals & UART_MSR_DCD);
+ if (msignals & UART_MSR_DDSR)
+ uart_handle_cts_change(&ch->uart_port, msignals & UART_MSR_CTS);
if (msignals & UART_MSR_DCD)
ch->ch_mistat |= UART_MSR_DCD;
else
diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c
index be22bbdbc8e5..281f23a371b2 100644
--- a/drivers/serial/jsm/jsm_tty.c
+++ b/drivers/serial/jsm/jsm_tty.c
@@ -448,6 +448,7 @@ int jsm_uart_port_init(struct jsm_board *brd)
continue;
brd->channels[i]->uart_port.irq = brd->irq;
+ brd->channels[i]->uart_port.uartclk = 14745600;
brd->channels[i]->uart_port.type = PORT_JSM;
brd->channels[i]->uart_port.iotype = UPIO_MEM;
brd->channels[i]->uart_port.membase = brd->re_map_membase;
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index 8d24cd521056..35f8b86cc78f 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -257,9 +257,10 @@ mpc52xx_uart_shutdown(struct uart_port *port)
{
struct mpc52xx_psc __iomem *psc = PSC(port);
- /* Shut down the port, interrupt and all */
+ /* Shut down the port. Leave TX active if on a console port */
out_8(&psc->command,MPC52xx_PSC_RST_RX);
- out_8(&psc->command,MPC52xx_PSC_RST_TX);
+ if (!uart_console(port))
+ out_8(&psc->command,MPC52xx_PSC_RST_TX);
port->read_status_mask = 0;
out_be16(&psc->mpc52xx_psc_imr,port->read_status_mask);
@@ -1069,7 +1070,7 @@ mpc52xx_uart_of_enumerate(void)
continue;
/* Is a particular device number requested? */
- devno = get_property(np, "port-number", NULL);
+ devno = of_get_property(np, "port-number", NULL);
mpc52xx_uart_of_assign(of_node_get(np), devno ? *devno : -1);
}
diff --git a/drivers/serial/of_serial.c b/drivers/serial/of_serial.c
index 336d0f4580d9..7ffdaeaf0545 100644
--- a/drivers/serial/of_serial.c
+++ b/drivers/serial/of_serial.c
@@ -29,8 +29,8 @@ static int __devinit of_platform_serial_setup(struct of_device *ofdev,
int ret;
memset(port, 0, sizeof *port);
- spd = get_property(np, "current-speed", NULL);
- clk = get_property(np, "clock-frequency", NULL);
+ spd = of_get_property(np, "current-speed", NULL);
+ clk = of_get_property(np, "clock-frequency", NULL);
if (!clk) {
dev_warn(&ofdev->dev, "no clock-frequency property set\n");
return -ENODEV;
diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c
index be8d75721a85..0fa9f6761763 100644
--- a/drivers/serial/pmac_zilog.c
+++ b/drivers/serial/pmac_zilog.c
@@ -1450,14 +1450,14 @@ no_dma:
/*
* Detect port type
*/
- if (device_is_compatible(np, "cobalt"))
+ if (of_device_is_compatible(np, "cobalt"))
uap->flags |= PMACZILOG_FLAG_IS_INTMODEM;
- conn = get_property(np, "AAPL,connector", &len);
+ conn = of_get_property(np, "AAPL,connector", &len);
if (conn && (strcmp(conn, "infrared") == 0))
uap->flags |= PMACZILOG_FLAG_IS_IRDA;
uap->port_type = PMAC_SCC_ASYNC;
/* 1999 Powerbook G3 has slot-names property instead */
- slots = get_property(np, "slot-names", &len);
+ slots = of_get_property(np, "slot-names", &len);
if (slots && slots->count > 0) {
if (strcmp(slots->name, "IrDA") == 0)
uap->flags |= PMACZILOG_FLAG_IS_IRDA;
@@ -1471,7 +1471,7 @@ no_dma:
of_find_node_by_name(NULL, "i2c-modem");
if (i2c_modem) {
const char* mid =
- get_property(i2c_modem, "modem-id", NULL);
+ of_get_property(i2c_modem, "modem-id", NULL);
if (mid) switch(*mid) {
case 0x04 :
case 0x05 :
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
index 3ba9208ebd0c..10bc0209cd66 100644
--- a/drivers/serial/s3c2410.c
+++ b/drivers/serial/s3c2410.c
@@ -957,7 +957,7 @@ static struct uart_driver s3c24xx_uart_drv = {
static struct s3c24xx_uart_port s3c24xx_serial_ports[NR_PORTS] = {
[0] = {
.port = {
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock),
.iotype = UPIO_MEM,
.irq = IRQ_S3CUART_RX0,
.uartclk = 0,
@@ -969,7 +969,7 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[NR_PORTS] = {
},
[1] = {
.port = {
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[1].port.lock),
.iotype = UPIO_MEM,
.irq = IRQ_S3CUART_RX1,
.uartclk = 0,
@@ -983,7 +983,7 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[NR_PORTS] = {
[2] = {
.port = {
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock),
.iotype = UPIO_MEM,
.irq = IRQ_S3CUART_RX2,
.uartclk = 0,
diff --git a/drivers/serial/serial_ks8695.c b/drivers/serial/serial_ks8695.c
new file mode 100644
index 000000000000..8721afe1ae4f
--- /dev/null
+++ b/drivers/serial/serial_ks8695.c
@@ -0,0 +1,657 @@
+/*
+ * drivers/serial/serial_ks8695.c
+ *
+ * Driver for KS8695 serial ports
+ *
+ * Based on drivers/serial/serial_amba.c, by Kam Lee.
+ *
+ * Copyright 2002-2005 Micrel Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/device.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+
+#include <asm/arch/regs-uart.h>
+#include <asm/arch/regs-irq.h>
+
+#if defined(CONFIG_SERIAL_KS8695_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+
+#define SERIAL_KS8695_MAJOR 204
+#define SERIAL_KS8695_MINOR 16
+#define SERIAL_KS8695_DEVNAME "ttyAM"
+
+#define SERIAL_KS8695_NR 1
+
+/*
+ * Access macros for the KS8695 UART
+ */
+#define UART_GET_CHAR(p) (__raw_readl((p)->membase + KS8695_URRB) & 0xFF)
+#define UART_PUT_CHAR(p, c) __raw_writel((c), (p)->membase + KS8695_URTH)
+#define UART_GET_FCR(p) __raw_readl((p)->membase + KS8695_URFC)
+#define UART_PUT_FCR(p, c) __raw_writel((c), (p)->membase + KS8695_URFC)
+#define UART_GET_MSR(p) __raw_readl((p)->membase + KS8695_URMS)
+#define UART_GET_LSR(p) __raw_readl((p)->membase + KS8695_URLS)
+#define UART_GET_LCR(p) __raw_readl((p)->membase + KS8695_URLC)
+#define UART_PUT_LCR(p, c) __raw_writel((c), (p)->membase + KS8695_URLC)
+#define UART_GET_MCR(p) __raw_readl((p)->membase + KS8695_URMC)
+#define UART_PUT_MCR(p, c) __raw_writel((c), (p)->membase + KS8695_URMC)
+#define UART_GET_BRDR(p) __raw_readl((p)->membase + KS8695_URBD)
+#define UART_PUT_BRDR(p, c) __raw_writel((c), (p)->membase + KS8695_URBD)
+
+#define KS8695_CLR_TX_INT() __raw_writel(1 << KS8695_IRQ_UART_TX, KS8695_IRQ_VA + KS8695_INTST)
+
+#define UART_DUMMY_LSR_RX 0x100
+#define UART_PORT_SIZE (KS8695_USR - KS8695_URRB + 4)
+
+#define tx_enabled(port) ((port)->unused[0])
+#define rx_enabled(port) ((port)->unused[1])
+
+
+#ifdef SUPPORT_SYSRQ
+static struct console ks8695_console;
+#endif
+
+static void ks8695uart_stop_tx(struct uart_port *port)
+{
+ if (tx_enabled(port)) {
+ disable_irq(KS8695_IRQ_UART_TX);
+ tx_enabled(port) = 0;
+ }
+}
+
+static void ks8695uart_start_tx(struct uart_port *port)
+{
+ if (!tx_enabled(port)) {
+ enable_irq(KS8695_IRQ_UART_TX);
+ tx_enabled(port) = 1;
+ }
+}
+
+static void ks8695uart_stop_rx(struct uart_port *port)
+{
+ if (rx_enabled(port)) {
+ disable_irq(KS8695_IRQ_UART_RX);
+ rx_enabled(port) = 0;
+ }
+}
+
+static void ks8695uart_enable_ms(struct uart_port *port)
+{
+ enable_irq(KS8695_IRQ_UART_MODEM_STATUS);
+}
+
+static void ks8695uart_disable_ms(struct uart_port *port)
+{
+ disable_irq(KS8695_IRQ_UART_MODEM_STATUS);
+}
+
+static irqreturn_t ks8695uart_rx_chars(int irq, void *dev_id)
+{
+ struct uart_port *port = dev_id;
+ struct tty_struct *tty = port->info->tty;
+ unsigned int status, ch, lsr, flg, max_count = 256;
+
+ status = UART_GET_LSR(port); /* clears pending LSR interrupts */
+ while ((status & URLS_URDR) && max_count--) {
+ ch = UART_GET_CHAR(port);
+ flg = TTY_NORMAL;
+
+ port->icount.rx++;
+
+ /*
+ * Note that the error handling code is
+ * out of the main execution path
+ */
+ lsr = UART_GET_LSR(port) | UART_DUMMY_LSR_RX;
+ if (unlikely(lsr & (URLS_URBI | URLS_URPE | URLS_URFE | URLS_URROE))) {
+ if (lsr & URLS_URBI) {
+ lsr &= ~(URLS_URFE | URLS_URPE);
+ port->icount.brk++;
+ if (uart_handle_break(port))
+ goto ignore_char;
+ }
+ if (lsr & URLS_URPE)
+ port->icount.parity++;
+ if (lsr & URLS_URFE)
+ port->icount.frame++;
+ if (lsr & URLS_URROE)
+ port->icount.overrun++;
+
+ lsr &= port->read_status_mask;
+
+ if (lsr & URLS_URBI)
+ flg = TTY_BREAK;
+ else if (lsr & URLS_URPE)
+ flg = TTY_PARITY;
+ else if (lsr & URLS_URFE)
+ flg = TTY_FRAME;
+ }
+
+ if (uart_handle_sysrq_char(port, ch))
+ goto ignore_char;
+
+ uart_insert_char(port, lsr, URLS_URROE, ch, flg);
+
+ignore_char:
+ status = UART_GET_LSR(port);
+ }
+ tty_flip_buffer_push(tty);
+
+ return IRQ_HANDLED;
+}
+
+
+static irqreturn_t ks8695uart_tx_chars(int irq, void *dev_id)
+{
+ struct uart_port *port = dev_id;
+ struct circ_buf *xmit = &port->info->xmit;
+ unsigned int count;
+
+ if (port->x_char) {
+ KS8695_CLR_TX_INT();
+ UART_PUT_CHAR(port, port->x_char);
+ port->icount.tx++;
+ port->x_char = 0;
+ return IRQ_HANDLED;
+ }
+
+ if (uart_tx_stopped(port) || uart_circ_empty(xmit)) {
+ ks8695uart_stop_tx(port);
+ return IRQ_HANDLED;
+ }
+
+ count = 16; /* fifo size */
+ while (!uart_circ_empty(xmit) && (count-- > 0)) {
+ KS8695_CLR_TX_INT();
+ UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
+
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+
+ if (uart_circ_empty(xmit))
+ ks8695uart_stop_tx(port);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ks8695uart_modem_status(int irq, void *dev_id)
+{
+ struct uart_port *port = dev_id;
+ unsigned int status;
+
+ /*
+ * clear modem interrupt by reading MSR
+ */
+ status = UART_GET_MSR(port);
+
+ if (status & URMS_URDDCD)
+ uart_handle_dcd_change(port, status & URMS_URDDCD);
+
+ if (status & URMS_URDDST)
+ port->icount.dsr++;
+
+ if (status & URMS_URDCTS)
+ uart_handle_cts_change(port, status & URMS_URDCTS);
+
+ if (status & URMS_URTERI)
+ port->icount.rng++;
+
+ wake_up_interruptible(&port->info->delta_msr_wait);
+
+ return IRQ_HANDLED;
+}
+
+static unsigned int ks8695uart_tx_empty(struct uart_port *port)
+{
+ return (UART_GET_LSR(port) & URLS_URTE) ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int ks8695uart_get_mctrl(struct uart_port *port)
+{
+ unsigned int result = 0;
+ unsigned int status;
+
+ status = UART_GET_MSR(port);
+ if (status & URMS_URDCD)
+ result |= TIOCM_CAR;
+ if (status & URMS_URDSR)
+ result |= TIOCM_DSR;
+ if (status & URMS_URCTS)
+ result |= TIOCM_CTS;
+ if (status & URMS_URRI)
+ result |= TIOCM_RI;
+
+ return result;
+}
+
+static void ks8695uart_set_mctrl(struct uart_port *port, u_int mctrl)
+{
+ unsigned int mcr;
+
+ mcr = UART_GET_MCR(port);
+ if (mctrl & TIOCM_RTS)
+ mcr |= URMC_URRTS;
+ else
+ mcr &= ~URMC_URRTS;
+
+ if (mctrl & TIOCM_DTR)
+ mcr |= URMC_URDTR;
+ else
+ mcr &= ~URMC_URDTR;
+
+ UART_PUT_MCR(port, mcr);
+}
+
+static void ks8695uart_break_ctl(struct uart_port *port, int break_state)
+{
+ unsigned int lcr;
+
+ lcr = UART_GET_LCR(port);
+
+ if (break_state == -1)
+ lcr |= URLC_URSBC;
+ else
+ lcr &= ~URLC_URSBC;
+
+ UART_PUT_LCR(port, lcr);
+}
+
+static int ks8695uart_startup(struct uart_port *port)
+{
+ int retval;
+
+ set_irq_flags(KS8695_IRQ_UART_TX, IRQF_VALID | IRQF_NOAUTOEN);
+ tx_enabled(port) = 0;
+ rx_enabled(port) = 1;
+
+ /*
+ * Allocate the IRQ
+ */
+ retval = request_irq(KS8695_IRQ_UART_TX, ks8695uart_tx_chars, IRQF_DISABLED, "UART TX", port);
+ if (retval)
+ goto err_tx;
+
+ retval = request_irq(KS8695_IRQ_UART_RX, ks8695uart_rx_chars, IRQF_DISABLED, "UART RX", port);
+ if (retval)
+ goto err_rx;
+
+ retval = request_irq(KS8695_IRQ_UART_LINE_STATUS, ks8695uart_rx_chars, IRQF_DISABLED, "UART LineStatus", port);
+ if (retval)
+ goto err_ls;
+
+ retval = request_irq(KS8695_IRQ_UART_MODEM_STATUS, ks8695uart_modem_status, IRQF_DISABLED, "UART ModemStatus", port);
+ if (retval)
+ goto err_ms;
+
+ return 0;
+
+err_ms:
+ free_irq(KS8695_IRQ_UART_LINE_STATUS, port);
+err_ls:
+ free_irq(KS8695_IRQ_UART_RX, port);
+err_rx:
+ free_irq(KS8695_IRQ_UART_TX, port);
+err_tx:
+ return retval;
+}
+
+static void ks8695uart_shutdown(struct uart_port *port)
+{
+ /*
+ * Free the interrupt
+ */
+ free_irq(KS8695_IRQ_UART_RX, port);
+ free_irq(KS8695_IRQ_UART_TX, port);
+ free_irq(KS8695_IRQ_UART_MODEM_STATUS, port);
+ free_irq(KS8695_IRQ_UART_LINE_STATUS, port);
+
+ /* disable break condition and fifos */
+ UART_PUT_LCR(port, UART_GET_LCR(port) & ~URLC_URSBC);
+ UART_PUT_FCR(port, UART_GET_FCR(port) & ~URFC_URFE);
+}
+
+static void ks8695uart_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old)
+{
+ unsigned int lcr, fcr = 0;
+ unsigned long flags;
+ unsigned int baud, quot;
+
+ /*
+ * Ask the core to calculate the divisor for us.
+ */
+ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+ quot = uart_get_divisor(port, baud);
+
+ switch (termios->c_cflag & CSIZE) {
+ case CS5:
+ lcr = URCL_5;
+ break;
+ case CS6:
+ lcr = URCL_6;
+ break;
+ case CS7:
+ lcr = URCL_7;
+ break;
+ default:
+ lcr = URCL_8;
+ break;
+ }
+
+ /* stop bits */
+ if (termios->c_cflag & CSTOPB)
+ lcr |= URLC_URSB;
+
+ /* parity */
+ if (termios->c_cflag & PARENB) {
+ if (termios->c_cflag & CMSPAR) { /* Mark or Space parity */
+ if (termios->c_cflag & PARODD)
+ lcr |= URPE_MARK;
+ else
+ lcr |= URPE_SPACE;
+ }
+ else if (termios->c_cflag & PARODD)
+ lcr |= URPE_ODD;
+ else
+ lcr |= URPE_EVEN;
+ }
+
+ if (port->fifosize > 1)
+ fcr = URFC_URFRT_8 | URFC_URTFR | URFC_URRFR | URFC_URFE;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ /*
+ * Update the per-port timeout.
+ */
+ uart_update_timeout(port, termios->c_cflag, baud);
+
+ port->read_status_mask = URLS_URROE;
+ if (termios->c_iflag & INPCK)
+ port->read_status_mask |= (URLS_URFE | URLS_URPE);
+ if (termios->c_iflag & (BRKINT | PARMRK))
+ port->read_status_mask |= URLS_URBI;
+
+ /*
+ * Characters to ignore
+ */
+ port->ignore_status_mask = 0;
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |= (URLS_URFE | URLS_URPE);
+ if (termios->c_iflag & IGNBRK) {
+ port->ignore_status_mask |= URLS_URBI;
+ /*
+ * If we're ignoring parity and break indicators,
+ * ignore overruns too (for real raw support).
+ */
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |= URLS_URROE;
+ }
+
+ /*
+ * Ignore all characters if CREAD is not set.
+ */
+ if ((termios->c_cflag & CREAD) == 0)
+ port->ignore_status_mask |= UART_DUMMY_LSR_RX;
+
+ /* first, disable everything */
+ if (UART_ENABLE_MS(port, termios->c_cflag))
+ ks8695uart_enable_ms(port);
+ else
+ ks8695uart_disable_ms(port);
+
+ /* Set baud rate */
+ UART_PUT_BRDR(port, quot);
+
+ UART_PUT_LCR(port, lcr);
+ UART_PUT_FCR(port, fcr);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *ks8695uart_type(struct uart_port *port)
+{
+ return port->type == PORT_KS8695 ? "KS8695" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'
+ */
+static void ks8695uart_release_port(struct uart_port *port)
+{
+ release_mem_region(port->mapbase, UART_PORT_SIZE);
+}
+
+/*
+ * Request the memory region(s) being used by 'port'
+ */
+static int ks8695uart_request_port(struct uart_port *port)
+{
+ return request_mem_region(port->mapbase, UART_PORT_SIZE,
+ "serial_ks8695") != NULL ? 0 : -EBUSY;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void ks8695uart_config_port(struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE) {
+ port->type = PORT_KS8695;
+ ks8695uart_request_port(port);
+ }
+}
+
+/*
+ * verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int ks8695uart_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ int ret = 0;
+
+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_KS8695)
+ ret = -EINVAL;
+ if (ser->irq != port->irq)
+ ret = -EINVAL;
+ if (ser->baud_base < 9600)
+ ret = -EINVAL;
+ return ret;
+}
+
+static struct uart_ops ks8695uart_pops = {
+ .tx_empty = ks8695uart_tx_empty,
+ .set_mctrl = ks8695uart_set_mctrl,
+ .get_mctrl = ks8695uart_get_mctrl,
+ .stop_tx = ks8695uart_stop_tx,
+ .start_tx = ks8695uart_start_tx,
+ .stop_rx = ks8695uart_stop_rx,
+ .enable_ms = ks8695uart_enable_ms,
+ .break_ctl = ks8695uart_break_ctl,
+ .startup = ks8695uart_startup,
+ .shutdown = ks8695uart_shutdown,
+ .set_termios = ks8695uart_set_termios,
+ .type = ks8695uart_type,
+ .release_port = ks8695uart_release_port,
+ .request_port = ks8695uart_request_port,
+ .config_port = ks8695uart_config_port,
+ .verify_port = ks8695uart_verify_port,
+};
+
+static struct uart_port ks8695uart_ports[SERIAL_KS8695_NR] = {
+ {
+ .membase = (void *) KS8695_UART_VA,
+ .mapbase = KS8695_UART_VA,
+ .iotype = SERIAL_IO_MEM,
+ .irq = KS8695_IRQ_UART_TX,
+ .uartclk = CLOCK_TICK_RATE * 16,
+ .fifosize = 16,
+ .ops = &ks8695uart_pops,
+ .flags = ASYNC_BOOT_AUTOCONF,
+ .line = 0,
+ }
+};
+
+#ifdef CONFIG_SERIAL_KS8695_CONSOLE
+static void ks8695_console_putchar(struct uart_port *port, int ch)
+{
+ while (!(UART_GET_LSR(port) & URLS_URTHRE))
+ barrier();
+
+ UART_PUT_CHAR(port, ch);
+}
+
+static void ks8695_console_write(struct console *co, const char *s, u_int count)
+{
+ struct uart_port *port = ks8695uart_ports + co->index;
+
+ uart_console_write(port, s, count, ks8695_console_putchar);
+}
+
+static void __init ks8695_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
+{
+ unsigned int lcr;
+
+ lcr = UART_GET_LCR(port);
+
+ switch (lcr & URLC_PARITY) {
+ case URPE_ODD:
+ *parity = 'o';
+ break;
+ case URPE_EVEN:
+ *parity = 'e';
+ break;
+ default:
+ *parity = 'n';
+ }
+
+ switch (lcr & URLC_URCL) {
+ case URCL_5:
+ *bits = 5;
+ break;
+ case URCL_6:
+ *bits = 6;
+ break;
+ case URCL_7:
+ *bits = 7;
+ break;
+ default:
+ *bits = 8;
+ }
+
+ *baud = port->uartclk / (UART_GET_BRDR(port) & 0x0FFF);
+ *baud /= 16;
+ *baud &= 0xFFFFFFF0;
+}
+
+static int __init ks8695_console_setup(struct console *co, char *options)
+{
+ struct uart_port *port;
+ int baud = 115200;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ /*
+ * Check whether an invalid uart number has been specified, and
+ * if so, search for the first available port that does have
+ * console support.
+ */
+ port = uart_get_console(ks8695uart_ports, SERIAL_KS8695_NR, co);
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+ else
+ ks8695_console_get_options(port, &baud, &parity, &bits);
+
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver ks8695_reg;
+
+static struct console ks8695_console = {
+ .name = SERIAL_KS8695_DEVNAME,
+ .write = ks8695_console_write,
+ .device = uart_console_device,
+ .setup = ks8695_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &ks8695_reg,
+};
+
+static int __init ks8695_console_init(void)
+{
+ register_console(&ks8695_console);
+ return 0;
+}
+
+console_initcall(ks8695_console_init);
+
+#define KS8695_CONSOLE &ks8695_console
+#else
+#define KS8695_CONSOLE NULL
+#endif
+
+static struct uart_driver ks8695_reg = {
+ .owner = THIS_MODULE,
+ .driver_name = "serial_ks8695",
+ .dev_name = SERIAL_KS8695_DEVNAME,
+ .major = SERIAL_KS8695_MAJOR,
+ .minor = SERIAL_KS8695_MINOR,
+ .nr = SERIAL_KS8695_NR,
+ .cons = KS8695_CONSOLE,
+};
+
+static int __init ks8695uart_init(void)
+{
+ int i, ret;
+
+ printk(KERN_INFO "Serial: Micrel KS8695 UART driver\n");
+
+ ret = uart_register_driver(&ks8695_reg);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < SERIAL_KS8695_NR; i++)
+ uart_add_one_port(&ks8695_reg, &ks8695uart_ports[0]);
+
+ return 0;
+}
+
+static void __exit ks8695uart_exit(void)
+{
+ int i;
+
+ for (i = 0; i < SERIAL_KS8695_NR; i++)
+ uart_remove_one_port(&ks8695_reg, &ks8695uart_ports[0]);
+ uart_unregister_driver(&ks8695_reg);
+}
+
+module_init(ks8695uart_init);
+module_exit(ks8695uart_exit);
+
+MODULE_DESCRIPTION("KS8695 serial port driver");
+MODULE_AUTHOR("Micrel Inc.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c
index 509ace7e6881..1deb5764326d 100644
--- a/drivers/serial/serial_txx9.c
+++ b/drivers/serial/serial_txx9.c
@@ -15,31 +15,6 @@
* published by the Free Software Foundation.
*
* Serial driver for TX3927/TX4927/TX4925/TX4938 internal SIO controller
- *
- * Revision History:
- * 0.30 Initial revision. (Renamed from serial_txx927.c)
- * 0.31 Use save_flags instead of local_irq_save.
- * 0.32 Support SCLK.
- * 0.33 Switch TXX9_TTY_NAME by CONFIG_SERIAL_TXX9_STDSERIAL.
- * Support TIOCSERGETLSR.
- * 0.34 Support slow baudrate.
- * 0.40 Merge codes from mainstream kernel (2.4.22).
- * 0.41 Fix console checking in rs_shutdown_port().
- * Disable flow-control in serial_console_write().
- * 0.42 Fix minor compiler warning.
- * 1.00 Kernel 2.6. Converted to new serial core (based on 8250.c).
- * 1.01 Set fifosize to make tx_empry called properly.
- * Use standard uart_get_divisor.
- * 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.
- * 1.07 Use CONFIG_SERIAL_TXX9_NR_UARTS. Cleanup.
- * 1.08 Use platform_device.
- * Fix and cleanup suspend/resume/initialization codes.
*/
#if defined(CONFIG_SERIAL_TXX9_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
@@ -62,7 +37,7 @@
#include <asm/io.h>
-static char *serial_version = "1.08";
+static char *serial_version = "1.09";
static char *serial_name = "TX39/49 Serial driver";
#define PASS_LIMIT 256
@@ -70,13 +45,14 @@ static char *serial_name = "TX39/49 Serial driver";
#if !defined(CONFIG_SERIAL_TXX9_STDSERIAL)
/* "ttyS" is used for standard serial driver */
#define TXX9_TTY_NAME "ttyTX"
-#define TXX9_TTY_MINOR_START (64 + 64) /* ttyTX0(128), ttyTX1(129) */
+#define TXX9_TTY_MINOR_START 196
+#define TXX9_TTY_MAJOR 204
#else
/* acts like standard serial driver */
#define TXX9_TTY_NAME "ttyS"
#define TXX9_TTY_MINOR_START 64
-#endif
#define TXX9_TTY_MAJOR TTY_MAJOR
+#endif
/* flag aliases */
#define UPF_TXX9_HAVE_CTS_LINE UPF_BUGGY_UART
diff --git a/drivers/serial/suncore.c b/drivers/serial/suncore.c
index e35d9ab359f1..b45ba5392dd3 100644
--- a/drivers/serial/suncore.c
+++ b/drivers/serial/suncore.c
@@ -30,9 +30,9 @@ void
sunserial_console_termios(struct console *con)
{
char mode[16], buf[16], *s;
- char *mode_prop = "ttyX-mode";
- char *cd_prop = "ttyX-ignore-cd";
- char *dtr_prop = "ttyX-rts-dtr-off";
+ char mode_prop[] = "ttyX-mode";
+ char cd_prop[] = "ttyX-ignore-cd";
+ char dtr_prop[] = "ttyX-rts-dtr-off";
char *ssp_console_modes_prop = "ssp-console-modes";
int baud, bits, stop, cflag;
char parity;
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c
index 40d48566215c..96557e6dba60 100644
--- a/drivers/serial/sunhv.c
+++ b/drivers/serial/sunhv.c
@@ -1,6 +1,6 @@
/* sunhv.c: Serial driver for SUN4V hypervisor console.
*
- * Copyright (C) 2006 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 2006, 2007 David S. Miller (davem@davemloft.net)
*/
#include <linux/module.h>
@@ -35,57 +35,51 @@
#define CON_BREAK ((long)-1)
#define CON_HUP ((long)-2)
-static inline long hypervisor_con_getchar(long *status)
-{
- register unsigned long func asm("%o5");
- register unsigned long arg0 asm("%o0");
- register unsigned long arg1 asm("%o1");
-
- func = HV_FAST_CONS_GETCHAR;
- arg0 = 0;
- arg1 = 0;
- __asm__ __volatile__("ta %6"
- : "=&r" (func), "=&r" (arg0), "=&r" (arg1)
- : "0" (func), "1" (arg0), "2" (arg1),
- "i" (HV_FAST_TRAP));
+#define IGNORE_BREAK 0x1
+#define IGNORE_ALL 0x2
- *status = arg0;
+static char *con_write_page;
+static char *con_read_page;
- return (long) arg1;
-}
+static int hung_up = 0;
-static inline long hypervisor_con_putchar(long ch)
+static void transmit_chars_putchar(struct uart_port *port, struct circ_buf *xmit)
{
- register unsigned long func asm("%o5");
- register unsigned long arg0 asm("%o0");
+ while (!uart_circ_empty(xmit)) {
+ long status = sun4v_con_putchar(xmit->buf[xmit->tail]);
- func = HV_FAST_CONS_PUTCHAR;
- arg0 = ch;
- __asm__ __volatile__("ta %4"
- : "=&r" (func), "=&r" (arg0)
- : "0" (func), "1" (arg0), "i" (HV_FAST_TRAP));
+ if (status != HV_EOK)
+ break;
- return (long) arg0;
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ }
}
-#define IGNORE_BREAK 0x1
-#define IGNORE_ALL 0x2
+static void transmit_chars_write(struct uart_port *port, struct circ_buf *xmit)
+{
+ while (!uart_circ_empty(xmit)) {
+ unsigned long ra = __pa(xmit->buf + xmit->tail);
+ unsigned long len, status, sent;
-static int hung_up = 0;
+ len = CIRC_CNT_TO_END(xmit->head, xmit->tail,
+ UART_XMIT_SIZE);
+ status = sun4v_con_write(ra, len, &sent);
+ if (status != HV_EOK)
+ break;
+ xmit->tail = (xmit->tail + sent) & (UART_XMIT_SIZE - 1);
+ port->icount.tx += sent;
+ }
+}
-static struct tty_struct *receive_chars(struct uart_port *port)
+static int receive_chars_getchar(struct uart_port *port, struct tty_struct *tty)
{
- struct tty_struct *tty = NULL;
int saw_console_brk = 0;
int limit = 10000;
- if (port->info != NULL) /* Unopened serial console */
- tty = port->info->tty;
-
while (limit-- > 0) {
long status;
- long c = hypervisor_con_getchar(&status);
- unsigned char flag;
+ long c = sun4v_con_getchar(&status);
if (status == HV_EWOULDBLOCK)
break;
@@ -110,27 +104,90 @@ static struct tty_struct *receive_chars(struct uart_port *port)
continue;
}
- flag = TTY_NORMAL;
port->icount.rx++;
- if (c == CON_BREAK) {
- port->icount.brk++;
- if (uart_handle_break(port))
- continue;
- flag = TTY_BREAK;
- }
if (uart_handle_sysrq_char(port, c))
continue;
- if ((port->ignore_status_mask & IGNORE_ALL) ||
- ((port->ignore_status_mask & IGNORE_BREAK) &&
- (c == CON_BREAK)))
+ tty_insert_flip_char(tty, c, TTY_NORMAL);
+ }
+
+ return saw_console_brk;
+}
+
+static int receive_chars_read(struct uart_port *port, struct tty_struct *tty)
+{
+ int saw_console_brk = 0;
+ int limit = 10000;
+
+ while (limit-- > 0) {
+ unsigned long ra = __pa(con_read_page);
+ unsigned long bytes_read, i;
+ long stat = sun4v_con_read(ra, PAGE_SIZE, &bytes_read);
+
+ if (stat != HV_EOK) {
+ bytes_read = 0;
+
+ if (stat == CON_BREAK) {
+ if (uart_handle_break(port))
+ continue;
+ saw_console_brk = 1;
+ *con_read_page = 0;
+ bytes_read = 1;
+ } else if (stat == CON_HUP) {
+ hung_up = 1;
+ uart_handle_dcd_change(port, 0);
+ continue;
+ } else {
+ /* HV_EWOULDBLOCK, etc. */
+ break;
+ }
+ }
+
+ if (hung_up) {
+ hung_up = 0;
+ uart_handle_dcd_change(port, 1);
+ }
+
+ for (i = 0; i < bytes_read; i++)
+ uart_handle_sysrq_char(port, con_read_page[i]);
+
+ if (tty == NULL)
continue;
- tty_insert_flip_char(tty, c, flag);
+ port->icount.rx += bytes_read;
+
+ tty_insert_flip_string(tty, con_read_page, bytes_read);
}
- if (saw_console_brk)
+ return saw_console_brk;
+}
+
+struct sunhv_ops {
+ void (*transmit_chars)(struct uart_port *port, struct circ_buf *xmit);
+ int (*receive_chars)(struct uart_port *port, struct tty_struct *tty);
+};
+
+static struct sunhv_ops bychar_ops = {
+ .transmit_chars = transmit_chars_putchar,
+ .receive_chars = receive_chars_getchar,
+};
+
+static struct sunhv_ops bywrite_ops = {
+ .transmit_chars = transmit_chars_write,
+ .receive_chars = receive_chars_read,
+};
+
+static struct sunhv_ops *sunhv_ops = &bychar_ops;
+
+static struct tty_struct *receive_chars(struct uart_port *port)
+{
+ struct tty_struct *tty = NULL;
+
+ if (port->info != NULL) /* Unopened serial console */
+ tty = port->info->tty;
+
+ if (sunhv_ops->receive_chars(port, tty))
sun_do_break();
return tty;
@@ -147,15 +204,7 @@ static void transmit_chars(struct uart_port *port)
if (uart_circ_empty(xmit) || uart_tx_stopped(port))
return;
- while (!uart_circ_empty(xmit)) {
- long status = hypervisor_con_putchar(xmit->buf[xmit->tail]);
-
- if (status != HV_EOK)
- break;
-
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
- }
+ sunhv_ops->transmit_chars(port, xmit);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
@@ -212,7 +261,7 @@ static void sunhv_start_tx(struct uart_port *port)
struct circ_buf *xmit = &port->info->xmit;
while (!uart_circ_empty(xmit)) {
- long status = hypervisor_con_putchar(xmit->buf[xmit->tail]);
+ long status = sun4v_con_putchar(xmit->buf[xmit->tail]);
if (status != HV_EOK)
break;
@@ -231,9 +280,10 @@ static void sunhv_send_xchar(struct uart_port *port, char ch)
spin_lock_irqsave(&port->lock, flags);
while (limit-- > 0) {
- long status = hypervisor_con_putchar(ch);
+ long status = sun4v_con_putchar(ch);
if (status == HV_EOK)
break;
+ udelay(1);
}
spin_unlock_irqrestore(&port->lock, flags);
@@ -254,15 +304,15 @@ static void sunhv_break_ctl(struct uart_port *port, int break_state)
{
if (break_state) {
unsigned long flags;
- int limit = 1000000;
+ int limit = 10000;
spin_lock_irqsave(&port->lock, flags);
while (limit-- > 0) {
- long status = hypervisor_con_putchar(CON_BREAK);
+ long status = sun4v_con_putchar(CON_BREAK);
if (status == HV_EOK)
break;
- udelay(2);
+ udelay(1);
}
spin_unlock_irqrestore(&port->lock, flags);
@@ -359,38 +409,99 @@ static struct uart_driver sunhv_reg = {
static struct uart_port *sunhv_port;
-static inline void sunhv_console_putchar(struct uart_port *port, char c)
+/* Copy 's' into the con_write_page, decoding "\n" into
+ * "\r\n" along the way. We have to return two lengths
+ * because the caller needs to know how much to advance
+ * 's' and also how many bytes to output via con_write_page.
+ */
+static int fill_con_write_page(const char *s, unsigned int n,
+ unsigned long *page_bytes)
{
+ const char *orig_s = s;
+ char *p = con_write_page;
+ int left = PAGE_SIZE;
+
+ while (n--) {
+ if (*s == '\n') {
+ if (left < 2)
+ break;
+ *p++ = '\r';
+ left--;
+ } else if (left < 1)
+ break;
+ *p++ = *s++;
+ left--;
+ }
+ *page_bytes = p - con_write_page;
+ return s - orig_s;
+}
+
+static void sunhv_console_write_paged(struct console *con, const char *s, unsigned n)
+{
+ struct uart_port *port = sunhv_port;
unsigned long flags;
- int limit = 1000000;
spin_lock_irqsave(&port->lock, flags);
+ while (n > 0) {
+ unsigned long ra = __pa(con_write_page);
+ unsigned long page_bytes;
+ unsigned int cpy = fill_con_write_page(s, n,
+ &page_bytes);
+
+ n -= cpy;
+ s += cpy;
+ while (page_bytes > 0) {
+ unsigned long written;
+ int limit = 1000000;
+
+ while (limit--) {
+ unsigned long stat;
+
+ stat = sun4v_con_write(ra, page_bytes,
+ &written);
+ if (stat == HV_EOK)
+ break;
+ udelay(1);
+ }
+ if (limit <= 0)
+ break;
+ page_bytes -= written;
+ ra += written;
+ }
+ }
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static inline void sunhv_console_putchar(struct uart_port *port, char c)
+{
+ int limit = 1000000;
while (limit-- > 0) {
- long status = hypervisor_con_putchar(c);
+ long status = sun4v_con_putchar(c);
if (status == HV_EOK)
break;
- udelay(2);
+ udelay(1);
}
-
- spin_unlock_irqrestore(&port->lock, flags);
}
-static void sunhv_console_write(struct console *con, const char *s, unsigned n)
+static void sunhv_console_write_bychar(struct console *con, const char *s, unsigned n)
{
struct uart_port *port = sunhv_port;
+ unsigned long flags;
int i;
+ spin_lock_irqsave(&port->lock, flags);
for (i = 0; i < n; i++) {
if (*s == '\n')
sunhv_console_putchar(port, '\r');
sunhv_console_putchar(port, *s++);
}
+ spin_unlock_irqrestore(&port->lock, flags);
}
static struct console sunhv_console = {
.name = "ttyHV",
- .write = sunhv_console_write,
+ .write = sunhv_console_write_bychar,
.device = uart_console_device,
.flags = CON_PRINTBUFFER,
.index = -1,
@@ -410,6 +521,7 @@ static inline struct console *SUNHV_CONSOLE(void)
static int __devinit hv_probe(struct of_device *op, const struct of_device_id *match)
{
struct uart_port *port;
+ unsigned long minor;
int err;
if (op->irqs[0] == 0xffffffff)
@@ -419,6 +531,22 @@ static int __devinit hv_probe(struct of_device *op, const struct of_device_id *m
if (unlikely(!port))
return -ENOMEM;
+ minor = 1;
+ if (sun4v_hvapi_register(HV_GRP_CORE, 1, &minor) == 0 &&
+ minor >= 1) {
+ err = -ENOMEM;
+ con_write_page = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!con_write_page)
+ goto out_free_port;
+
+ con_read_page = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!con_read_page)
+ goto out_free_con_write_page;
+
+ sunhv_console.write = sunhv_console_write_paged;
+ sunhv_ops = &bywrite_ops;
+ }
+
sunhv_port = port;
port->line = 0;
@@ -437,7 +565,7 @@ static int __devinit hv_probe(struct of_device *op, const struct of_device_id *m
err = uart_register_driver(&sunhv_reg);
if (err)
- goto out_free_port;
+ goto out_free_con_read_page;
sunhv_reg.tty_driver->name_base = sunhv_reg.minor - 64;
sunserial_current_minor += 1;
@@ -463,6 +591,12 @@ out_unregister_driver:
sunserial_current_minor -= 1;
uart_unregister_driver(&sunhv_reg);
+out_free_con_read_page:
+ kfree(con_read_page);
+
+out_free_con_write_page:
+ kfree(con_write_page);
+
out_free_port:
kfree(port);
sunhv_port = NULL;
@@ -493,6 +627,10 @@ static struct of_device_id hv_match[] = {
.name = "console",
.compatible = "qcn",
},
+ {
+ .name = "console",
+ .compatible = "SUNW,sun4v-console",
+ },
{},
};
MODULE_DEVICE_TABLE(of, hv_match);
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
index da73205e54cd..15b6e1cb040b 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -92,6 +92,8 @@ struct uart_sunzilog_port {
#define SUNZILOG_FLAG_REGS_HELD 0x00000040
#define SUNZILOG_FLAG_TX_STOPPED 0x00000080
#define SUNZILOG_FLAG_TX_ACTIVE 0x00000100
+#define SUNZILOG_FLAG_ESCC 0x00000200
+#define SUNZILOG_FLAG_ISR_HANDLER 0x00000400
unsigned int cflag;
@@ -174,9 +176,11 @@ static void sunzilog_clear_fifo(struct zilog_channel __iomem *channel)
/* This function must only be called when the TX is not busy. The UART
* port lock must be held and local interrupts disabled.
*/
-static void __load_zsregs(struct zilog_channel __iomem *channel, unsigned char *regs)
+static int __load_zsregs(struct zilog_channel __iomem *channel, unsigned char *regs)
{
int i;
+ int escc;
+ unsigned char r15;
/* Let pending transmits finish. */
for (i = 0; i < 1000; i++) {
@@ -229,11 +233,25 @@ static void __load_zsregs(struct zilog_channel __iomem *channel, unsigned char *
write_zsreg(channel, R14, regs[R14]);
/* External status interrupt control. */
- write_zsreg(channel, R15, regs[R15]);
+ write_zsreg(channel, R15, (regs[R15] | WR7pEN) & ~FIFOEN);
+
+ /* ESCC Extension Register */
+ r15 = read_zsreg(channel, R15);
+ if (r15 & 0x01) {
+ write_zsreg(channel, R7, regs[R7p]);
+
+ /* External status interrupt and FIFO control. */
+ write_zsreg(channel, R15, regs[R15] & ~WR7pEN);
+ escc = 1;
+ } else {
+ /* Clear FIFO bit case it is an issue */
+ regs[R15] &= ~FIFOEN;
+ escc = 0;
+ }
/* Reset external status interrupts. */
- write_zsreg(channel, R0, RES_EXT_INT);
- write_zsreg(channel, R0, RES_EXT_INT);
+ write_zsreg(channel, R0, RES_EXT_INT); /* First Latch */
+ write_zsreg(channel, R0, RES_EXT_INT); /* Second Latch */
/* Rewrite R3/R5, this time without enables masked. */
write_zsreg(channel, R3, regs[R3]);
@@ -241,6 +259,8 @@ static void __load_zsregs(struct zilog_channel __iomem *channel, unsigned char *
/* Rewrite R1, this time without IRQ enabled masked. */
write_zsreg(channel, R1, regs[R1]);
+
+ return escc;
}
/* Reprogram the Zilog channel HW registers with the copies found in the
@@ -731,7 +751,7 @@ static void sunzilog_enable_ms(struct uart_port *port)
up->curregs[R15] = new_reg;
/* NOTE: Not subject to 'transmitter active' rule. */
- write_zsreg(channel, R15, up->curregs[R15]);
+ write_zsreg(channel, R15, up->curregs[R15] & ~WR7pEN);
}
}
@@ -861,44 +881,44 @@ sunzilog_convert_to_zs(struct uart_sunzilog_port *up, unsigned int cflag,
up->curregs[R14] = BRSRC | BRENAB;
/* Character size, stop bits, and parity. */
- up->curregs[3] &= ~RxN_MASK;
- up->curregs[5] &= ~TxN_MASK;
+ up->curregs[R3] &= ~RxN_MASK;
+ up->curregs[R5] &= ~TxN_MASK;
switch (cflag & CSIZE) {
case CS5:
- up->curregs[3] |= Rx5;
- up->curregs[5] |= Tx5;
+ up->curregs[R3] |= Rx5;
+ up->curregs[R5] |= Tx5;
up->parity_mask = 0x1f;
break;
case CS6:
- up->curregs[3] |= Rx6;
- up->curregs[5] |= Tx6;
+ up->curregs[R3] |= Rx6;
+ up->curregs[R5] |= Tx6;
up->parity_mask = 0x3f;
break;
case CS7:
- up->curregs[3] |= Rx7;
- up->curregs[5] |= Tx7;
+ up->curregs[R3] |= Rx7;
+ up->curregs[R5] |= Tx7;
up->parity_mask = 0x7f;
break;
case CS8:
default:
- up->curregs[3] |= Rx8;
- up->curregs[5] |= Tx8;
+ up->curregs[R3] |= Rx8;
+ up->curregs[R5] |= Tx8;
up->parity_mask = 0xff;
break;
};
- up->curregs[4] &= ~0x0c;
+ up->curregs[R4] &= ~0x0c;
if (cflag & CSTOPB)
- up->curregs[4] |= SB2;
+ up->curregs[R4] |= SB2;
else
- up->curregs[4] |= SB1;
+ up->curregs[R4] |= SB1;
if (cflag & PARENB)
- up->curregs[4] |= PAR_ENAB;
+ up->curregs[R4] |= PAR_ENAB;
else
- up->curregs[4] &= ~PAR_ENAB;
+ up->curregs[R4] &= ~PAR_ENAB;
if (!(cflag & PARODD))
- up->curregs[4] |= PAR_EVEN;
+ up->curregs[R4] |= PAR_EVEN;
else
- up->curregs[4] &= ~PAR_EVEN;
+ up->curregs[R4] &= ~PAR_EVEN;
up->port.read_status_mask = Rx_OVR;
if (iflag & INPCK)
@@ -952,7 +972,9 @@ sunzilog_set_termios(struct uart_port *port, struct ktermios *termios,
static const char *sunzilog_type(struct uart_port *port)
{
- return "zs";
+ struct uart_sunzilog_port *up = UART_ZILOG(port);
+
+ return (up->flags & SUNZILOG_FLAG_ESCC) ? "zs (ESCC)" : "zs";
}
/* We do not request/release mappings of the registers here, this
@@ -1170,7 +1192,7 @@ static int __init sunzilog_console_setup(struct console *con, char *options)
spin_lock_irqsave(&up->port.lock, flags);
- up->curregs[R15] = BRKIE;
+ up->curregs[R15] |= BRKIE;
sunzilog_convert_to_zs(up, con->cflag, 0, brg);
sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS);
@@ -1217,7 +1239,7 @@ static inline struct console *SUNZILOG_CONSOLE(void)
#define SUNZILOG_CONSOLE() (NULL)
#endif
-static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channel)
+static void __devinit sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channel)
{
int baud, brg;
@@ -1229,7 +1251,7 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe
baud = 4800;
}
- up->curregs[R15] = BRKIE;
+ up->curregs[R15] |= BRKIE;
brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
sunzilog_convert_to_zs(up, up->cflag, 0, brg);
sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS);
@@ -1237,7 +1259,7 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe
}
#ifdef CONFIG_SERIO
-static void __init sunzilog_register_serio(struct uart_sunzilog_port *up)
+static void __devinit sunzilog_register_serio(struct uart_sunzilog_port *up)
{
struct serio *serio = &up->serio;
@@ -1283,8 +1305,18 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up)
if (up->flags & (SUNZILOG_FLAG_CONS_KEYB |
SUNZILOG_FLAG_CONS_MOUSE)) {
+ up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
+ up->curregs[R4] = PAR_EVEN | X16CLK | SB1;
+ up->curregs[R3] = RxENAB | Rx8;
+ up->curregs[R5] = TxENAB | Tx8;
+ up->curregs[R6] = 0x00; /* SDLC Address */
+ up->curregs[R7] = 0x7E; /* SDLC Flag */
+ up->curregs[R9] = NV;
+ up->curregs[R7p] = 0x00;
sunzilog_init_kbdms(up, up->port.line);
- up->curregs[R9] |= (NV | MIE);
+ /* Only enable interrupts if an ISR handler available */
+ if (up->flags & SUNZILOG_FLAG_ISR_HANDLER)
+ up->curregs[R9] |= MIE;
write_zsreg(channel, R9, up->curregs[R9]);
} else {
/* Normal serial TTY. */
@@ -1293,7 +1325,9 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up)
up->curregs[R4] = PAR_EVEN | X16CLK | SB1;
up->curregs[R3] = RxENAB | Rx8;
up->curregs[R5] = TxENAB | Tx8;
- up->curregs[R9] = NV | MIE;
+ up->curregs[R6] = 0x00; /* SDLC Address */
+ up->curregs[R7] = 0x7E; /* SDLC Flag */
+ up->curregs[R9] = NV;
up->curregs[R10] = NRZ;
up->curregs[R11] = TCBR | RCBR;
baud = 9600;
@@ -1301,7 +1335,14 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up)
up->curregs[R12] = (brg & 0xff);
up->curregs[R13] = (brg >> 8) & 0xff;
up->curregs[R14] = BRSRC | BRENAB;
- __load_zsregs(channel, up->curregs);
+ up->curregs[R15] = FIFOEN; /* Use FIFO if on ESCC */
+ up->curregs[R7p] = TxFIFO_LVL | RxFIFO_LVL;
+ if (__load_zsregs(channel, up->curregs)) {
+ up->flags |= SUNZILOG_FLAG_ESCC;
+ }
+ /* Only enable interrupts if an ISR handler available */
+ if (up->flags & SUNZILOG_FLAG_ISR_HANDLER)
+ up->curregs[R9] |= MIE;
write_zsreg(channel, R9, up->curregs[R9]);
}
@@ -1390,12 +1431,14 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m
return err;
}
} else {
- printk(KERN_INFO "%s: Keyboard at MMIO %lx (irq = %d) "
- "is a zs\n",
- op->dev.bus_id, up[0].port.mapbase, op->irqs[0]);
- printk(KERN_INFO "%s: Mouse at MMIO %lx (irq = %d) "
- "is a zs\n",
- op->dev.bus_id, up[1].port.mapbase, op->irqs[0]);
+ printk(KERN_INFO "%s: Keyboard at MMIO 0x%lx (irq = %d) "
+ "is a %s\n",
+ op->dev.bus_id, up[0].port.mapbase, op->irqs[0],
+ sunzilog_type (&up[0].port));
+ printk(KERN_INFO "%s: Mouse at MMIO 0x%lx (irq = %d) "
+ "is a %s\n",
+ op->dev.bus_id, up[1].port.mapbase, op->irqs[0],
+ sunzilog_type (&up[1].port));
}
dev_set_drvdata(&op->dev, &up[0]);
@@ -1487,10 +1530,23 @@ static int __init sunzilog_init(void)
goto out_unregister_uart;
if (zilog_irq != -1) {
+ struct uart_sunzilog_port *up = sunzilog_irq_chain;
err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED,
"zs", sunzilog_irq_chain);
if (err)
goto out_unregister_driver;
+
+ /* Enable Interrupts */
+ while (up) {
+ struct zilog_channel __iomem *channel;
+
+ /* printk (KERN_INFO "Enable IRQ for ZILOG Hardware %p\n", up); */
+ channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
+ up->flags |= SUNZILOG_FLAG_ISR_HANDLER;
+ up->curregs[R9] |= MIE;
+ write_zsreg(channel, R9, up->curregs[R9]);
+ up = up->next;
+ }
}
out:
@@ -1515,6 +1571,20 @@ static void __exit sunzilog_exit(void)
of_unregister_driver(&zs_driver);
if (zilog_irq != -1) {
+ struct uart_sunzilog_port *up = sunzilog_irq_chain;
+
+ /* Disable Interrupts */
+ while (up) {
+ struct zilog_channel __iomem *channel;
+
+ /* printk (KERN_INFO "Disable IRQ for ZILOG Hardware %p\n", up); */
+ channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
+ up->flags &= ~SUNZILOG_FLAG_ISR_HANDLER;
+ up->curregs[R9] &= ~MIE;
+ write_zsreg(channel, R9, up->curregs[R9]);
+ up = up->next;
+ }
+
free_irq(zilog_irq, sunzilog_irq_chain);
zilog_irq = -1;
}
diff --git a/drivers/serial/sunzilog.h b/drivers/serial/sunzilog.h
index 7939b6d71270..5dec7b47cc38 100644
--- a/drivers/serial/sunzilog.h
+++ b/drivers/serial/sunzilog.h
@@ -13,7 +13,8 @@ struct zilog_layout {
struct zilog_channel channelA;
};
-#define NUM_ZSREGS 16
+#define NUM_ZSREGS 17
+#define R7p 16 /* Written as R7 with P15 bit 0 set */
/* Conversion routines to/from brg time constants from/to bits
* per second.
@@ -127,6 +128,15 @@ struct zilog_layout {
/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
+/* Write Register 7' (ESCC Only) */
+#define AUTO_TxFLAG 1 /* Automatic Tx SDLC Flag */
+#define AUTO_EOM_RST 2 /* Automatic EOM Reset */
+#define AUTOnRTS 4 /* Automatic /RTS pin deactivation */
+#define RxFIFO_LVL 8 /* Receive FIFO interrupt level */
+#define nDTRnREQ 0x10 /* /DTR/REQ timing */
+#define TxFIFO_LVL 0x20 /* Transmit FIFO interrupt level */
+#define EXT_RD_EN 0x40 /* Extended read register enable */
+
/* Write Register 8 (transmit buffer) */
/* Write Register 9 (Master interrupt control) */
@@ -135,6 +145,7 @@ struct zilog_layout {
#define DLC 4 /* Disable Lower Chain */
#define MIE 8 /* Master Interrupt Enable */
#define STATHI 0x10 /* Status high */
+#define SWIACK 0x20 /* Software Interrupt Ack (not on NMOS) */
#define NORESET 0 /* No reset on write to R9 */
#define CHRB 0x40 /* Reset channel B */
#define CHRA 0x80 /* Reset channel A */
@@ -187,7 +198,9 @@ struct zilog_layout {
#define SNRZI 0xe0 /* Set NRZI mode */
/* Write Register 15 (external/status interrupt control) */
+#define WR7pEN 1 /* WR7' Enable (ESCC only) */
#define ZCIE 2 /* Zero count IE */
+#define FIFOEN 4 /* FIFO Enable (ESCC only) */
#define DCDIE 8 /* DCD IE */
#define SYNCIE 0x10 /* Sync/hunt IE */
#define CTSIE 0x20 /* CTS IE */
@@ -241,6 +254,10 @@ struct zilog_layout {
#define CHATxIP 0x10 /* Channel A Tx IP */
#define CHARxIP 0x20 /* Channel A Rx IP */
+/* Read Register 6 (LSB frame byte count [Not on NMOS]) */
+
+/* Read Register 7 (MSB frame byte count and FIFO status [Not on NMOS]) */
+
/* Read Register 8 (receive data register) */
/* Read Register 10 (misc status bits) */