diff options
Diffstat (limited to 'drivers/tty')
-rw-r--r-- | drivers/tty/hvc/hvc_opal.c | 22 | ||||
-rw-r--r-- | drivers/tty/serial/Kconfig | 3 | ||||
-rw-r--r-- | drivers/tty/serial/amba-pl011.c | 8 | ||||
-rw-r--r-- | drivers/tty/serial/atmel_serial.c | 49 | ||||
-rw-r--r-- | drivers/tty/serial/clps711x.c | 20 | ||||
-rw-r--r-- | drivers/tty/serial/efm32-uart.c | 3 | ||||
-rw-r--r-- | drivers/tty/serial/omap-serial.c | 30 | ||||
-rw-r--r-- | drivers/tty/serial/serial_core.c | 5 | ||||
-rw-r--r-- | drivers/tty/serial/st-asc.c | 4 | ||||
-rw-r--r-- | drivers/tty/tty_audit.c | 3 | ||||
-rw-r--r-- | drivers/tty/tty_io.c | 4 |
11 files changed, 96 insertions, 55 deletions
diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c index b01659bd4f7c..a585079b4b38 100644 --- a/drivers/tty/hvc/hvc_opal.c +++ b/drivers/tty/hvc/hvc_opal.c @@ -61,6 +61,7 @@ static struct hvc_opal_priv *hvc_opal_privs[MAX_NR_HVC_CONSOLES]; /* For early boot console */ static struct hvc_opal_priv hvc_opal_boot_priv; static u32 hvc_opal_boot_termno; +static bool hvc_opal_event_registered; static const struct hv_ops hvc_opal_raw_ops = { .get_chars = opal_get_chars, @@ -161,6 +162,18 @@ static const struct hv_ops hvc_opal_hvsi_ops = { .tiocmset = hvc_opal_hvsi_tiocmset, }; +static int hvc_opal_console_event(struct notifier_block *nb, + unsigned long events, void *change) +{ + if (events & OPAL_EVENT_CONSOLE_INPUT) + hvc_kick(); + return 0; +} + +static struct notifier_block hvc_opal_console_nb = { + .notifier_call = hvc_opal_console_event, +}; + static int hvc_opal_probe(struct platform_device *dev) { const struct hv_ops *ops; @@ -170,6 +183,7 @@ static int hvc_opal_probe(struct platform_device *dev) unsigned int termno, boot = 0; const __be32 *reg; + if (of_device_is_compatible(dev->dev.of_node, "ibm,opal-console-raw")) { proto = HV_PROTOCOL_RAW; ops = &hvc_opal_raw_ops; @@ -213,12 +227,18 @@ static int hvc_opal_probe(struct platform_device *dev) dev->dev.of_node->full_name, boot ? " (boot console)" : ""); - /* We don't do IRQ yet */ + /* We don't do IRQ ... */ hp = hvc_alloc(termno, 0, ops, MAX_VIO_PUT_CHARS); if (IS_ERR(hp)) return PTR_ERR(hp); dev_set_drvdata(&dev->dev, hp); + /* ... but we use OPAL event to kick the console */ + if (!hvc_opal_event_registered) { + opal_notifier_register(&hvc_opal_console_nb); + hvc_opal_event_registered = true; + } + return 0; } diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 2577d67bacb2..5d9b01aa54f4 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1024,7 +1024,7 @@ config SERIAL_SGI_IOC3 config SERIAL_MSM bool "MSM on-chip serial port support" - depends on ARCH_MSM + depends on ARCH_MSM || ARCH_QCOM select SERIAL_CORE config SERIAL_MSM_CONSOLE @@ -1226,6 +1226,7 @@ config SERIAL_BFIN_SPORT3_UART_CTSRTS config SERIAL_TIMBERDALE tristate "Support for timberdale UART" select SERIAL_CORE + depends on X86_32 || COMPILE_TEST ---help--- Add support for UART controller on timberdale. diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index d4eda24aa68b..dacf0a09ab24 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -318,7 +318,7 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port * .src_addr = uap->port.mapbase + UART01x_DR, .src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, .direction = DMA_DEV_TO_MEM, - .src_maxburst = uap->fifosize >> 1, + .src_maxburst = uap->fifosize >> 2, .device_fc = false, }; @@ -2176,6 +2176,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) static int pl011_remove(struct amba_device *dev) { struct uart_amba_port *uap = amba_get_drvdata(dev); + bool busy = false; int i; uart_remove_one_port(&amba_reg, &uap->port); @@ -2183,9 +2184,12 @@ static int pl011_remove(struct amba_device *dev) for (i = 0; i < ARRAY_SIZE(amba_ports); i++) if (amba_ports[i] == uap) amba_ports[i] = NULL; + else if (amba_ports[i]) + busy = true; pl011_dma_remove(uap); - uart_unregister_driver(&amba_reg); + if (!busy) + uart_unregister_driver(&amba_reg); return 0; } diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index b0603e1f7d82..53eeea13ff16 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -35,21 +35,18 @@ #include <linux/platform_device.h> #include <linux/of.h> #include <linux/of_device.h> +#include <linux/of_gpio.h> #include <linux/dma-mapping.h> #include <linux/atmel_pdc.h> #include <linux/atmel_serial.h> #include <linux/uaccess.h> #include <linux/platform_data/atmel.h> #include <linux/timer.h> +#include <linux/gpio.h> #include <asm/io.h> #include <asm/ioctls.h> -#ifdef CONFIG_ARM -#include <mach/cpu.h> -#include <asm/gpio.h> -#endif - #define PDC_BUFFER_SIZE 512 /* Revisit: We should calculate this based on the actual port settings */ #define PDC_RX_TIMEOUT (3 * 10) /* 3 bytes */ @@ -165,6 +162,7 @@ struct atmel_uart_port { struct circ_buf rx_ring; struct serial_rs485 rs485; /* rs485 settings */ + int rts_gpio; /* optional RTS GPIO */ unsigned int tx_done_mask; bool is_usart; /* usart or uart */ struct timer_list uart_timer; /* uart timer */ @@ -298,20 +296,16 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl) unsigned int mode; struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); -#ifdef CONFIG_ARCH_AT91RM9200 - if (cpu_is_at91rm9200()) { - /* - * AT91RM9200 Errata #39: RTS0 is not internally connected - * to PA21. We need to drive the pin manually. - */ - if (port->mapbase == AT91RM9200_BASE_US0) { - if (mctrl & TIOCM_RTS) - at91_set_gpio_value(AT91_PIN_PA21, 0); - else - at91_set_gpio_value(AT91_PIN_PA21, 1); - } + /* + * AT91RM9200 Errata #39: RTS0 is not internally connected + * to PA21. We need to drive the pin as a GPIO. + */ + if (gpio_is_valid(atmel_port->rts_gpio)) { + if (mctrl & TIOCM_RTS) + gpio_set_value(atmel_port->rts_gpio, 0); + else + gpio_set_value(atmel_port->rts_gpio, 1); } -#endif if (mctrl & TIOCM_RTS) control |= ATMEL_US_RTSEN; @@ -2365,6 +2359,25 @@ static int atmel_serial_probe(struct platform_device *pdev) port = &atmel_ports[ret]; port->backup_imr = 0; port->uart.line = ret; + port->rts_gpio = -EINVAL; /* Invalid, zero could be valid */ + if (pdata) + port->rts_gpio = pdata->rts_gpio; + else if (np) + port->rts_gpio = of_get_named_gpio(np, "rts-gpios", 0); + + if (gpio_is_valid(port->rts_gpio)) { + ret = devm_gpio_request(&pdev->dev, port->rts_gpio, "RTS"); + if (ret) { + dev_err(&pdev->dev, "error requesting RTS GPIO\n"); + goto err; + } + /* Default to 1 as RTS is active low */ + ret = gpio_direction_output(port->rts_gpio, 1); + if (ret) { + dev_err(&pdev->dev, "error setting up RTS GPIO\n"); + goto err; + } + } ret = atmel_init_port(port, pdev); if (ret) diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c index 5e6fdb1ea73b..14aaea0d4131 100644 --- a/drivers/tty/serial/clps711x.c +++ b/drivers/tty/serial/clps711x.c @@ -368,16 +368,12 @@ static const struct uart_ops uart_clps711x_ops = { static void uart_clps711x_console_putchar(struct uart_port *port, int ch) { struct clps711x_port *s = dev_get_drvdata(port->dev); + u32 sysflg = 0; /* Wait for FIFO is not full */ - while (1) { - u32 sysflg = 0; - + do { regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg); - if (!(sysflg & SYSFLG_UTXFF)) - break; - cond_resched(); - } + } while (sysflg & SYSFLG_UTXFF); writew(ch, port->membase + UARTDR_OFFSET); } @@ -387,18 +383,14 @@ static void uart_clps711x_console_write(struct console *co, const char *c, { struct uart_port *port = clps711x_uart.state[co->index].uart_port; struct clps711x_port *s = dev_get_drvdata(port->dev); + u32 sysflg = 0; uart_console_write(port, c, n, uart_clps711x_console_putchar); /* Wait for transmitter to become empty */ - while (1) { - u32 sysflg = 0; - + do { regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg); - if (!(sysflg & SYSFLG_UBUSY)) - break; - cond_resched(); - } + } while (sysflg & SYSFLG_UBUSY); } static int uart_clps711x_console_setup(struct console *co, char *options) diff --git a/drivers/tty/serial/efm32-uart.c b/drivers/tty/serial/efm32-uart.c index 028582e924a5..c167a710dc39 100644 --- a/drivers/tty/serial/efm32-uart.c +++ b/drivers/tty/serial/efm32-uart.c @@ -798,6 +798,9 @@ static int efm32_uart_remove(struct platform_device *pdev) static const struct of_device_id efm32_uart_dt_ids[] = { { + .compatible = "energymicro,efm32-uart", + }, { + /* doesn't follow the "vendor,device" scheme, don't use */ .compatible = "efm32,uart", }, { /* sentinel */ diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index dd8b1a5458ff..08b6b9419f0d 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -225,14 +225,19 @@ static inline void serial_omap_enable_wakeirq(struct uart_omap_port *up, if (enable) enable_irq(up->wakeirq); else - disable_irq(up->wakeirq); + disable_irq_nosync(up->wakeirq); } static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable) { struct omap_uart_port_info *pdata = dev_get_platdata(up->dev); + if (enable == up->wakeups_enabled) + return; + serial_omap_enable_wakeirq(up, enable); + up->wakeups_enabled = enable; + if (!pdata || !pdata->enable_wakeup) return; @@ -1495,6 +1500,11 @@ static int serial_omap_suspend(struct device *dev) uart_suspend_port(&serial_omap_reg, &up->port); flush_work(&up->qos_work); + if (device_may_wakeup(dev)) + serial_omap_enable_wakeup(up, true); + else + serial_omap_enable_wakeup(up, false); + return 0; } @@ -1502,6 +1512,9 @@ static int serial_omap_resume(struct device *dev) { struct uart_omap_port *up = dev_get_drvdata(dev); + if (device_may_wakeup(dev)) + serial_omap_enable_wakeup(up, false); + uart_resume_port(&serial_omap_reg, &up->port); return 0; @@ -1789,6 +1802,7 @@ static int serial_omap_remove(struct platform_device *dev) pm_runtime_disable(up->dev); uart_remove_one_port(&serial_omap_reg, &up->port); pm_qos_remove_request(&up->pm_qos_request); + device_init_wakeup(&dev->dev, false); return 0; } @@ -1877,17 +1891,7 @@ static int serial_omap_runtime_suspend(struct device *dev) up->context_loss_cnt = serial_omap_get_context_loss_count(up); - if (device_may_wakeup(dev)) { - if (!up->wakeups_enabled) { - serial_omap_enable_wakeup(up, true); - up->wakeups_enabled = true; - } - } else { - if (up->wakeups_enabled) { - serial_omap_enable_wakeup(up, false); - up->wakeups_enabled = false; - } - } + serial_omap_enable_wakeup(up, true); up->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; schedule_work(&up->qos_work); @@ -1901,6 +1905,8 @@ static int serial_omap_runtime_resume(struct device *dev) int loss_cnt = serial_omap_get_context_loss_count(up); + serial_omap_enable_wakeup(up, false); + if (loss_cnt < 0) { dev_dbg(dev, "serial_omap_get_context_loss_count failed : %d\n", loss_cnt); diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 2cf5649a6dc0..f26834d262b3 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -89,8 +89,7 @@ static void __uart_start(struct tty_struct *tty) 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 (!tty->stopped && !tty->hw_stopped) port->ops->start_tx(port); } @@ -1452,6 +1451,8 @@ static void uart_hangup(struct tty_struct *tty) 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); } diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c index 21e6e84c0df8..dd3a96e07026 100644 --- a/drivers/tty/serial/st-asc.c +++ b/drivers/tty/serial/st-asc.c @@ -295,7 +295,7 @@ static void asc_receive_chars(struct uart_port *port) status & ASC_STA_OE) { if (c & ASC_RXBUF_FE) { - if (c == ASC_RXBUF_FE) { + if (c == (ASC_RXBUF_FE | ASC_RXBUF_DUMMY_RX)) { port->icount.brk++; if (uart_handle_break(port)) continue; @@ -325,7 +325,7 @@ static void asc_receive_chars(struct uart_port *port) flag = TTY_FRAME; } - if (uart_handle_sysrq_char(port, c)) + if (uart_handle_sysrq_char(port, c & 0xff)) continue; uart_insert_char(port, c, ASC_RXBUF_DUMMY_OE, c & 0xff, flag); diff --git a/drivers/tty/tty_audit.c b/drivers/tty/tty_audit.c index b0e540137e39..90ca082935f6 100644 --- a/drivers/tty/tty_audit.c +++ b/drivers/tty/tty_audit.c @@ -65,6 +65,7 @@ static void tty_audit_log(const char *description, int major, int minor, { struct audit_buffer *ab; struct task_struct *tsk = current; + pid_t pid = task_pid_nr(tsk); uid_t uid = from_kuid(&init_user_ns, task_uid(tsk)); uid_t loginuid = from_kuid(&init_user_ns, audit_get_loginuid(tsk)); unsigned int sessionid = audit_get_sessionid(tsk); @@ -74,7 +75,7 @@ static void tty_audit_log(const char *description, int major, int minor, char name[sizeof(tsk->comm)]; audit_log_format(ab, "%s pid=%u uid=%u auid=%u ses=%u major=%d" - " minor=%d comm=", description, tsk->pid, uid, + " minor=%d comm=", description, pid, uid, loginuid, sessionid, major, minor); get_task_comm(name, tsk); audit_log_untrustedstring(ab, name); diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index d3448a90f0f9..34110719fe03 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -878,9 +878,8 @@ void disassociate_ctty(int on_exit) spin_lock_irq(¤t->sighand->siglock); put_pid(current->signal->tty_old_pgrp); current->signal->tty_old_pgrp = NULL; - spin_unlock_irq(¤t->sighand->siglock); - tty = get_current_tty(); + tty = tty_kref_get(current->signal->tty); if (tty) { unsigned long flags; spin_lock_irqsave(&tty->ctrl_lock, flags); @@ -897,6 +896,7 @@ void disassociate_ctty(int on_exit) #endif } + spin_unlock_irq(¤t->sighand->siglock); /* Now clear signal->tty under the lock */ read_lock(&tasklist_lock); session_clear_tty(task_session(current)); |