summaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-11-22 05:36:46 +0100
committerLinus Torvalds <torvalds@linux-foundation.org>2011-11-22 05:36:46 +0100
commit3b9abc7e48561b0b140ee267e190bc1031f82ff3 (patch)
treeec5d8174f89cb8555c74eb3eb770054aa22fc724 /drivers/tty
parentMerge branch 'driver-core-linus' of git://git.kernel.org/pub/scm/linux/kernel... (diff)
parentTTY: ldisc, wait for ldisc infinitely in hangup (diff)
downloadlinux-3b9abc7e48561b0b140ee267e190bc1031f82ff3.tar.xz
linux-3b9abc7e48561b0b140ee267e190bc1031f82ff3.zip
Merge branch 'tty-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
* 'tty-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: TTY: ldisc, wait for ldisc infinitely in hangup TTY: ldisc, move wait idle to caller TTY: ldisc, allow waiting for ldisc arbitrarily long Revert "tty/serial: Prevent drop of DCD on suspend for Tegra UARTs" RS485: fix inconsistencies in the meaning of some variables pch_uart: Fix DMA resource leak issue serial,mfd: Fix CMSPAR setup tty/serial: Prevent drop of DCD on suspend for Tegra UARTs pch_uart: Change company name OKI SEMICONDUCTOR to LAPIS Semiconductor pch_uart: Support new device LAPIS Semiconductor ML7831 IOH pch_uart: Fix hw-flow control issue tty: hvc_dcc: Fix duplicate character inputs jsm: Change maintainership
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/hvc/hvc_dcc.c2
-rw-r--r--drivers/tty/serial/Kconfig14
-rw-r--r--drivers/tty/serial/atmel_serial.c16
-rw-r--r--drivers/tty/serial/crisv10.c10
-rw-r--r--drivers/tty/serial/mfd.c4
-rw-r--r--drivers/tty/serial/pch_uart.c19
-rw-r--r--drivers/tty/tty_ldisc.c30
7 files changed, 52 insertions, 43 deletions
diff --git a/drivers/tty/hvc/hvc_dcc.c b/drivers/tty/hvc/hvc_dcc.c
index 435f6facbc23..44fbebab5075 100644
--- a/drivers/tty/hvc/hvc_dcc.c
+++ b/drivers/tty/hvc/hvc_dcc.c
@@ -46,6 +46,7 @@ static inline char __dcc_getchar(void)
asm volatile("mrc p14, 0, %0, c0, c5, 0 @ read comms data reg"
: "=r" (__c));
+ isb();
return __c;
}
@@ -55,6 +56,7 @@ static inline void __dcc_putchar(char c)
asm volatile("mcr p14, 0, %0, c0, c5, 0 @ write a char"
: /* no output register */
: "r" (c));
+ isb();
}
static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count)
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 5f479dada6f2..925a1e547a83 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1560,7 +1560,7 @@ config SERIAL_IFX6X60
Support for the IFX6x60 modem devices on Intel MID platforms.
config SERIAL_PCH_UART
- tristate "Intel EG20T PCH / OKI SEMICONDUCTOR IOH(ML7213/ML7223) UART"
+ tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) UART"
depends on PCI
select SERIAL_CORE
help
@@ -1568,12 +1568,12 @@ config SERIAL_PCH_UART
which is an IOH(Input/Output Hub) for x86 embedded processor.
Enabling PCH_DMA, this PCH UART works as DMA mode.
- This driver also can be used for OKI SEMICONDUCTOR IOH(Input/
- Output Hub), ML7213 and ML7223.
- ML7213 IOH is for IVI(In-Vehicle Infotainment) use and ML7223 IOH is
- for MP(Media Phone) use.
- ML7213/ML7223 is companion chip for Intel Atom E6xx series.
- ML7213/ML7223 is completely compatible for Intel EG20T PCH.
+ This driver also can be used for LAPIS Semiconductor IOH(Input/
+ Output Hub), ML7213, ML7223 and ML7831.
+ ML7213 IOH is for IVI(In-Vehicle Infotainment) use, ML7223 IOH is
+ for MP(Media Phone) use and ML7831 IOH is for general purpose use.
+ ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series.
+ ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH.
config SERIAL_MSM_SMD
bool "Enable tty device interface for some SMD ports"
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 4a0f86fa1e90..4c823f341d98 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -228,7 +228,7 @@ void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
if (rs485conf->flags & SER_RS485_ENABLED) {
dev_dbg(port->dev, "Setting UART to RS485\n");
atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
- if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND)
+ if ((rs485conf->delay_rts_after_send) > 0)
UART_PUT_TTGR(port, rs485conf->delay_rts_after_send);
mode |= ATMEL_US_USMODE_RS485;
} else {
@@ -304,7 +304,7 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
dev_dbg(port->dev, "Setting UART to RS485\n");
- if (atmel_port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
+ if ((atmel_port->rs485.delay_rts_after_send) > 0)
UART_PUT_TTGR(port,
atmel_port->rs485.delay_rts_after_send);
mode |= ATMEL_US_USMODE_RS485;
@@ -1228,7 +1228,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
dev_dbg(port->dev, "Setting UART to RS485\n");
- if (atmel_port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
+ if ((atmel_port->rs485.delay_rts_after_send) > 0)
UART_PUT_TTGR(port,
atmel_port->rs485.delay_rts_after_send);
mode |= ATMEL_US_USMODE_RS485;
@@ -1447,16 +1447,6 @@ static void __devinit atmel_of_init_port(struct atmel_uart_port *atmel_port,
rs485conf->delay_rts_after_send = rs485_delay[1];
rs485conf->flags = 0;
- if (rs485conf->delay_rts_before_send == 0 &&
- rs485conf->delay_rts_after_send == 0) {
- rs485conf->flags |= SER_RS485_RTS_ON_SEND;
- } else {
- if (rs485conf->delay_rts_before_send)
- rs485conf->flags |= SER_RS485_RTS_BEFORE_SEND;
- if (rs485conf->delay_rts_after_send)
- rs485conf->flags |= SER_RS485_RTS_AFTER_SEND;
- }
-
if (of_get_property(np, "rs485-rx-during-tx", NULL))
rs485conf->flags |= SER_RS485_RX_DURING_TX;
diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c
index b7435043f2fe..1dfba7b779c8 100644
--- a/drivers/tty/serial/crisv10.c
+++ b/drivers/tty/serial/crisv10.c
@@ -3234,9 +3234,8 @@ rs_write(struct tty_struct *tty,
e100_disable_rx(info);
e100_enable_rx_irq(info);
#endif
- if ((info->rs485.flags & SER_RS485_RTS_BEFORE_SEND) &&
- (info->rs485.delay_rts_before_send > 0))
- msleep(info->rs485.delay_rts_before_send);
+ if (info->rs485.delay_rts_before_send > 0)
+ msleep(info->rs485.delay_rts_before_send);
}
#endif /* CONFIG_ETRAX_RS485 */
@@ -3693,10 +3692,6 @@ rs_ioctl(struct tty_struct *tty,
rs485data.delay_rts_before_send = rs485ctrl.delay_rts_before_send;
rs485data.flags = 0;
- if (rs485data.delay_rts_before_send != 0)
- rs485data.flags |= SER_RS485_RTS_BEFORE_SEND;
- else
- rs485data.flags &= ~(SER_RS485_RTS_BEFORE_SEND);
if (rs485ctrl.enabled)
rs485data.flags |= SER_RS485_ENABLED;
@@ -4531,7 +4526,6 @@ static int __init rs_init(void)
/* Set sane defaults */
info->rs485.flags &= ~(SER_RS485_RTS_ON_SEND);
info->rs485.flags |= SER_RS485_RTS_AFTER_SEND;
- info->rs485.flags &= ~(SER_RS485_RTS_BEFORE_SEND);
info->rs485.delay_rts_before_send = 0;
info->rs485.flags &= ~(SER_RS485_ENABLED);
#endif
diff --git a/drivers/tty/serial/mfd.c b/drivers/tty/serial/mfd.c
index 286c386d9c46..e272d3919c67 100644
--- a/drivers/tty/serial/mfd.c
+++ b/drivers/tty/serial/mfd.c
@@ -884,7 +884,6 @@ serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios,
{
struct uart_hsu_port *up =
container_of(port, struct uart_hsu_port, port);
- struct tty_struct *tty = port->state->port.tty;
unsigned char cval, fcr = 0;
unsigned long flags;
unsigned int baud, quot;
@@ -907,8 +906,7 @@ serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios,
}
/* CMSPAR isn't supported by this driver */
- if (tty)
- tty->termios->c_cflag &= ~CMSPAR;
+ termios->c_cflag &= ~CMSPAR;
if (termios->c_cflag & CSTOPB)
cval |= UART_LCR_STOP;
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index 21febef926aa..d6aba8c087e4 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -1,5 +1,5 @@
/*
- *Copyright (C) 2010 OKI SEMICONDUCTOR CO., LTD.
+ *Copyright (C) 2011 LAPIS Semiconductor Co., Ltd.
*
*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
@@ -46,8 +46,8 @@ enum {
/* Set the max number of UART port
* Intel EG20T PCH: 4 port
- * OKI SEMICONDUCTOR ML7213 IOH: 3 port
- * OKI SEMICONDUCTOR ML7223 IOH: 2 port
+ * LAPIS Semiconductor ML7213 IOH: 3 port
+ * LAPIS Semiconductor ML7223 IOH: 2 port
*/
#define PCH_UART_NR 4
@@ -258,6 +258,8 @@ enum pch_uart_num_t {
pch_ml7213_uart2,
pch_ml7223_uart0,
pch_ml7223_uart1,
+ pch_ml7831_uart0,
+ pch_ml7831_uart1,
};
static struct pch_uart_driver_data drv_dat[] = {
@@ -270,6 +272,8 @@ static struct pch_uart_driver_data drv_dat[] = {
[pch_ml7213_uart2] = {PCH_UART_2LINE, 2},
[pch_ml7223_uart0] = {PCH_UART_8LINE, 0},
[pch_ml7223_uart1] = {PCH_UART_2LINE, 1},
+ [pch_ml7831_uart0] = {PCH_UART_8LINE, 0},
+ [pch_ml7831_uart1] = {PCH_UART_2LINE, 1},
};
static unsigned int default_baud = 9600;
@@ -628,6 +632,7 @@ static void pch_request_dma(struct uart_port *port)
dev_err(priv->port.dev, "%s:dma_request_channel FAILS(Rx)\n",
__func__);
dma_release_channel(priv->chan_tx);
+ priv->chan_tx = NULL;
return;
}
@@ -1215,8 +1220,7 @@ static void pch_uart_shutdown(struct uart_port *port)
dev_err(priv->port.dev,
"pch_uart_hal_set_fifo Failed(ret=%d)\n", ret);
- if (priv->use_dma_flag)
- pch_free_dma(port);
+ pch_free_dma(port);
free_irq(priv->port.irq, priv);
}
@@ -1280,6 +1284,7 @@ static void pch_uart_set_termios(struct uart_port *port,
if (rtn)
goto out;
+ pch_uart_set_mctrl(&priv->port, priv->port.mctrl);
/* Don't rewrite B0 */
if (tty_termios_baud_rate(termios))
tty_termios_encode_baud_rate(termios, baud, baud);
@@ -1552,6 +1557,10 @@ static DEFINE_PCI_DEVICE_TABLE(pch_uart_pci_id) = {
.driver_data = pch_ml7223_uart0},
{PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x800D),
.driver_data = pch_ml7223_uart1},
+ {PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8811),
+ .driver_data = pch_ml7831_uart0},
+ {PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8812),
+ .driver_data = pch_ml7831_uart1},
{0,},
};
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index 512c49f98e85..8e0924f55446 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -36,6 +36,7 @@
#include <linux/kmod.h>
#include <linux/nsproxy.h>
+#include <linux/ratelimit.h>
/*
* This guards the refcounted line discipline lists. The lock
@@ -547,15 +548,16 @@ static void tty_ldisc_flush_works(struct tty_struct *tty)
/**
* tty_ldisc_wait_idle - wait for the ldisc to become idle
* @tty: tty to wait for
+ * @timeout: for how long to wait at most
*
* Wait for the line discipline to become idle. The discipline must
* have been halted for this to guarantee it remains idle.
*/
-static int tty_ldisc_wait_idle(struct tty_struct *tty)
+static int tty_ldisc_wait_idle(struct tty_struct *tty, long timeout)
{
- int ret;
+ long ret;
ret = wait_event_timeout(tty_ldisc_idle,
- atomic_read(&tty->ldisc->users) == 1, 5 * HZ);
+ atomic_read(&tty->ldisc->users) == 1, timeout);
if (ret < 0)
return ret;
return ret > 0 ? 0 : -EBUSY;
@@ -665,7 +667,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
tty_ldisc_flush_works(tty);
- retval = tty_ldisc_wait_idle(tty);
+ retval = tty_ldisc_wait_idle(tty, 5 * HZ);
tty_lock();
mutex_lock(&tty->ldisc_mutex);
@@ -762,8 +764,6 @@ static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
if (IS_ERR(ld))
return -1;
- WARN_ON_ONCE(tty_ldisc_wait_idle(tty));
-
tty_ldisc_close(tty, tty->ldisc);
tty_ldisc_put(tty->ldisc);
tty->ldisc = NULL;
@@ -838,7 +838,7 @@ void tty_ldisc_hangup(struct tty_struct *tty)
tty_unlock();
cancel_work_sync(&tty->buf.work);
mutex_unlock(&tty->ldisc_mutex);
-
+retry:
tty_lock();
mutex_lock(&tty->ldisc_mutex);
@@ -847,6 +847,22 @@ void tty_ldisc_hangup(struct tty_struct *tty)
it means auditing a lot of other paths so this is
a FIXME */
if (tty->ldisc) { /* Not yet closed */
+ if (atomic_read(&tty->ldisc->users) != 1) {
+ char cur_n[TASK_COMM_LEN], tty_n[64];
+ long timeout = 3 * HZ;
+ tty_unlock();
+
+ while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) {
+ timeout = MAX_SCHEDULE_TIMEOUT;
+ printk_ratelimited(KERN_WARNING
+ "%s: waiting (%s) for %s took too long, but we keep waiting...\n",
+ __func__, get_task_comm(cur_n, current),
+ tty_name(tty, tty_n));
+ }
+ mutex_unlock(&tty->ldisc_mutex);
+ goto retry;
+ }
+
if (reset == 0) {
if (!tty_ldisc_reinit(tty, tty->termios->c_line))