X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fserial%2Fserial_core.c;h=17839e753e4cfb1fb550832d8613b0ec579c83ef;hb=4e76c8a9fa413ccc09d3f7f664183dcce3555d57;hp=66bb3cfb22f06f800add7e251258170fbe3413be;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index 66bb3cfb2..17839e753 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -32,6 +32,8 @@ #include #include #include /* for serial_state and serial_icounter_struct */ +#include +#include #include #include @@ -46,7 +48,7 @@ /* * This is used to lock changes in serial line configuration. */ -static DECLARE_MUTEX(port_sem); +static DEFINE_MUTEX(port_mutex); #define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) @@ -69,6 +71,11 @@ static void uart_change_pm(struct uart_state *state, int pm_state); void uart_write_wakeup(struct uart_port *port) { struct uart_info *info = port->info; + /* + * This means you called this function _after_ the port was + * closed. No cookie for you. + */ + BUG_ON(!info); tasklet_schedule(&info->tlet); } @@ -79,7 +86,7 @@ static void uart_stop(struct tty_struct *tty) unsigned long flags; spin_lock_irqsave(&port->lock, flags); - port->ops->stop_tx(port, 1); + port->ops->stop_tx(port); spin_unlock_irqrestore(&port->lock, flags); } @@ -90,7 +97,7 @@ static void __uart_start(struct tty_struct *tty) if (!uart_circ_empty(&state->info->xmit) && state->info->xmit.buf && !tty->stopped && !tty->hw_stopped) - port->ops->start_tx(port, 1); + port->ops->start_tx(port); } static void uart_start(struct tty_struct *tty) @@ -107,15 +114,7 @@ static void uart_start(struct tty_struct *tty) static void uart_tasklet_action(unsigned long data) { struct uart_state *state = (struct uart_state *)data; - struct tty_struct *tty; - - tty = state->info->tty; - if (tty) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - tty->ldisc.write_wakeup(tty); - wake_up_interruptible(&tty->write_wait); - } + tty_wakeup(state->info->tty); } static inline void @@ -154,8 +153,7 @@ static int uart_startup(struct uart_state *state, int init_hw) * once we have successfully opened the port. Also set * up the tty->alt_speed kludge */ - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); + set_bit(TTY_IO_ERROR, &info->tty->flags); if (port->type == PORT_UNKNOWN) return 0; @@ -170,8 +168,6 @@ static int uart_startup(struct uart_state *state, int init_hw) return -ENOMEM; info->xmit.buf = (unsigned char *) page; - info->tmpbuf = info->xmit.buf + UART_XMIT_SIZE; - init_MUTEX(&info->tmpbuf_sem); uart_circ_clear(&info->xmit); } @@ -191,6 +187,13 @@ static int uart_startup(struct uart_state *state, int init_hw) uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR); } + if (info->flags & UIF_CTS_FLOW) { + spin_lock_irq(&port->lock); + if (!(port->ops->get_mctrl(port) & TIOCM_CTS)) + info->tty->hw_stopped = 1; + spin_unlock_irq(&port->lock); + } + info->flags |= UIF_INITIALIZED; clear_bit(TTY_IO_ERROR, &info->tty->flags); @@ -212,33 +215,45 @@ static void uart_shutdown(struct uart_state *state) struct uart_info *info = state->info; struct uart_port *port = state->port; - if (!(info->flags & UIF_INITIALIZED)) - return; - /* - * Turn off DTR and RTS early. + * Set the TTY IO error marker */ - if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) - uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); - /* - * clear delta_msr_wait queue to avoid mem leaks: we may free - * the irq here so the queue might never be woken up. Note - * that we won't end up waiting on delta_msr_wait again since - * any outstanding file descriptors should be pointing at - * hung_up_tty_fops now. - */ - wake_up_interruptible(&info->delta_msr_wait); + if (info->flags & UIF_INITIALIZED) { + info->flags &= ~UIF_INITIALIZED; - /* - * Free the IRQ and disable the port. - */ - port->ops->shutdown(port); + /* + * Turn off DTR and RTS early. + */ + if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) + uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); + + /* + * clear delta_msr_wait queue to avoid mem leaks: we may free + * the irq here so the queue might never be woken up. Note + * that we won't end up waiting on delta_msr_wait again since + * any outstanding file descriptors should be pointing at + * hung_up_tty_fops now. + */ + wake_up_interruptible(&info->delta_msr_wait); + + /* + * Free the IRQ and disable the port. + */ + port->ops->shutdown(port); + + /* + * Ensure that the IRQ handler isn't running on another CPU. + */ + synchronize_irq(port->irq); + } /* - * Ensure that the IRQ handler isn't running on another CPU. + * kill off our tasklet */ - synchronize_irq(port->irq); + tasklet_kill(&info->tlet); /* * Free the transmit buffer page. @@ -246,17 +261,7 @@ static void uart_shutdown(struct uart_state *state) if (info->xmit.buf) { free_page((unsigned long)info->xmit.buf); info->xmit.buf = NULL; - info->tmpbuf = NULL; } - - /* - * kill off our tasklet - */ - tasklet_kill(&info->tlet); - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); - - info->flags &= ~UIF_INITIALIZED; } /** @@ -332,7 +337,7 @@ uart_get_baud_rate(struct uart_port *port, struct termios *termios, struct termios *old, unsigned int min, unsigned int max) { unsigned int try, baud, altbaud = 38400; - unsigned int flags = port->flags & UPF_SPD_MASK; + upf_t flags = port->flags & UPF_SPD_MASK; if (flags == UPF_SPD_HI) altbaud = 57600; @@ -403,7 +408,7 @@ uart_get_divisor(struct uart_port *port, unsigned int baud) if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) quot = port->custom_divisor; else - quot = port->uartclk / (16 * baud); + quot = (port->uartclk + (8 * baud)) / (16 * baud); return quot; } @@ -458,53 +463,42 @@ __uart_put_char(struct uart_port *port, struct circ_buf *circ, unsigned char c) spin_unlock_irqrestore(&port->lock, flags); } -static inline int -__uart_user_write(struct uart_port *port, struct circ_buf *circ, - const unsigned char *buf, int count) +static void uart_put_char(struct tty_struct *tty, unsigned char ch) { - unsigned long flags; - int c, ret = 0; - - if (down_interruptible(&port->info->tmpbuf_sem)) - return -EINTR; - - while (1) { - int c1; - c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); - if (count < c) - c = count; - if (c <= 0) - break; + struct uart_state *state = tty->driver_data; - c -= copy_from_user(port->info->tmpbuf, buf, c); - if (!c) { - if (!ret) - ret = -EFAULT; - break; - } - spin_lock_irqsave(&port->lock, flags); - c1 = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); - if (c1 < c) - c = c1; - memcpy(circ->buf + circ->head, port->info->tmpbuf, c); - circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1); - spin_unlock_irqrestore(&port->lock, flags); - buf += c; - count -= c; - ret += c; - } - up(&port->info->tmpbuf_sem); + __uart_put_char(state->port, &state->info->xmit, ch); +} - return ret; +static void uart_flush_chars(struct tty_struct *tty) +{ + uart_start(tty); } -static inline int -__uart_kern_write(struct uart_port *port, struct circ_buf *circ, - const unsigned char *buf, int count) +static int +uart_write(struct tty_struct *tty, const unsigned char *buf, int count) { + struct uart_state *state = tty->driver_data; + struct uart_port *port; + struct circ_buf *circ; unsigned long flags; int c, ret = 0; + /* + * This means you called this function _after_ the port was + * closed. No cookie for you. + */ + if (!state || !state->info) { + WARN_ON(1); + return -EL3HLT; + } + + port = state->port; + circ = &state->info->xmit; + + if (!circ->buf) + return 0; + spin_lock_irqsave(&port->lock, flags); while (1) { c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); @@ -520,36 +514,6 @@ __uart_kern_write(struct uart_port *port, struct circ_buf *circ, } spin_unlock_irqrestore(&port->lock, flags); - return ret; -} - -static void 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); -} - -static void uart_flush_chars(struct tty_struct *tty) -{ - uart_start(tty); -} - -static int -uart_write(struct tty_struct *tty, int from_user, const unsigned char * buf, - int count) -{ - struct uart_state *state = tty->driver_data; - int ret; - - if (!state->info->xmit.buf) - return 0; - - if (from_user) - ret = __uart_user_write(state->port, &state->info->xmit, buf, count); - else - ret = __uart_kern_write(state->port, &state->info->xmit, buf, count); - uart_start(tty); return ret; } @@ -574,15 +538,21 @@ static void uart_flush_buffer(struct tty_struct *tty) struct uart_port *port = state->port; unsigned long flags; + /* + * This means you called this function _after_ the port was + * closed. No cookie for you. + */ + if (!state || !state->info) { + WARN_ON(1); + return; + } + DPRINTK("uart_flush_buffer(%d) called\n", tty->index); spin_lock_irqsave(&port->lock, flags); uart_circ_clear(&state->info->xmit); spin_unlock_irqrestore(&port->lock, flags); - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } /* @@ -601,7 +571,7 @@ static void uart_send_xchar(struct tty_struct *tty, char ch) port->x_char = ch; if (ch) { spin_lock_irqsave(&port->lock, flags); - port->ops->start_tx(port, 0); + port->ops->start_tx(port); spin_unlock_irqrestore(&port->lock, flags); } } @@ -634,7 +604,8 @@ static void uart_unthrottle(struct tty_struct *tty) uart_set_mctrl(port, TIOCM_RTS); } -static int uart_get_info(struct uart_state *state, struct serial_struct *retinfo) +static int uart_get_info(struct uart_state *state, + struct serial_struct __user *retinfo) { struct uart_port *port = state->port; struct serial_struct tmp; @@ -649,8 +620,10 @@ static int uart_get_info(struct uart_state *state, struct serial_struct *retinfo tmp.flags = port->flags; tmp.xmit_fifo_size = port->fifosize; tmp.baud_base = port->uartclk / 16; - tmp.close_delay = state->close_delay; - tmp.closing_wait = state->closing_wait; + tmp.close_delay = state->close_delay / 10; + tmp.closing_wait = state->closing_wait == USF_CLOSING_WAIT_NONE ? + ASYNC_CLOSING_WAIT_NONE : + state->closing_wait / 10; tmp.custom_divisor = port->custom_divisor; tmp.hub6 = port->hub6; tmp.io_type = port->iotype; @@ -662,14 +635,15 @@ static int uart_get_info(struct uart_state *state, struct serial_struct *retinfo return 0; } -static int -uart_set_info(struct uart_state *state, struct serial_struct *newinfo) +static int uart_set_info(struct uart_state *state, + struct serial_struct __user *newinfo) { struct serial_struct new_serial; struct uart_port *port = state->port; unsigned long new_port; - unsigned int change_irq, change_port, old_flags; - unsigned int old_custom_divisor; + unsigned int change_irq, change_port, closing_wait; + unsigned int old_custom_divisor, close_delay; + upf_t old_flags, new_flags; int retval = 0; if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) @@ -680,6 +654,9 @@ uart_set_info(struct uart_state *state, struct serial_struct *newinfo) new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET; new_serial.irq = irq_canonicalize(new_serial.irq); + close_delay = new_serial.close_delay * 10; + closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ? + USF_CLOSING_WAIT_NONE : new_serial.closing_wait * 10; /* * This semaphore protects state->count. It is also @@ -688,7 +665,7 @@ uart_set_info(struct uart_state *state, struct serial_struct *newinfo) * module insertion/removal doesn't change anything * under us. */ - down(&state->sem); + mutex_lock(&state->mutex); change_irq = new_serial.irq != port->irq; @@ -705,19 +682,20 @@ uart_set_info(struct uart_state *state, struct serial_struct *newinfo) new_serial.type != port->type; old_flags = port->flags; + new_flags = new_serial.flags; old_custom_divisor = port->custom_divisor; if (!capable(CAP_SYS_ADMIN)) { retval = -EPERM; if (change_irq || change_port || (new_serial.baud_base != port->uartclk / 16) || - (new_serial.close_delay != state->close_delay) || - (new_serial.closing_wait != state->closing_wait) || + (close_delay != state->close_delay) || + (closing_wait != state->closing_wait) || (new_serial.xmit_fifo_size != port->fifosize) || - (((new_serial.flags ^ old_flags) & ~UPF_USR_MASK) != 0)) + (((new_flags ^ old_flags) & ~UPF_USR_MASK) != 0)) goto exit; port->flags = ((port->flags & ~UPF_USR_MASK) | - (new_serial.flags & UPF_USR_MASK)); + (new_flags & UPF_USR_MASK)); port->custom_divisor = new_serial.custom_divisor; goto check_and_exit; } @@ -814,10 +792,10 @@ uart_set_info(struct uart_state *state, struct serial_struct *newinfo) port->irq = new_serial.irq; port->uartclk = new_serial.baud_base * 16; port->flags = (port->flags & ~UPF_CHANGE_MASK) | - (new_serial.flags & UPF_CHANGE_MASK); + (new_flags & UPF_CHANGE_MASK); port->custom_divisor = new_serial.custom_divisor; - state->close_delay = new_serial.close_delay * HZ / 100; - state->closing_wait = new_serial.closing_wait * HZ / 100; + state->close_delay = close_delay; + state->closing_wait = closing_wait; port->fifosize = new_serial.xmit_fifo_size; if (state->info->tty) state->info->tty->low_latency = @@ -847,7 +825,7 @@ uart_set_info(struct uart_state *state, struct serial_struct *newinfo) } else retval = uart_startup(state, 1); exit: - up(&state->sem); + mutex_unlock(&state->mutex); return retval; } @@ -856,7 +834,8 @@ uart_set_info(struct uart_state *state, struct serial_struct *newinfo) * uart_get_lsr_info - get line status register info. * Note: uart_ioctl protects us against hangups. */ -static int uart_get_lsr_info(struct uart_state *state, unsigned int *value) +static int uart_get_lsr_info(struct uart_state *state, + unsigned int __user *value) { struct uart_port *port = state->port; unsigned int result; @@ -883,13 +862,16 @@ static int uart_tiocmget(struct tty_struct *tty, struct file *file) struct uart_port *port = state->port; int result = -EIO; - down(&state->sem); + mutex_lock(&state->mutex); if ((!file || !tty_hung_up_p(file)) && !(tty->flags & (1 << TTY_IO_ERROR))) { result = port->mctrl; + + spin_lock_irq(&port->lock); result |= port->ops->get_mctrl(port); + spin_unlock_irq(&port->lock); } - up(&state->sem); + mutex_unlock(&state->mutex); return result; } @@ -902,13 +884,13 @@ uart_tiocmset(struct tty_struct *tty, struct file *file, struct uart_port *port = state->port; int ret = -EIO; - down(&state->sem); + mutex_lock(&state->mutex); if ((!file || !tty_hung_up_p(file)) && !(tty->flags & (1 << TTY_IO_ERROR))) { uart_update_mctrl(port, set, clear); ret = 0; } - up(&state->sem); + mutex_unlock(&state->mutex); return ret; } @@ -919,12 +901,12 @@ static void uart_break_ctl(struct tty_struct *tty, int break_state) BUG_ON(!kernel_locked()); - down(&state->sem); + mutex_lock(&state->mutex); if (port->type != PORT_UNKNOWN) port->ops->break_ctl(port, break_state); - up(&state->sem); + mutex_unlock(&state->mutex); } static int uart_do_autoconfig(struct uart_state *state) @@ -940,7 +922,7 @@ static int uart_do_autoconfig(struct uart_state *state) * changing, and hence any extra opens of the port while * we're auto-configuring. */ - if (down_interruptible(&state->sem)) + if (mutex_lock_interruptible(&state->mutex)) return -ERESTARTSYS; ret = -EBUSY; @@ -966,7 +948,7 @@ static int uart_do_autoconfig(struct uart_state *state) ret = uart_startup(state, 1); } - up(&state->sem); + mutex_unlock(&state->mutex); return ret; } @@ -1035,8 +1017,8 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg) * NB: both 1->0 and 0->1 transitions are counted except for * RI where only 0->1 is counted. */ -static int -uart_get_count(struct uart_state *state, struct serial_icounter_struct *icnt) +static int uart_get_count(struct uart_state *state, + struct serial_icounter_struct __user *icnt) { struct serial_icounter_struct icount; struct uart_icount cnow; @@ -1069,6 +1051,7 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, unsigned long arg) { struct uart_state *state = tty->driver_data; + void __user *uarg = (void __user *)arg; int ret = -ENOIOCTLCMD; BUG_ON(!kernel_locked()); @@ -1078,11 +1061,11 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, */ switch (cmd) { case TIOCGSERIAL: - ret = uart_get_info(state, (struct serial_struct *)arg); + ret = uart_get_info(state, uarg); break; case TIOCSSERIAL: - ret = uart_set_info(state, (struct serial_struct *)arg); + ret = uart_set_info(state, uarg); break; case TIOCSERCONFIG: @@ -1112,14 +1095,14 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, break; case TIOCGICOUNT: - ret = uart_get_count(state, (struct serial_icounter_struct *)arg); + ret = uart_get_count(state, uarg); break; } if (ret != -ENOIOCTLCMD) goto out; - down(&state->sem); + mutex_lock(&state->mutex); if (tty_hung_up_p(filp)) { ret = -EIO; @@ -1132,7 +1115,7 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, */ switch (cmd) { case TIOCSERGETLSR: /* Get line status register */ - ret = uart_get_lsr_info(state, (unsigned int *)arg); + ret = uart_get_lsr_info(state, uarg); break; default: { @@ -1143,7 +1126,7 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, } } out_up: - up(&state->sem); + mutex_unlock(&state->mutex); out: return ret; } @@ -1189,6 +1172,16 @@ static void uart_set_termios(struct tty_struct *tty, struct termios *old_termios spin_unlock_irqrestore(&state->port->lock, flags); } + /* Handle turning on CRTSCTS */ + if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) { + spin_lock_irqsave(&state->port->lock, flags); + if (!(state->port->ops->get_mctrl(state->port) & TIOCM_CTS)) { + tty->hw_stopped = 1; + state->port->ops->stop_tx(state->port); + } + spin_unlock_irqrestore(&state->port->lock, flags); + } + #if 0 /* * No need to wake up processes in open wait, since they @@ -1211,7 +1204,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp) { struct uart_state *state = tty->driver_data; struct uart_port *port; - + BUG_ON(!kernel_locked()); if (!state || !state->port) @@ -1221,7 +1214,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp) DPRINTK("uart_close(%d) called\n", port->line); - down(&state->sem); + mutex_lock(&state->mutex); if (tty_hung_up_p(filp)) goto done; @@ -1234,12 +1227,12 @@ static void uart_close(struct tty_struct *tty, struct file *filp) * one, we've got real problems, since it means the * serial port won't be shutdown. */ - printk("uart_close: bad serial port count; tty->count is 1, " + printk(KERN_ERR "uart_close: bad serial port count; tty->count is 1, " "state->count is %d\n", state->count); state->count = 1; } if (--state->count < 0) { - printk("rs_close: bad serial port count for %s: %d\n", + printk(KERN_ERR "uart_close: bad serial port count for %s: %d\n", tty->name, state->count); state->count = 0; } @@ -1254,7 +1247,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp) tty->closing = 1; if (state->closing_wait != USF_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, state->closing_wait); + tty_wait_until_sent(tty, msecs_to_jiffies(state->closing_wait)); /* * At this point, we stop accepting input. To do this, we @@ -1275,16 +1268,15 @@ static void uart_close(struct tty_struct *tty, struct file *filp) uart_shutdown(state); uart_flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + + tty_ldisc_flush(tty); + tty->closing = 0; state->info->tty = NULL; if (state->info->blocked_open) { - if (state->close_delay) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(state->close_delay); - } + if (state->close_delay) + msleep_interruptible(state->close_delay); } else if (!uart_console(port)) { uart_change_pm(state, 3); } @@ -1296,7 +1288,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp) wake_up_interruptible(&state->info->open_wait); done: - up(&state->sem); + mutex_unlock(&state->mutex); } static void uart_wait_until_sent(struct tty_struct *tty, int timeout) @@ -1348,8 +1340,7 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout) * we wait. */ while (!port->ops->tx_empty(port)) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(char_time); + msleep_interruptible(jiffies_to_msecs(char_time)); if (signal_pending(current)) break; if (time_after(jiffies, expire)) @@ -1371,7 +1362,7 @@ static void uart_hangup(struct tty_struct *tty) BUG_ON(!kernel_locked()); DPRINTK("uart_hangup(%d)\n", state->port->line); - down(&state->sem); + mutex_lock(&state->mutex); if (state->info && state->info->flags & UIF_NORMAL_ACTIVE) { uart_flush_buffer(tty); uart_shutdown(state); @@ -1381,7 +1372,7 @@ static void uart_hangup(struct tty_struct *tty) wake_up_interruptible(&state->info->open_wait); wake_up_interruptible(&state->info->delta_msr_wait); } - up(&state->sem); + mutex_unlock(&state->mutex); } /* @@ -1429,6 +1420,7 @@ uart_block_til_ready(struct file *filp, struct uart_state *state) DECLARE_WAITQUEUE(wait, current); struct uart_info *info = state->info; struct uart_port *port = state->port; + unsigned int mctrl; info->blocked_open++; state->count--; @@ -1476,12 +1468,16 @@ uart_block_til_ready(struct file *filp, struct uart_state *state) * and wait for the carrier to indicate that the * modem is ready for us. */ - if (port->ops->get_mctrl(port) & TIOCM_CAR) + spin_lock_irq(&port->lock); + port->ops->enable_ms(port); + mctrl = port->ops->get_mctrl(port); + spin_unlock_irq(&port->lock); + if (mctrl & TIOCM_CAR) break; - up(&state->sem); + mutex_unlock(&state->mutex); schedule(); - down(&state->sem); + mutex_lock(&state->mutex); if (signal_pending(current)) break; @@ -1504,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; - down(&port_sem); state = drv->state + line; - if (down_interruptible(&state->sem)) { - state = ERR_PTR(-ERESTARTSYS); - goto out; + if (mutex_lock_interruptible(&state->mutex)) { + ret = -ERESTARTSYS; + goto err; } state->count++; - if (!state->port) { - state->count--; - up(&state->sem); - state = ERR_PTR(-ENXIO); - goto out; + if (!state->port || state->port->flags & UPF_DEAD) { + ret = -ENXIO; + goto err_unlock; } if (!state->info) { @@ -1535,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--; - up(&state->sem); - state = ERR_PTR(-ENOMEM); + ret = -ENOMEM; + goto err_unlock; } } - - out: - up(&port_sem); return state; + + err_unlock: + state->count--; + mutex_unlock(&state->mutex); + err: + return ERR_PTR(ret); } /* @@ -1603,7 +1599,7 @@ static int uart_open(struct tty_struct *tty, struct file *filp) if (tty_hung_up_p(filp)) { retval = -EAGAIN; state->count--; - up(&state->sem); + mutex_unlock(&state->mutex); goto fail; } @@ -1623,7 +1619,7 @@ static int uart_open(struct tty_struct *tty, struct file *filp) */ if (retval == 0) retval = uart_block_til_ready(filp, state); - up(&state->sem); + mutex_unlock(&state->mutex); /* * If this is the first open to succeed, adjust things to suit. @@ -1678,7 +1674,9 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i) if(capable(CAP_SYS_ADMIN)) { + spin_lock_irq(&port->lock); status = port->ops->get_mctrl(port); + spin_unlock_irq(&port->lock); ret += sprintf(buf + ret, " tx:%d rx:%d", port->icount.tx, port->icount.rx); @@ -1756,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 @@ -1811,7 +1830,7 @@ struct baud_rates { unsigned int cflag; }; -static struct baud_rates baud_rates[] = { +static const struct baud_rates baud_rates[] = { { 921600, B921600 }, { 460800, B460800 }, { 230400, B230400 }, @@ -1842,6 +1861,12 @@ uart_set_options(struct uart_port *port, struct console *co, struct termios termios; int i; + /* + * Ensure that the serial console lock is initialised + * early. + */ + spin_lock_init(&port->lock); + memset(&termios, 0, sizeof(struct termios)); termios.c_cflag = CREAD | HUPCL | CLOCAL; @@ -1882,22 +1907,25 @@ 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) { struct uart_state *state = drv->state + port->line; - down(&state->sem); + mutex_lock(&state->mutex); if (state->info && state->info->flags & UIF_INITIALIZED) { - struct uart_ops *ops = port->ops; + const struct uart_ops *ops = port->ops; spin_lock_irq(&port->lock); - ops->stop_tx(port, 0); + ops->stop_tx(port); ops->set_mctrl(port, 0); ops->stop_rx(port); spin_unlock_irq(&port->lock); @@ -1906,10 +1934,8 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port) * Wait for the transmitter to empty. */ while (!ops->tx_empty(port)) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(10*HZ/1000); + msleep(10); } - set_current_state(TASK_RUNNING); ops->shutdown(port); } @@ -1918,11 +1944,11 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port) * Disable the console device before suspending. */ if (uart_console(port)) - port->cons->flags &= ~CON_ENABLED; + console_stop(port->cons); uart_change_pm(state, 3); - up(&state->sem); + mutex_unlock(&state->mutex); return 0; } @@ -1931,7 +1957,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port) { struct uart_state *state = drv->state + port->line; - down(&state->sem); + mutex_lock(&state->mutex); uart_change_pm(state, 0); @@ -1939,23 +1965,48 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port) * Re-enable the console device after suspending. */ if (uart_console(port)) { - uart_change_speed(state, NULL); - port->cons->flags |= CON_ENABLED; + struct termios termios; + + /* + * First try to use the console cflag setting. + */ + memset(&termios, 0, sizeof(struct termios)); + termios.c_cflag = port->cons->cflag; + + /* + * If that's unset, use the tty termios setting. + */ + if (state->info && state->info->tty && termios.c_cflag == 0) + termios = *state->info->tty->termios; + + port->ops->set_termios(port, &termios, NULL); + console_start(port->cons); } if (state->info && state->info->flags & UIF_INITIALIZED) { - struct uart_ops *ops = port->ops; + const struct uart_ops *ops = port->ops; + int ret; ops->set_mctrl(port, 0); - ops->startup(port); - uart_change_speed(state, NULL); - spin_lock_irq(&port->lock); - ops->set_mctrl(port, port->mctrl); - ops->start_tx(port, 0); - spin_unlock_irq(&port->lock); + ret = ops->startup(port); + if (ret == 0) { + uart_change_speed(state, NULL); + spin_lock_irq(&port->lock); + ops->set_mctrl(port, port->mctrl); + ops->start_tx(port); + spin_unlock_irq(&port->lock); + } 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); + } } - up(&state->sem); + mutex_unlock(&state->mutex); return 0; } @@ -1963,20 +2014,32 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port) static inline void uart_report_port(struct uart_driver *drv, struct uart_port *port) { - printk("%s%d", drv->dev_name, port->line); - printk(" at "); + char address[64]; + switch (port->iotype) { case UPIO_PORT: - printk("I/O 0x%x", port->iobase); + snprintf(address, sizeof(address), + "I/O 0x%x", port->iobase); break; case UPIO_HUB6: - printk("I/O 0x%x offset 0x%x", port->iobase, port->hub6); + snprintf(address, sizeof(address), + "I/O 0x%x offset 0x%x", port->iobase, port->hub6); break; case UPIO_MEM: - printk("MMIO 0x%lx", port->mapbase); + case UPIO_MEM32: + case UPIO_AU: + snprintf(address, sizeof(address), + "MMIO 0x%lx", port->mapbase); + break; + default: + strlcpy(address, "*unknown*", sizeof(address)); break; } - printk(" (irq = %d) is a %s\n", port->irq, uart_type(port)); + + printk(KERN_INFO "%s%s%s%d at %s (irq = %d) is a %s\n", + port->dev ? port->dev->bus_id : "", + port->dev ? ": " : "", + drv->dev_name, port->line, address, port->irq, uart_type(port)); } static void @@ -2025,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); - - down(&state->sem); - - 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); - } - - up(&state->sem); -} - static struct tty_operations uart_ops = { .open = uart_open, .close = uart_close, @@ -2147,10 +2171,10 @@ int uart_register_driver(struct uart_driver *drv) for (i = 0; i < drv->nr; i++) { struct uart_state *state = drv->state + i; - state->close_delay = 5 * HZ / 10; - state->closing_wait = 30 * HZ; + state->close_delay = 500; /* .5 seconds */ + state->closing_wait = 30000; /* 30 seconds */ - init_MUTEX(&state->sem); + mutex_init(&state->mutex); } retval = tty_register_driver(normal); @@ -2209,7 +2233,8 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) state = drv->state + port->line; - down(&port_sem); + mutex_lock(&port_mutex); + mutex_lock(&state->mutex); if (state->port) { ret = -EINVAL; goto out; @@ -2217,10 +2242,16 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) state->port = port; - spin_lock_init(&port->lock); port->cons = drv->cons; port->info = state->info; + /* + * If this port is a console, then the spinlock is already + * initialised. + */ + if (!(uart_console(port) && (port->cons->flags & CON_ENABLED))) + spin_lock_init(&port->lock); + uart_configure_port(drv, state, port); /* @@ -2229,8 +2260,23 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) */ tty_register_device(drv->tty_driver, port->line, port->dev); + /* + * If this driver supports console, and it hasn't been + * successfully registered yet, try to re-register it. + * It may be that the port was not available. + */ + if (port->type != PORT_UNKNOWN && + port->cons && !(port->cons->flags & CON_ENABLED)) + register_console(port->cons); + + /* + * Ensure UPF_DEAD is not set. + */ + port->flags &= ~UPF_DEAD; + out: - up(&port_sem); + mutex_unlock(&state->mutex); + mutex_unlock(&port_mutex); return ret; } @@ -2247,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()); @@ -2254,16 +2301,53 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port) printk(KERN_ALERT "Removing wrong port: %p != %p\n", state->port, port); - down(&port_sem); + 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; - up(&port_sem); + mutex_unlock(&port_mutex); return 0; } @@ -2271,7 +2355,7 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port) /* * Are the two ports equivalent? */ -static int uart_match_port(struct uart_port *port1, struct uart_port *port2) +int uart_match_port(struct uart_port *port1, struct uart_port *port2) { if (port1->iotype != port2->iotype) return 0; @@ -2283,148 +2367,17 @@ static int uart_match_port(struct uart_port *port1, struct uart_port *port2) return (port1->iobase == port2->iobase) && (port1->hub6 == port2->hub6); case UPIO_MEM: - return (port1->membase == port2->membase); + return (port1->mapbase == port2->mapbase); } return 0; } - -/* - * Try to find an unused uart_state slot for a port. - */ -static struct uart_state * -uart_find_match_or_unused(struct uart_driver *drv, struct uart_port *port) -{ - int i; - - /* - * First, find a port entry which matches. Note: if we do - * find a matching entry, and it has a non-zero use count, - * then we can't register the port. - */ - for (i = 0; i < drv->nr; i++) - if (uart_match_port(drv->state[i].port, port)) - return &drv->state[i]; - - /* - * We didn't find a matching entry, so look for the first - * free entry. We look for one which hasn't been previously - * used (indicated by zero iobase). - */ - for (i = 0; i < drv->nr; i++) - if (drv->state[i].port->type == PORT_UNKNOWN && - drv->state[i].port->iobase == 0 && - drv->state[i].count == 0) - return &drv->state[i]; - - /* - * That also failed. Last resort is to find any currently - * entry which doesn't have a real port associated with it. - */ - for (i = 0; i < drv->nr; i++) - if (drv->state[i].port->type == PORT_UNKNOWN && - drv->state[i].count == 0) - return &drv->state[i]; - - return NULL; -} - -/** - * uart_register_port: register uart settings with a port - * @drv: pointer to the uart low level driver structure for this port - * @port: uart port structure describing the port - * - * Register UART settings with the specified low level driver. Detect - * the type of the port if UPF_BOOT_AUTOCONF is set, and detect the - * IRQ if UPF_AUTO_IRQ is set. - * - * We try to pick the same port for the same IO base address, so that - * when a modem is plugged in, unplugged and plugged back in, it gets - * allocated the same port. - * - * Returns negative error, or positive line number. - */ -int uart_register_port(struct uart_driver *drv, struct uart_port *port) -{ - struct uart_state *state; - int ret; - - down(&port_sem); - - state = uart_find_match_or_unused(drv, port); - - if (state) { - /* - * Ok, we've found a line that we can use. - * - * If we find a port that matches this one, and it appears - * to be in-use (even if it doesn't have a type) we shouldn't - * alter it underneath itself - the port may be open and - * trying to do useful work. - */ - if (uart_users(state) != 0) { - ret = -EBUSY; - goto out; - } - - /* - * If the port is already initialised, don't touch it. - */ - if (state->port->type == PORT_UNKNOWN) { - state->port->iobase = port->iobase; - state->port->membase = port->membase; - state->port->irq = port->irq; - state->port->uartclk = port->uartclk; - state->port->fifosize = port->fifosize; - state->port->regshift = port->regshift; - state->port->iotype = port->iotype; - state->port->flags = port->flags; - state->port->line = state - drv->state; - state->port->mapbase = port->mapbase; - - uart_configure_port(drv, state, state->port); - } - - ret = state->port->line; - } else - ret = -ENOSPC; - out: - up(&port_sem); - return ret; -} - -/** - * uart_unregister_port - de-allocate a port - * @drv: pointer to the uart low level driver structure for this port - * @line: line index previously returned from uart_register_port() - * - * Hang up the specified line associated with the low level driver, - * and mark the port as unused. - */ -void uart_unregister_port(struct uart_driver *drv, int line) -{ - struct uart_state *state; - - if (line < 0 || line >= drv->nr) { - printk(KERN_ERR "Attempt to unregister "); - printk("%s%d", drv->dev_name, line); - printk("\n"); - return; - } - - state = drv->state + line; - - down(&port_sem); - uart_unconfigure_port(drv, state); - up(&port_sem); -} +EXPORT_SYMBOL(uart_match_port); EXPORT_SYMBOL(uart_write_wakeup); EXPORT_SYMBOL(uart_register_driver); EXPORT_SYMBOL(uart_unregister_driver); EXPORT_SYMBOL(uart_suspend_port); EXPORT_SYMBOL(uart_resume_port); -EXPORT_SYMBOL(uart_register_port); -EXPORT_SYMBOL(uart_unregister_port); EXPORT_SYMBOL(uart_add_one_port); EXPORT_SYMBOL(uart_remove_one_port);