X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=drivers%2Fserial%2Fserial_core.c;h=17839e753e4cfb1fb550832d8613b0ec579c83ef;hb=b0c51b7d650d5109c8e71e19d5e7ce9b71af7dff;hp=cc1faa31d124f0308a565970bc968245cf73f351;hpb=0f76ee451484d02c7405d92e7bceb39b415abb01;p=powerpc.git diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index cc1faa31d1..17839e753e 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -1500,20 +1500,18 @@ 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)) { - state = ERR_PTR(-ERESTARTSYS); - goto out; + ret = -ERESTARTSYS; + goto err; } state->count++; - if (!state->port) { - state->count--; - mutex_unlock(&state->mutex); - state = ERR_PTR(-ENXIO); - goto out; + if (!state->port || state->port->flags & UPF_DEAD) { + ret = -ENXIO; + goto err_unlock; } if (!state->info) { @@ -1531,15 +1529,17 @@ static struct uart_state *uart_get(struct uart_driver *drv, int line) tasklet_init(&state->info->tlet, uart_tasklet_action, (unsigned long)state); } else { - state->count--; - mutex_unlock(&state->mutex); - state = ERR_PTR(-ENOMEM); + ret = -ENOMEM; + goto err_unlock; } } - - out: - mutex_unlock(&port_mutex); return state; + + err_unlock: + state->count--; + mutex_unlock(&state->mutex); + err: + return ERR_PTR(ret); } /* @@ -1754,6 +1754,27 @@ 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 @@ -1886,9 +1907,12 @@ 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 (port->ops->pm) - port->ops->pm(port, pm_state, state->pm_state); - state->pm_state = pm_state; + + if (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) @@ -2064,45 +2088,6 @@ 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, @@ -2249,6 +2234,7 @@ 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; @@ -2283,7 +2269,13 @@ 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; @@ -2301,6 +2293,7 @@ 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()); @@ -2310,12 +2303,49 @@ 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); - uart_unconfigure_port(drv, state); + 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); + } + state->port = NULL; mutex_unlock(&port_mutex);