Skip to content

Commit

Permalink
serial: move the flags into the tty_port field
Browse files Browse the repository at this point in the history
Fortunately the serial layer was designed to use the same flag values but
with different names. It has its own SUSPENDED flag which is a free slot in
the ASYNC flags so we allocate it in the ASYNC flags instead.

Signed-off-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Alan Cox authored and Live-CD User committed Sep 19, 2009
1 parent 91312cd commit ccce6de
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 105 deletions.
153 changes: 77 additions & 76 deletions drivers/serial/serial_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@
#include <linux/console.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/serial_core.h>
#include <linux/smp_lock.h>
#include <linux/device.h>
#include <linux/serial.h> /* for serial_state and serial_icounter_struct */
#include <linux/serial_core.h>
#include <linux/delay.h>
#include <linux/mutex.h>

Expand Down Expand Up @@ -146,7 +146,7 @@ static int uart_startup(struct uart_state *state, int init_hw)
unsigned long page;
int retval = 0;

if (state->flags & UIF_INITIALIZED)
if (port->flags & ASYNC_INITIALIZED)
return 0;

/*
Expand Down Expand Up @@ -189,14 +189,14 @@ static int uart_startup(struct uart_state *state, int init_hw)
uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
}

if (state->flags & UIF_CTS_FLOW) {
if (port->flags & ASYNC_CTS_FLOW) {
spin_lock_irq(&uport->lock);
if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS))
port->tty->hw_stopped = 1;
spin_unlock_irq(&uport->lock);
}

state->flags |= UIF_INITIALIZED;
set_bit(ASYNCB_INITIALIZED, &port->flags);

clear_bit(TTY_IO_ERROR, &port->tty->flags);
}
Expand All @@ -214,7 +214,7 @@ static int uart_startup(struct uart_state *state, int init_hw)
*/
static void uart_shutdown(struct uart_state *state)
{
struct uart_port *port = state->uart_port;
struct uart_port *uport = state->uart_port;
struct tty_struct *tty = state->port.tty;

/*
Expand All @@ -223,14 +223,12 @@ static void uart_shutdown(struct uart_state *state)
if (tty)
set_bit(TTY_IO_ERROR, &tty->flags);

if (state->flags & UIF_INITIALIZED) {
state->flags &= ~UIF_INITIALIZED;

if (test_and_clear_bit(ASYNCB_INITIALIZED, &state->port.flags)) {
/*
* Turn off DTR and RTS early.
*/
if (!tty || (tty->termios->c_cflag & HUPCL))
uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);

/*
* clear delta_msr_wait queue to avoid mem leaks: we may free
Expand All @@ -244,12 +242,12 @@ static void uart_shutdown(struct uart_state *state)
/*
* Free the IRQ and disable the port.
*/
port->ops->shutdown(port);
uport->ops->shutdown(uport);

/*
* Ensure that the IRQ handler isn't running on another CPU.
*/
synchronize_irq(port->irq);
synchronize_irq(uport->irq);
}

/*
Expand Down Expand Up @@ -429,15 +427,16 @@ EXPORT_SYMBOL(uart_get_divisor);
static void
uart_change_speed(struct uart_state *state, struct ktermios *old_termios)
{
struct tty_struct *tty = state->port.tty;
struct uart_port *port = state->uart_port;
struct tty_port *port = &state->port;
struct tty_struct *tty = port->tty;
struct uart_port *uport = state->uart_port;
struct ktermios *termios;

/*
* If we have no tty, termios, or the port does not exist,
* then we can't set the parameters for this port.
*/
if (!tty || !tty->termios || port->type == PORT_UNKNOWN)
if (!tty || !tty->termios || uport->type == PORT_UNKNOWN)
return;

termios = tty->termios;
Expand All @@ -446,16 +445,16 @@ uart_change_speed(struct uart_state *state, struct ktermios *old_termios)
* Set flags based on termios cflag
*/
if (termios->c_cflag & CRTSCTS)
state->flags |= UIF_CTS_FLOW;
set_bit(ASYNCB_CTS_FLOW, &port->flags);
else
state->flags &= ~UIF_CTS_FLOW;
clear_bit(ASYNCB_CTS_FLOW, &port->flags);

if (termios->c_cflag & CLOCAL)
state->flags &= ~UIF_CHECK_CD;
clear_bit(ASYNCB_CHECK_CD, &port->flags);
else
state->flags |= UIF_CHECK_CD;
set_bit(ASYNCB_CHECK_CD, &port->flags);

port->ops->set_termios(port, termios, old_termios);
uport->ops->set_termios(uport, termios, old_termios);
}

