]> err.no Git - linux-2.6/blobdiff - drivers/serial/serial_core.c
Merge branch 'virtex-for-2.6.25' of git://git.secretlab.ca/git/linux-2.6-virtex into...
[linux-2.6] / drivers / serial / serial_core.c
index a055f58f342f3a1570f8648eb35c4df8550be353..276da148c57e015a6a148ec60a028d3d2e840ba6 100644 (file)
@@ -371,7 +371,8 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
                 */
                termios->c_cflag &= ~CBAUD;
                if (old) {
-                       termios->c_cflag |= old->c_cflag & CBAUD;
+                       baud = tty_termios_baud_rate(old);
+                       tty_termios_encode_baud_rate(termios, baud, baud);
                        old = NULL;
                        continue;
                }
@@ -380,7 +381,7 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
                 * As a last resort, if the quotient is zero,
                 * default to 9600 bps
                 */
-               termios->c_cflag |= B9600;
+               tty_termios_encode_baud_rate(termios, 9600, 9600);
        }
 
        return 0;
@@ -1875,6 +1876,7 @@ uart_set_options(struct uart_port *port, struct console *co,
                 int baud, int parity, int bits, int flow)
 {
        struct ktermios termios;
+       static struct ktermios dummy;
        int i;
 
        /*
@@ -1920,7 +1922,7 @@ uart_set_options(struct uart_port *port, struct console *co,
         */
        port->mctrl |= TIOCM_DTR;
 
-       port->ops->set_termios(port, &termios, NULL);
+       port->ops->set_termios(port, &termios, &dummy);
        co->cflag = termios.c_cflag;
 
        return 0;
@@ -1938,21 +1940,45 @@ 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);
 
-#ifdef CONFIG_DISABLE_CONSOLE_SUSPEND
-       if (uart_console(port)) {
+       if (!console_suspend_enabled && uart_console(port)) {
+               /* we're going to avoid suspending serial console */
                mutex_unlock(&state->mutex);
                return 0;
        }
-#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;
+               int tries;
 
                state->info->flags = (state->info->flags & ~UIF_INITIALIZED)
                                     | UIF_SUSPENDED;
@@ -1966,9 +1992,14 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
                /*
                 * Wait for the transmitter to empty.
                 */
-               while (!ops->tx_empty(port)) {
+               for (tries = 3; !ops->tx_empty(port) && tries; tries--) {
                        msleep(10);
                }
+               if (!tries)
+                       printk(KERN_ERR "%s%s%s%d: Unable to drain transmitter\n",
+                              port->dev ? port->dev->bus_id : "",
+                              port->dev ? ": " : "",
+                              drv->dev_name, port->line);
 
                ops->shutdown(port);
        }
@@ -1992,14 +2023,18 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
 
        mutex_lock(&state->mutex);
 
-#ifdef CONFIG_DISABLE_CONSOLE_SUSPEND
-       if (uart_console(port)) {
+       if (!console_suspend_enabled && uart_console(port)) {
+               /* no need to resume serial console, it wasn't suspended */
                mutex_unlock(&state->mutex);
                return 0;
        }
-#endif
 
-       uart_change_pm(state, 0);
+       if (!port->suspended) {
+               disable_irq_wake(port->irq);
+               mutex_unlock(&state->mutex);
+               return 0;
+       }
+       port->suspended = 0;
 
        /*
         * Re-enable the console device after suspending.
@@ -2019,6 +2054,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
                if (state->info && state->info->tty && termios.c_cflag == 0)
                        termios = *state->info->tty->termios;
 
+               uart_change_pm(state, 0);
                port->ops->set_termios(port, &termios, NULL);
                console_start(port->cons);
        }
@@ -2027,6 +2063,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
                const struct uart_ops *ops = port->ops;
                int ret;
 
+               uart_change_pm(state, 0);
                ops->set_mctrl(port, 0);
                ret = ops->startup(port);
                if (ret == 0) {
@@ -2120,12 +2157,21 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
 
                /*
                 * Ensure that the modem control lines are de-activated.
+                * keep the DTR setting that is set in uart_set_options()
                 * We probably don't need a spinlock around this, but
                 */
                spin_lock_irqsave(&port->lock, flags);
-               port->ops->set_mctrl(port, 0);
+               port->ops->set_mctrl(port, port->mctrl & TIOCM_DTR);
                spin_unlock_irqrestore(&port->lock, flags);
 
+               /*
+                * If this driver supports console, and it hasn't been
+                * successfully registered yet, try to re-register it.
+                * It may be that the port was not available.
+                */
+               if (port->cons && !(port->cons->flags & CON_ENABLED))
+                       register_console(port->cons);
+
                /*
                 * Power down all ports by default, except the
                 * console if we have one.
@@ -2270,6 +2316,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());
 
@@ -2286,6 +2333,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
        }
 
        state->port = port;
+       state->pm_state = -1;
 
        port->cons = drv->cons;
        port->info = state->info;
@@ -2305,16 +2353,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);
-
-       /*
-        * If this driver supports console, and it hasn't been
-        * successfully registered yet, try to re-register it.
-        * It may be that the port was not available.
-        */
-       if (port->type != PORT_UNKNOWN &&
-           port->cons && !(port->cons->flags & CON_ENABLED))
-               register_console(port->cons);
+       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.