linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / drivers / serial / serial_core.c
index 17839e7..cc1faa3 100644 (file)
@@ -1500,18 +1500,20 @@ uart_block_til_ready(struct file *filp, struct uart_state *state)
 static struct uart_state *uart_get(struct uart_driver *drv, int line)
 {
        struct uart_state *state;
-       int ret = 0;
 
+       mutex_lock(&port_mutex);
        state = drv->state + line;
        if (mutex_lock_interruptible(&state->mutex)) {
-               ret = -ERESTARTSYS;
-               goto err;
+               state = ERR_PTR(-ERESTARTSYS);
+               goto out;
        }
 
        state->count++;
-       if (!state->port || state->port->flags & UPF_DEAD) {
-               ret = -ENXIO;
-               goto err_unlock;
+       if (!state->port) {
+               state->count--;
+               mutex_unlock(&state->mutex);
+               state = ERR_PTR(-ENXIO);
+               goto out;
        }
 
        if (!state->info) {
@@ -1529,17 +1531,15 @@ static struct uart_state *uart_get(struct uart_driver *drv, int line)
                        tasklet_init(&state->info->tlet, uart_tasklet_action,
                                     (unsigned long)state);
                } else {
-                       ret = -ENOMEM;
-                       goto err_unlock;
+                       state->count--;
+                       mutex_unlock(&state->mutex);
+                       state = ERR_PTR(-ENOMEM);
                }
        }
-       return state;
 
- err_unlock:
-       state->count--;
-       mutex_unlock(&state->mutex);
- err:
-       return ERR_PTR(ret);
+ out:
+       mutex_unlock(&port_mutex);
+       return state;
 }
 
 /*
@@ -1754,27 +1754,6 @@ static int uart_read_proc(char *page, char **start, off_t off,
 #endif
 
 #ifdef CONFIG_SERIAL_CORE_CONSOLE
-/*
- *     uart_console_write - write a console message to a serial port
- *     @port: the port to write the message
- *     @s: array of characters
- *     @count: number of characters in string to write
- *     @write: function to write character to port
- */
-void uart_console_write(struct uart_port *port, const char *s,
-                       unsigned int count,
-                       void (*putchar)(struct uart_port *, int))
-{
-       unsigned int i;
-
-       for (i = 0; i < count; i++, s++) {
-               if (*s == '\n')
-                       putchar(port, '\r');
-               putchar(port, *s);
-       }
-}
-EXPORT_SYMBOL_GPL(uart_console_write);
-
 /*
  *     Check whether an invalid uart number has been specified, and
  *     if so, search for the first available port that does have
@@ -1907,12 +1886,9 @@ uart_set_options(struct uart_port *port, struct console *co,
 static void uart_change_pm(struct uart_state *state, int pm_state)
 {
        struct uart_port *port = state->port;
-
-       if (state->pm_state != pm_state) {
-               if (port->ops->pm)
-                       port->ops->pm(port, pm_state, state->pm_state);
-               state->pm_state = pm_state;
-       }
+       if (port->ops->pm)
+               port->ops->pm(port, pm_state, state->pm_state);
+       state->pm_state = pm_state;
 }
 
 int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
@@ -2088,6 +2064,45 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
        }
 }
 
+/*
+ * This reverses the effects of uart_configure_port, hanging up the
+ * port before removal.
+ */
+static void
+uart_unconfigure_port(struct uart_driver *drv, struct uart_state *state)
+{
+       struct uart_port *port = state->port;
+       struct uart_info *info = state->info;
+
+       if (info && info->tty)
+               tty_vhangup(info->tty);
+
+       mutex_lock(&state->mutex);
+
+       state->info = NULL;
+
+       /*
+        * Free the port IO and memory resources, if any.
+        */
+       if (port->type != PORT_UNKNOWN)
+               port->ops->release_port(port);
+
+       /*
+        * Indicate that there isn't a port here anymore.
+        */
+       port->type = PORT_UNKNOWN;
+
+       /*
+        * Kill the tasklet, and free resources.
+        */
+       if (info) {
+               tasklet_kill(&info->tlet);
+               kfree(info);
+       }
+
+       mutex_unlock(&state->mutex);
+}
+
 static struct tty_operations uart_ops = {
        .open           = uart_open,
        .close          = uart_close,
@@ -2234,7 +2249,6 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
        state = drv->state + port->line;
 
        mutex_lock(&port_mutex);
-       mutex_lock(&state->mutex);
        if (state->port) {
                ret = -EINVAL;
                goto out;
@@ -2269,13 +2283,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
            port->cons && !(port->cons->flags & CON_ENABLED))
                register_console(port->cons);
 
-       /*
-        * Ensure UPF_DEAD is not set.
-        */
-       port->flags &= ~UPF_DEAD;
-
  out:
-       mutex_unlock(&state->mutex);
        mutex_unlock(&port_mutex);
 
        return ret;
@@ -2293,7 +2301,6 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
 int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port)
 {
        struct uart_state *state = drv->state + port->line;
-       struct uart_info *info;
 
        BUG_ON(in_interrupt());
 
@@ -2303,49 +2310,12 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port)
 
        mutex_lock(&port_mutex);
 
-       /*
-        * Mark the port "dead" - this prevents any opens from
-        * succeeding while we shut down the port.
-        */
-       mutex_lock(&state->mutex);
-       port->flags |= UPF_DEAD;
-       mutex_unlock(&state->mutex);
-
        /*
         * Remove the devices from devfs
         */
        tty_unregister_device(drv->tty_driver, port->line);
 
-       info = state->info;
-       if (info && info->tty)
-               tty_vhangup(info->tty);
-
-       /*
-        * All users of this port should now be disconnected from
-        * this driver, and the port shut down.  We should be the
-        * only thread fiddling with this port from now on.
-        */
-       state->info = NULL;
-
-       /*
-        * Free the port IO and memory resources, if any.
-        */
-       if (port->type != PORT_UNKNOWN)
-               port->ops->release_port(port);
-
-       /*
-        * Indicate that there isn't a port here anymore.
-        */
-       port->type = PORT_UNKNOWN;
-
-       /*
-        * Kill the tasklet, and free resources.
-        */
-       if (info) {
-               tasklet_kill(&info->tlet);
-               kfree(info);
-       }
-
+       uart_unconfigure_port(drv, state);
        state->port = NULL;
        mutex_unlock(&port_mutex);