diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-21 23:36:46 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-21 23:36:46 -0500 |
commit | 3b9abc7e48561b0b140ee267e190bc1031f82ff3 (patch) | |
tree | ec5d8174f89cb8555c74eb3eb770054aa22fc724 /drivers/tty | |
parent | 0cda56962b883cd5e7aa036350e5a0283a88c590 (diff) | |
parent | 0c73c08ec73dbe080b9ec56696ee21d32754d918 (diff) |
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.c | 2 | ||||
-rw-r--r-- | drivers/tty/serial/Kconfig | 14 | ||||
-rw-r--r-- | drivers/tty/serial/atmel_serial.c | 16 | ||||
-rw-r--r-- | drivers/tty/serial/crisv10.c | 10 | ||||
-rw-r--r-- | drivers/tty/serial/mfd.c | 4 | ||||
-rw-r--r-- | drivers/tty/serial/pch_uart.c | 19 | ||||
-rw-r--r-- | drivers/tty/tty_ldisc.c | 30 |
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) | |||
46 | 46 | ||
47 | asm volatile("mrc p14, 0, %0, c0, c5, 0 @ read comms data reg" | 47 | asm volatile("mrc p14, 0, %0, c0, c5, 0 @ read comms data reg" |
48 | : "=r" (__c)); | 48 | : "=r" (__c)); |
49 | isb(); | ||
49 | 50 | ||
50 | return __c; | 51 | return __c; |
51 | } | 52 | } |
@@ -55,6 +56,7 @@ static inline void __dcc_putchar(char c) | |||
55 | asm volatile("mcr p14, 0, %0, c0, c5, 0 @ write a char" | 56 | asm volatile("mcr p14, 0, %0, c0, c5, 0 @ write a char" |
56 | : /* no output register */ | 57 | : /* no output register */ |
57 | : "r" (c)); | 58 | : "r" (c)); |
59 | isb(); | ||
58 | } | 60 | } |
59 | 61 | ||
60 | static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count) | 62 | 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 | |||
1560 | Support for the IFX6x60 modem devices on Intel MID platforms. | 1560 | Support for the IFX6x60 modem devices on Intel MID platforms. |
1561 | 1561 | ||
1562 | config SERIAL_PCH_UART | 1562 | config SERIAL_PCH_UART |
1563 | tristate "Intel EG20T PCH / OKI SEMICONDUCTOR IOH(ML7213/ML7223) UART" | 1563 | tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) UART" |
1564 | depends on PCI | 1564 | depends on PCI |
1565 | select SERIAL_CORE | 1565 | select SERIAL_CORE |
1566 | help | 1566 | help |
@@ -1568,12 +1568,12 @@ config SERIAL_PCH_UART | |||
1568 | which is an IOH(Input/Output Hub) for x86 embedded processor. | 1568 | which is an IOH(Input/Output Hub) for x86 embedded processor. |
1569 | Enabling PCH_DMA, this PCH UART works as DMA mode. | 1569 | Enabling PCH_DMA, this PCH UART works as DMA mode. |
1570 | 1570 | ||
1571 | This driver also can be used for OKI SEMICONDUCTOR IOH(Input/ | 1571 | This driver also can be used for LAPIS Semiconductor IOH(Input/ |
1572 | Output Hub), ML7213 and ML7223. | 1572 | Output Hub), ML7213, ML7223 and ML7831. |
1573 | ML7213 IOH is for IVI(In-Vehicle Infotainment) use and ML7223 IOH is | 1573 | ML7213 IOH is for IVI(In-Vehicle Infotainment) use, ML7223 IOH is |
1574 | for MP(Media Phone) use. | 1574 | for MP(Media Phone) use and ML7831 IOH is for general purpose use. |
1575 | ML7213/ML7223 is companion chip for Intel Atom E6xx series. | 1575 | ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series. |
1576 | ML7213/ML7223 is completely compatible for Intel EG20T PCH. | 1576 | ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH. |
1577 | 1577 | ||
1578 | config SERIAL_MSM_SMD | 1578 | config SERIAL_MSM_SMD |
1579 | bool "Enable tty device interface for some SMD ports" | 1579 | 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) | |||
228 | if (rs485conf->flags & SER_RS485_ENABLED) { | 228 | if (rs485conf->flags & SER_RS485_ENABLED) { |
229 | dev_dbg(port->dev, "Setting UART to RS485\n"); | 229 | dev_dbg(port->dev, "Setting UART to RS485\n"); |
230 | atmel_port->tx_done_mask = ATMEL_US_TXEMPTY; | 230 | atmel_port->tx_done_mask = ATMEL_US_TXEMPTY; |
231 | if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND) | 231 | if ((rs485conf->delay_rts_after_send) > 0) |
232 | UART_PUT_TTGR(port, rs485conf->delay_rts_after_send); | 232 | UART_PUT_TTGR(port, rs485conf->delay_rts_after_send); |
233 | mode |= ATMEL_US_USMODE_RS485; | 233 | mode |= ATMEL_US_USMODE_RS485; |
234 | } else { | 234 | } else { |
@@ -304,7 +304,7 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl) | |||
304 | 304 | ||
305 | if (atmel_port->rs485.flags & SER_RS485_ENABLED) { | 305 | if (atmel_port->rs485.flags & SER_RS485_ENABLED) { |
306 | dev_dbg(port->dev, "Setting UART to RS485\n"); | 306 | dev_dbg(port->dev, "Setting UART to RS485\n"); |
307 | if (atmel_port->rs485.flags & SER_RS485_RTS_AFTER_SEND) | 307 | if ((atmel_port->rs485.delay_rts_after_send) > 0) |
308 | UART_PUT_TTGR(port, | 308 | UART_PUT_TTGR(port, |
309 | atmel_port->rs485.delay_rts_after_send); | 309 | atmel_port->rs485.delay_rts_after_send); |
310 | mode |= ATMEL_US_USMODE_RS485; | 310 | mode |= ATMEL_US_USMODE_RS485; |
@@ -1228,7 +1228,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, | |||
1228 | 1228 | ||
1229 | if (atmel_port->rs485.flags & SER_RS485_ENABLED) { | 1229 | if (atmel_port->rs485.flags & SER_RS485_ENABLED) { |
1230 | dev_dbg(port->dev, "Setting UART to RS485\n"); | 1230 | dev_dbg(port->dev, "Setting UART to RS485\n"); |
1231 | if (atmel_port->rs485.flags & SER_RS485_RTS_AFTER_SEND) | 1231 | if ((atmel_port->rs485.delay_rts_after_send) > 0) |
1232 | UART_PUT_TTGR(port, | 1232 | UART_PUT_TTGR(port, |
1233 | atmel_port->rs485.delay_rts_after_send); | 1233 | atmel_port->rs485.delay_rts_after_send); |
1234 | mode |= ATMEL_US_USMODE_RS485; | 1234 | mode |= ATMEL_US_USMODE_RS485; |
@@ -1447,16 +1447,6 @@ static void __devinit atmel_of_init_port(struct atmel_uart_port *atmel_port, | |||
1447 | rs485conf->delay_rts_after_send = rs485_delay[1]; | 1447 | rs485conf->delay_rts_after_send = rs485_delay[1]; |
1448 | rs485conf->flags = 0; | 1448 | rs485conf->flags = 0; |
1449 | 1449 | ||
1450 | if (rs485conf->delay_rts_before_send == 0 && | ||
1451 | rs485conf->delay_rts_after_send == 0) { | ||
1452 | rs485conf->flags |= SER_RS485_RTS_ON_SEND; | ||
1453 | } else { | ||
1454 | if (rs485conf->delay_rts_before_send) | ||
1455 | rs485conf->flags |= SER_RS485_RTS_BEFORE_SEND; | ||
1456 | if (rs485conf->delay_rts_after_send) | ||
1457 | rs485conf->flags |= SER_RS485_RTS_AFTER_SEND; | ||
1458 | } | ||
1459 | |||
1460 | if (of_get_property(np, "rs485-rx-during-tx", NULL)) | 1450 | if (of_get_property(np, "rs485-rx-during-tx", NULL)) |
1461 | rs485conf->flags |= SER_RS485_RX_DURING_TX; | 1451 | rs485conf->flags |= SER_RS485_RX_DURING_TX; |
1462 | 1452 | ||
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, | |||
3234 | e100_disable_rx(info); | 3234 | e100_disable_rx(info); |
3235 | e100_enable_rx_irq(info); | 3235 | e100_enable_rx_irq(info); |
3236 | #endif | 3236 | #endif |
3237 | if ((info->rs485.flags & SER_RS485_RTS_BEFORE_SEND) && | 3237 | if (info->rs485.delay_rts_before_send > 0) |
3238 | (info->rs485.delay_rts_before_send > 0)) | 3238 | msleep(info->rs485.delay_rts_before_send); |
3239 | msleep(info->rs485.delay_rts_before_send); | ||
3240 | } | 3239 | } |
3241 | #endif /* CONFIG_ETRAX_RS485 */ | 3240 | #endif /* CONFIG_ETRAX_RS485 */ |
3242 | 3241 | ||
@@ -3693,10 +3692,6 @@ rs_ioctl(struct tty_struct *tty, | |||
3693 | 3692 | ||
3694 | rs485data.delay_rts_before_send = rs485ctrl.delay_rts_before_send; | 3693 | rs485data.delay_rts_before_send = rs485ctrl.delay_rts_before_send; |
3695 | rs485data.flags = 0; | 3694 | rs485data.flags = 0; |
3696 | if (rs485data.delay_rts_before_send != 0) | ||
3697 | rs485data.flags |= SER_RS485_RTS_BEFORE_SEND; | ||
3698 | else | ||
3699 | rs485data.flags &= ~(SER_RS485_RTS_BEFORE_SEND); | ||
3700 | 3695 | ||
3701 | if (rs485ctrl.enabled) | 3696 | if (rs485ctrl.enabled) |
3702 | rs485data.flags |= SER_RS485_ENABLED; | 3697 | rs485data.flags |= SER_RS485_ENABLED; |
@@ -4531,7 +4526,6 @@ static int __init rs_init(void) | |||
4531 | /* Set sane defaults */ | 4526 | /* Set sane defaults */ |
4532 | info->rs485.flags &= ~(SER_RS485_RTS_ON_SEND); | 4527 | info->rs485.flags &= ~(SER_RS485_RTS_ON_SEND); |
4533 | info->rs485.flags |= SER_RS485_RTS_AFTER_SEND; | 4528 | info->rs485.flags |= SER_RS485_RTS_AFTER_SEND; |
4534 | info->rs485.flags &= ~(SER_RS485_RTS_BEFORE_SEND); | ||
4535 | info->rs485.delay_rts_before_send = 0; | 4529 | info->rs485.delay_rts_before_send = 0; |
4536 | info->rs485.flags &= ~(SER_RS485_ENABLED); | 4530 | info->rs485.flags &= ~(SER_RS485_ENABLED); |
4537 | #endif | 4531 | #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, | |||
884 | { | 884 | { |
885 | struct uart_hsu_port *up = | 885 | struct uart_hsu_port *up = |
886 | container_of(port, struct uart_hsu_port, port); | 886 | container_of(port, struct uart_hsu_port, port); |
887 | struct tty_struct *tty = port->state->port.tty; | ||
888 | unsigned char cval, fcr = 0; | 887 | unsigned char cval, fcr = 0; |
889 | unsigned long flags; | 888 | unsigned long flags; |
890 | unsigned int baud, quot; | 889 | unsigned int baud, quot; |
@@ -907,8 +906,7 @@ serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios, | |||
907 | } | 906 | } |
908 | 907 | ||
909 | /* CMSPAR isn't supported by this driver */ | 908 | /* CMSPAR isn't supported by this driver */ |
910 | if (tty) | 909 | termios->c_cflag &= ~CMSPAR; |
911 | tty->termios->c_cflag &= ~CMSPAR; | ||
912 | 910 | ||
913 | if (termios->c_cflag & CSTOPB) | 911 | if (termios->c_cflag & CSTOPB) |
914 | cval |= UART_LCR_STOP; | 912 | 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 @@ | |||
1 | /* | 1 | /* |
2 | *Copyright (C) 2010 OKI SEMICONDUCTOR CO., LTD. | 2 | *Copyright (C) 2011 LAPIS Semiconductor Co., Ltd. |
3 | * | 3 | * |
4 | *This program is free software; you can redistribute it and/or modify | 4 | *This program is free software; you can redistribute it and/or modify |
5 | *it under the terms of the GNU General Public License as published by | 5 | *it under the terms of the GNU General Public License as published by |
@@ -46,8 +46,8 @@ enum { | |||
46 | 46 | ||
47 | /* Set the max number of UART port | 47 | /* Set the max number of UART port |
48 | * Intel EG20T PCH: 4 port | 48 | * Intel EG20T PCH: 4 port |
49 | * OKI SEMICONDUCTOR ML7213 IOH: 3 port | 49 | * LAPIS Semiconductor ML7213 IOH: 3 port |
50 | * OKI SEMICONDUCTOR ML7223 IOH: 2 port | 50 | * LAPIS Semiconductor ML7223 IOH: 2 port |
51 | */ | 51 | */ |
52 | #define PCH_UART_NR 4 | 52 | #define PCH_UART_NR 4 |
53 | 53 | ||
@@ -258,6 +258,8 @@ enum pch_uart_num_t { | |||
258 | pch_ml7213_uart2, | 258 | pch_ml7213_uart2, |
259 | pch_ml7223_uart0, | 259 | pch_ml7223_uart0, |
260 | pch_ml7223_uart1, | 260 | pch_ml7223_uart1, |
261 | pch_ml7831_uart0, | ||
262 | pch_ml7831_uart1, | ||
261 | }; | 263 | }; |
262 | 264 | ||
263 | static struct pch_uart_driver_data drv_dat[] = { | 265 | static struct pch_uart_driver_data drv_dat[] = { |
@@ -270,6 +272,8 @@ static struct pch_uart_driver_data drv_dat[] = { | |||
270 | [pch_ml7213_uart2] = {PCH_UART_2LINE, 2}, | 272 | [pch_ml7213_uart2] = {PCH_UART_2LINE, 2}, |
271 | [pch_ml7223_uart0] = {PCH_UART_8LINE, 0}, | 273 | [pch_ml7223_uart0] = {PCH_UART_8LINE, 0}, |
272 | [pch_ml7223_uart1] = {PCH_UART_2LINE, 1}, | 274 | [pch_ml7223_uart1] = {PCH_UART_2LINE, 1}, |
275 | [pch_ml7831_uart0] = {PCH_UART_8LINE, 0}, | ||
276 | [pch_ml7831_uart1] = {PCH_UART_2LINE, 1}, | ||
273 | }; | 277 | }; |
274 | 278 | ||
275 | static unsigned int default_baud = 9600; | 279 | static unsigned int default_baud = 9600; |
@@ -628,6 +632,7 @@ static void pch_request_dma(struct uart_port *port) | |||
628 | dev_err(priv->port.dev, "%s:dma_request_channel FAILS(Rx)\n", | 632 | dev_err(priv->port.dev, "%s:dma_request_channel FAILS(Rx)\n", |
629 | __func__); | 633 | __func__); |
630 | dma_release_channel(priv->chan_tx); | 634 | dma_release_channel(priv->chan_tx); |
635 | priv->chan_tx = NULL; | ||
631 | return; | 636 | return; |
632 | } | 637 | } |
633 | 638 | ||
@@ -1215,8 +1220,7 @@ static void pch_uart_shutdown(struct uart_port *port) | |||
1215 | dev_err(priv->port.dev, | 1220 | dev_err(priv->port.dev, |
1216 | "pch_uart_hal_set_fifo Failed(ret=%d)\n", ret); | 1221 | "pch_uart_hal_set_fifo Failed(ret=%d)\n", ret); |
1217 | 1222 | ||
1218 | if (priv->use_dma_flag) | 1223 | pch_free_dma(port); |
1219 | pch_free_dma(port); | ||
1220 | 1224 | ||
1221 | free_irq(priv->port.irq, priv); | 1225 | free_irq(priv->port.irq, priv); |
1222 | } | 1226 | } |
@@ -1280,6 +1284,7 @@ static void pch_uart_set_termios(struct uart_port *port, | |||
1280 | if (rtn) | 1284 | if (rtn) |
1281 | goto out; | 1285 | goto out; |
1282 | 1286 | ||
1287 | pch_uart_set_mctrl(&priv->port, priv->port.mctrl); | ||
1283 | /* Don't rewrite B0 */ | 1288 | /* Don't rewrite B0 */ |
1284 | if (tty_termios_baud_rate(termios)) | 1289 | if (tty_termios_baud_rate(termios)) |
1285 | tty_termios_encode_baud_rate(termios, baud, baud); | 1290 | tty_termios_encode_baud_rate(termios, baud, baud); |
@@ -1552,6 +1557,10 @@ static DEFINE_PCI_DEVICE_TABLE(pch_uart_pci_id) = { | |||
1552 | .driver_data = pch_ml7223_uart0}, | 1557 | .driver_data = pch_ml7223_uart0}, |
1553 | {PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x800D), | 1558 | {PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x800D), |
1554 | .driver_data = pch_ml7223_uart1}, | 1559 | .driver_data = pch_ml7223_uart1}, |
1560 | {PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8811), | ||
1561 | .driver_data = pch_ml7831_uart0}, | ||
1562 | {PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8812), | ||
1563 | .driver_data = pch_ml7831_uart1}, | ||
1555 | {0,}, | 1564 | {0,}, |
1556 | }; | 1565 | }; |
1557 | 1566 | ||
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 @@ | |||
36 | 36 | ||
37 | #include <linux/kmod.h> | 37 | #include <linux/kmod.h> |
38 | #include <linux/nsproxy.h> | 38 | #include <linux/nsproxy.h> |
39 | #include <linux/ratelimit.h> | ||
39 | 40 | ||
40 | /* | 41 | /* |
41 | * This guards the refcounted line discipline lists. The lock | 42 | * This guards the refcounted line discipline lists. The lock |
@@ -547,15 +548,16 @@ static void tty_ldisc_flush_works(struct tty_struct *tty) | |||
547 | /** | 548 | /** |
548 | * tty_ldisc_wait_idle - wait for the ldisc to become idle | 549 | * tty_ldisc_wait_idle - wait for the ldisc to become idle |
549 | * @tty: tty to wait for | 550 | * @tty: tty to wait for |
551 | * @timeout: for how long to wait at most | ||
550 | * | 552 | * |
551 | * Wait for the line discipline to become idle. The discipline must | 553 | * Wait for the line discipline to become idle. The discipline must |
552 | * have been halted for this to guarantee it remains idle. | 554 | * have been halted for this to guarantee it remains idle. |
553 | */ | 555 | */ |
554 | static int tty_ldisc_wait_idle(struct tty_struct *tty) | 556 | static int tty_ldisc_wait_idle(struct tty_struct *tty, long timeout) |
555 | { | 557 | { |
556 | int ret; | 558 | long ret; |
557 | ret = wait_event_timeout(tty_ldisc_idle, | 559 | ret = wait_event_timeout(tty_ldisc_idle, |
558 | atomic_read(&tty->ldisc->users) == 1, 5 * HZ); | 560 | atomic_read(&tty->ldisc->users) == 1, timeout); |
559 | if (ret < 0) | 561 | if (ret < 0) |
560 | return ret; | 562 | return ret; |
561 | return ret > 0 ? 0 : -EBUSY; | 563 | return ret > 0 ? 0 : -EBUSY; |
@@ -665,7 +667,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) | |||
665 | 667 | ||
666 | tty_ldisc_flush_works(tty); | 668 | tty_ldisc_flush_works(tty); |
667 | 669 | ||
668 | retval = tty_ldisc_wait_idle(tty); | 670 | retval = tty_ldisc_wait_idle(tty, 5 * HZ); |
669 | 671 | ||
670 | tty_lock(); | 672 | tty_lock(); |
671 | mutex_lock(&tty->ldisc_mutex); | 673 | mutex_lock(&tty->ldisc_mutex); |
@@ -762,8 +764,6 @@ static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc) | |||
762 | if (IS_ERR(ld)) | 764 | if (IS_ERR(ld)) |
763 | return -1; | 765 | return -1; |
764 | 766 | ||
765 | WARN_ON_ONCE(tty_ldisc_wait_idle(tty)); | ||
766 | |||
767 | tty_ldisc_close(tty, tty->ldisc); | 767 | tty_ldisc_close(tty, tty->ldisc); |
768 | tty_ldisc_put(tty->ldisc); | 768 | tty_ldisc_put(tty->ldisc); |
769 | tty->ldisc = NULL; | 769 | tty->ldisc = NULL; |
@@ -838,7 +838,7 @@ void tty_ldisc_hangup(struct tty_struct *tty) | |||
838 | tty_unlock(); | 838 | tty_unlock(); |
839 | cancel_work_sync(&tty->buf.work); | 839 | cancel_work_sync(&tty->buf.work); |
840 | mutex_unlock(&tty->ldisc_mutex); | 840 | mutex_unlock(&tty->ldisc_mutex); |
841 | 841 | retry: | |
842 | tty_lock(); | 842 | tty_lock(); |
843 | mutex_lock(&tty->ldisc_mutex); | 843 | mutex_lock(&tty->ldisc_mutex); |
844 | 844 | ||
@@ -847,6 +847,22 @@ void tty_ldisc_hangup(struct tty_struct *tty) | |||
847 | it means auditing a lot of other paths so this is | 847 | it means auditing a lot of other paths so this is |
848 | a FIXME */ | 848 | a FIXME */ |
849 | if (tty->ldisc) { /* Not yet closed */ | 849 | if (tty->ldisc) { /* Not yet closed */ |
850 | if (atomic_read(&tty->ldisc->users) != 1) { | ||
851 | char cur_n[TASK_COMM_LEN], tty_n[64]; | ||
852 | long timeout = 3 * HZ; | ||
853 | tty_unlock(); | ||
854 | |||
855 | while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) { | ||
856 | timeout = MAX_SCHEDULE_TIMEOUT; | ||
857 | printk_ratelimited(KERN_WARNING | ||
858 | "%s: waiting (%s) for %s took too long, but we keep waiting...\n", | ||
859 | __func__, get_task_comm(cur_n, current), | ||
860 | tty_name(tty, tty_n)); | ||
861 | } | ||
862 | mutex_unlock(&tty->ldisc_mutex); | ||
863 | goto retry; | ||
864 | } | ||
865 | |||
850 | if (reset == 0) { | 866 | if (reset == 0) { |
851 | 867 | ||
852 | if (!tty_ldisc_reinit(tty, tty->termios->c_line)) | 868 | if (!tty_ldisc_reinit(tty, tty->termios->c_line)) |