--- zzzz-none-000/linux-3.10.107/drivers/tty/serial/serial_core.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/tty/serial/serial_core.c 2021-02-04 17:41:59.000000000 +0000 @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -50,12 +51,6 @@ #define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) -#ifdef CONFIG_SERIAL_CORE_CONSOLE -#define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line) -#else -#define uart_console(port) (0) -#endif - static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, struct ktermios *old_termios); static void uart_wait_until_sent(struct tty_struct *tty, int timeout); @@ -64,6 +59,11 @@ static void uart_port_shutdown(struct tty_port *port); +static int uart_dcd_enabled(struct uart_port *uport) +{ + return !!(uport->status & UPSTAT_DCD_ENABLE); +} + /* * This routine is used by the interrupt handler to schedule processing in * the software interrupt portion of the driver. @@ -95,8 +95,7 @@ struct uart_state *state = tty->driver_data; struct uart_port *port = state->uart_port; - if (!uart_circ_empty(&state->xmit) && state->xmit.buf && - !tty->stopped && !tty->hw_stopped) + if (!uart_tx_stopped(port)) port->ops->start_tx(port); } @@ -136,7 +135,6 @@ int init_hw) { struct uart_port *uport = state->uart_port; - struct tty_port *port = &state->port; unsigned long page; int retval = 0; @@ -144,6 +142,11 @@ return 1; /* + * Make sure the device is in D0 state. + */ + uart_change_pm(state, UART_PM_STATE_ON); + + /* * Initialise and allocate the transmit and temporary * buffer. */ @@ -161,6 +164,8 @@ if (retval == 0) { if (uart_console(uport) && uport->cons->cflag) { tty->termios.c_cflag = uport->cons->cflag; + tty->termios.c_ospeed = uport->cons->baud; + tty->termios.c_ispeed = uport->cons->baud; uport->cons->cflag = 0; } /* @@ -176,13 +181,6 @@ if (tty->termios.c_cflag & CBAUD) uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR); } - - if (tty_port_cts_enabled(port)) { - spin_lock_irq(&uport->lock); - if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) - tty->hw_stopped = 1; - spin_unlock_irq(&uport->lock); - } } /* @@ -339,18 +337,29 @@ 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; + unsigned int try; + unsigned int baud; + unsigned int altbaud; int hung_up = 0; upf_t flags = port->flags & UPF_SPD_MASK; - if (flags == UPF_SPD_HI) + switch (flags) { + case UPF_SPD_HI: altbaud = 57600; - else if (flags == UPF_SPD_VHI) + break; + case UPF_SPD_VHI: altbaud = 115200; - else if (flags == UPF_SPD_SHI) + break; + case UPF_SPD_SHI: altbaud = 230400; - else if (flags == UPF_SPD_WARP) + break; + case UPF_SPD_WARP: altbaud = 460800; + break; + default: + altbaud = 38400; + break; + } for (try = 0; try < 2; try++) { baud = tty_termios_baud_rate(termios); @@ -432,13 +441,13 @@ EXPORT_SYMBOL(uart_get_divisor); -/* FIXME: Consistent locking policy */ +/* Caller holds port mutex */ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, struct ktermios *old_termios) { - struct tty_port *port = &state->port; struct uart_port *uport = state->uart_port; struct ktermios *termios; + int hw_stopped; /* * If we have no tty, termios, or the port does not exist, @@ -448,21 +457,34 @@ return; termios = &tty->termios; + uport->ops->set_termios(uport, termios, old_termios); /* - * Set flags based on termios cflag + * Set modem status enables based on termios cflag */ + spin_lock_irq(&uport->lock); if (termios->c_cflag & CRTSCTS) - set_bit(ASYNCB_CTS_FLOW, &port->flags); + uport->status |= UPSTAT_CTS_ENABLE; else - clear_bit(ASYNCB_CTS_FLOW, &port->flags); + uport->status &= ~UPSTAT_CTS_ENABLE; if (termios->c_cflag & CLOCAL) - clear_bit(ASYNCB_CHECK_CD, &port->flags); + uport->status &= ~UPSTAT_DCD_ENABLE; else - set_bit(ASYNCB_CHECK_CD, &port->flags); + uport->status |= UPSTAT_DCD_ENABLE; - uport->ops->set_termios(uport, termios, old_termios); + /* reset sw-assisted CTS flow control based on (possibly) new mode */ + hw_stopped = uport->hw_stopped; + uport->hw_stopped = uart_softcts_mode(uport) && + !(uport->ops->get_mctrl(uport) & TIOCM_CTS); + if (uport->hw_stopped) { + if (!hw_stopped) + uport->ops->stop_tx(uport); + } else { + if (hw_stopped) + __uart_start(tty); + } + spin_unlock_irq(&uport->lock); } static inline int __uart_put_char(struct uart_port *port, @@ -533,9 +555,10 @@ count -= c; ret += c; } + + __uart_start(tty); spin_unlock_irqrestore(&port->lock, flags); - uart_start(tty); return ret; } @@ -602,12 +625,11 @@ if (port->ops->send_xchar) port->ops->send_xchar(port, ch); else { + spin_lock_irqsave(&port->lock, flags); port->x_char = ch; - if (ch) { - spin_lock_irqsave(&port->lock, flags); + if (ch) port->ops->start_tx(port); - spin_unlock_irqrestore(&port->lock, flags); - } + spin_unlock_irqrestore(&port->lock, flags); } } @@ -615,22 +637,22 @@ { struct uart_state *state = tty->driver_data; struct uart_port *port = state->uart_port; - uint32_t mask = 0; + upstat_t mask = 0; if (I_IXOFF(tty)) - mask |= UPF_SOFT_FLOW; + mask |= UPSTAT_AUTOXOFF; if (tty->termios.c_cflag & CRTSCTS) - mask |= UPF_HARD_FLOW; + mask |= UPSTAT_AUTORTS; - if (port->flags & mask) { + if (port->status & mask) { port->ops->throttle(port); - mask &= ~port->flags; + mask &= ~port->status; } - if (mask & UPF_SOFT_FLOW) + if (mask & UPSTAT_AUTOXOFF) uart_send_xchar(tty, STOP_CHAR(tty)); - if (mask & UPF_HARD_FLOW) + if (mask & UPSTAT_AUTORTS) uart_clear_mctrl(port, TIOCM_RTS); } @@ -638,26 +660,22 @@ { struct uart_state *state = tty->driver_data; struct uart_port *port = state->uart_port; - uint32_t mask = 0; + upstat_t mask = 0; if (I_IXOFF(tty)) - mask |= UPF_SOFT_FLOW; + mask |= UPSTAT_AUTOXOFF; if (tty->termios.c_cflag & CRTSCTS) - mask |= UPF_HARD_FLOW; + mask |= UPSTAT_AUTORTS; - if (port->flags & mask) { + if (port->status & mask) { port->ops->unthrottle(port); - mask &= ~port->flags; + mask &= ~port->status; } - if (mask & UPF_SOFT_FLOW) { - if (port->x_char) - port->x_char = 0; - else - uart_send_xchar(tty, START_CHAR(tty)); - } + if (mask & UPSTAT_AUTOXOFF) + uart_send_xchar(tty, START_CHAR(tty)); - if (mask & UPF_HARD_FLOW) + if (mask & UPSTAT_AUTORTS) uart_set_mctrl(port, TIOCM_RTS); } @@ -835,25 +853,29 @@ * If we fail to request resources for the * new port, try to restore the old settings. */ - if (retval && old_type != PORT_UNKNOWN) { + if (retval) { uport->iobase = old_iobase; uport->type = old_type; uport->hub6 = old_hub6; uport->iotype = old_iotype; uport->regshift = old_shift; uport->mapbase = old_mapbase; - retval = uport->ops->request_port(uport); - /* - * If we failed to restore the old settings, - * we fail like this. - */ - if (retval) - uport->type = PORT_UNKNOWN; - /* - * We failed anyway. - */ - retval = -EBUSY; + if (old_type != PORT_UNKNOWN) { + retval = uport->ops->request_port(uport); + /* + * If we failed to restore the old settings, + * we fail like this. + */ + if (retval) + uport->type = PORT_UNKNOWN; + + /* + * We failed anyway. + */ + retval = -EBUSY; + } + /* Added to return the correct error -Ram Gupta */ goto exit; } @@ -885,11 +907,10 @@ * need to rate-limit; it's CAP_SYS_ADMIN only. */ if (uport->flags & UPF_SPD_MASK) { - char buf[64]; - printk(KERN_NOTICE - "%s sets custom speed on %s. This " - "is deprecated.\n", current->comm, - tty_name(port->tty, buf)); + dev_notice(uport->dev, + "%s sets custom speed on %s. This is deprecated.\n", + current->comm, + tty_name(port->tty)); } uart_change_speed(tty, state, NULL); } @@ -946,7 +967,7 @@ */ if (uport->x_char || ((uart_circ_chars_pending(&state->xmit) > 0) && - !tty->stopped && !tty->hw_stopped)) + !uart_tx_stopped(uport))) result &= ~TIOCSER_TEMT; return put_user(result, value); @@ -1047,6 +1068,15 @@ return ret; } +static void uart_enable_ms(struct uart_port *uport) +{ + /* + * Force modem status interrupts on + */ + if (uport->ops->enable_ms) + uport->ops->enable_ms(uport); +} + /* * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change * - mask passed in arg for lines of interest @@ -1070,11 +1100,7 @@ */ spin_lock_irq(&uport->lock); memcpy(&cprev, &uport->icount, sizeof(struct uart_icount)); - - /* - * Force modem status interrupts on - */ - uport->ops->enable_ms(uport); + uart_enable_ms(uport); spin_unlock_irq(&uport->lock); add_wait_queue(&port->delta_msr_wait, &wait); @@ -1103,8 +1129,7 @@ cprev = cnow; } - - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue(&port->delta_msr_wait, &wait); return ret; @@ -1142,6 +1167,47 @@ return 0; } +static int uart_get_rs485_config(struct uart_port *port, + struct serial_rs485 __user *rs485) +{ + unsigned long flags; + struct serial_rs485 aux; + + spin_lock_irqsave(&port->lock, flags); + aux = port->rs485; + spin_unlock_irqrestore(&port->lock, flags); + + if (copy_to_user(rs485, &aux, sizeof(aux))) + return -EFAULT; + + return 0; +} + +static int uart_set_rs485_config(struct uart_port *port, + struct serial_rs485 __user *rs485_user) +{ + struct serial_rs485 rs485; + int ret; + unsigned long flags; + + if (!port->rs485_config) + return -ENOIOCTLCMD; + + if (copy_from_user(&rs485, rs485_user, sizeof(*rs485_user))) + return -EFAULT; + + spin_lock_irqsave(&port->lock, flags); + ret = port->rs485_config(port, &rs485); + spin_unlock_irqrestore(&port->lock, flags); + if (ret) + return ret; + + if (copy_to_user(rs485_user, &port->rs485, sizeof(port->rs485))) + return -EFAULT; + + return 0; +} + /* * Called via sys_ioctl. We can use spin_lock_irq() here. */ @@ -1164,11 +1230,15 @@ break; case TIOCSSERIAL: + down_write(&tty->termios_rwsem); ret = uart_set_info_user(tty, state, uarg); + up_write(&tty->termios_rwsem); break; case TIOCSERCONFIG: + down_write(&tty->termios_rwsem); ret = uart_do_autoconfig(tty, state); + up_write(&tty->termios_rwsem); break; case TIOCSERGWILD: /* obsolete */ @@ -1208,11 +1278,19 @@ * All these rely on hardware being present and need to be * protected against the tty being hung up. */ + switch (cmd) { case TIOCSERGETLSR: /* Get line status register */ ret = uart_get_lsr_info(tty, state, uarg); break; + case TIOCGRS485: + ret = uart_get_rs485_config(state->uart_port, uarg); + break; + + case TIOCSRS485: + ret = uart_set_rs485_config(state->uart_port, uarg); + break; default: { struct uart_port *uport = state->uart_port; if (uport->ops->ioctl) @@ -1231,8 +1309,11 @@ struct uart_state *state = tty->driver_data; struct uart_port *uport = state->uart_port; - if (uport->ops->set_ldisc) - uport->ops->set_ldisc(uport, tty->termios.c_line); + if (uport->ops->set_ldisc) { + mutex_lock(&state->port.mutex); + uport->ops->set_ldisc(uport, &tty->termios); + mutex_unlock(&state->port.mutex); + } } static void uart_set_termios(struct tty_struct *tty, @@ -1240,7 +1321,6 @@ { struct uart_state *state = tty->driver_data; struct uart_port *uport = state->uart_port; - unsigned long flags; unsigned int cflag = tty->termios.c_cflag; unsigned int iflag_mask = IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK; bool sw_changed = false; @@ -1270,7 +1350,11 @@ return; } + mutex_lock(&state->port.mutex); uart_change_speed(tty, state, old_termios); + mutex_unlock(&state->port.mutex); + /* reload cflag from termios; port driver may have overriden flags */ + cflag = tty->termios.c_cflag; /* Handle transition to B0 status */ if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) @@ -1278,35 +1362,10 @@ /* Handle transition away from B0 status */ else if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) { unsigned int mask = TIOCM_DTR; - if (!(cflag & CRTSCTS) || - !test_bit(TTY_THROTTLED, &tty->flags)) + if (!(cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags)) mask |= TIOCM_RTS; uart_set_mctrl(uport, mask); } - - /* - * If the port is doing h/w assisted flow control, do nothing. - * We assume that tty->hw_stopped has never been set. - */ - if (uport->flags & UPF_HARD_FLOW) - return; - - /* Handle turning off CRTSCTS */ - if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) { - spin_lock_irqsave(&uport->lock, flags); - tty->hw_stopped = 0; - __uart_start(tty); - spin_unlock_irqrestore(&uport->lock, flags); - } - /* Handle turning on CRTSCTS */ - else if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) { - spin_lock_irqsave(&uport->lock, flags); - if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) { - tty->hw_stopped = 1; - uport->ops->stop_tx(uport); - } - spin_unlock_irqrestore(&uport->lock, flags); - } } /* @@ -1320,17 +1379,24 @@ struct uart_state *state = tty->driver_data; struct tty_port *port; struct uart_port *uport; - unsigned long flags; - if (!state) + if (!state) { + struct uart_driver *drv = tty->driver->driver_state; + + state = drv->state + tty->index; + port = &state->port; + spin_lock_irq(&port->lock); + --port->count; + spin_unlock_irq(&port->lock); return; + } uport = state->uart_port; port = &state->port; - pr_debug("uart_close(%d) called\n", uport->line); + pr_debug("uart_close(%d) called\n", uport ? uport->line : -1); - if (tty_port_close_start(port, tty, filp) == 0) + if (!port->count || tty_port_close_start(port, tty, filp) == 0) return; /* @@ -1338,10 +1404,9 @@ * disable the receive line status interrupts. */ if (port->flags & ASYNC_INITIALIZED) { - unsigned long flags; - spin_lock_irqsave(&uport->lock, flags); + spin_lock_irq(&uport->lock); uport->ops->stop_rx(uport); - spin_unlock_irqrestore(&uport->lock, flags); + spin_unlock_irq(&uport->lock); /* * Before we drop DTR, make sure the UART transmitter * has completely drained; this is especially @@ -1352,24 +1417,19 @@ mutex_lock(&port->mutex); uart_shutdown(tty, state); - uart_flush_buffer(tty); - - tty_ldisc_flush(tty); - tty_port_tty_set(port, NULL); - spin_lock_irqsave(&port->lock, flags); - tty->closing = 0; + + spin_lock_irq(&port->lock); if (port->blocked_open) { - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock_irq(&port->lock); if (port->close_delay) - msleep_interruptible( - jiffies_to_msecs(port->close_delay)); - spin_lock_irqsave(&port->lock, flags); + msleep_interruptible(jiffies_to_msecs(port->close_delay)); + spin_lock_irq(&port->lock); } else if (!uart_console(uport)) { - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock_irq(&port->lock); uart_change_pm(state, UART_PM_STATE_OFF); - spin_lock_irqsave(&port->lock, flags); + spin_lock_irq(&port->lock); } /* @@ -1377,11 +1437,13 @@ */ clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); clear_bit(ASYNCB_CLOSING, &port->flags); - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock_irq(&port->lock); wake_up_interruptible(&port->open_wait); - wake_up_interruptible(&port->close_wait); mutex_unlock(&port->mutex); + + tty_ldisc_flush(tty); + tty->closing = 0; } static void uart_wait_until_sent(struct tty_struct *tty, int timeout) @@ -1461,17 +1523,14 @@ clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); spin_unlock_irqrestore(&port->lock, flags); tty_port_tty_set(port, NULL); + if (!uart_console(state->uart_port)) + uart_change_pm(state, UART_PM_STATE_OFF); wake_up_interruptible(&port->open_wait); wake_up_interruptible(&port->delta_msr_wait); } 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); @@ -1503,7 +1562,7 @@ struct uart_port *uport = state->uart_port; int mctrl; spin_lock_irq(&uport->lock); - uport->ops->enable_ms(uport); + uart_enable_ms(uport); mctrl = uport->ops->get_mctrl(uport); spin_unlock_irq(&uport->lock); if (mctrl & TIOCM_CAR) @@ -1541,6 +1600,10 @@ pr_debug("uart_open(%d) called\n", line); + spin_lock_irq(&port->lock); + ++port->count; + spin_unlock_irq(&port->lock); + /* * 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 @@ -1553,17 +1616,11 @@ goto end; } - port->count++; if (!state->uart_port || state->uart_port->flags & UPF_DEAD) { retval = -ENXIO; - goto err_dec_count; + goto err_unlock; } - /* - * Once we set tty->driver_data here, we are guaranteed that - * uart_close() will decrement the driver module use count. - * Any failures from here onwards should not touch the count. - */ tty->driver_data = state; state->uart_port->state = state; state->port.low_latency = @@ -1571,20 +1628,6 @@ tty_port_tty_set(port, tty); /* - * If the port is in the middle of closing, bail out now. - */ - if (tty_hung_up_p(filp)) { - retval = -EAGAIN; - goto err_dec_count; - } - - /* - * Make sure the device is in D0 state. - */ - if (port->count == 1) - uart_change_pm(state, UART_PM_STATE_ON); - - /* * Start up the serial port. */ retval = uart_startup(tty, state, 0); @@ -1598,8 +1641,7 @@ end: return retval; -err_dec_count: - port->count--; +err_unlock: mutex_unlock(&port->mutex); goto end; } @@ -1727,12 +1769,12 @@ #endif #if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL) -/* +/** * 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 + * @putchar: function to write character to port */ void uart_console_write(struct uart_port *port, const char *s, unsigned int count, @@ -1771,7 +1813,60 @@ } /** - * uart_parse_options - Parse serial port baud/parity/bits/flow contro. + * uart_parse_earlycon - Parse earlycon options + * @p: ptr to 2nd field (ie., just beyond ',') + * @iotype: ptr for decoded iotype (out) + * @addr: ptr for decoded mapbase/iobase (out) + * @options: ptr for field; NULL if not present (out) + * + * Decodes earlycon kernel command line parameters of the form + * earlycon=,io|mmio|mmio32|mmio32be|mmio32native,, + * console=,io|mmio|mmio32|mmio32be|mmio32native,, + * + * The optional form + * earlycon=,0x, + * console=,0x, + * is also accepted; the returned @iotype will be UPIO_MEM. + * + * Returns 0 on success or -EINVAL on failure + */ +int uart_parse_earlycon(char *p, unsigned char *iotype, unsigned long *addr, + char **options) +{ + if (strncmp(p, "mmio,", 5) == 0) { + *iotype = UPIO_MEM; + p += 5; + } else if (strncmp(p, "mmio32,", 7) == 0) { + *iotype = UPIO_MEM32; + p += 7; + } else if (strncmp(p, "mmio32be,", 9) == 0) { + *iotype = UPIO_MEM32BE; + p += 9; + } else if (strncmp(p, "mmio32native,", 13) == 0) { + *iotype = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) ? + UPIO_MEM32BE : UPIO_MEM32; + p += 13; + } else if (strncmp(p, "io,", 3) == 0) { + *iotype = UPIO_PORT; + p += 3; + } else if (strncmp(p, "0x", 2) == 0) { + *iotype = UPIO_MEM; + } else { + return -EINVAL; + } + + *addr = simple_strtoul(p, NULL, 0); + p = strchr(p, ','); + if (p) + p++; + + *options = p; + return 0; +} +EXPORT_SYMBOL_GPL(uart_parse_earlycon); + +/** + * uart_parse_options - Parse serial port baud/parity/bits/flow control. * @options: pointer to option string * @baud: pointer to an 'int' variable for the baud rate. * @parity: pointer to an 'int' variable for the parity. @@ -1816,7 +1911,7 @@ { 4800, B4800 }, { 2400, B2400 }, { 1200, B1200 }, - { 0, B38400 } + { 0, BOTHER } }; /** @@ -1839,9 +1934,13 @@ /* * Ensure that the serial console lock is initialised * early. + * If this port is a console, then the spinlock is already + * initialised. */ - spin_lock_init(&port->lock); - lockdep_set_class(&port->lock, &port_lock_key); + if (!(uart_console(port) && (port->cons->flags & CON_ENABLED))) { + spin_lock_init(&port->lock); + lockdep_set_class(&port->lock, &port_lock_key); + } memset(&termios, 0, sizeof(struct ktermios)); @@ -1851,10 +1950,13 @@ * Construct a cflag setting. */ for (i = 0; baud_rates[i].rate; i++) - if (baud_rates[i].rate <= baud) + if (baud_rates[i].rate == baud) break; termios.c_cflag |= baud_rates[i].cflag; + if (!baud_rates[i].rate) { + termios.c_ospeed = baud; + } if (bits == 7) termios.c_cflag |= CS7; @@ -1884,8 +1986,10 @@ * Allow the setting of the UART parameters with a NULL console * too: */ - if (co) + if (co) { co->cflag = termios.c_cflag; + co->baud = baud; + } return 0; } @@ -1946,23 +2050,24 @@ } put_device(tty_dev); - if (console_suspend_enabled || !uart_console(uport)) - uport->suspended = 1; + /* Nothing to do if the console is not suspending */ + if (!console_suspend_enabled && uart_console(uport)) + goto unlock; + + uport->suspended = 1; if (port->flags & ASYNC_INITIALIZED) { const struct uart_ops *ops = uport->ops; int tries; - if (console_suspend_enabled || !uart_console(uport)) { - set_bit(ASYNCB_SUSPENDED, &port->flags); - clear_bit(ASYNCB_INITIALIZED, &port->flags); + set_bit(ASYNCB_SUSPENDED, &port->flags); + clear_bit(ASYNCB_INITIALIZED, &port->flags); - spin_lock_irq(&uport->lock); - ops->stop_tx(uport); - ops->set_mctrl(uport, 0); - ops->stop_rx(uport); - spin_unlock_irq(&uport->lock); - } + spin_lock_irq(&uport->lock); + ops->stop_tx(uport); + ops->set_mctrl(uport, 0); + ops->stop_rx(uport); + spin_unlock_irq(&uport->lock); /* * Wait for the transmitter to empty. @@ -1970,26 +2075,21 @@ for (tries = 3; !ops->tx_empty(uport) && tries; tries--) msleep(10); if (!tries) - printk(KERN_ERR "%s%s%s%d: Unable to drain " - "transmitter\n", - uport->dev ? dev_name(uport->dev) : "", - uport->dev ? ": " : "", - drv->dev_name, - drv->tty_driver->name_base + uport->line); + dev_err(uport->dev, "%s%d: Unable to drain transmitter\n", + drv->dev_name, + drv->tty_driver->name_base + uport->line); - if (console_suspend_enabled || !uart_console(uport)) - ops->shutdown(uport); + ops->shutdown(uport); } /* * Disable the console device before suspending. */ - if (console_suspend_enabled && uart_console(uport)) + if (uart_console(uport)) console_stop(uport->cons); - if (console_suspend_enabled || !uart_console(uport)) - uart_change_pm(state, UART_PM_STATE_OFF); - + uart_change_pm(state, UART_PM_STATE_OFF); +unlock: mutex_unlock(&port->mutex); return 0; @@ -2094,6 +2194,7 @@ break; case UPIO_MEM: case UPIO_MEM32: + case UPIO_MEM32BE: case UPIO_AU: case UPIO_TSI: snprintf(address, sizeof(address), @@ -2104,12 +2205,12 @@ break; } - printk(KERN_INFO "%s%s%s%d at %s (irq = %d) is a %s\n", + printk(KERN_INFO "%s%s%s%d at %s (irq = %d, base_baud = %d) is a %s\n", port->dev ? dev_name(port->dev) : "", port->dev ? ": " : "", drv->dev_name, drv->tty_driver->name_base + port->line, - address, port->irq, uart_type(port)); + address, port->irq, port->uartclk / 16, uart_type(port)); } static void @@ -2240,6 +2341,9 @@ return; port = state->uart_port; + + if (ch == '\n') + port->ops->poll_put_char(port, '\r'); port->ops->poll_put_char(port, ch); } #endif @@ -2278,8 +2382,6 @@ }; 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, }; @@ -2340,8 +2442,6 @@ tty_port_init(port); port->ops = &uart_port_ops; - port->close_delay = HZ / 2; /* .5 seconds */ - port->closing_wait = 30 * HZ;/* 30 seconds */ } retval = tty_register_driver(normal); @@ -2557,12 +2657,6 @@ .attrs = tty_dev_attrs, }; -static const struct attribute_group *tty_dev_attr_groups[] = { - &tty_dev_attr_group, - NULL - }; - - /** * uart_add_one_port - attach a driver-defined port structure * @drv: pointer to the uart low level driver structure for this port @@ -2579,6 +2673,7 @@ struct tty_port *port; int ret = 0; struct device *tty_dev; + int num_groups; BUG_ON(in_interrupt()); @@ -2595,11 +2690,13 @@ goto out; } + /* Link the port to the driver state table and vice versa */ state->uart_port = uport; - state->pm_state = UART_PM_STATE_UNDEFINED; + uport->state = state; + state->pm_state = UART_PM_STATE_UNDEFINED; uport->cons = drv->cons; - uport->state = state; + uport->minor = drv->tty_driver->minor_start + uport->line; /* * If this port is a console, then the spinlock is already @@ -2609,19 +2706,35 @@ spin_lock_init(&uport->lock); lockdep_set_class(&uport->lock, &port_lock_key); } + if (uport->cons && uport->dev) + of_console_check(uport->dev->of_node, uport->cons->name, uport->line); uart_configure_port(drv, state, uport); + num_groups = 2; + if (uport->attr_group) + num_groups++; + + uport->tty_groups = kcalloc(num_groups, sizeof(*uport->tty_groups), + GFP_KERNEL); + if (!uport->tty_groups) { + ret = -ENOMEM; + goto out; + } + uport->tty_groups[0] = &tty_dev_attr_group; + if (uport->attr_group) + uport->tty_groups[1] = uport->attr_group; + /* * Register the port whether it's detected or not. This allows - * setserial to be used to alter this ports parameters. + * setserial to be used to alter this port's parameters. */ tty_dev = tty_port_register_device_attr(port, drv->tty_driver, - uport->line, uport->dev, port, tty_dev_attr_groups); + uport->line, uport->dev, port, uport->tty_groups); if (likely(!IS_ERR(tty_dev))) { device_set_wakeup_capable(tty_dev, 1); } else { - printk(KERN_ERR "Cannot register tty device on line %d\n", + dev_err(uport->dev, "Cannot register tty device on line %d\n", uport->line); } @@ -2650,12 +2763,13 @@ { struct uart_state *state = drv->state + uport->line; struct tty_port *port = &state->port; + struct tty_struct *tty; int ret = 0; BUG_ON(in_interrupt()); if (state->uart_port != uport) - printk(KERN_ALERT "Removing wrong port: %p != %p\n", + dev_alert(uport->dev, "Removing wrong port: %p != %p\n", state->uart_port, uport); mutex_lock(&port_mutex); @@ -2678,14 +2792,24 @@ */ tty_unregister_device(drv->tty_driver, uport->line); - if (port->tty) + tty = tty_port_tty_get(port); + if (tty) { tty_vhangup(port->tty); + tty_kref_put(tty); + } + + /* + * If the port is used as a console, unregister it + */ + if (uart_console(uport)) + unregister_console(uport->cons); /* * Free the port IO and memory resources, if any. */ if (uport->type != PORT_UNKNOWN) uport->ops->release_port(uport); + kfree(uport->tty_groups); /* * Indicate that there isn't a port here anymore. @@ -2715,6 +2839,7 @@ (port1->hub6 == port2->hub6); case UPIO_MEM: case UPIO_MEM32: + case UPIO_MEM32BE: case UPIO_AU: case UPIO_TSI: return (port1->mapbase == port2->mapbase); @@ -2727,22 +2852,29 @@ * 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 + * + * Caller must hold uport->lock */ void uart_handle_dcd_change(struct uart_port *uport, unsigned int status) { struct tty_port *port = &uport->state->port; struct tty_struct *tty = port->tty; - struct tty_ldisc *ld = tty ? tty_ldisc_ref(tty) : NULL; + struct tty_ldisc *ld; + + lockdep_assert_held_once(&uport->lock); - if (ld) { - if (ld->ops->dcd_change) - ld->ops->dcd_change(tty, status); - tty_ldisc_deref(ld); + if (tty) { + ld = tty_ldisc_ref(tty); + if (ld) { + if (ld->ops->dcd_change) + ld->ops->dcd_change(tty, status); + tty_ldisc_deref(ld); + } } uport->icount.dcd++; - if (port->flags & ASYNC_CHECK_CD) { + if (uart_dcd_enabled(uport)) { if (status) wake_up_interruptible(&port->open_wait); else if (tty) @@ -2755,27 +2887,29 @@ * 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 + * + * Caller must hold uport->lock */ 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; + lockdep_assert_held_once(&uport->lock); uport->icount.cts++; - if (tty_port_cts_enabled(port)) { - if (tty->hw_stopped) { + if (uart_softcts_mode(uport)) { + if (uport->hw_stopped) { if (status) { - tty->hw_stopped = 0; + uport->hw_stopped = 0; uport->ops->start_tx(uport); uart_write_wakeup(uport); } } else { if (!status) { - tty->hw_stopped = 1; + uport->hw_stopped = 1; uport->ops->stop_tx(uport); } } + } } EXPORT_SYMBOL_GPL(uart_handle_cts_change);