Re: [PATCH, RFC] wake up from a serial port
From: Guennadi Liakhovetski <hidden>
Date: 2007-08-20 21:53:49
Also in:
linux-serial
Subsystem:
the rest · Maintainer:
Linus Torvalds
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 Signed-off-by: Guennadi Liakhovetski <redacted> --- (I still find it strange having to put a formal patch description above and its discussion below, anyway) On Mon, 13 Aug 2007, Greg KH wrote:
So, the serial8250 device is the "bridge" for the 4 different serial ports in my machine. You have the tty:ttyS? symlinks in that directory as you have CONFIG_SYSFS_DEPRECATED still enabled, but the directory structure should all still be the same for you. So, if you want to put things into the tty device's directory, you can, they will just show up in the proper place, under /sys/devices/platform/serial8250/tty/ttyS0 for the first serial port. Does that make sense?
I think it does... Following this, and a suggestion from Scott to switch wakeup-enable on and off at run-time over sysfs, here's another attempt... Well, easy to see I'm out in the wild here in this area (pm/sysfs/tty), so, this might well be way off... Please, comment. Thanks Guennadi
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 0b3ec38..5118914 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c@@ -130,6 +130,7 @@ struct uart_8250_port { unsigned char mcr_mask; /* mask of user bits */ unsigned char mcr_force; /* mask of forced bits */ unsigned char lsr_break_flag; + char suspended; /* * We provide a per-port pm hook.
@@ -2673,6 +2674,14 @@ static int __devexit serial8250_remove(struct platform_device *dev) return 0; } +static int serial8250_match_port(struct device *dev, void *data) +{ + struct uart_port *port = data; + dev_t devt = MKDEV(serial8250_reg.major, serial8250_reg.minor) + port->line; + + return dev->devt == devt; /* Actually, only one tty per port */ +} + static int serial8250_suspend(struct platform_device *dev, pm_message_t state) { int i;
@@ -2680,8 +2689,16 @@ static int serial8250_suspend(struct platform_device *dev, pm_message_t state) for (i = 0; i < UART_NR; i++) { struct uart_8250_port *up = &serial8250_ports[i]; - if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev) - uart_suspend_port(&serial8250_reg, &up->port); + if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev) { + struct device *tty_dev = device_find_child(up->port.dev, &up->port, + serial8250_match_port); + if (device_may_wakeup(tty_dev)) + enable_irq_wake(up->port.irq); + else { + uart_suspend_port(&serial8250_reg, &up->port); + up->suspended = 1; + } + } } return 0;
@@ -2694,8 +2711,13 @@ static int serial8250_resume(struct platform_device *dev) for (i = 0; i < UART_NR; i++) { struct uart_8250_port *up = &serial8250_ports[i]; - if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev) - serial8250_resume_port(i); + if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev) { + if (up->suspended) { + serial8250_resume_port(i); + up->suspended = 0; + } else + disable_irq_wake(up->port.irq); + } } return 0;
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 9c57486..716fbe2 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c@@ -2266,6 +2266,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());
@@ -2301,7 +2302,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); + 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); /* * If this driver supports console, and it hasn't been