diff options
Diffstat (limited to 'drivers/serial/serial_core.c')
-rw-r--r-- | drivers/serial/serial_core.c | 58 |
1 files changed, 48 insertions, 10 deletions
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index a055f58f342f..68aa4da01865 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -1938,9 +1938,24 @@ static void uart_change_pm(struct uart_state *state, int pm_state) } } +struct uart_match { + struct uart_port *port; + struct uart_driver *driver; +}; + +static int serial_match_port(struct device *dev, void *data) +{ + struct uart_match *match = data; + dev_t devt = MKDEV(match->driver->major, match->driver->minor) + match->port->line; + + return dev->devt == devt; /* Actually, only one tty per port */ +} + int uart_suspend_port(struct uart_driver *drv, struct uart_port *port) { struct uart_state *state = drv->state + port->line; + struct device *tty_dev; + struct uart_match match = {port, drv}; mutex_lock(&state->mutex); @@ -1951,6 +1966,15 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port) } #endif + tty_dev = device_find_child(port->dev, &match, serial_match_port); + if (device_may_wakeup(tty_dev)) { + enable_irq_wake(port->irq); + put_device(tty_dev); + mutex_unlock(&state->mutex); + return 0; + } + port->suspended = 1; + if (state->info && state->info->flags & UIF_INITIALIZED) { const struct uart_ops *ops = port->ops; @@ -1999,6 +2023,13 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port) } #endif + if (!port->suspended) { + disable_irq_wake(port->irq); + mutex_unlock(&state->mutex); + return 0; + } + port->suspended = 0; + uart_change_pm(state, 0); /* @@ -2127,6 +2158,14 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state, spin_unlock_irqrestore(&port->lock, flags); /* + * If this driver supports console, and it hasn't been + * successfully registered yet, try to re-register it. + * It may be that the port was not available. + */ + if (port->cons && !(port->cons->flags & CON_ENABLED)) + register_console(port->cons); + + /* * Power down all ports by default, except the * console if we have one. */ @@ -2270,6 +2309,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) { struct uart_state *state; int ret = 0; + struct device *tty_dev; BUG_ON(in_interrupt()); @@ -2286,6 +2326,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) } state->port = port; + state->pm_state = -1; port->cons = drv->cons; port->info = state->info; @@ -2305,16 +2346,13 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) * Register the port whether it's detected or not. This allows * setserial to be used to alter this ports parameters. */ - tty_register_device(drv->tty_driver, port->line, port->dev); - - /* - * If this driver supports console, and it hasn't been - * successfully registered yet, try to re-register it. - * It may be that the port was not available. - */ - if (port->type != PORT_UNKNOWN && - port->cons && !(port->cons->flags & CON_ENABLED)) - register_console(port->cons); + tty_dev = tty_register_device(drv->tty_driver, port->line, port->dev); + if (likely(!IS_ERR(tty_dev))) { + device_can_wakeup(tty_dev) = 1; + device_set_wakeup_enable(tty_dev, 0); + } else + printk(KERN_ERR "Cannot register tty device on line %d\n", + port->line); /* * Ensure UPF_DEAD is not set. |