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 <[EMAIL PROTECTED]>

---

I've sent this rfc/patch earlier to linuxppc-dev (I need it for a ppc 
platform) and to linux-serial, and got no comments - but no objections 
either from either of them. So, re-sending to a broader and hopefully more 
relevant audience this time.

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
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to