X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fserial%2Fserial_core.c;h=eab032733790d5524ac9f14e8596c1a5a62e462c;hb=da1ba891f22835db9a2c349315c3763e9f4e4e67;hp=6c7a5cf765828fc7007e7e630a5a90b8f6a0c414;hpb=23d22cea85ba9114a59a32ca8dfb1e2aef52a278;p=linux-2.6 diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index 6c7a5cf765..eab0327337 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -532,21 +532,31 @@ uart_write(struct tty_struct *tty, const unsigned char *buf, int count) static int uart_write_room(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; + unsigned long flags; + int ret; - return uart_circ_chars_free(&state->info->xmit); + spin_lock_irqsave(&state->port->lock, flags); + ret = uart_circ_chars_free(&state->info->xmit); + spin_unlock_irqrestore(&state->port->lock, flags); + return ret; } static int uart_chars_in_buffer(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; + unsigned long flags; + int ret; - return uart_circ_chars_pending(&state->info->xmit); + spin_lock_irqsave(&state->port->lock, flags); + ret = uart_circ_chars_pending(&state->info->xmit); + spin_unlock_irqrestore(&state->port->lock, flags); + return ret; } static void uart_flush_buffer(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; - struct uart_port *port = state->port; + struct uart_port *port; unsigned long flags; /* @@ -558,6 +568,7 @@ static void uart_flush_buffer(struct tty_struct *tty) return; } + port = state->port; pr_debug("uart_flush_buffer(%d) called\n", tty->index); spin_lock_irqsave(&port->lock, flags); @@ -622,6 +633,11 @@ static int uart_get_info(struct uart_state *state, struct serial_struct tmp; memset(&tmp, 0, sizeof(tmp)); + + /* Ensure the state we copy is consistent and no hardware changes + occur as we go */ + mutex_lock(&state->mutex); + tmp.type = port->type; tmp.line = port->line; tmp.port = port->iobase; @@ -641,6 +657,8 @@ static int uart_get_info(struct uart_state *state, tmp.iomem_reg_shift = port->regshift; tmp.iomem_base = (void *)(unsigned long)port->mapbase; + mutex_unlock(&state->mutex); + if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) return -EFAULT; return 0; @@ -918,14 +936,12 @@ static void uart_break_ctl(struct tty_struct *tty, int break_state) struct uart_state *state = tty->driver_data; struct uart_port *port = state->port; - lock_kernel(); mutex_lock(&state->mutex); if (port->type != PORT_UNKNOWN) port->ops->break_ctl(port, break_state); mutex_unlock(&state->mutex); - unlock_kernel(); } static int uart_do_autoconfig(struct uart_state *state) @@ -1074,7 +1090,6 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, int ret = -ENOIOCTLCMD; - lock_kernel(); /* * These ioctls don't rely on the hardware to be present. */ @@ -1144,10 +1159,9 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, break; } } - out_up: +out_up: mutex_unlock(&state->mutex); - out: - unlock_kernel(); +out: return ret; } @@ -1173,7 +1187,6 @@ static void uart_set_termios(struct tty_struct *tty, return; } - lock_kernel(); uart_change_speed(state, old_termios); /* Handle transition to B0 status */ @@ -1206,7 +1219,6 @@ static void uart_set_termios(struct tty_struct *tty, } spin_unlock_irqrestore(&state->port->lock, flags); } - unlock_kernel(); #if 0 /* * No need to wake up processes in open wait, since they @@ -1322,11 +1334,11 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout) struct uart_port *port = state->port; unsigned long char_time, expire; - BUG_ON(!kernel_locked()); - if (port->type == PORT_UNKNOWN || port->fifosize == 0) return; + lock_kernel(); + /* * Set the check interval to be 1/5 of the estimated time to * send a single character, and make it at least 1. The check @@ -1372,6 +1384,7 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout) break; } set_current_state(TASK_RUNNING); /* might not be needed */ + unlock_kernel(); } /* @@ -2085,7 +2098,9 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port) int ret; uart_change_pm(state, 0); + spin_lock_irq(&port->lock); ops->set_mctrl(port, 0); + spin_unlock_irq(&port->lock); ret = ops->startup(port); if (ret == 0) { uart_change_speed(state, NULL);