diff options
Diffstat (limited to 'drivers/tty/serial/serial_core.c')
-rw-r--r-- | drivers/tty/serial/serial_core.c | 62 |
1 files changed, 38 insertions, 24 deletions
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index fbf6c5ad222..29a7be47389 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -26,6 +26,7 @@ #include <linux/slab.h> #include <linux/init.h> #include <linux/console.h> +#include <linux/of.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/device.h> @@ -243,6 +244,9 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) /* * Turn off DTR and RTS early. */ + if (uart_console(uport) && tty) + uport->cons->cflag = tty->termios.c_cflag; + if (!tty || (tty->termios.c_cflag & HUPCL)) uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS); @@ -447,6 +451,7 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, return; termios = &tty->termios; + uport->ops->set_termios(uport, termios, old_termios); /* * Set flags based on termios cflag @@ -460,8 +465,6 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, clear_bit(ASYNCB_CHECK_CD, &port->flags); else set_bit(ASYNCB_CHECK_CD, &port->flags); - - uport->ops->set_termios(uport, termios, old_termios); } static inline int __uart_put_char(struct uart_port *port, @@ -1050,6 +1053,15 @@ static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state) return ret; } +static void uart_enable_ms(struct uart_port *uport) +{ + /* + * Force modem status interrupts on + */ + if (uport->ops->enable_ms) + uport->ops->enable_ms(uport); +} + /* * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change * - mask passed in arg for lines of interest @@ -1073,11 +1085,7 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg) */ spin_lock_irq(&uport->lock); memcpy(&cprev, &uport->icount, sizeof(struct uart_icount)); - - /* - * Force modem status interrupts on - */ - uport->ops->enable_ms(uport); + uart_enable_ms(uport); spin_unlock_irq(&uport->lock); add_wait_queue(&port->delta_msr_wait, &wait); @@ -1274,6 +1282,8 @@ static void uart_set_termios(struct tty_struct *tty, } uart_change_speed(tty, state, old_termios); + /* reload cflag from termios; port driver may have overriden flags */ + cflag = tty->termios.c_cflag; /* Handle transition to B0 status */ if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) @@ -1360,8 +1370,8 @@ static void uart_close(struct tty_struct *tty, struct file *filp) tty_ldisc_flush(tty); tty_port_tty_set(port, NULL); - spin_lock_irqsave(&port->lock, flags); tty->closing = 0; + spin_lock_irqsave(&port->lock, flags); if (port->blocked_open) { spin_unlock_irqrestore(&port->lock, flags); @@ -1508,7 +1518,7 @@ static int uart_carrier_raised(struct tty_port *port) struct uart_port *uport = state->uart_port; int mctrl; spin_lock_irq(&uport->lock); - uport->ops->enable_ms(uport); + uart_enable_ms(uport); mctrl = uport->ops->get_mctrl(uport); spin_unlock_irq(&uport->lock); if (mctrl & TIOCM_CAR) @@ -1576,14 +1586,6 @@ static int uart_open(struct tty_struct *tty, struct file *filp) tty_port_tty_set(port, tty); /* - * If the port is in the middle of closing, bail out now. - */ - if (tty_hung_up_p(filp)) { - retval = -EAGAIN; - goto err_dec_count; - } - - /* * Start up the serial port. */ retval = uart_startup(tty, state, 0); @@ -2563,12 +2565,6 @@ static const struct attribute_group tty_dev_attr_group = { .attrs = tty_dev_attrs, }; -static const struct attribute_group *tty_dev_attr_groups[] = { - &tty_dev_attr_group, - NULL - }; - - /** * uart_add_one_port - attach a driver-defined port structure * @drv: pointer to the uart low level driver structure for this port @@ -2585,6 +2581,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) struct tty_port *port; int ret = 0; struct device *tty_dev; + int num_groups; BUG_ON(in_interrupt()); @@ -2615,15 +2612,31 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) spin_lock_init(&uport->lock); lockdep_set_class(&uport->lock, &port_lock_key); } + if (uport->cons && uport->dev) + of_console_check(uport->dev->of_node, uport->cons->name, uport->line); uart_configure_port(drv, state, uport); + num_groups = 2; + if (uport->attr_group) + num_groups++; + + uport->tty_groups = kcalloc(num_groups, sizeof(*uport->tty_groups), + GFP_KERNEL); + if (!uport->tty_groups) { + ret = -ENOMEM; + goto out; + } + uport->tty_groups[0] = &tty_dev_attr_group; + if (uport->attr_group) + uport->tty_groups[1] = uport->attr_group; + /* * Register the port whether it's detected or not. This allows * setserial to be used to alter this port's parameters. */ tty_dev = tty_port_register_device_attr(port, drv->tty_driver, - uport->line, uport->dev, port, tty_dev_attr_groups); + uport->line, uport->dev, port, uport->tty_groups); if (likely(!IS_ERR(tty_dev))) { device_set_wakeup_capable(tty_dev, 1); } else { @@ -2702,6 +2715,7 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport) */ if (uport->type != PORT_UNKNOWN) uport->ops->release_port(uport); + kfree(uport->tty_groups); /* * Indicate that there isn't a port here anymore. |