diff options
Diffstat (limited to 'drivers/tty/serial/serial_core.c')
-rw-r--r-- | drivers/tty/serial/serial_core.c | 331 |
1 files changed, 201 insertions, 130 deletions
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 0406d7ff505..13056180adf 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -22,6 +22,7 @@ */ #include <linux/module.h> #include <linux/tty.h> +#include <linux/tty_flip.h> #include <linux/slab.h> #include <linux/init.h> #include <linux/console.h> @@ -60,6 +61,8 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, static void uart_wait_until_sent(struct tty_struct *tty, int timeout); static void uart_change_pm(struct uart_state *state, int pm_state); +static void uart_port_shutdown(struct tty_port *port); + /* * This routine is used by the interrupt handler to schedule processing in * the software interrupt portion of the driver. @@ -128,25 +131,16 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear) * Startup the port. This will be called once per open. All calls * will be serialised by the per-port mutex. */ -static int uart_startup(struct tty_struct *tty, struct uart_state *state, int init_hw) +static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, + int init_hw) { struct uart_port *uport = state->uart_port; struct tty_port *port = &state->port; unsigned long page; int retval = 0; - if (port->flags & ASYNC_INITIALIZED) - return 0; - - /* - * Set the TTY IO error marker - we will only clear this - * once we have successfully opened the port. Also set - * up the tty->alt_speed kludge - */ - set_bit(TTY_IO_ERROR, &tty->flags); - if (uport->type == PORT_UNKNOWN) - return 0; + return 1; /* * Initialise and allocate the transmit and temporary @@ -188,10 +182,6 @@ static int uart_startup(struct tty_struct *tty, struct uart_state *state, int in tty->hw_stopped = 1; spin_unlock_irq(&uport->lock); } - - set_bit(ASYNCB_INITIALIZED, &port->flags); - - clear_bit(TTY_IO_ERROR, &tty->flags); } /* @@ -200,6 +190,31 @@ static int uart_startup(struct tty_struct *tty, struct uart_state *state, int in * now. */ if (retval && capable(CAP_SYS_ADMIN)) + return 1; + + return retval; +} + +static int uart_startup(struct tty_struct *tty, struct uart_state *state, + int init_hw) +{ + struct tty_port *port = &state->port; + int retval; + + if (port->flags & ASYNC_INITIALIZED) + return 0; + + /* + * Set the TTY IO error marker - we will only clear this + * once we have successfully opened the port. + */ + set_bit(TTY_IO_ERROR, &tty->flags); + + retval = uart_port_startup(tty, state, init_hw); + if (!retval) { + set_bit(ASYNCB_INITIALIZED, &port->flags); + clear_bit(TTY_IO_ERROR, &tty->flags); + } else if (retval > 0) retval = 0; return retval; @@ -228,24 +243,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) if (!tty || (tty->termios->c_cflag & HUPCL)) uart_clear_mctrl(uport, 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(&port->delta_msr_wait); - - /* - * Free the IRQ and disable the port. - */ - uport->ops->shutdown(uport); - - /* - * Ensure that the IRQ handler isn't running on another CPU. - */ - synchronize_irq(uport->irq); + uart_port_shutdown(port); } /* @@ -423,7 +421,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 + (8 * baud)) / (16 * baud); + quot = DIV_ROUND_CLOSEST(port->uartclk, 16 * baud); return quot; } @@ -658,10 +656,10 @@ static int uart_get_info(struct uart_state *state, tmp.flags = uport->flags; tmp.xmit_fifo_size = uport->fifosize; tmp.baud_base = uport->uartclk / 16; - tmp.close_delay = port->close_delay / 10; + tmp.close_delay = jiffies_to_msecs(port->close_delay) / 10; tmp.closing_wait = port->closing_wait == ASYNC_CLOSING_WAIT_NONE ? ASYNC_CLOSING_WAIT_NONE : - port->closing_wait / 10; + jiffies_to_msecs(port->closing_wait) / 10; tmp.custom_divisor = uport->custom_divisor; tmp.hub6 = uport->hub6; tmp.io_type = uport->iotype; @@ -695,9 +693,10 @@ static int uart_set_info(struct tty_struct *tty, struct uart_state *state, 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; + close_delay = msecs_to_jiffies(new_serial.close_delay * 10); closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ? - ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10; + ASYNC_CLOSING_WAIT_NONE : + msecs_to_jiffies(new_serial.closing_wait * 10); /* * This semaphore protects port->count. It is also @@ -1265,47 +1264,8 @@ static void uart_close(struct tty_struct *tty, struct file *filp) pr_debug("uart_close(%d) called\n", uport->line); - spin_lock_irqsave(&port->lock, flags); - - if (tty_hung_up_p(filp)) { - spin_unlock_irqrestore(&port->lock, flags); + if (tty_port_close_start(port, tty, filp) == 0) return; - } - - if ((tty->count == 1) && (port->count != 1)) { - /* - * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. port->count should always - * be one in these conditions. If it's greater than - * one, we've got real problems, since it means the - * serial port won't be shutdown. - */ - printk(KERN_ERR "uart_close: bad serial port count; tty->count is 1, " - "port->count is %d\n", port->count); - port->count = 1; - } - if (--port->count < 0) { - printk(KERN_ERR "uart_close: bad serial port count for %s: %d\n", - tty->name, port->count); - port->count = 0; - } - if (port->count) { - spin_unlock_irqrestore(&port->lock, flags); - return; - } - - /* - * Now we wait for the transmit buffer to clear; and we notify - * the line discipline to only process XON/XOFF characters by - * setting tty->closing. - */ - set_bit(ASYNCB_CLOSING, &port->flags); - tty->closing = 1; - spin_unlock_irqrestore(&port->lock, flags); - - if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent_from_close(tty, - msecs_to_jiffies(port->closing_wait)); /* * At this point, we stop accepting input. To do this, we @@ -1337,7 +1297,8 @@ static void uart_close(struct tty_struct *tty, struct file *filp) if (port->blocked_open) { spin_unlock_irqrestore(&port->lock, flags); if (port->close_delay) - msleep_interruptible(port->close_delay); + msleep_interruptible( + jiffies_to_msecs(port->close_delay)); spin_lock_irqsave(&port->lock, flags); } else if (!uart_console(uport)) { spin_unlock_irqrestore(&port->lock, flags); @@ -1441,6 +1402,36 @@ static void uart_hangup(struct tty_struct *tty) mutex_unlock(&port->mutex); } +static int uart_port_activate(struct tty_port *port, struct tty_struct *tty) +{ + return 0; +} + +static void uart_port_shutdown(struct tty_port *port) +{ + struct uart_state *state = container_of(port, struct uart_state, port); + struct uart_port *uport = state->uart_port; + + /* + * 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(&port->delta_msr_wait); + + /* + * Free the IRQ and disable the port. + */ + uport->ops->shutdown(uport); + + /* + * Ensure that the IRQ handler isn't running on another CPU. + */ + synchronize_irq(uport->irq); +} + static int uart_carrier_raised(struct tty_port *port) { struct uart_state *state = container_of(port, struct uart_state, port); @@ -1466,33 +1457,6 @@ static void uart_dtr_rts(struct tty_port *port, int onoff) uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS); } -static struct uart_state *uart_get(struct uart_driver *drv, int line) -{ - struct uart_state *state; - struct tty_port *port; - int ret = 0; - - state = drv->state + line; - port = &state->port; - if (mutex_lock_interruptible(&port->mutex)) { - ret = -ERESTARTSYS; - goto err; - } - - port->count++; - if (!state->uart_port || state->uart_port->flags & UPF_DEAD) { - ret = -ENXIO; - goto err_unlock; - } - return state; - - err_unlock: - port->count--; - mutex_unlock(&port->mutex); - err: - return ERR_PTR(ret); -} - /* * calls to uart_open are serialised by the BKL in * fs/char_dev.c:chrdev_open() @@ -1506,26 +1470,29 @@ static struct uart_state *uart_get(struct uart_driver *drv, int line) static int uart_open(struct tty_struct *tty, struct file *filp) { struct uart_driver *drv = (struct uart_driver *)tty->driver->driver_state; - struct uart_state *state; - struct tty_port *port; int retval, line = tty->index; + struct uart_state *state = drv->state + line; + struct tty_port *port = &state->port; pr_debug("uart_open(%d) called\n", line); /* - * We take the semaphore inside uart_get to guarantee that we won't - * be re-entered while allocating the state structure, or while we - * request any IRQs that the driver may need. This also has the nice - * side-effect that it delays the action of uart_hangup, so we can - * guarantee that state->port.tty will always contain something - * reasonable. + * We take the semaphore here to guarantee that we won't be re-entered + * while allocating the state structure, or while we request any IRQs + * that the driver may need. This also has the nice side-effect that + * it delays the action of uart_hangup, so we can guarantee that + * state->port.tty will always contain something reasonable. */ - state = uart_get(drv, line); - if (IS_ERR(state)) { - retval = PTR_ERR(state); - goto fail; + if (mutex_lock_interruptible(&port->mutex)) { + retval = -ERESTARTSYS; + goto end; + } + + port->count++; + if (!state->uart_port || state->uart_port->flags & UPF_DEAD) { + retval = -ENXIO; + goto err_dec_count; } - port = &state->port; /* * Once we set tty->driver_data here, we are guaranteed that @@ -1535,7 +1502,6 @@ static int uart_open(struct tty_struct *tty, struct file *filp) tty->driver_data = state; state->uart_port->state = state; tty->low_latency = (state->uart_port->flags & UPF_LOW_LATENCY) ? 1 : 0; - tty->alt_speed = 0; tty_port_tty_set(port, tty); /* @@ -1543,9 +1509,7 @@ static int uart_open(struct tty_struct *tty, struct file *filp) */ if (tty_hung_up_p(filp)) { retval = -EAGAIN; - port->count--; - mutex_unlock(&port->mutex); - goto fail; + goto err_dec_count; } /* @@ -1566,8 +1530,12 @@ static int uart_open(struct tty_struct *tty, struct file *filp) if (retval == 0) retval = tty_port_block_til_ready(port, tty, filp); -fail: +end: return retval; +err_dec_count: + port->count--; + mutex_unlock(&port->mutex); + goto end; } static const char *uart_type(struct uart_port *port) @@ -1858,6 +1826,14 @@ uart_set_options(struct uart_port *port, struct console *co, EXPORT_SYMBOL_GPL(uart_set_options); #endif /* CONFIG_SERIAL_CORE_CONSOLE */ +/** + * uart_change_pm - set power state of the port + * + * @state: port descriptor + * @pm_state: new state + * + * Locking: port->mutex has to be held + */ static void uart_change_pm(struct uart_state *state, int pm_state) { struct uart_port *port = state->uart_port; @@ -2214,6 +2190,8 @@ static const struct tty_operations uart_ops = { }; static const struct tty_port_operations uart_port_ops = { + .activate = uart_port_activate, + .shutdown = uart_port_shutdown, .carrier_raised = uart_carrier_raised, .dtr_rts = uart_dtr_rts, }; @@ -2275,8 +2253,8 @@ int uart_register_driver(struct uart_driver *drv) tty_port_init(port); port->ops = &uart_port_ops; - port->close_delay = 500; /* .5 seconds */ - port->closing_wait = 30000; /* 30 seconds */ + port->close_delay = HZ / 2; /* .5 seconds */ + port->closing_wait = 30 * HZ;/* 30 seconds */ } retval = tty_register_driver(normal); @@ -2370,11 +2348,11 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) */ tty_dev = tty_register_device(drv->tty_driver, uport->line, uport->dev); if (likely(!IS_ERR(tty_dev))) { - device_init_wakeup(tty_dev, 1); - device_set_wakeup_enable(tty_dev, 0); - } else + device_set_wakeup_capable(tty_dev, 1); + } else { printk(KERN_ERR "Cannot register tty device on line %d\n", uport->line); + } /* * Ensure UPF_DEAD is not set. @@ -2467,6 +2445,99 @@ int uart_match_port(struct uart_port *port1, struct uart_port *port2) } EXPORT_SYMBOL(uart_match_port); +/** + * uart_handle_dcd_change - handle a change of carrier detect state + * @uport: uart_port structure for the open port + * @status: new carrier detect status, nonzero if active + */ +void uart_handle_dcd_change(struct uart_port *uport, unsigned int status) +{ + struct uart_state *state = uport->state; + struct tty_port *port = &state->port; + struct tty_ldisc *ld = tty_ldisc_ref(port->tty); + struct pps_event_time ts; + + if (ld && ld->ops->dcd_change) + pps_get_ts(&ts); + + uport->icount.dcd++; +#ifdef CONFIG_HARD_PPS + if ((uport->flags & UPF_HARDPPS_CD) && status) + hardpps(); +#endif + + if (port->flags & ASYNC_CHECK_CD) { + if (status) + wake_up_interruptible(&port->open_wait); + else if (port->tty) + tty_hangup(port->tty); + } + + if (ld && ld->ops->dcd_change) + ld->ops->dcd_change(port->tty, status, &ts); + if (ld) + tty_ldisc_deref(ld); +} +EXPORT_SYMBOL_GPL(uart_handle_dcd_change); + +/** + * uart_handle_cts_change - handle a change of clear-to-send state + * @uport: uart_port structure for the open port + * @status: new clear to send status, nonzero if active + */ +void uart_handle_cts_change(struct uart_port *uport, unsigned int status) +{ + struct tty_port *port = &uport->state->port; + struct tty_struct *tty = port->tty; + + uport->icount.cts++; + + if (port->flags & ASYNC_CTS_FLOW) { + if (tty->hw_stopped) { + if (status) { + tty->hw_stopped = 0; + uport->ops->start_tx(uport); + uart_write_wakeup(uport); + } + } else { + if (!status) { + tty->hw_stopped = 1; + uport->ops->stop_tx(uport); + } + } + } +} +EXPORT_SYMBOL_GPL(uart_handle_cts_change); + +/** + * uart_insert_char - push a char to the uart layer + * + * User is responsible to call tty_flip_buffer_push when they are done with + * insertion. + * + * @port: corresponding port + * @status: state of the serial port RX buffer (LSR for 8250) + * @overrun: mask of overrun bits in @status + * @ch: character to push + * @flag: flag for the character (see TTY_NORMAL and friends) + */ +void uart_insert_char(struct uart_port *port, unsigned int status, + unsigned int overrun, unsigned int ch, unsigned int flag) +{ + struct tty_struct *tty = port->state->port.tty; + + if ((status & port->ignore_status_mask & ~overrun) == 0) + tty_insert_flip_char(tty, ch, flag); + + /* + * Overrun is special. Since it's reported immediately, + * it doesn't affect the current character. + */ + if (status & ~port->ignore_status_mask & overrun) + tty_insert_flip_char(tty, 0, TTY_OVERRUN); +} +EXPORT_SYMBOL_GPL(uart_insert_char); + EXPORT_SYMBOL(uart_write_wakeup); EXPORT_SYMBOL(uart_register_driver); EXPORT_SYMBOL(uart_unregister_driver); |