X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fserial%2Fserial_core.c;h=f84982e508c7efc7e2eb6bcdca37f95ee22e8b67;hb=refs%2Fheads%2Fvserver;hp=cc1faa31d124f0308a565970bc968245cf73f351;hpb=76828883507a47dae78837ab5dec5a5b4513c667;p=linux-2.6.git diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index cc1faa31d..f84982e50 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -22,7 +22,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include #include #include @@ -50,6 +49,12 @@ */ static DEFINE_MUTEX(port_mutex); +/* + * lockdep: port->lock is initialized in two places, but we + * want only one lock-class: + */ +static struct lock_class_key port_lock_key; + #define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) #define uart_users(state) ((state)->count + ((state)->info ? (state)->info->blocked_open : 0)) @@ -60,7 +65,7 @@ static DEFINE_MUTEX(port_mutex); #define uart_console(port) (0) #endif -static void uart_change_speed(struct uart_state *state, struct termios *old_termios); +static void uart_change_speed(struct uart_state *state, struct ktermios *old_termios); static void uart_wait_until_sent(struct tty_struct *tty, int timeout); static void uart_change_pm(struct uart_state *state, int pm_state); @@ -333,8 +338,8 @@ EXPORT_SYMBOL(uart_update_timeout); * we're actually going to be using. */ unsigned int -uart_get_baud_rate(struct uart_port *port, struct termios *termios, - struct termios *old, unsigned int min, unsigned int max) +uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, + struct ktermios *old, unsigned int min, unsigned int max) { unsigned int try, baud, altbaud = 38400; upf_t flags = port->flags & UPF_SPD_MASK; @@ -416,11 +421,11 @@ uart_get_divisor(struct uart_port *port, unsigned int baud) EXPORT_SYMBOL(uart_get_divisor); static void -uart_change_speed(struct uart_state *state, struct termios *old_termios) +uart_change_speed(struct uart_state *state, struct ktermios *old_termios) { struct tty_struct *tty = state->info->tty; struct uart_port *port = state->port; - struct termios *termios; + struct ktermios *termios; /* * If we have no tty, termios, or the port does not exist, @@ -691,7 +696,8 @@ static int uart_set_info(struct uart_state *state, (new_serial.baud_base != port->uartclk / 16) || (close_delay != state->close_delay) || (closing_wait != state->closing_wait) || - (new_serial.xmit_fifo_size != port->fifosize) || + (new_serial.xmit_fifo_size && + new_serial.xmit_fifo_size != port->fifosize) || (((new_flags ^ old_flags) & ~UPF_USR_MASK) != 0)) goto exit; port->flags = ((port->flags & ~UPF_USR_MASK) | @@ -786,6 +792,7 @@ static int uart_set_info(struct uart_state *state, * We failed anyway. */ retval = -EBUSY; + goto exit; // Added to return the correct error -Ram Gupta } } @@ -796,7 +803,8 @@ static int uart_set_info(struct uart_state *state, port->custom_divisor = new_serial.custom_divisor; state->close_delay = close_delay; state->closing_wait = closing_wait; - port->fifosize = new_serial.xmit_fifo_size; + if (new_serial.xmit_fifo_size) + port->fifosize = new_serial.xmit_fifo_size; if (state->info->tty) state->info->tty->low_latency = (port->flags & UPF_LOW_LATENCY) ? 1 : 0; @@ -1131,7 +1139,7 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, return ret; } -static void uart_set_termios(struct tty_struct *tty, struct termios *old_termios) +static void uart_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct uart_state *state = tty->driver_data; unsigned long flags; @@ -1500,20 +1508,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 +1537,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); } /* @@ -1655,16 +1663,16 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i) struct uart_port *port = state->port; char stat_buf[32]; unsigned int status; - int ret; + int mmio, ret; if (!port) return 0; + mmio = port->iotype >= UPIO_MEM; ret = sprintf(buf, "%d: uart:%s %s%08lX irq:%d", port->line, uart_type(port), - port->iotype == UPIO_MEM ? "mmio:0x" : "port:", - port->iotype == UPIO_MEM ? port->mapbase : - (unsigned long) port->iobase, + mmio ? "mmio:0x" : "port:", + mmio ? port->mapbase : (unsigned long) port->iobase, port->irq); if (port->type == PORT_UNKNOWN) { @@ -1754,6 +1762,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 @@ -1837,7 +1866,7 @@ int __init uart_set_options(struct uart_port *port, struct console *co, int baud, int parity, int bits, int flow) { - struct termios termios; + struct ktermios termios; int i; /* @@ -1845,8 +1874,9 @@ uart_set_options(struct uart_port *port, struct console *co, * early. */ spin_lock_init(&port->lock); + lockdep_set_class(&port->lock, &port_lock_key); - memset(&termios, 0, sizeof(struct termios)); + memset(&termios, 0, sizeof(struct ktermios)); termios.c_cflag = CREAD | HUPCL | CLOCAL; @@ -1886,9 +1916,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) @@ -1897,9 +1930,19 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port) mutex_lock(&state->mutex); +#ifdef CONFIG_DISABLE_CONSOLE_SUSPEND + if (uart_console(port)) { + mutex_unlock(&state->mutex); + return 0; + } +#endif + if (state->info && state->info->flags & UIF_INITIALIZED) { const struct uart_ops *ops = port->ops; + state->info->flags = (state->info->flags & ~UIF_INITIALIZED) + | UIF_SUSPENDED; + spin_lock_irq(&port->lock); ops->stop_tx(port); ops->set_mctrl(port, 0); @@ -1935,18 +1978,25 @@ 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)) { + mutex_unlock(&state->mutex); + return 0; + } +#endif + uart_change_pm(state, 0); /* * Re-enable the console device after suspending. */ if (uart_console(port)) { - struct termios termios; + struct ktermios termios; /* * First try to use the console cflag setting. */ - memset(&termios, 0, sizeof(struct termios)); + memset(&termios, 0, sizeof(struct ktermios)); termios.c_cflag = port->cons->cflag; /* @@ -1959,7 +2009,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port) console_start(port->cons); } - if (state->info && state->info->flags & UIF_INITIALIZED) { + if (state->info && state->info->flags & UIF_SUSPENDED) { const struct uart_ops *ops = port->ops; int ret; @@ -1971,15 +2021,17 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port) ops->set_mctrl(port, port->mctrl); ops->start_tx(port); spin_unlock_irq(&port->lock); + state->info->flags |= UIF_INITIALIZED; } else { /* * Failed to resume - maybe hardware went away? * Clear the "initialized" flag so we won't try * to call the low level drivers shutdown method. */ - state->info->flags &= ~UIF_INITIALIZED; uart_shutdown(state); } + + state->info->flags &= ~UIF_SUSPENDED; } mutex_unlock(&state->mutex); @@ -2004,6 +2056,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port) case UPIO_MEM: case UPIO_MEM32: case UPIO_AU: + case UPIO_TSI: snprintf(address, sizeof(address), "MMIO 0x%lx", port->mapbase); break; @@ -2064,46 +2117,7 @@ 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 = { +static const struct tty_operations uart_ops = { .open = uart_open, .close = uart_close, .write = uart_write, @@ -2168,7 +2182,6 @@ int uart_register_driver(struct uart_driver *drv) normal->owner = drv->owner; normal->driver_name = drv->driver_name; - normal->devfs_name = drv->devfs_name; normal->name = drv->dev_name; normal->major = drv->major; normal->minor_start = drv->minor; @@ -2176,7 +2189,8 @@ int uart_register_driver(struct uart_driver *drv) normal->subtype = SERIAL_TYPE_NORMAL; normal->init_termios = tty_std_termios; normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; + normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600; + normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; normal->driver_state = drv; tty_set_operations(normal, &uart_ops); @@ -2249,6 +2263,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; @@ -2263,8 +2278,10 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) * If this port is a console, then the spinlock is already * initialised. */ - if (!(uart_console(port) && (port->cons->flags & CON_ENABLED))) + if (!(uart_console(port) && (port->cons->flags & CON_ENABLED))) { spin_lock_init(&port->lock); + lockdep_set_class(&port->lock, &port_lock_key); + } uart_configure_port(drv, state, port); @@ -2283,7 +2300,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 +2324,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()); @@ -2311,11 +2335,48 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port) mutex_lock(&port_mutex); /* - * Remove the devices from devfs + * 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 the tty layer */ 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); @@ -2337,6 +2398,9 @@ int uart_match_port(struct uart_port *port1, struct uart_port *port2) return (port1->iobase == port2->iobase) && (port1->hub6 == port2->hub6); case UPIO_MEM: + case UPIO_MEM32: + case UPIO_AU: + case UPIO_TSI: return (port1->mapbase == port2->mapbase); } return 0;