diff options
Diffstat (limited to 'drivers/tty/serial/serial_core.c')
-rw-r--r-- | drivers/tty/serial/serial_core.c | 125 |
1 files changed, 64 insertions, 61 deletions
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 2bd32c8ece39..54e82f476a2c 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -15,6 +15,7 @@ #include <linux/init.h> #include <linux/console.h> #include <linux/gpio/consumer.h> +#include <linux/kernel.h> #include <linux/of.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> @@ -48,9 +49,6 @@ static struct lock_class_key port_lock_key; */ #define RS485_MAX_RTS_DELAY 100 /* msecs */ -static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, - const struct ktermios *old_termios); -static void uart_wait_until_sent(struct tty_struct *tty, int timeout); static void uart_change_pm(struct uart_state *state, enum uart_pm_state pm_state); @@ -137,7 +135,7 @@ static void __uart_start(struct tty_struct *tty) struct uart_state *state = tty->driver_data; struct uart_port *port = state->uart_port; - if (port && !uart_tx_stopped(port)) + if (port && !(port->flags & UPF_DEAD) && !uart_tx_stopped(port)) port->ops->start_tx(port); } @@ -177,6 +175,51 @@ static void uart_port_dtr_rts(struct uart_port *uport, bool active) uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS); } +/* Caller holds port mutex */ +static void uart_change_line_settings(struct tty_struct *tty, struct uart_state *state, + const struct ktermios *old_termios) +{ + struct uart_port *uport = uart_port_check(state); + struct ktermios *termios; + bool old_hw_stopped; + + /* + * If we have no tty, termios, or the port does not exist, + * then we can't set the parameters for this port. + */ + if (!tty || uport->type == PORT_UNKNOWN) + return; + + termios = &tty->termios; + uport->ops->set_termios(uport, termios, old_termios); + + /* + * Set modem status enables based on termios cflag + */ + spin_lock_irq(&uport->lock); + if (termios->c_cflag & CRTSCTS) + uport->status |= UPSTAT_CTS_ENABLE; + else + uport->status &= ~UPSTAT_CTS_ENABLE; + + if (termios->c_cflag & CLOCAL) + uport->status &= ~UPSTAT_DCD_ENABLE; + else + uport->status |= UPSTAT_DCD_ENABLE; + + /* reset sw-assisted CTS flow control based on (possibly) new mode */ + old_hw_stopped = uport->hw_stopped; + uport->hw_stopped = uart_softcts_mode(uport) && + !(uport->ops->get_mctrl(uport) & TIOCM_CTS); + if (uport->hw_stopped != old_hw_stopped) { + if (!old_hw_stopped) + uport->ops->stop_tx(uport); + else + __uart_start(tty); + } + spin_unlock_irq(&uport->lock); +} + /* * Startup the port. This will be called once per open. All calls * will be serialised by the per-port mutex. @@ -232,7 +275,7 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, /* * Initialise the hardware port settings. */ - uart_change_speed(tty, state, NULL); + uart_change_line_settings(tty, state, NULL); /* * Setup the RTS and DTR signals once the @@ -485,52 +528,6 @@ uart_get_divisor(struct uart_port *port, unsigned int baud) } EXPORT_SYMBOL(uart_get_divisor); -/* Caller holds port mutex */ -static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, - const struct ktermios *old_termios) -{ - struct uart_port *uport = uart_port_check(state); - struct ktermios *termios; - int hw_stopped; - - /* - * If we have no tty, termios, or the port does not exist, - * then we can't set the parameters for this port. - */ - if (!tty || uport->type == PORT_UNKNOWN) - return; - - termios = &tty->termios; - uport->ops->set_termios(uport, termios, old_termios); - - /* - * Set modem status enables based on termios cflag - */ - spin_lock_irq(&uport->lock); - if (termios->c_cflag & CRTSCTS) - uport->status |= UPSTAT_CTS_ENABLE; - else - uport->status &= ~UPSTAT_CTS_ENABLE; - - if (termios->c_cflag & CLOCAL) - uport->status &= ~UPSTAT_DCD_ENABLE; - else - uport->status |= UPSTAT_DCD_ENABLE; - - /* reset sw-assisted CTS flow control based on (possibly) new mode */ - hw_stopped = uport->hw_stopped; - uport->hw_stopped = uart_softcts_mode(uport) && - !(uport->ops->get_mctrl(uport) & TIOCM_CTS); - if (uport->hw_stopped) { - if (!hw_stopped) - uport->ops->stop_tx(uport); - } else { - if (hw_stopped) - __uart_start(tty); - } - spin_unlock_irq(&uport->lock); -} - static int uart_put_char(struct tty_struct *tty, unsigned char c) { struct uart_state *state = tty->driver_data; @@ -994,7 +991,7 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port, current->comm, tty_name(port->tty)); } - uart_change_speed(tty, state, NULL); + uart_change_line_settings(tty, state, NULL); } } else { retval = uart_startup(tty, state, true); @@ -1491,7 +1488,7 @@ static int uart_set_iso7816_config(struct uart_port *port, * There are 5 words reserved for future use. Check that userspace * doesn't put stuff in there to prevent breakages in the future. */ - for (i = 0; i < 5; i++) + for (i = 0; i < ARRAY_SIZE(iso7816.reserved); i++) if (iso7816.reserved[i]) return -EINVAL; @@ -1552,7 +1549,7 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) goto out; /* rs485_config requires more locking than others */ - if (cmd == TIOCGRS485) + if (cmd == TIOCSRS485) down_write(&tty->termios_rwsem); mutex_lock(&port->mutex); @@ -1595,7 +1592,7 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) } out_up: mutex_unlock(&port->mutex); - if (cmd == TIOCGRS485) + if (cmd == TIOCSRS485) up_write(&tty->termios_rwsem); out: return ret; @@ -1656,15 +1653,15 @@ static void uart_set_termios(struct tty_struct *tty, goto out; } - uart_change_speed(tty, state, old_termios); + uart_change_line_settings(tty, state, old_termios); /* reload cflag from termios; port driver may have overridden flags */ cflag = tty->termios.c_cflag; /* Handle transition to B0 status */ - if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) + if (((old_termios->c_cflag & CBAUD) != B0) && ((cflag & CBAUD) == B0)) uart_clear_mctrl(uport, TIOCM_RTS | TIOCM_DTR); /* Handle transition away from B0 status */ - else if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) { + else if (((old_termios->c_cflag & CBAUD) == B0) && ((cflag & CBAUD) != B0)) { unsigned int mask = TIOCM_DTR; if (!(cflag & CRTSCTS) || !tty_throttled(tty)) @@ -2452,7 +2449,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) ret = ops->startup(uport); if (ret == 0) { if (tty) - uart_change_speed(tty, state, NULL); + uart_change_line_settings(tty, state, NULL); spin_lock_irq(&uport->lock); if (!(uport->rs485.flags & SER_RS485_ENABLED)) ops->set_mctrl(uport, uport->mctrl); @@ -2593,6 +2590,7 @@ static int uart_poll_init(struct tty_driver *driver, int line, char *options) { struct uart_driver *drv = driver->driver_state; struct uart_state *state = drv->state + line; + enum uart_pm_state pm_state; struct tty_port *tport; struct uart_port *port; int baud = 9600; @@ -2610,6 +2608,9 @@ static int uart_poll_init(struct tty_driver *driver, int line, char *options) goto out; } + pm_state = state->pm_state; + uart_change_pm(state, UART_PM_STATE_ON); + if (port->ops->poll_init) { /* * We don't set initialized as we only initialized the hw, @@ -2626,6 +2627,8 @@ static int uart_poll_init(struct tty_driver *driver, int line, char *options) console_list_unlock(); } out: + if (ret) + uart_change_pm(state, pm_state); mutex_unlock(&tport->mutex); return ret; } @@ -3305,13 +3308,13 @@ void uart_handle_cts_change(struct uart_port *uport, bool active) if (uart_softcts_mode(uport)) { if (uport->hw_stopped) { if (active) { - uport->hw_stopped = 0; + uport->hw_stopped = false; uport->ops->start_tx(uport); uart_write_wakeup(uport); } } else { if (!active) { - uport->hw_stopped = 1; + uport->hw_stopped = true; uport->ops->stop_tx(uport); } } |