static inline int
Expand Down Expand Up @@ -848,7 +847,7 @@ static int uart_set_info(struct uart_state *state,
retval = 0;
if (uport->type == PORT_UNKNOWN)
goto exit;
if (state->flags & UIF_INITIALIZED) {
if (port->flags & ASYNC_INITIALIZED) {
if (((old_flags ^ uport->flags) & UPF_SPD_MASK) ||
old_custom_divisor != uport->custom_divisor) {
/*
Expand Down Expand Up @@ -1306,7 +1305,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
* At this point, we stop accepting input. To do this, we
* disable the receive line status interrupts.
*/
if (state->flags & UIF_INITIALIZED) {
if (port->flags & ASYNC_INITIALIZED) {
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
uport->ops->stop_rx(uport);
Expand Down Expand Up @@ -1337,7 +1336,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
/*
* Wake up anyone trying to open this port.
*/
state->flags &= ~UIF_NORMAL_ACTIVE;
clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
wake_up_interruptible(&port->open_wait);

done:
Expand Down Expand Up @@ -1418,11 +1417,11 @@ static void uart_hangup(struct tty_struct *tty)
pr_debug("uart_hangup(%d)\n", state->uart_port->line);

mutex_lock(&state->mutex);
if (state->flags & UIF_NORMAL_ACTIVE) {
if (port->flags & ASYNC_NORMAL_ACTIVE) {
uart_flush_buffer(tty);
uart_shutdown(state);
port->count = 0;
state->flags &= ~UIF_NORMAL_ACTIVE;
clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
port->tty = NULL;
wake_up_interruptible(&port->open_wait);
wake_up_interruptible(&state->delta_msr_wait);
Expand Down Expand Up @@ -1493,7 +1492,7 @@ uart_block_til_ready(struct file *filp, struct uart_state *state)
/*
* If the port has been closed, tell userspace/restart open.
*/
if (!(state->flags & UIF_INITIALIZED))
if (!(port->flags & ASYNC_INITIALIZED))
break;

/*
Expand Down Expand Up @@ -1662,8 +1661,8 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
/*
* If this is the first open to succeed, adjust things to suit.
*/
if (retval == 0 && !(state->flags & UIF_NORMAL_ACTIVE)) {
state->flags |= UIF_NORMAL_ACTIVE;
if (retval == 0 && !(port->flags & ASYNC_NORMAL_ACTIVE)) {
set_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);

uart_update_termios(state);
}
Expand Down Expand Up @@ -1985,63 +1984,64 @@ static int serial_match_port(struct device *dev, void *data)
return dev->devt == devt; /* Actually, only one tty per port */
}

int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
{
struct uart_state *state = drv->state + port->line;
struct uart_state *state = drv->state + uport->line;
struct tty_port *port = &state->port;
struct device *tty_dev;
struct uart_match match = {port, drv};
struct uart_match match = {uport, drv};

mutex_lock(&state->mutex);

if (!console_suspend_enabled && uart_console(port)) {
if (!console_suspend_enabled && uart_console(uport)) {
/* we're going to avoid suspending serial console */
mutex_unlock(&state->mutex);
return 0;
}

tty_dev = device_find_child(port->dev, &match, serial_match_port);
tty_dev = device_find_child(uport->dev, &match, serial_match_port);
if (device_may_wakeup(tty_dev)) {
enable_irq_wake(port->irq);
enable_irq_wake(uport->irq);
put_device(tty_dev);
mutex_unlock(&state->mutex);
return 0;
}
port->suspended = 1;
uport->suspended = 1;

if (state->flags & UIF_INITIALIZED) {
const struct uart_ops *ops = port->ops;
if (port->flags & ASYNC_INITIALIZED) {
const struct uart_ops *ops = uport->ops;
int tries;

state->flags = (state->flags & ~UIF_INITIALIZED)
| UIF_SUSPENDED;
set_bit(ASYNCB_SUSPENDED, &port->flags);
clear_bit(ASYNCB_INITIALIZED, &port->flags);

spin_lock_irq(&port->lock);
ops->stop_tx(port);
ops->set_mctrl(port, 0);
ops->stop_rx(port);
spin_unlock_irq(&port->lock);
spin_lock_irq(&uport->lock);
ops->stop_tx(uport);
ops->set_mctrl(uport, 0);
ops->stop_rx(uport);
spin_unlock_irq(&uport->lock);

/*
* Wait for the transmitter to empty.
*/
for (tries = 3; !ops->tx_empty(port) && tries; tries--)
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",
port->dev ? dev_name(port->dev) : "",
port->dev ? ": " : "",
uport->dev ? dev_name(uport->dev) : "",
uport->dev ? ": " : "",
drv->dev_name,
drv->tty_driver->name_base + port->line);
drv->tty_driver->name_base + uport->line);

ops->shutdown(port);
ops->shutdown(uport);
}

/*
* Disable the console device before suspending.
*/
if (uart_console(port))
console_stop(port->cons);
if (uart_console(uport))
console_stop(uport->cons);

uart_change_pm(state, 3);

Expand All @@ -2050,67 +2050,68 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
return 0;
}

int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
{
struct uart_state *state = drv->state + port->line;
struct uart_state *state = drv->state + uport->line;
struct tty_port *port = &state->port;
struct device *tty_dev;
struct uart_match match = {port, drv};
struct uart_match match = {uport, drv};

mutex_lock(&state->mutex);

if (!console_suspend_enabled && uart_console(port)) {
if (!console_suspend_enabled && uart_console(uport)) {
/* no need to resume serial console, it wasn't suspended */
mutex_unlock(&state->mutex);
return 0;
}

tty_dev = device_find_child(port->dev, &match, serial_match_port);
if (!port->suspended && device_may_wakeup(tty_dev)) {
disable_irq_wake(port->irq);
tty_dev = device_find_child(uport->dev, &match, serial_match_port);
if (!uport->suspended && device_may_wakeup(tty_dev)) {
disable_irq_wake(uport->irq);
mutex_unlock(&state->mutex);
return 0;
}
port->suspended = 0;
uport->suspended = 0;

/*
* Re-enable the console device after suspending.
*/
if (uart_console(port)) {
if (uart_console(uport)) {
struct ktermios termios;

/*
* First try to use the console cflag setting.
*/
memset(&termios, 0, sizeof(struct ktermios));
termios.c_cflag = port->cons->cflag;
termios.c_cflag = uport->cons->cflag;

/*
* If that's unset, use the tty termios setting.
*/
if (state->port.tty && termios.c_cflag == 0)
termios = *state->port.tty->termios;
if (port->tty && termios.c_cflag == 0)
termios = *port->tty->termios;

uart_change_pm(state, 0);
port->ops->set_termios(port, &termios, NULL);
console_start(port->cons);
uport->ops->set_termios(uport, &termios, NULL);
console_start(uport->cons);
}

if (state->flags & UIF_SUSPENDED) {
const struct uart_ops *ops = port->ops;
if (port->flags & ASYNC_SUSPENDED) {
const struct uart_ops *ops = uport->ops;
int ret;

uart_change_pm(state, 0);
spin_lock_irq(&port->lock);
ops->set_mctrl(port, 0);
spin_unlock_irq(&port->lock);
ret = ops->startup(port);
spin_lock_irq(&uport->lock);
ops->set_mctrl(uport, 0);
spin_unlock_irq(&uport->lock);
ret = ops->startup(uport);
if (ret == 0) {
uart_change_speed(state, NULL);
spin_lock_irq(&port->lock);
ops->set_mctrl(port, port->mctrl);
ops->start_tx(port);
spin_unlock_irq(&port->lock);
state->flags |= UIF_INITIALIZED;
spin_lock_irq(&uport->lock);
ops->set_mctrl(uport, uport->mctrl);
ops->start_tx(uport);
spin_unlock_irq(&uport->lock);
set_bit(ASYNCB_INITIALIZED, &port->flags);
} else {
/*
* Failed to resume - maybe hardware went away?
Expand All @@ -2120,7 +2121,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
uart_shutdown(state);
}

state->flags &= ~UIF_SUSPENDED;
clear_bit(ASYNCB_SUSPENDED, &port->flags);
}

mutex_unlock(&state->mutex);
Expand Down
2 changes: 2 additions & 0 deletions include/linux/serial.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ struct serial_uart_config {

/* Internal flags used only by kernel */
#define ASYNCB_INITIALIZED 31 /* Serial port was initialized */
#define ASYNCB_SUSPENDED 30 /* Serial port is suspended */
#define ASYNCB_NORMAL_ACTIVE 29 /* Normal device is active */
#define ASYNCB_BOOT_AUTOCONF 28 /* Autoconfigure port on bootup */
#define ASYNCB_CLOSING 27 /* Serial port is closing */
Expand All @@ -133,6 +134,7 @@ struct serial_uart_config {
#define ASYNCB_FIRST_KERNEL 22

#define ASYNC_HUP_NOTIFY (1U << ASYNCB_HUP_NOTIFY)
#define ASYNC_SUSPENDED (1U << ASYNCB_SUSPENDED)
#define ASYNC_FOURPORT (1U << ASYNCB_FOURPORT)
#define ASYNC_SAK (1U << ASYNCB_SAK)
#define ASYNC_SPLIT_TERMIOS (1U << ASYNCB_SPLIT_TERMIOS)
Expand Down
Loading

0 comments on commit ccce6de

Please sign in to comment.