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]>

---

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.

Thanks
Guennadi

diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 9c57486..8a3d6ea 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -1934,9 +1934,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);
 
@@ -1947,6 +1962,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;
 
@@ -1995,6 +2019,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);
 
        /*
@@ -2266,6 +2297,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 +2333,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
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 773d8d8..60dedc0 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -291,7 +291,8 @@ struct uart_port {
        unsigned long           mapbase;                /* for ioremap */
        struct device           *dev;                   /* parent device */
        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 */
 };
 
-
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