summaryrefslogtreecommitdiffstats
path: root/drivers/tty/serial/serial_core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/serial/serial_core.c')
-rw-r--r--drivers/tty/serial/serial_core.c62
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.