X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fserial%2Fserial_core.c;h=eab032733790d5524ac9f14e8596c1a5a62e462c;hb=e616c6303306df62223ebe2e68bb2f19c420dd81;hp=f7263e104d81de7c622379e04ad0097284926042;hpb=e52384426064bca0669a954736206adca7595d48;p=linux-2.6 diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index f7263e104d..eab0327337 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -422,6 +422,7 @@ uart_get_divisor(struct uart_port *port, unsigned int baud) EXPORT_SYMBOL(uart_get_divisor); +/* FIXME: Consistent locking policy */ static void uart_change_speed(struct uart_state *state, struct ktermios *old_termios) { @@ -454,27 +455,30 @@ uart_change_speed(struct uart_state *state, struct ktermios *old_termios) port->ops->set_termios(port, termios, old_termios); } -static inline void +static inline int __uart_put_char(struct uart_port *port, struct circ_buf *circ, unsigned char c) { unsigned long flags; + int ret = 0; if (!circ->buf) - return; + return 0; spin_lock_irqsave(&port->lock, flags); if (uart_circ_chars_free(circ) != 0) { circ->buf[circ->head] = c; circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1); + ret = 1; } spin_unlock_irqrestore(&port->lock, flags); + return ret; } -static void uart_put_char(struct tty_struct *tty, unsigned char ch) +static int uart_put_char(struct tty_struct *tty, unsigned char ch) { struct uart_state *state = tty->driver_data; - __uart_put_char(state->port, &state->info->xmit, ch); + return __uart_put_char(state->port, &state->info->xmit, ch); } static void uart_flush_chars(struct tty_struct *tty) @@ -528,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; /* @@ -554,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); @@ -618,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; @@ -637,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; @@ -914,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) @@ -1070,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. */ @@ -1140,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; } @@ -1169,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 */ @@ -1202,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 @@ -1318,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 @@ -1368,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(); } /* @@ -2081,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);