Skip to content

Commit

Permalink
Merge branch 'tty-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/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
  • Loading branch information
Linus Torvalds committed Nov 22, 2011
2 parents 0cda569 + 0c73c08 commit 3b9abc7
Show file tree
Hide file tree
Showing 10 changed files with 72 additions and 53 deletions.
14 changes: 11 additions & 3 deletions Documentation/serial/serial-rs485.txt
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,23 @@

struct serial_rs485 rs485conf;

/* Set RS485 mode: */
/* Enable RS485 mode: */
rs485conf.flags |= SER_RS485_ENABLED;

/* Set logical level for RTS pin equal to 1 when sending: */
rs485conf.flags |= SER_RS485_RTS_ON_SEND;
/* or, set logical level for RTS pin equal to 0 when sending: */
rs485conf.flags &= ~(SER_RS485_RTS_ON_SEND);

/* Set logical level for RTS pin equal to 1 after sending: */
rs485conf.flags |= SER_RS485_RTS_AFTER_SEND;
/* or, set logical level for RTS pin equal to 0 after sending: */
rs485conf.flags &= ~(SER_RS485_RTS_AFTER_SEND);

/* Set rts delay before send, if needed: */
rs485conf.flags |= SER_RS485_RTS_BEFORE_SEND;
rs485conf.delay_rts_before_send = ...;

/* Set rts delay after send, if needed: */
rs485conf.flags |= SER_RS485_RTS_AFTER_SEND;
rs485conf.delay_rts_after_send = ...;

/* Set this flag if you want to receive data even whilst sending data */
Expand Down
2 changes: 1 addition & 1 deletion MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -3728,7 +3728,7 @@ F: fs/jbd2/
F: include/linux/jbd2.h

JSM Neo PCI based serial card
M: Breno Leitao <leitao@linux.vnet.ibm.com>
M: Lucas Tavares <lucaskt@linux.vnet.ibm.com>
L: linux-serial@vger.kernel.org
S: Maintained
F: drivers/tty/serial/jsm/
Expand Down
2 changes: 2 additions & 0 deletions drivers/tty/hvc/hvc_dcc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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)
Expand Down
14 changes: 7 additions & 7 deletions drivers/tty/serial/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1560,20 +1560,20 @@ 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
This driver is for PCH(Platform controller Hub) UART of Intel EG20T
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"
Expand Down
16 changes: 3 additions & 13 deletions drivers/tty/serial/atmel_serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand Down
10 changes: 2 additions & 8 deletions drivers/tty/serial/crisv10.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
4 changes: 1 addition & 3 deletions drivers/tty/serial/mfd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
19 changes: 14 additions & 5 deletions drivers/tty/serial/pch_uart.c
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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[] = {
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,},
};

Expand Down
30 changes: 23 additions & 7 deletions drivers/tty/tty_ldisc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand All @@ -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))
Expand Down
14 changes: 8 additions & 6 deletions include/linux/serial.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,13 +207,15 @@ struct serial_icounter_struct {

struct serial_rs485 {
__u32 flags; /* RS485 feature flags */
#define SER_RS485_ENABLED (1 << 0)
#define SER_RS485_RTS_ON_SEND (1 << 1)
#define SER_RS485_RTS_AFTER_SEND (1 << 2)
#define SER_RS485_RTS_BEFORE_SEND (1 << 3)
#define SER_RS485_ENABLED (1 << 0) /* If enabled */
#define SER_RS485_RTS_ON_SEND (1 << 1) /* Logical level for
RTS pin when
sending */
#define SER_RS485_RTS_AFTER_SEND (1 << 2) /* Logical level for
RTS pin after sent*/
#define SER_RS485_RX_DURING_TX (1 << 4)
__u32 delay_rts_before_send; /* Milliseconds */
__u32 delay_rts_after_send; /* Milliseconds */
__u32 delay_rts_before_send; /* Delay before send (milliseconds) */
__u32 delay_rts_after_send; /* Delay after send (milliseconds) */
__u32 padding[5]; /* Memory is cheap, new structs
are a royal PITA .. */
};
Expand Down

0 comments on commit 3b9abc7

Please sign in to comment.