Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2
Commit:     b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2
Parent:     aa5346a2126ea65e8ef04eebea0f2481f701bdb8
Author:     Guennadi Liakhovetski <[EMAIL PROTECTED]>
AuthorDate: Tue Oct 16 01:24:02 2007 -0700
Committer:  Linus Torvalds <[EMAIL PROTECTED]>
CommitDate: Tue Oct 16 09:42:50 2007 -0700

    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 <[EMAIL PROTECTED]>
    Cc: Alan Cox <[EMAIL PROTECTED]>
    Cc: Russell King <[EMAIL PROTECTED]>
    Cc: Kay Sievers <[EMAIL PROTECTED]>
    Cc: Greg KH <[EMAIL PROTECTED]>
    Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
    Signed-off-by: Linus Torvalds <[EMAIL PROTECTED]>
---
 drivers/serial/serial_core.c |   40 +++++++++++++++++++++++++++++++++++++++-
 include/linux/serial_core.h  |    3 ++-
 2 files changed, 41 insertions(+), 2 deletions(-)

diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index a3bd3a3..68aa4da 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);
 
        /*
@@ -2278,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());
 
@@ -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
         * 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.
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 09d17b0..4db7724 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -291,7 +291,8 @@ struct uart_port {
        resource_size_t         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 git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to