mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-11-01 17:08:10 +00:00
wake up from a serial port
Enable wakeup from serial ports, make it run-time configurable over sysfs, e.g., echo enabled > /sys/devices/platform/serial8250.0/tty/ttyS0/power/wakeup Requires # CONFIG_SYSFS_DEPRECATED is not set Following suggestions from Alan and Russell moved the may_wake_up checks to serial_core.c. This time actually tested - it does even work. Could someone, please, verify, that put_device after device_find_child is correct? Also would be nice to test with a Natsemi UART, that can wake up the system, if such systems exist. For this you just have to apply the patch below, issue the above "echo" command to one of your Natsemi port, suspend and resume your system, and verify that your Natsemi port still works. If you are actually capable of waking up the system from that port, would be nice to test that as well. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Cc: Russell King <rmk@arm.linux.org.uk> Cc: Kay Sievers <kay.sievers@vrfy.org> Cc: Greg KH <greg@kroah.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
aa5346a212
commit
b3b708fa27
2 changed files with 41 additions and 2 deletions
|
@ -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)
|
int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
|
||||||
{
|
{
|
||||||
struct uart_state *state = drv->state + port->line;
|
struct uart_state *state = drv->state + port->line;
|
||||||
|
struct device *tty_dev;
|
||||||
|
struct uart_match match = {port, drv};
|
||||||
|
|
||||||
mutex_lock(&state->mutex);
|
mutex_lock(&state->mutex);
|
||||||
|
|
||||||
|
@ -1951,6 +1966,15 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
|
||||||
}
|
}
|
||||||
#endif
|
#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) {
|
if (state->info && state->info->flags & UIF_INITIALIZED) {
|
||||||
const struct uart_ops *ops = port->ops;
|
const struct uart_ops *ops = port->ops;
|
||||||
|
|
||||||
|
@ -1999,6 +2023,13 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (!port->suspended) {
|
||||||
|
disable_irq_wake(port->irq);
|
||||||
|
mutex_unlock(&state->mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
port->suspended = 0;
|
||||||
|
|
||||||
uart_change_pm(state, 0);
|
uart_change_pm(state, 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2278,6 +2309,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
|
||||||
{
|
{
|
||||||
struct uart_state *state;
|
struct uart_state *state;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
struct device *tty_dev;
|
||||||
|
|
||||||
BUG_ON(in_interrupt());
|
BUG_ON(in_interrupt());
|
||||||
|
|
||||||
|
@ -2314,7 +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
|
* Register the port whether it's detected or not. This allows
|
||||||
* setserial to be used to alter this ports parameters.
|
* setserial to be used to alter this ports parameters.
|
||||||
*/
|
*/
|
||||||
tty_register_device(drv->tty_driver, port->line, port->dev);
|
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.
|
* Ensure UPF_DEAD is not set.
|
||||||
|
|
|
@ -291,7 +291,8 @@ struct uart_port {
|
||||||
resource_size_t mapbase; /* for ioremap */
|
resource_size_t mapbase; /* for ioremap */
|
||||||
struct device *dev; /* parent device */
|
struct device *dev; /* parent device */
|
||||||
unsigned char hub6; /* this should be in the 8250 driver */
|
unsigned char hub6; /* this should be in the 8250 driver */
|
||||||
unsigned char unused[3];
|
unsigned char suspended;
|
||||||
|
unsigned char unused[2];
|
||||||
void *private_data; /* generic platform data pointer */
|
void *private_data; /* generic platform data pointer */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue