aboutsummaryrefslogtreecommitdiffstats
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.c140
1 files changed, 70 insertions, 70 deletions
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 8bb19da01639..eaeb9a02c7fe 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>
@@ -58,6 +59,11 @@ static void uart_change_pm(struct uart_state *state,
static void uart_port_shutdown(struct tty_port *port);
+static int uart_dcd_enabled(struct uart_port *uport)
+{
+ return uport->status & UPSTAT_DCD_ENABLE;
+}
+
/*
* This routine is used by the interrupt handler to schedule processing in
* the software interrupt portion of the driver.
@@ -89,7 +95,7 @@ static void __uart_start(struct tty_struct *tty)
struct uart_state *state = tty->driver_data;
struct uart_port *port = state->uart_port;
- if (!tty->stopped && !tty->hw_stopped)
+ if (!uart_tx_stopped(port))
port->ops->start_tx(port);
}
@@ -129,7 +135,6 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
int init_hw)
{
struct uart_port *uport = state->uart_port;
- struct tty_port *port = &state->port;
unsigned long page;
int retval = 0;
@@ -174,17 +179,14 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
if (tty->termios.c_cflag & CBAUD)
uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
}
- /*
- * if hw support flow control without software intervention,
- * then skip the below check
- */
- if (tty_port_cts_enabled(port) &&
- !(uport->flags & UPF_HARD_FLOW)) {
- spin_lock_irq(&uport->lock);
- if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS))
- tty->hw_stopped = 1;
- spin_unlock_irq(&uport->lock);
- }
+
+ spin_lock_irq(&uport->lock);
+ if (uart_cts_enabled(uport) &&
+ !(uport->ops->get_mctrl(uport) & TIOCM_CTS))
+ uport->hw_stopped = 1;
+ else
+ uport->hw_stopped = 0;
+ spin_unlock_irq(&uport->lock);
}
/*
@@ -361,7 +363,7 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
* The spd_hi, spd_vhi, spd_shi, spd_warp kludge...
* Die! Die! Die!
*/
- if (baud == 38400)
+ if (try == 0 && baud == 38400)
baud = altbaud;
/*
@@ -438,7 +440,6 @@ EXPORT_SYMBOL(uart_get_divisor);
static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
struct ktermios *old_termios)
{
- struct tty_port *port = &state->port;
struct uart_port *uport = state->uart_port;
struct ktermios *termios;
@@ -453,17 +454,19 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
uport->ops->set_termios(uport, termios, old_termios);
/*
- * Set flags based on termios cflag
+ * Set modem status enables based on termios cflag
*/
+ spin_lock_irq(&uport->lock);
if (termios->c_cflag & CRTSCTS)
- set_bit(ASYNCB_CTS_FLOW, &port->flags);
+ uport->status |= UPSTAT_CTS_ENABLE;
else
- clear_bit(ASYNCB_CTS_FLOW, &port->flags);
+ uport->status &= ~UPSTAT_CTS_ENABLE;
if (termios->c_cflag & CLOCAL)
- clear_bit(ASYNCB_CHECK_CD, &port->flags);
+ uport->status &= ~UPSTAT_DCD_ENABLE;
else
- set_bit(ASYNCB_CHECK_CD, &port->flags);
+ uport->status |= UPSTAT_DCD_ENABLE;
+ spin_unlock_irq(&uport->lock);
}
static inline int __uart_put_char(struct uart_port *port,
@@ -603,12 +606,11 @@ static void uart_send_xchar(struct tty_struct *tty, char ch)
if (port->ops->send_xchar)
port->ops->send_xchar(port, ch);
else {
+ spin_lock_irqsave(&port->lock, flags);
port->x_char = ch;
- if (ch) {
- spin_lock_irqsave(&port->lock, flags);
+ if (ch)
port->ops->start_tx(port);
- spin_unlock_irqrestore(&port->lock, flags);
- }
+ spin_unlock_irqrestore(&port->lock, flags);
}
}
@@ -651,12 +653,8 @@ static void uart_unthrottle(struct tty_struct *tty)
mask &= ~port->flags;
}
- if (mask & UPF_SOFT_FLOW) {
- if (port->x_char)
- port->x_char = 0;
- else
- uart_send_xchar(tty, START_CHAR(tty));
- }
+ if (mask & UPF_SOFT_FLOW)
+ uart_send_xchar(tty, START_CHAR(tty));
if (mask & UPF_HARD_FLOW)
uart_set_mctrl(port, TIOCM_RTS);
@@ -891,10 +889,11 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
*/
if (uport->flags & UPF_SPD_MASK) {
char buf[64];
- printk(KERN_NOTICE
- "%s sets custom speed on %s. This "
- "is deprecated.\n", current->comm,
- tty_name(port->tty, buf));
+
+ dev_notice(uport->dev,
+ "%s sets custom speed on %s. This is deprecated.\n",
+ current->comm,
+ tty_name(port->tty, buf));
}
uart_change_speed(tty, state, NULL);
}
@@ -951,7 +950,7 @@ static int uart_get_lsr_info(struct tty_struct *tty,
*/
if (uport->x_char ||
((uart_circ_chars_pending(&state->xmit) > 0) &&
- !tty->stopped && !tty->hw_stopped))
+ !uart_tx_stopped(uport)))
result &= ~TIOCSER_TEMT;
return put_user(result, value);
@@ -1250,7 +1249,6 @@ static void uart_set_termios(struct tty_struct *tty,
{
struct uart_state *state = tty->driver_data;
struct uart_port *uport = state->uart_port;
- unsigned long flags;
unsigned int cflag = tty->termios.c_cflag;
unsigned int iflag_mask = IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK;
bool sw_changed = false;
@@ -1290,34 +1288,33 @@ static void uart_set_termios(struct tty_struct *tty,
/* Handle transition away from B0 status */
else if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
unsigned int mask = TIOCM_DTR;
- if (!(cflag & CRTSCTS) ||
- !test_bit(TTY_THROTTLED, &tty->flags))
+ if (!(cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags))
mask |= TIOCM_RTS;
uart_set_mctrl(uport, mask);
}
/*
* If the port is doing h/w assisted flow control, do nothing.
- * We assume that tty->hw_stopped has never been set.
+ * We assume that port->hw_stopped has never been set.
*/
if (uport->flags & UPF_HARD_FLOW)
return;
/* Handle turning off CRTSCTS */
if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) {
- spin_lock_irqsave(&uport->lock, flags);
- tty->hw_stopped = 0;
+ spin_lock_irq(&uport->lock);
+ uport->hw_stopped = 0;
__uart_start(tty);
- spin_unlock_irqrestore(&uport->lock, flags);
+ spin_unlock_irq(&uport->lock);
}
/* Handle turning on CRTSCTS */
else if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
- spin_lock_irqsave(&uport->lock, flags);
+ spin_lock_irq(&uport->lock);
if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) {
- tty->hw_stopped = 1;
+ uport->hw_stopped = 1;
uport->ops->stop_tx(uport);
}
- spin_unlock_irqrestore(&uport->lock, flags);
+ spin_unlock_irq(&uport->lock);
}
}
@@ -1974,12 +1971,9 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
for (tries = 3; !ops->tx_empty(uport) && tries; tries--)
msleep(10);
if (!tries)
- printk(KERN_ERR "%s%s%s%d: Unable to drain "
- "transmitter\n",
- uport->dev ? dev_name(uport->dev) : "",
- uport->dev ? ": " : "",
- drv->dev_name,
- drv->tty_driver->name_base + uport->line);
+ dev_err(uport->dev, "%s%d: Unable to drain transmitter\n",
+ drv->dev_name,
+ drv->tty_driver->name_base + uport->line);
if (console_suspend_enabled || !uart_console(uport))
ops->shutdown(uport);
@@ -2108,9 +2102,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
break;
}
- printk(KERN_INFO "%s%s%s%d at %s (irq = %d, base_baud = %d) is a %s\n",
- port->dev ? dev_name(port->dev) : "",
- port->dev ? ": " : "",
+ dev_info(port->dev, "%s%d at %s (irq = %d, base_baud = %d) is a %s\n",
drv->dev_name,
drv->tty_driver->name_base + port->line,
address, port->irq, port->uartclk / 16, uart_type(port));
@@ -2611,6 +2603,8 @@ 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);
@@ -2637,7 +2631,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
if (likely(!IS_ERR(tty_dev))) {
device_set_wakeup_capable(tty_dev, 1);
} else {
- printk(KERN_ERR "Cannot register tty device on line %d\n",
+ dev_err(uport->dev, "Cannot register tty device on line %d\n",
uport->line);
}
@@ -2672,7 +2666,7 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
BUG_ON(in_interrupt());
if (state->uart_port != uport)
- printk(KERN_ALERT "Removing wrong port: %p != %p\n",
+ dev_alert(uport->dev, "Removing wrong port: %p != %p\n",
state->uart_port, uport);
mutex_lock(&port_mutex);
@@ -2754,22 +2748,29 @@ EXPORT_SYMBOL(uart_match_port);
* uart_handle_dcd_change - handle a change of carrier detect state
* @uport: uart_port structure for the open port
* @status: new carrier detect status, nonzero if active
+ *
+ * Caller must hold uport->lock
*/
void uart_handle_dcd_change(struct uart_port *uport, unsigned int status)
{
struct tty_port *port = &uport->state->port;
struct tty_struct *tty = port->tty;
- struct tty_ldisc *ld = tty ? tty_ldisc_ref(tty) : NULL;
+ struct tty_ldisc *ld;
- if (ld) {
- if (ld->ops->dcd_change)
- ld->ops->dcd_change(tty, status);
- tty_ldisc_deref(ld);
+ lockdep_assert_held_once(&uport->lock);
+
+ if (tty) {
+ ld = tty_ldisc_ref(tty);
+ if (ld) {
+ if (ld->ops->dcd_change)
+ ld->ops->dcd_change(tty, status);
+ tty_ldisc_deref(ld);
+ }
}
uport->icount.dcd++;
- if (port->flags & ASYNC_CHECK_CD) {
+ if (uart_dcd_enabled(uport)) {
if (status)
wake_up_interruptible(&port->open_wait);
else if (tty)
@@ -2782,26 +2783,25 @@ EXPORT_SYMBOL_GPL(uart_handle_dcd_change);
* uart_handle_cts_change - handle a change of clear-to-send state
* @uport: uart_port structure for the open port
* @status: new clear to send status, nonzero if active
+ *
+ * Caller must hold uport->lock
*/
void uart_handle_cts_change(struct uart_port *uport, unsigned int status)
{
- struct tty_port *port = &uport->state->port;
- struct tty_struct *tty = port->tty;
+ lockdep_assert_held_once(&uport->lock);
uport->icount.cts++;
- /* skip below code if the hw flow control is supported */
- if (tty_port_cts_enabled(port) &&
- !(uport->flags & UPF_HARD_FLOW)) {
- if (tty->hw_stopped) {
+ if (uart_cts_enabled(uport)) {
+ if (uport->hw_stopped) {
if (status) {
- tty->hw_stopped = 0;
+ uport->hw_stopped = 0;
uport->ops->start_tx(uport);
uart_write_wakeup(uport);
}
} else {
if (!status) {
- tty->hw_stopped = 1;
+ uport->hw_stopped = 1;
uport->ops->stop_tx(uport);
}
}