From fec4daecadcf3b73facf6b48ed03453c96c7f2dd Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 9 May 2016 09:11:53 +0200 Subject: tty: ipwireless, cleanup TIOCGSERIAL In ipwireless_get_serial_info, struct serial_struct is memset to 0 and then some members set to 0 explicitly. Remove the latter as it is obviously superfluous. And remove the retinfo check against NULL. copy_to_user will take care of that. Part of hub6 cleanup series. Signed-off-by: Jiri Slaby Cc: Jiri Kosina Acked-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- drivers/tty/ipwireless/tty.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c index 345cebb07ae7..2685d59d2724 100644 --- a/drivers/tty/ipwireless/tty.c +++ b/drivers/tty/ipwireless/tty.c @@ -252,20 +252,11 @@ static int ipwireless_get_serial_info(struct ipw_tty *tty, { struct serial_struct tmp; - if (!retinfo) - return (-EFAULT); - memset(&tmp, 0, sizeof(tmp)); tmp.type = PORT_UNKNOWN; tmp.line = tty->index; - tmp.port = 0; - tmp.irq = 0; - tmp.flags = 0; tmp.baud_base = 115200; - tmp.close_delay = 0; - tmp.closing_wait = 0; - tmp.custom_divisor = 0; - tmp.hub6 = 0; + if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) return -EFAULT; -- cgit v1.2.3 From 322b7d6d3efd34c7da858b27d7a410b84a9ed6db Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 9 May 2016 09:11:55 +0200 Subject: tty: cyclades+mxser, do not initialize to zero Do not initialize members of initialized structures to zero. They are zeroed automatically. Part of hub6 cleanup series. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/cyclades.c | 1 - drivers/tty/mxser.c | 1 - 2 files changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index 3840d6b421c4..fcc4962fa4c6 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -2288,7 +2288,6 @@ static int cy_get_serial_info(struct cyclades_port *info, .closing_wait = info->port.closing_wait, .baud_base = info->baud, .custom_divisor = info->custom_divisor, - .hub6 = 0, /*!!! */ }; return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0; } diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 98d2bd16706d..69294ae154be 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -1219,7 +1219,6 @@ static int mxser_get_serial_info(struct tty_struct *tty, .close_delay = info->port.close_delay, .closing_wait = info->port.closing_wait, .custom_divisor = info->custom_divisor, - .hub6 = 0 }; if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) return -EFAULT; -- cgit v1.2.3 From 6137b7a62978915d76db69e17e25e8e0b1057254 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 9 May 2016 09:11:57 +0200 Subject: tty: stop defining STD_COM_FLAGS in drivers STD_COM_FLAGS is mostly a bad name for what the drivers thinks it is. Stop using it and pass the flags directly. cyclades defines it as 0, so we do not assign anything to freshly tty_port_init'ed structure. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- arch/xtensa/platforms/xt2000/setup.c | 1 - drivers/tty/cyclades.c | 3 --- drivers/tty/serial/m32r_sio.c | 5 +---- 3 files changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers') diff --git a/arch/xtensa/platforms/xt2000/setup.c b/arch/xtensa/platforms/xt2000/setup.c index 5f4bd71971d6..4904c5c16918 100644 --- a/arch/xtensa/platforms/xt2000/setup.c +++ b/arch/xtensa/platforms/xt2000/setup.c @@ -113,7 +113,6 @@ void platform_heartbeat(void) } //#define RS_TABLE_SIZE 2 -//#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF|UPF_SKIP_TEST) #define _SERIAL_PORT(_base,_irq) \ { \ diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index fcc4962fa4c6..5e4fa9206861 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -93,8 +93,6 @@ static void cy_send_xchar(struct tty_struct *tty, char ch); #define SERIAL_XMIT_SIZE (min(PAGE_SIZE, 4096)) #endif -#define STD_COM_FLAGS (0) - /* firmware stuff */ #define ZL_MAX_BLOCKS 16 #define DRIVER_VERSION 0x02010203 @@ -3083,7 +3081,6 @@ static int cy_init_card(struct cyclades_card *cinfo) info->port.closing_wait = CLOSING_WAIT_DELAY; info->port.close_delay = 5 * HZ / 10; - info->port.flags = STD_COM_FLAGS; init_completion(&info->shutdown_wait); if (cy_is_Z(cinfo)) { diff --git a/drivers/tty/serial/m32r_sio.c b/drivers/tty/serial/m32r_sio.c index 68765f7c2645..1b01504cf306 100644 --- a/drivers/tty/serial/m32r_sio.c +++ b/drivers/tty/serial/m32r_sio.c @@ -51,9 +51,6 @@ #define PASS_LIMIT 256 -/* Standard COM flags */ -#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST) - static const struct { unsigned int port; unsigned int irq; @@ -892,7 +889,7 @@ static void __init m32r_sio_init_ports(void) up->port.iobase = old_serial_port[i].port; up->port.irq = irq_canonicalize(old_serial_port[i].irq); up->port.uartclk = BAUD_RATE * 16; - up->port.flags = STD_COM_FLAGS; + up->port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; up->port.membase = 0; up->port.iotype = 0; up->port.regshift = 0; -- cgit v1.2.3 From b0f8aed2cdabb01225b85087d7ea1a88bd22e079 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 9 May 2016 09:11:58 +0200 Subject: tty: 8250, drop unused members from struct old_serial_port hub6 and irqflags from struct old_serial_port are nowhere set. Drop them from the structure and replace the reads by zeros. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250.h | 2 -- drivers/tty/serial/8250/8250_core.c | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 215a99237e95..563ccbe3612b 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -53,11 +53,9 @@ struct old_serial_port { unsigned int port; unsigned int irq; upf_t flags; - unsigned char hub6; unsigned char io_type; unsigned char __iomem *iomem_base; unsigned short iomem_reg_shift; - unsigned long irqflags; }; struct serial8250_config { diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 0fbd7c033a25..e938ac93743a 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -546,10 +546,10 @@ static void __init serial8250_isa_init_ports(void) port->iobase = old_serial_port[i].port; port->irq = irq_canonicalize(old_serial_port[i].irq); - port->irqflags = old_serial_port[i].irqflags; + port->irqflags = 0; port->uartclk = old_serial_port[i].baud_base * 16; port->flags = old_serial_port[i].flags; - port->hub6 = old_serial_port[i].hub6; + port->hub6 = 0; port->membase = old_serial_port[i].iomem_base; port->iotype = old_serial_port[i].io_type; port->regshift = old_serial_port[i].iomem_reg_shift; -- cgit v1.2.3 From 934014d5220616dc6ea62da6685b79855b164643 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 9 May 2016 09:11:59 +0200 Subject: tty: 8250, kill DEBUG_INTR Convert DEBUG_INTR to pr_debug: * defined semantics (DEBUG, DYNAMIC_DEBUG) * KERN_DEBUG level instead of KERN_DEFAULT * emit __func__ and \n * verified 'fmt' even when !DEBUG I wonder if anybody ever used that or whether we should just drop the lines. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250.h | 6 ------ drivers/tty/serial/8250/8250_core.c | 4 ++-- drivers/tty/serial/8250/8250_port.c | 6 +++--- 3 files changed, 5 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 563ccbe3612b..31b3d55211d0 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -235,9 +235,3 @@ static inline int serial_index(struct uart_port *port) { return port->minor - 64; } - -#if 0 -#define DEBUG_INTR(fmt...) printk(fmt) -#else -#define DEBUG_INTR(fmt...) do { } while (0) -#endif diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index e938ac93743a..fa823a54cf35 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -114,7 +114,7 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id) struct list_head *l, *end = NULL; int pass_counter = 0, handled = 0; - DEBUG_INTR("serial8250_interrupt(%d)...", irq); + pr_debug("%s(%d): start\n", __func__, irq); spin_lock(&i->lock); @@ -144,7 +144,7 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id) spin_unlock(&i->lock); - DEBUG_INTR("end.\n"); + pr_debug("%s(%d): end\n", __func__, irq); return IRQ_RETVAL(handled); } diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index d4036038a4dd..b10d05f2004b 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1686,7 +1686,7 @@ static void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr) lsr &= port->read_status_mask; if (lsr & UART_LSR_BI) { - DEBUG_INTR("handling break...."); + pr_debug("%s: handling break\n", __func__); flag = TTY_BREAK; } else if (lsr & UART_LSR_PE) flag = TTY_PARITY; @@ -1757,7 +1757,7 @@ void serial8250_tx_chars(struct uart_8250_port *up) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); - DEBUG_INTR("THRE..."); + pr_debug("%s: THRE\n", __func__); /* * With RPM enabled, we have to wait until the FIFO is empty before the @@ -1823,7 +1823,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) status = serial_port_in(port, UART_LSR); - DEBUG_INTR("status = %x...", status); + pr_debug("%s: status = %x\n", __func__, status); if (status & (UART_LSR_DR | UART_LSR_BI)) { if (!up->dma || handle_rx_dma(up, iir)) -- cgit v1.2.3 From 394a9e2ca2b6326c939c90453184cbc65542cfa1 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 9 May 2016 09:23:35 +0200 Subject: TTY: serial, handle platform_get_irq retval properly platform_get_irq can fail, so we should handle negative value when returned. [v2] platform_get_irq can actually return zero on some platforms. So do not remove checks for irq == 0 there. Signed-off-by: Jiri Slaby Cc: Russell King Cc: "Uwe Kleine-König" Cc: Russell King Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Michael Ellerman Cc: Laxman Dewangan Cc: Stephen Warren Cc: Thierry Reding Cc: Alexandre Courbot Cc: linux-serial@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linuxppc-dev@lists.ozlabs.org Cc: linux-tegra@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 8 +++++++- drivers/tty/serial/fsl_lpuart.c | 8 +++++++- drivers/tty/serial/pmac_zilog.c | 2 +- drivers/tty/serial/serial-tegra.c | 7 ++++++- 4 files changed, 21 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 1b7331e40d79..8a9e213387a7 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -2553,11 +2553,17 @@ static int sbsa_uart_probe(struct platform_device *pdev) if (!uap) return -ENOMEM; + ret = platform_get_irq(pdev, 0); + if (ret < 0) { + dev_err(&pdev->dev, "cannot obtain irq\n"); + return ret; + } + uap->port.irq = ret; + uap->reg_offset = vendor_sbsa.reg_offset; uap->vendor = &vendor_sbsa; uap->fifosize = 32; uap->port.iotype = vendor_sbsa.access_32b ? UPIO_MEM32 : UPIO_MEM; - uap->port.irq = platform_get_irq(pdev, 0); uap->port.ops = &sbsa_uart_pops; uap->fixed_baud = baudrate; diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 3d790033744e..7f95f782a485 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -1830,7 +1830,13 @@ static int lpuart_probe(struct platform_device *pdev) sport->port.dev = &pdev->dev; sport->port.type = PORT_LPUART; sport->port.iotype = UPIO_MEM; - sport->port.irq = platform_get_irq(pdev, 0); + ret = platform_get_irq(pdev, 0); + if (ret < 0) { + dev_err(&pdev->dev, "cannot obtain irq\n"); + return ret; + } + sport->port.irq = ret; + if (sport->lpuart32) sport->port.ops = &lpuart32_pops; else diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index e156e39d620c..b24b0556f5a8 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -1720,7 +1720,7 @@ static int __init pmz_init_port(struct uart_pmac_port *uap) r_ports = platform_get_resource(uap->pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(uap->pdev, 0); - if (!r_ports || !irq) + if (!r_ports || irq <= 0) return -ENODEV; uap->port.mapbase = r_ports->start; diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c index 1dba6719db8d..731ac35acb31 100644 --- a/drivers/tty/serial/serial-tegra.c +++ b/drivers/tty/serial/serial-tegra.c @@ -1317,7 +1317,12 @@ static int tegra_uart_probe(struct platform_device *pdev) } u->iotype = UPIO_MEM32; - u->irq = platform_get_irq(pdev, 0); + ret = platform_get_irq(pdev, 0); + if (ret < 0) { + dev_err(&pdev->dev, "Couldn't get IRQ\n"); + return ret; + } + u->irq = ret; u->regshift = 2; ret = uart_add_one_port(&tegra_uart_driver, u); if (ret < 0) { -- cgit v1.2.3 From 17b2720b114cc95b2b7c8c0f5cfa20e44e1f5912 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:22 +0200 Subject: tty: 8250, remove shadow and unused variables The compiler complains about variables that are set, but never used: * intX variables in exar_handle_irq drivers/tty/serial/8250/8250_port.c:1864:34: warning: variable ‘int3’ set but not used [-Wunused-but-set-variable] * val variable in pci_quatech_wqopr drivers/tty/serial/8250/8250_pci.c:1139:10: warning: variable ‘val’ set but not used [-Wunused-but-set-variable] And about a shadow variable: * tmout in wait_for_xmitr is defined twice with the same type. Both of them are also initialized before use. Remove all of them. Signed-off-by: Jiri Slaby Cc: Matt Schulte Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 4 ++-- drivers/tty/serial/8250/8250_port.c | 11 ++++------- 2 files changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 8dd250fbd367..3d6287a8981e 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1136,11 +1136,11 @@ static int pci_quatech_rqopr(struct uart_8250_port *port) static void pci_quatech_wqopr(struct uart_8250_port *port, u8 qopr) { unsigned long base = port->port.iobase; - u8 LCR, val; + u8 LCR; LCR = inb(base + UART_LCR); outb(0xBF, base + UART_LCR); - val = inb(base + UART_SCR); + inb(base + UART_SCR); outb(qopr, base + UART_SCR); outb(LCR, base + UART_LCR); } diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index b10d05f2004b..c8d8d245350b 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1861,7 +1861,6 @@ static int serial8250_default_handle_irq(struct uart_port *port) */ static int exar_handle_irq(struct uart_port *port) { - unsigned char int0, int1, int2, int3; unsigned int iir = serial_port_in(port, UART_IIR); int ret; @@ -1869,10 +1868,10 @@ static int exar_handle_irq(struct uart_port *port) if ((port->type == PORT_XR17V35X) || (port->type == PORT_XR17D15X)) { - int0 = serial_port_in(port, 0x80); - int1 = serial_port_in(port, 0x81); - int2 = serial_port_in(port, 0x82); - int3 = serial_port_in(port, 0x83); + serial_port_in(port, 0x80); + serial_port_in(port, 0x81); + serial_port_in(port, 0x82); + serial_port_in(port, 0x83); } return ret; @@ -1994,8 +1993,6 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits) /* Wait up to 1s for flow control if necessary */ if (up->port.flags & UPF_CONS_FLOW) { - unsigned int tmout; - for (tmout = 1000000; tmout; tmout--) { unsigned int msr = serial_in(up, UART_MSR); up->msr_saved_flags |= msr & MSR_SAVE_FLAGS; -- cgit v1.2.3 From 1b0ec88ac1cb0413a717bc3cefea72d6f2533672 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:23 +0200 Subject: vt: remove lines parameter from scrollback It is always called with 0, so remove the parameter and pass the default down to scrolldelta without checking. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/keyboard.c | 2 +- drivers/tty/vt/vt.c | 6 ++---- include/linux/vt_kern.h | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index f973bfce5d08..cd08c103eb47 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -579,7 +579,7 @@ static void fn_scroll_forw(struct vc_data *vc) static void fn_scroll_back(struct vc_data *vc) { - scrollback(vc, 0); + scrollback(vc); } static void fn_show_mem(struct vc_data *vc) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index dc125322f48f..abc79ae19079 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1102,11 +1102,9 @@ static void gotoxay(struct vc_data *vc, int new_x, int new_y) gotoxy(vc, new_x, vc->vc_decom ? (vc->vc_top + new_y) : new_y); } -void scrollback(struct vc_data *vc, int lines) +void scrollback(struct vc_data *vc) { - if (!lines) - lines = vc->vc_rows / 2; - scrolldelta(-lines); + scrolldelta(-(vc->vc_rows / 2)); } void scrollfront(struct vc_data *vc, int lines) diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h index 8d7634247fb4..160f81fe3eb8 100644 --- a/include/linux/vt_kern.h +++ b/include/linux/vt_kern.h @@ -45,7 +45,7 @@ void poke_blanked_console(void); int con_font_op(struct vc_data *vc, struct console_font_op *op); int con_set_cmap(unsigned char __user *cmap); int con_get_cmap(unsigned char __user *cmap); -void scrollback(struct vc_data *vc, int lines); +void scrollback(struct vc_data *vc); void scrollfront(struct vc_data *vc, int lines); void clear_buffer_attributes(struct vc_data *vc); void update_region(struct vc_data *vc, unsigned long start, int count); -- cgit v1.2.3 From 3cc5be7739295ce00f5658c6f45c5c453412f708 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:25 +0200 Subject: sisusb: remove dummy variables bytes_written parameter of sisusb_copy_memory and sisusb_read_memory is an out parameter, but its value is never used. So remove it and pass a dummy variable down to sisusb_read_mem_bulk. Signed-off-by: Jiri Slaby Cc: Thomas Winischhofer Cc: linux-usb@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb.c | 28 +++++++++++++--------------- drivers/usb/misc/sisusbvga/sisusb_con.c | 28 ++++++++++------------------ drivers/usb/misc/sisusbvga/sisusb_init.h | 2 +- 3 files changed, 24 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 15666ad7c772..02abfcdfbf7b 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -1285,18 +1285,22 @@ int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data) } int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src, - u32 dest, int length, size_t *bytes_written) + u32 dest, int length) { + size_t dummy; + return sisusb_write_mem_bulk(sisusb, dest, src, length, - NULL, 0, bytes_written); + NULL, 0, &dummy); } #ifdef SISUSBENDIANTEST -int sisusb_read_memory(struct sisusb_usb_data *sisusb, char *dest, - u32 src, int length, size_t *bytes_written) +static int sisusb_read_memory(struct sisusb_usb_data *sisusb, char *dest, + u32 src, int length) { + size_t dummy; + return sisusb_read_mem_bulk(sisusb, src, dest, length, - NULL, bytes_written); + NULL, &dummy); } #endif #endif @@ -1306,16 +1310,14 @@ static void sisusb_testreadwrite(struct sisusb_usb_data *sisusb) { static char srcbuffer[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }; char destbuffer[10]; - size_t dummy; int i, j; - sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy); + sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7); for (i = 1; i <= 7; i++) { dev_dbg(&sisusb->sisusb_dev->dev, "sisusb: rwtest %d bytes\n", i); - sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, - i, &dummy); + sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i); for (j = 0; j < i; j++) { dev_dbg(&sisusb->sisusb_dev->dev, "rwtest read[%d] = %x\n", @@ -2276,7 +2278,6 @@ int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init) const struct font_desc *myfont; u8 *tempbuf; u16 *tempbufb; - size_t written; static const char bootstring[] = "SiSUSB VGA text console, (C) 2005 Thomas Winischhofer."; static const char bootlogo[] = "(o_ //\\ V_/_"; @@ -2343,18 +2344,15 @@ int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init) *(tempbufb++) = 0x0700 | bootstring[i++]; ret |= sisusb_copy_memory(sisusb, tempbuf, - sisusb->vrambase, 8192, &written); + sisusb->vrambase, 8192); vfree(tempbuf); } } else if (sisusb->scrbuf) { - ret |= sisusb_copy_memory(sisusb, (char *)sisusb->scrbuf, - sisusb->vrambase, sisusb->scrbuf_size, - &written); - + sisusb->vrambase, sisusb->scrbuf_size); } if (sisusb->sisusb_cursor_size_from >= 0 && diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index afa853209f1d..0ebbf49cd649 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -370,7 +370,6 @@ static void sisusbcon_putc(struct vc_data *c, int ch, int y, int x) { struct sisusb_usb_data *sisusb; - ssize_t written; sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num); if (!sisusb) @@ -384,7 +383,7 @@ sisusbcon_putc(struct vc_data *c, int ch, int y, int x) sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y), - (long)SISUSB_HADDR(x, y), 2, &written); + (long)SISUSB_HADDR(x, y), 2); mutex_unlock(&sisusb->lock); } @@ -395,7 +394,6 @@ sisusbcon_putcs(struct vc_data *c, const unsigned short *s, int count, int y, int x) { struct sisusb_usb_data *sisusb; - ssize_t written; u16 *dest; int i; @@ -420,7 +418,7 @@ sisusbcon_putcs(struct vc_data *c, const unsigned short *s, } sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y), - (long)SISUSB_HADDR(x, y), count * 2, &written); + (long)SISUSB_HADDR(x, y), count * 2); mutex_unlock(&sisusb->lock); } @@ -431,7 +429,6 @@ sisusbcon_clear(struct vc_data *c, int y, int x, int height, int width) { struct sisusb_usb_data *sisusb; u16 eattr = c->vc_video_erase_char; - ssize_t written; int i, length, cols; u16 *dest; @@ -475,7 +472,7 @@ sisusbcon_clear(struct vc_data *c, int y, int x, int height, int width) sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(x, y), - (long)SISUSB_HADDR(x, y), length, &written); + (long)SISUSB_HADDR(x, y), length); mutex_unlock(&sisusb->lock); } @@ -486,7 +483,6 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx, int dy, int dx, int height, int width) { struct sisusb_usb_data *sisusb; - ssize_t written; int cols, length; if (width <= 0 || height <= 0) @@ -509,7 +505,7 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx, sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(dx, dy), - (long)SISUSB_HADDR(dx, dy), length, &written); + (long)SISUSB_HADDR(dx, dy), length); mutex_unlock(&sisusb->lock); } @@ -519,7 +515,6 @@ static int sisusbcon_switch(struct vc_data *c) { struct sisusb_usb_data *sisusb; - ssize_t written; int length; /* Returnvalue 0 means we have fully restored screen, @@ -559,7 +554,7 @@ sisusbcon_switch(struct vc_data *c) sisusb_copy_memory(sisusb, (unsigned char *)c->vc_origin, (long)SISUSB_HADDR(0, 0), - length, &written); + length); mutex_unlock(&sisusb->lock); @@ -644,7 +639,6 @@ sisusbcon_blank(struct vc_data *c, int blank, int mode_switch) { struct sisusb_usb_data *sisusb; u8 sr1, cr17, pmreg, cr63; - ssize_t written; int ret = 0; sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num); @@ -672,7 +666,7 @@ sisusbcon_blank(struct vc_data *c, int blank, int mode_switch) (unsigned char *)c->vc_origin, (u32)(sisusb->vrambase + (c->vc_origin - sisusb->scrbuf)), - c->vc_screenbuf_size, &written); + c->vc_screenbuf_size); sisusb->con_blanked = 1; ret = 1; break; @@ -860,7 +854,6 @@ sisusbcon_scroll_area(struct vc_data *c, struct sisusb_usb_data *sisusb, int cols = sisusb->sisusb_num_columns; int length = ((b - t) * cols) * 2; u16 eattr = c->vc_video_erase_char; - ssize_t written; /* sisusb->lock is down */ @@ -890,7 +883,7 @@ sisusbcon_scroll_area(struct vc_data *c, struct sisusb_usb_data *sisusb, } sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(0, t), - (long)SISUSB_HADDR(0, t), length, &written); + (long)SISUSB_HADDR(0, t), length); mutex_unlock(&sisusb->lock); @@ -903,7 +896,6 @@ sisusbcon_scroll(struct vc_data *c, int t, int b, int dir, int lines) { struct sisusb_usb_data *sisusb; u16 eattr = c->vc_video_erase_char; - ssize_t written; int copyall = 0; unsigned long oldorigin; unsigned int delta = lines * c->vc_size_row; @@ -996,18 +988,18 @@ sisusbcon_scroll(struct vc_data *c, int t, int b, int dir, int lines) sisusb_copy_memory(sisusb, (char *)c->vc_origin, (u32)(sisusb->vrambase + originoffset), - c->vc_screenbuf_size, &written); + c->vc_screenbuf_size); else if (dir == SM_UP) sisusb_copy_memory(sisusb, (char *)c->vc_origin + c->vc_screenbuf_size - delta, (u32)sisusb->vrambase + originoffset + c->vc_screenbuf_size - delta, - delta, &written); + delta); else sisusb_copy_memory(sisusb, (char *)c->vc_origin, (u32)(sisusb->vrambase + originoffset), - delta, &written); + delta); c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size; c->vc_visible_origin = c->vc_origin; diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.h b/drivers/usb/misc/sisusbvga/sisusb_init.h index c46ce42d4489..e79a616f0d26 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_init.h +++ b/drivers/usb/misc/sisusbvga/sisusb_init.h @@ -828,7 +828,7 @@ void sisusb_delete(struct kref *kref); int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data); int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 * data); int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src, - u32 dest, int length, size_t * bytes_written); + u32 dest, int length); int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init); int sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot, u8 * arg, int cmapsz, int ch512, int dorecalc, -- cgit v1.2.3 From 97293de977365fe672daec2523e66ef457104921 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:26 +0200 Subject: tty: vt, consw->con_scrolldelta cleanup * allow NULL consw->con_scrolldelta (some consoles define an empty hook) * => remove empty hooks now * return value of consw->con_scrolldelta is never checked => make the function void * document consw->con_scrolldelta a bit Signed-off-by: Jiri Slaby Cc: Thomas Winischhofer Cc: linux-usb@vger.kernel.org Cc: Jean-Christophe Plagniol-Villard Cc: Tomi Valkeinen Cc: "James E.J. Bottomley" Cc: Helge Deller Cc: linux-fbdev@vger.kernel.org Cc: linux-parisc@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 2 +- drivers/usb/misc/sisusbvga/sisusb_con.c | 11 +++-------- drivers/video/console/dummycon.c | 1 - drivers/video/console/fbcon.c | 16 +++++++--------- drivers/video/console/mdacon.c | 6 ------ drivers/video/console/newport_con.c | 7 ------- drivers/video/console/sticon.c | 6 ------ drivers/video/console/vgacon.c | 13 +++++-------- include/linux/console.h | 8 +++++++- 9 files changed, 23 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index abc79ae19079..365a91d01a0e 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2468,7 +2468,7 @@ static void console_callback(struct work_struct *ignored) if (scrollback_delta) { struct vc_data *vc = vc_cons[fg_console].d; clear_selection(); - if (vc->vc_mode == KD_TEXT) + if (vc->vc_mode == KD_TEXT && vc->vc_sw->con_scrolldelta) vc->vc_sw->con_scrolldelta(vc, scrollback_delta); scrollback_delta = 0; } diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index 0ebbf49cd649..a8244ebeb7a7 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -717,24 +717,22 @@ sisusbcon_blank(struct vc_data *c, int blank, int mode_switch) } /* interface routine */ -static int +static void sisusbcon_scrolldelta(struct vc_data *c, int lines) { struct sisusb_usb_data *sisusb; int margin = c->vc_size_row * 4; int ul, we, p, st; - /* The return value does not seem to be used */ - sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num); if (!sisusb) - return 0; + return; /* sisusb->lock is down */ if (sisusb_is_inactive(c, sisusb)) { mutex_unlock(&sisusb->lock); - return 0; + return; } if (!lines) /* Turn scrollback off */ @@ -774,8 +772,6 @@ sisusbcon_scrolldelta(struct vc_data *c, int lines) sisusbcon_set_start_address(sisusb, c); mutex_unlock(&sisusb->lock); - - return 1; } /* Interface routine */ @@ -1433,7 +1429,6 @@ static const struct consw sisusb_dummy_con = { .con_font_default = SISUSBCONDUMMY, .con_font_copy = SISUSBCONDUMMY, .con_set_palette = SISUSBCONDUMMY, - .con_scrolldelta = SISUSBCONDUMMY, }; int diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c index 0efc52f11ad0..9ce03b9aba88 100644 --- a/drivers/video/console/dummycon.c +++ b/drivers/video/console/dummycon.c @@ -72,6 +72,5 @@ const struct consw dummy_con = { .con_font_default = DUMMY, .con_font_copy = DUMMY, .con_set_palette = DUMMY, - .con_scrolldelta = DUMMY, }; EXPORT_SYMBOL_GPL(dummy_con); diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index afd3301ac40c..eadc7bf62eb3 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -171,7 +171,6 @@ static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, static int fbcon_switch(struct vc_data *vc); static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch); static int fbcon_set_palette(struct vc_data *vc, const unsigned char *table); -static int fbcon_scrolldelta(struct vc_data *vc, int lines); /* * Internal routines @@ -2765,7 +2764,7 @@ static void fbcon_invert_region(struct vc_data *vc, u16 * p, int cnt) } } -static int fbcon_scrolldelta(struct vc_data *vc, int lines) +static void fbcon_scrolldelta(struct vc_data *vc, int lines) { struct fb_info *info = registered_fb[con2fb_map[fg_console]]; struct fbcon_ops *ops = info->fbcon_par; @@ -2774,9 +2773,9 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines) if (softback_top) { if (vc->vc_num != fg_console) - return 0; + return; if (vc->vc_mode != KD_TEXT || !lines) - return 0; + return; if (logo_shown >= 0) { struct vc_data *conp2 = vc_cons[logo_shown].d; @@ -2809,11 +2808,11 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines) fbcon_cursor(vc, CM_ERASE | CM_SOFTBACK); fbcon_redraw_softback(vc, disp, lines); fbcon_cursor(vc, CM_DRAW | CM_SOFTBACK); - return 0; + return; } if (!scrollback_phys_max) - return -ENOSYS; + return; scrollback_old = scrollback_current; scrollback_current -= lines; @@ -2822,10 +2821,10 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines) else if (scrollback_current > scrollback_max) scrollback_current = scrollback_max; if (scrollback_current == scrollback_old) - return 0; + return; if (fbcon_is_inactive(vc, info)) - return 0; + return; fbcon_cursor(vc, CM_ERASE); @@ -2852,7 +2851,6 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines) if (!scrollback_current) fbcon_cursor(vc, CM_DRAW); - return 0; } static int fbcon_set_origin(struct vc_data *vc) diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index 8edc062536a8..234af26b4829 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c @@ -505,11 +505,6 @@ static int mdacon_blank(struct vc_data *c, int blank, int mode_switch) } } -static int mdacon_scrolldelta(struct vc_data *c, int lines) -{ - return 0; -} - static void mdacon_cursor(struct vc_data *c, int mode) { if (mode == CM_ERASE) { @@ -578,7 +573,6 @@ static const struct consw mda_con = { .con_switch = mdacon_switch, .con_blank = mdacon_blank, .con_set_palette = mdacon_set_palette, - .con_scrolldelta = mdacon_scrolldelta, .con_build_attr = mdacon_build_attr, .con_invert_region = mdacon_invert_region, }; diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index 0553dfe684ef..eb3d4ce12cd5 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -579,12 +579,6 @@ static int newport_set_palette(struct vc_data *vc, const unsigned char *table) return -EINVAL; } -static int newport_scrolldelta(struct vc_data *vc, int lines) -{ - /* there is (nearly) no off-screen memory, so we can't scroll back */ - return 0; -} - static int newport_scroll(struct vc_data *vc, int t, int b, int dir, int lines) { @@ -735,7 +729,6 @@ const struct consw newport_con = { .con_font_set = newport_font_set, .con_font_default = newport_font_default, .con_set_palette = newport_set_palette, - .con_scrolldelta = newport_scrolldelta, .con_set_origin = DUMMY, .con_save_screen = DUMMY }; diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index e440c2d9fe7c..20f6a2f5d4a7 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c @@ -256,11 +256,6 @@ static int sticon_blank(struct vc_data *c, int blank, int mode_switch) return 1; } -static int sticon_scrolldelta(struct vc_data *conp, int lines) -{ - return 0; -} - static u16 *sticon_screen_pos(struct vc_data *conp, int offset) { int line; @@ -359,7 +354,6 @@ static const struct consw sti_con = { .con_switch = sticon_switch, .con_blank = sticon_blank, .con_set_palette = sticon_set_palette, - .con_scrolldelta = sticon_scrolldelta, .con_set_origin = sticon_set_origin, .con_save_screen = sticon_save_screen, .con_build_attr = sticon_build_attr, diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 8bf911002cba..f447d6916991 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -80,7 +80,7 @@ static void vgacon_deinit(struct vc_data *c); static void vgacon_cursor(struct vc_data *c, int mode); static int vgacon_switch(struct vc_data *c); static int vgacon_blank(struct vc_data *c, int blank, int mode_switch); -static int vgacon_scrolldelta(struct vc_data *c, int lines); +static void vgacon_scrolldelta(struct vc_data *c, int lines); static int vgacon_set_origin(struct vc_data *c); static void vgacon_save_screen(struct vc_data *c); static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, @@ -248,18 +248,18 @@ static void vgacon_restore_screen(struct vc_data *c) } } -static int vgacon_scrolldelta(struct vc_data *c, int lines) +static void vgacon_scrolldelta(struct vc_data *c, int lines) { int start, end, count, soff; if (!lines) { c->vc_visible_origin = c->vc_origin; vga_set_mem_top(c); - return 1; + return; } if (!vgacon_scrollback) - return 1; + return; if (!vgacon_scrollback_save) { vgacon_cursor(c, CM_ERASE); @@ -320,8 +320,6 @@ static int vgacon_scrolldelta(struct vc_data *c, int lines) scr_memcpyw(d, s, diff * c->vc_size_row); } else vgacon_cursor(c, CM_MOVE); - - return 1; } #else #define vgacon_scrollback_startup(...) do { } while (0) @@ -334,7 +332,7 @@ static void vgacon_restore_screen(struct vc_data *c) vgacon_scrolldelta(c, 0); } -static int vgacon_scrolldelta(struct vc_data *c, int lines) +static void vgacon_scrolldelta(struct vc_data *c, int lines) { if (!lines) /* Turn scrollback off */ c->vc_visible_origin = c->vc_origin; @@ -362,7 +360,6 @@ static int vgacon_scrolldelta(struct vc_data *c, int lines) c->vc_visible_origin = vga_vram_base + (p + ul) % we; } vga_set_mem_top(c); - return 1; } #endif /* CONFIG_VGACON_SOFT_SCROLLBACK */ diff --git a/include/linux/console.h b/include/linux/console.h index 98c8615dc300..d175de8d7006 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -28,6 +28,12 @@ struct tty_struct; #define VT100ID "\033[?1;2c" #define VT102ID "\033[?6c" +/** + * struct consw - callbacks for consoles + * + * @con_scrolldelta: the contents of the console should be scrolled by @lines. + * Invoked by user. (optional) + */ struct consw { struct module *owner; const char *(*con_startup)(void); @@ -48,7 +54,7 @@ struct consw { int (*con_resize)(struct vc_data *, unsigned int, unsigned int, unsigned int); int (*con_set_palette)(struct vc_data *, const unsigned char *); - int (*con_scrolldelta)(struct vc_data *, int); + void (*con_scrolldelta)(struct vc_data *, int lines); int (*con_set_origin)(struct vc_data *); void (*con_save_screen)(struct vc_data *); u8 (*con_build_attr)(struct vc_data *, u8, u8, u8, u8, u8, u8); -- cgit v1.2.3 From 709280da6238629c3b488b7be87c6d9185f4d03e Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:27 +0200 Subject: tty: vt, consw->con_set_palette cleanup * allow NULL consw->con_set_palette (some consoles define an empty hook) * => remove empty hooks now * return value of consw->con_set_palette is never checked => make the function void * document consw->con_set_palette a bit Signed-off-by: Jiri Slaby Cc: Thomas Winischhofer Cc: linux-usb@vger.kernel.org Cc: Jean-Christophe Plagniol-Villard Cc: Tomi Valkeinen Cc: "James E.J. Bottomley" Cc: Helge Deller Cc: linux-fbdev@vger.kernel.org Cc: linux-parisc@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 2 +- drivers/usb/misc/sisusbvga/sisusb_con.c | 11 ++++------- drivers/video/console/dummycon.c | 1 - drivers/video/console/fbcon.c | 10 +++++----- drivers/video/console/mdacon.c | 6 ------ drivers/video/console/newport_con.c | 6 ------ drivers/video/console/sticon.c | 6 ------ drivers/video/console/vgacon.c | 7 ++----- include/linux/console.h | 4 +++- 9 files changed, 15 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 365a91d01a0e..d5d906051613 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -3978,7 +3978,7 @@ static void set_palette(struct vc_data *vc) { WARN_CONSOLE_UNLOCKED(); - if (vc->vc_mode != KD_GRAPHICS) + if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_set_palette) vc->vc_sw->con_set_palette(vc, color_table); } diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index a8244ebeb7a7..4112835f4aed 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -595,7 +595,7 @@ sisusbcon_save_screen(struct vc_data *c) } /* interface routine */ -static int +static void sisusbcon_set_palette(struct vc_data *c, const unsigned char *table) { struct sisusb_usb_data *sisusb; @@ -604,17 +604,17 @@ sisusbcon_set_palette(struct vc_data *c, const unsigned char *table) /* Return value not used by vt */ if (!CON_IS_VISIBLE(c)) - return -EINVAL; + return; sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num); if (!sisusb) - return -EINVAL; + return; /* sisusb->lock is down */ if (sisusb_is_inactive(c, sisusb)) { mutex_unlock(&sisusb->lock); - return -EINVAL; + return; } for (i = j = 0; i < 16; i++) { @@ -629,8 +629,6 @@ sisusbcon_set_palette(struct vc_data *c, const unsigned char *table) } mutex_unlock(&sisusb->lock); - - return 0; } /* interface routine */ @@ -1428,7 +1426,6 @@ static const struct consw sisusb_dummy_con = { .con_font_get = SISUSBCONDUMMY, .con_font_default = SISUSBCONDUMMY, .con_font_copy = SISUSBCONDUMMY, - .con_set_palette = SISUSBCONDUMMY, }; int diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c index 9ce03b9aba88..0ef544ef5634 100644 --- a/drivers/video/console/dummycon.c +++ b/drivers/video/console/dummycon.c @@ -71,6 +71,5 @@ const struct consw dummy_con = { .con_font_get = DUMMY, .con_font_default = DUMMY, .con_font_copy = DUMMY, - .con_set_palette = DUMMY, }; EXPORT_SYMBOL_GPL(dummy_con); diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index eadc7bf62eb3..9359b06377cf 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -170,7 +170,7 @@ static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, int height, int width); static int fbcon_switch(struct vc_data *vc); static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch); -static int fbcon_set_palette(struct vc_data *vc, const unsigned char *table); +static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table); /* * Internal routines @@ -2651,17 +2651,17 @@ static struct fb_cmap palette_cmap = { 0, 16, palette_red, palette_green, palette_blue, NULL }; -static int fbcon_set_palette(struct vc_data *vc, const unsigned char *table) +static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table) { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; int i, j, k, depth; u8 val; if (fbcon_is_inactive(vc, info)) - return -EINVAL; + return; if (!CON_IS_VISIBLE(vc)) - return 0; + return; depth = fb_get_color_depth(&info->var, &info->fix); if (depth > 3) { @@ -2683,7 +2683,7 @@ static int fbcon_set_palette(struct vc_data *vc, const unsigned char *table) } else fb_copy_cmap(fb_default_cmap(1 << depth), &palette_cmap); - return fb_set_cmap(&palette_cmap, info); + fb_set_cmap(&palette_cmap, info); } static u16 *fbcon_screen_pos(struct vc_data *vc, int offset) diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index 234af26b4829..1fe5245eb6dd 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c @@ -481,11 +481,6 @@ static int mdacon_switch(struct vc_data *c) return 1; /* redrawing needed */ } -static int mdacon_set_palette(struct vc_data *c, const unsigned char *table) -{ - return -EINVAL; -} - static int mdacon_blank(struct vc_data *c, int blank, int mode_switch) { if (mda_type == TYPE_MDA) { @@ -572,7 +567,6 @@ static const struct consw mda_con = { .con_bmove = mdacon_bmove, .con_switch = mdacon_switch, .con_blank = mdacon_blank, - .con_set_palette = mdacon_set_palette, .con_build_attr = mdacon_build_attr, .con_invert_region = mdacon_invert_region, }; diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index eb3d4ce12cd5..a436930f9e5d 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -574,11 +574,6 @@ static int newport_font_set(struct vc_data *vc, struct console_font *font, unsig return newport_set_font(vc->vc_num, font); } -static int newport_set_palette(struct vc_data *vc, const unsigned char *table) -{ - return -EINVAL; -} - static int newport_scroll(struct vc_data *vc, int t, int b, int dir, int lines) { @@ -728,7 +723,6 @@ const struct consw newport_con = { .con_blank = newport_blank, .con_font_set = newport_font_set, .con_font_default = newport_font_default, - .con_set_palette = newport_set_palette, .con_set_origin = DUMMY, .con_save_screen = DUMMY }; diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index 20f6a2f5d4a7..fe7c4dbb676e 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c @@ -79,11 +79,6 @@ static const char *sticon_startup(void) return "STI console"; } -static int sticon_set_palette(struct vc_data *c, const unsigned char *table) -{ - return -EINVAL; -} - static void sticon_putc(struct vc_data *conp, int c, int ypos, int xpos) { int redraw_cursor = 0; @@ -353,7 +348,6 @@ static const struct consw sti_con = { .con_bmove = sticon_bmove, .con_switch = sticon_switch, .con_blank = sticon_blank, - .con_set_palette = sticon_set_palette, .con_set_origin = sticon_set_origin, .con_save_screen = sticon_save_screen, .con_build_attr = sticon_build_attr, diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index f447d6916991..aaae9bd23900 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -856,16 +856,13 @@ static void vga_set_palette(struct vc_data *vc, const unsigned char *table) } } -static int vgacon_set_palette(struct vc_data *vc, const unsigned char *table) +static void vgacon_set_palette(struct vc_data *vc, const unsigned char *table) { #ifdef CAN_LOAD_PALETTE if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked || !CON_IS_VISIBLE(vc)) - return -EINVAL; + return; vga_set_palette(vc, table); - return 0; -#else - return -EINVAL; #endif } diff --git a/include/linux/console.h b/include/linux/console.h index d175de8d7006..382a527104c4 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -31,6 +31,7 @@ struct tty_struct; /** * struct consw - callbacks for consoles * + * @con_set_palette: sets the palette of the console to @table (optional) * @con_scrolldelta: the contents of the console should be scrolled by @lines. * Invoked by user. (optional) */ @@ -53,7 +54,8 @@ struct consw { int (*con_font_copy)(struct vc_data *, int); int (*con_resize)(struct vc_data *, unsigned int, unsigned int, unsigned int); - int (*con_set_palette)(struct vc_data *, const unsigned char *); + void (*con_set_palette)(struct vc_data *, + const unsigned char *table); void (*con_scrolldelta)(struct vc_data *, int lines); int (*con_set_origin)(struct vc_data *); void (*con_save_screen)(struct vc_data *); -- cgit v1.2.3 From 52ad1f38b4f6e2f2133668247036ad64ef7ae18a Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:28 +0200 Subject: tty: vt, remove consw->con_bmove It is never called since commit 81732c3b2fede (tty vt: Fix line garbage in virtual console on command line edition) in 3.7. So remove all the callbacks. Signed-off-by: Jiri Slaby Cc: Thomas Winischhofer Cc: linux-usb@vger.kernel.org Cc: Jean-Christophe Plagniol-Villard Cc: Tomi Valkeinen Cc: "James E.J. Bottomley" Cc: Helge Deller Cc: linux-fbdev@vger.kernel.org Cc: linux-parisc@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb_con.c | 35 --------------------------------- drivers/video/console/dummycon.c | 1 - drivers/video/console/fbcon.c | 1 - drivers/video/console/mdacon.c | 33 ------------------------------- drivers/video/console/newport_con.c | 29 --------------------------- drivers/video/console/sticon.c | 17 ---------------- drivers/video/console/vgacon.c | 1 - include/linux/console.h | 1 - 8 files changed, 118 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index 4112835f4aed..52a6da991165 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -477,39 +477,6 @@ sisusbcon_clear(struct vc_data *c, int y, int x, int height, int width) mutex_unlock(&sisusb->lock); } -/* Interface routine */ -static void -sisusbcon_bmove(struct vc_data *c, int sy, int sx, - int dy, int dx, int height, int width) -{ - struct sisusb_usb_data *sisusb; - int cols, length; - - if (width <= 0 || height <= 0) - return; - - sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num); - if (!sisusb) - return; - - /* sisusb->lock is down */ - - cols = sisusb->sisusb_num_columns; - - if (sisusb_is_inactive(c, sisusb)) { - mutex_unlock(&sisusb->lock); - return; - } - - length = ((height * cols) - dx - (cols - width - dx)) * 2; - - - sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(dx, dy), - (long)SISUSB_HADDR(dx, dy), length); - - mutex_unlock(&sisusb->lock); -} - /* interface routine */ static int sisusbcon_switch(struct vc_data *c) @@ -1371,7 +1338,6 @@ static const struct consw sisusb_con = { .con_putcs = sisusbcon_putcs, .con_cursor = sisusbcon_cursor, .con_scroll = sisusbcon_scroll, - .con_bmove = sisusbcon_bmove, .con_switch = sisusbcon_switch, .con_blank = sisusbcon_blank, .con_font_set = sisusbcon_font_set, @@ -1419,7 +1385,6 @@ static const struct consw sisusb_dummy_con = { .con_putcs = SISUSBCONDUMMY, .con_cursor = SISUSBCONDUMMY, .con_scroll = SISUSBCONDUMMY, - .con_bmove = SISUSBCONDUMMY, .con_switch = SISUSBCONDUMMY, .con_blank = SISUSBCONDUMMY, .con_font_set = SISUSBCONDUMMY, diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c index 0ef544ef5634..9269d5685239 100644 --- a/drivers/video/console/dummycon.c +++ b/drivers/video/console/dummycon.c @@ -64,7 +64,6 @@ const struct consw dummy_con = { .con_putcs = DUMMY, .con_cursor = DUMMY, .con_scroll = DUMMY, - .con_bmove = DUMMY, .con_switch = DUMMY, .con_blank = DUMMY, .con_font_set = DUMMY, diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 9359b06377cf..eef8a8b7274f 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -3334,7 +3334,6 @@ static const struct consw fb_con = { .con_putcs = fbcon_putcs, .con_cursor = fbcon_cursor, .con_scroll = fbcon_scroll, - .con_bmove = fbcon_bmove, .con_switch = fbcon_switch, .con_blank = fbcon_blank, .con_font_set = fbcon_set_font, diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index 1fe5245eb6dd..bacbb044d77c 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c @@ -444,38 +444,6 @@ static void mdacon_clear(struct vc_data *c, int y, int x, } } -static void mdacon_bmove(struct vc_data *c, int sy, int sx, - int dy, int dx, int height, int width) -{ - u16 *src, *dest; - - if (width <= 0 || height <= 0) - return; - - if (sx==0 && dx==0 && width==mda_num_columns) { - scr_memmovew(MDA_ADDR(0,dy), MDA_ADDR(0,sy), height*width*2); - - } else if (dy < sy || (dy == sy && dx < sx)) { - src = MDA_ADDR(sx, sy); - dest = MDA_ADDR(dx, dy); - - for (; height > 0; height--) { - scr_memmovew(dest, src, width*2); - src += mda_num_columns; - dest += mda_num_columns; - } - } else { - src = MDA_ADDR(sx, sy+height-1); - dest = MDA_ADDR(dx, dy+height-1); - - for (; height > 0; height--) { - scr_memmovew(dest, src, width*2); - src -= mda_num_columns; - dest -= mda_num_columns; - } - } -} - static int mdacon_switch(struct vc_data *c) { return 1; /* redrawing needed */ @@ -564,7 +532,6 @@ static const struct consw mda_con = { .con_putcs = mdacon_putcs, .con_cursor = mdacon_cursor, .con_scroll = mdacon_scroll, - .con_bmove = mdacon_bmove, .con_switch = mdacon_switch, .con_blank = mdacon_blank, .con_build_attr = mdacon_build_attr, diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index a436930f9e5d..e3b9521e4ec3 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -673,34 +673,6 @@ static int newport_scroll(struct vc_data *vc, int t, int b, int dir, return 1; } -static void newport_bmove(struct vc_data *vc, int sy, int sx, int dy, - int dx, int h, int w) -{ - short xs, ys, xe, ye, xoffs, yoffs; - - xs = sx << 3; - xe = ((sx + w) << 3) - 1; - /* - * as bmove is only used to move stuff around in the same line - * (h == 1), we don't care about wrap arounds caused by topscan != 0 - */ - ys = ((sy << 4) + topscan) & 0x3ff; - ye = (((sy + h) << 4) - 1 + topscan) & 0x3ff; - xoffs = (dx - sx) << 3; - yoffs = (dy - sy) << 4; - if (xoffs > 0) { - /* move to the right, exchange starting points */ - swap(xe, xs); - } - newport_wait(npregs); - npregs->set.drawmode0 = (NPORT_DMODE0_S2S | NPORT_DMODE0_BLOCK | - NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX - | NPORT_DMODE0_STOPY); - npregs->set.xystarti = (xs << 16) | ys; - npregs->set.xyendi = (xe << 16) | ye; - npregs->go.xymove = (xoffs << 16) | yoffs; -} - static int newport_dummy(struct vc_data *c) { return 0; @@ -718,7 +690,6 @@ const struct consw newport_con = { .con_putcs = newport_putcs, .con_cursor = newport_cursor, .con_scroll = newport_scroll, - .con_bmove = newport_bmove, .con_switch = newport_switch, .con_blank = newport_blank, .con_font_set = newport_font_set, diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index fe7c4dbb676e..3a10ac19598f 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c @@ -177,22 +177,6 @@ static int sticon_scroll(struct vc_data *conp, int t, int b, int dir, int count) return 0; } -static void sticon_bmove(struct vc_data *conp, int sy, int sx, - int dy, int dx, int height, int width) -{ - if (!width || !height) - return; -#if 0 - if (((sy <= p->cursor_y) && (p->cursor_y < sy+height) && - (sx <= p->cursor_x) && (p->cursor_x < sx+width)) || - ((dy <= p->cursor_y) && (p->cursor_y < dy+height) && - (dx <= p->cursor_x) && (p->cursor_x < dx+width))) - sticon_cursor(p, CM_ERASE /*|CM_SOFTBACK*/); -#endif - - sti_bmove(sticon_sti, sy, sx, dy, dx, height, width); -} - static void sticon_init(struct vc_data *c, int init) { struct sti_struct *sti = sticon_sti; @@ -345,7 +329,6 @@ static const struct consw sti_con = { .con_putcs = sticon_putcs, .con_cursor = sticon_cursor, .con_scroll = sticon_scroll, - .con_bmove = sticon_bmove, .con_switch = sticon_switch, .con_blank = sticon_blank, .con_set_origin = sticon_set_origin, diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index aaae9bd23900..e280b3ceebd9 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -1421,7 +1421,6 @@ const struct consw vga_con = { .con_putcs = DUMMY, .con_cursor = vgacon_cursor, .con_scroll = vgacon_scroll, - .con_bmove = DUMMY, .con_switch = vgacon_switch, .con_blank = vgacon_blank, .con_font_set = vgacon_font_set, diff --git a/include/linux/console.h b/include/linux/console.h index 382a527104c4..d530c4627e54 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -45,7 +45,6 @@ struct consw { void (*con_putcs)(struct vc_data *, const unsigned short *, int, int, int); void (*con_cursor)(struct vc_data *, int); int (*con_scroll)(struct vc_data *, int, int, int, int); - void (*con_bmove)(struct vc_data *, int, int, int, int, int, int); int (*con_switch)(struct vc_data *); int (*con_blank)(struct vc_data *, int, int); int (*con_font_set)(struct vc_data *, struct console_font *, unsigned); -- cgit v1.2.3 From 6af39ed30264691994647daba07a416830f674b2 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:29 +0200 Subject: tty: vt, drop VT_BUF_VRAM_ONLY It is never defined. And I spent quite some time looking into the history and cannot find how this was ever used. Given it was not used in the history, I doubt it currently works as expected after the years of changes all over the code. So kill it. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index d5d906051613..600c3bb706a5 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -278,12 +278,7 @@ static void notify_update(struct vc_data *vc) */ #define IS_FG(vc) ((vc)->vc_num == fg_console) - -#ifdef VT_BUF_VRAM_ONLY -#define DO_UPDATE(vc) 0 -#else #define DO_UPDATE(vc) (CON_IS_VISIBLE(vc) && !console_blanked) -#endif static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed) { @@ -349,7 +344,6 @@ static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr) static void do_update_region(struct vc_data *vc, unsigned long start, int count) { -#ifndef VT_BUF_VRAM_ONLY unsigned int xx, yy, offset; u16 *p; @@ -390,7 +384,6 @@ static void do_update_region(struct vc_data *vc, unsigned long start, int count) start = vc->vc_sw->con_getxy(vc, start, NULL, NULL); } } -#endif } void update_region(struct vc_data *vc, unsigned long start, int count) @@ -413,7 +406,6 @@ static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink, return vc->vc_sw->con_build_attr(vc, _color, _intensity, _blink, _underline, _reverse, _italic); -#ifndef VT_BUF_VRAM_ONLY /* * ++roman: I completely changed the attribute format for monochrome * mode (!can_do_color). The formerly used MDA (monochrome display @@ -448,9 +440,6 @@ static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink, a <<= 1; return a; } -#else - return 0; -#endif } static void update_attr(struct vc_data *vc) @@ -470,10 +459,9 @@ void invert_screen(struct vc_data *vc, int offset, int count, int viewed) count /= 2; p = screenpos(vc, offset, viewed); - if (vc->vc_sw->con_invert_region) + if (vc->vc_sw->con_invert_region) { vc->vc_sw->con_invert_region(vc, p, count); -#ifndef VT_BUF_VRAM_ONLY - else { + } else { u16 *q = p; int cnt = count; u16 a; @@ -501,7 +489,7 @@ void invert_screen(struct vc_data *vc, int offset, int count, int viewed) } } } -#endif + if (DO_UPDATE(vc)) do_update_region(vc, (unsigned long) p, count); notify_update(vc); @@ -2178,14 +2166,10 @@ static int is_double_width(uint32_t ucs) /* acquires console_lock */ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count) { -#ifdef VT_BUF_VRAM_ONLY -#define FLUSH do { } while(0); -#else #define FLUSH if (draw_x >= 0) { \ vc->vc_sw->con_putcs(vc, (u16 *)draw_from, (u16 *)draw_to - (u16 *)draw_from, vc->vc_y, draw_x); \ draw_x = -1; \ } -#endif int c, tc, ok, n = 0, draw_x = -1; unsigned int currcons; -- cgit v1.2.3 From d711ea8f762eec3bc057bc92423c6ec804523a40 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:30 +0200 Subject: tty: vt, get rid of ugly FLUSH macro It's a macro accessing and changing some local variables. And the code uses it without appending semicolon which confuses everybody too. Switch from this bad guy to a sane standard function. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 600c3bb706a5..6e12d9c0ea41 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2163,14 +2163,20 @@ static int is_double_width(uint32_t ucs) return bisearch(ucs, double_width, ARRAY_SIZE(double_width) - 1); } +static void con_flush(struct vc_data *vc, unsigned long draw_from, + unsigned long draw_to, int *draw_x) +{ + if (*draw_x < 0) + return; + + vc->vc_sw->con_putcs(vc, (u16 *)draw_from, + (u16 *)draw_to - (u16 *)draw_from, vc->vc_y, *draw_x); + *draw_x = -1; +} + /* acquires console_lock */ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count) { -#define FLUSH if (draw_x >= 0) { \ - vc->vc_sw->con_putcs(vc, (u16 *)draw_from, (u16 *)draw_to - (u16 *)draw_from, vc->vc_y, draw_x); \ - draw_x = -1; \ - } - int c, tc, ok, n = 0, draw_x = -1; unsigned int currcons; unsigned long draw_from = 0, draw_to = 0; @@ -2362,12 +2368,13 @@ rescan_last_byte: } else { vc_attr = ((vc->vc_attr) & 0x88) | (((vc->vc_attr) & 0x70) >> 4) | (((vc->vc_attr) & 0x07) << 4); } - FLUSH + con_flush(vc, draw_from, draw_to, &draw_x); } while (1) { if (vc->vc_need_wrap || vc->vc_decim) - FLUSH + con_flush(vc, draw_from, draw_to, + &draw_x); if (vc->vc_need_wrap) { cr(vc); lf(vc); @@ -2397,9 +2404,8 @@ rescan_last_byte: } notify_write(vc, c); - if (inverse) { - FLUSH - } + if (inverse) + con_flush(vc, draw_from, draw_to, &draw_x); if (rescan) { rescan = 0; @@ -2410,15 +2416,14 @@ rescan_last_byte: } continue; } - FLUSH + con_flush(vc, draw_from, draw_to, &draw_x); do_con_trol(tty, vc, orig); } - FLUSH + con_flush(vc, draw_from, draw_to, &draw_x); console_conditional_schedule(); console_unlock(); notify_update(vc); return n; -#undef FLUSH } /* -- cgit v1.2.3 From e05ab238e30572abbac0cc4aba051553928de949 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:31 +0200 Subject: tty: vt, separate T.416 high colors handler The code with T.416 high colors handling is flushed to the right and hard to read. Move the code to a separate function and remove code duplication for foreground & background colors. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 85 +++++++++++++++++++++++------------------------------ 1 file changed, 37 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 6e12d9c0ea41..da49f5cfa654 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1284,6 +1284,40 @@ static void rgb_background(struct vc_data *vc, struct rgb c) | (c.r&0x80) >> 1 | (c.g&0x80) >> 2 | (c.b&0x80) >> 3; } +/* + * ITU T.416 Higher colour modes. They break the usual properties of SGR codes + * and thus need to be detected and ignored by hand. Strictly speaking, that + * standard also wants : rather than ; as separators, contrary to ECMA-48, but + * no one produces such codes and almost no one accepts them. + * + * Subcommands 3 (CMY) and 4 (CMYK) are so insane there's no point in + * supporting them. + */ +static int vc_t416_color(struct vc_data *vc, int i, + void(*set_color)(struct vc_data *vc, struct rgb c)) +{ + i++; + if (i > vc->vc_npar) + return i; + + if (vc->vc_par[i] == 5 && i < vc->vc_npar) { + /* 256 colours -- ubiquitous */ + i++; + set_color(vc, rgb_from_256(vc->vc_par[i])); + } else if (vc->vc_par[i] == 2 && i <= vc->vc_npar + 3) { + /* 24 bit -- extremely rare */ + struct rgb c = { + .r = vc->vc_par[i + 1], + .g = vc->vc_par[i + 2], + .b = vc->vc_par[i + 3], + }; + set_color(vc, c); + i += 3; + } + + return i; +} + /* console_lock is held */ static void csi_m(struct vc_data *vc) { @@ -1355,56 +1389,11 @@ static void csi_m(struct vc_data *vc) case 27: vc->vc_reverse = 0; break; - case 38: /* ITU T.416 - * Higher colour modes. - * They break the usual properties of SGR codes - * and thus need to be detected and ignored by - * hand. Strictly speaking, that standard also - * wants : rather than ; as separators, contrary - * to ECMA-48, but no one produces such codes - * and almost no one accepts them. - */ - i++; - if (i > vc->vc_npar) - break; - if (vc->vc_par[i] == 5 && /* 256 colours */ - i < vc->vc_npar) { /* ubiquitous */ - i++; - rgb_foreground(vc, - rgb_from_256(vc->vc_par[i])); - } else if (vc->vc_par[i] == 2 && /* 24 bit */ - i <= vc->vc_npar + 3) {/* extremely rare */ - struct rgb c = { - .r = vc->vc_par[i + 1], - .g = vc->vc_par[i + 2], - .b = vc->vc_par[i + 3], - }; - rgb_foreground(vc, c); - i += 3; - } - /* Subcommands 3 (CMY) and 4 (CMYK) are so insane - * there's no point in supporting them. - */ + case 38: + i = vc_t416_color(vc, i, rgb_foreground); break; case 48: - i++; - if (i > vc->vc_npar) - break; - if (vc->vc_par[i] == 5 && /* 256 colours */ - i < vc->vc_npar) { - i++; - rgb_background(vc, - rgb_from_256(vc->vc_par[i])); - } else if (vc->vc_par[i] == 2 && /* 24 bit */ - i <= vc->vc_npar + 3) { - struct rgb c = { - .r = vc->vc_par[i + 1], - .g = vc->vc_par[i + 2], - .b = vc->vc_par[i + 3], - }; - rgb_background(vc, c); - i += 3; - } + i = vc_t416_color(vc, i, rgb_background); break; case 39: vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0); -- cgit v1.2.3 From 0f91e14264cb04c90987206f30d97385eef121c9 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:32 +0200 Subject: tty: vt, do not pass structure over stack The compiler noticed passing structure over stack. Even though rgb is a small structure, let us define one and pass that over all the functions wherever needed. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 66 ++++++++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index da49f5cfa654..63972336de20 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1240,36 +1240,34 @@ static void default_attr(struct vc_data *vc) struct rgb { u8 r; u8 g; u8 b; }; -static struct rgb rgb_from_256(int i) +static void rgb_from_256(int i, struct rgb *c) { - struct rgb c; if (i < 8) { /* Standard colours. */ - c.r = i&1 ? 0xaa : 0x00; - c.g = i&2 ? 0xaa : 0x00; - c.b = i&4 ? 0xaa : 0x00; + c->r = i&1 ? 0xaa : 0x00; + c->g = i&2 ? 0xaa : 0x00; + c->b = i&4 ? 0xaa : 0x00; } else if (i < 16) { - c.r = i&1 ? 0xff : 0x55; - c.g = i&2 ? 0xff : 0x55; - c.b = i&4 ? 0xff : 0x55; + c->r = i&1 ? 0xff : 0x55; + c->g = i&2 ? 0xff : 0x55; + c->b = i&4 ? 0xff : 0x55; } else if (i < 232) { /* 6x6x6 colour cube. */ - c.r = (i - 16) / 36 * 85 / 2; - c.g = (i - 16) / 6 % 6 * 85 / 2; - c.b = (i - 16) % 6 * 85 / 2; + c->r = (i - 16) / 36 * 85 / 2; + c->g = (i - 16) / 6 % 6 * 85 / 2; + c->b = (i - 16) % 6 * 85 / 2; } else /* Grayscale ramp. */ - c.r = c.g = c.b = i * 10 - 2312; - return c; + c->r = c->g = c->b = i * 10 - 2312; } -static void rgb_foreground(struct vc_data *vc, struct rgb c) +static void rgb_foreground(struct vc_data *vc, const struct rgb *c) { - u8 hue, max = c.r; - if (c.g > max) - max = c.g; - if (c.b > max) - max = c.b; - hue = (c.r > max/2 ? 4 : 0) - | (c.g > max/2 ? 2 : 0) - | (c.b > max/2 ? 1 : 0); + u8 hue, max = c->r; + if (c->g > max) + max = c->g; + if (c->b > max) + max = c->b; + hue = (c->r > max/2 ? 4 : 0) + | (c->g > max/2 ? 2 : 0) + | (c->b > max/2 ? 1 : 0); if (hue == 7 && max <= 0x55) hue = 0, vc->vc_intensity = 2; else @@ -1277,11 +1275,11 @@ static void rgb_foreground(struct vc_data *vc, struct rgb c) vc->vc_color = (vc->vc_color & 0xf0) | hue; } -static void rgb_background(struct vc_data *vc, struct rgb c) +static void rgb_background(struct vc_data *vc, const struct rgb *c) { /* For backgrounds, err on the dark side. */ vc->vc_color = (vc->vc_color & 0x0f) - | (c.r&0x80) >> 1 | (c.g&0x80) >> 2 | (c.b&0x80) >> 3; + | (c->r&0x80) >> 1 | (c->g&0x80) >> 2 | (c->b&0x80) >> 3; } /* @@ -1294,8 +1292,10 @@ static void rgb_background(struct vc_data *vc, struct rgb c) * supporting them. */ static int vc_t416_color(struct vc_data *vc, int i, - void(*set_color)(struct vc_data *vc, struct rgb c)) + void(*set_color)(struct vc_data *vc, const struct rgb *c)) { + struct rgb c; + i++; if (i > vc->vc_npar) return i; @@ -1303,17 +1303,17 @@ static int vc_t416_color(struct vc_data *vc, int i, if (vc->vc_par[i] == 5 && i < vc->vc_npar) { /* 256 colours -- ubiquitous */ i++; - set_color(vc, rgb_from_256(vc->vc_par[i])); + rgb_from_256(vc->vc_par[i], &c); } else if (vc->vc_par[i] == 2 && i <= vc->vc_npar + 3) { /* 24 bit -- extremely rare */ - struct rgb c = { - .r = vc->vc_par[i + 1], - .g = vc->vc_par[i + 2], - .b = vc->vc_par[i + 3], - }; - set_color(vc, c); + c.r = vc->vc_par[i + 1]; + c.g = vc->vc_par[i + 2]; + c.b = vc->vc_par[i + 3]; i += 3; - } + } else + return i; + + set_color(vc, &c); return i; } -- cgit v1.2.3 From 193df0227964a0620267bb0236dfd6463a0ccea0 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:33 +0200 Subject: tty: vt, too many commands per line in rgb_foreground Do not opencode max3, use the macro. Separate commands. Until now, I have not noticed the comma. Make it one line, one command. And make the code obvious. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 63972336de20..acecd6662426 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1260,18 +1260,23 @@ static void rgb_from_256(int i, struct rgb *c) static void rgb_foreground(struct vc_data *vc, const struct rgb *c) { - u8 hue, max = c->r; - if (c->g > max) - max = c->g; - if (c->b > max) - max = c->b; - hue = (c->r > max/2 ? 4 : 0) - | (c->g > max/2 ? 2 : 0) - | (c->b > max/2 ? 1 : 0); - if (hue == 7 && max <= 0x55) - hue = 0, vc->vc_intensity = 2; + u8 hue = 0, max = max3(c->r, c->g, c->b); + + if (c->r > max / 2) + hue |= 4; + if (c->g > max / 2) + hue |= 2; + if (c->b > max / 2) + hue |= 1; + + if (hue == 7 && max <= 0x55) { + hue = 0; + vc->vc_intensity = 2; + } else if (max > 0xaa) + vc->vc_intensity = 2; else - vc->vc_intensity = (max > 0xaa) + 1; + vc->vc_intensity = 1; + vc->vc_color = (vc->vc_color & 0xf0) | hue; } -- cgit v1.2.3 From aada0a344182e3aec7bfb0cc611f272e6297c3e3 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:34 +0200 Subject: tty: vt, whitespace cleanup in csi_m Flush the switch cases to be aligned with the switch. Mostly everything can now fit to the 80-chars terminal. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 169 ++++++++++++++++++++++++++-------------------------- 1 file changed, 85 insertions(+), 84 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index acecd6662426..8ceabfd20561 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1330,90 +1330,91 @@ static void csi_m(struct vc_data *vc) for (i = 0; i <= vc->vc_npar; i++) switch (vc->vc_par[i]) { - case 0: /* all attributes off */ - default_attr(vc); - break; - case 1: - vc->vc_intensity = 2; - break; - case 2: - vc->vc_intensity = 0; - break; - case 3: - vc->vc_italic = 1; - break; - case 4: - vc->vc_underline = 1; - break; - case 5: - vc->vc_blink = 1; - break; - case 7: - vc->vc_reverse = 1; - break; - case 10: /* ANSI X3.64-1979 (SCO-ish?) - * Select primary font, don't display - * control chars if defined, don't set - * bit 8 on output. - */ - vc->vc_translate = set_translate(vc->vc_charset == 0 - ? vc->vc_G0_charset - : vc->vc_G1_charset, vc); - vc->vc_disp_ctrl = 0; - vc->vc_toggle_meta = 0; - break; - case 11: /* ANSI X3.64-1979 (SCO-ish?) - * Select first alternate font, lets - * chars < 32 be displayed as ROM chars. - */ - vc->vc_translate = set_translate(IBMPC_MAP, vc); - vc->vc_disp_ctrl = 1; - vc->vc_toggle_meta = 0; - break; - case 12: /* ANSI X3.64-1979 (SCO-ish?) - * Select second alternate font, toggle - * high bit before displaying as ROM char. - */ - vc->vc_translate = set_translate(IBMPC_MAP, vc); - vc->vc_disp_ctrl = 1; - vc->vc_toggle_meta = 1; - break; - case 21: - case 22: - vc->vc_intensity = 1; - break; - case 23: - vc->vc_italic = 0; - break; - case 24: - vc->vc_underline = 0; - break; - case 25: - vc->vc_blink = 0; - break; - case 27: - vc->vc_reverse = 0; - break; - case 38: - i = vc_t416_color(vc, i, rgb_foreground); - break; - case 48: - i = vc_t416_color(vc, i, rgb_background); - break; - case 39: - vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0); - break; - case 49: - vc->vc_color = (vc->vc_def_color & 0xf0) | (vc->vc_color & 0x0f); - break; - default: - if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37) - vc->vc_color = color_table[vc->vc_par[i] - 30] - | (vc->vc_color & 0xf0); - else if (vc->vc_par[i] >= 40 && vc->vc_par[i] <= 47) - vc->vc_color = (color_table[vc->vc_par[i] - 40] << 4) - | (vc->vc_color & 0x0f); - break; + case 0: /* all attributes off */ + default_attr(vc); + break; + case 1: + vc->vc_intensity = 2; + break; + case 2: + vc->vc_intensity = 0; + break; + case 3: + vc->vc_italic = 1; + break; + case 4: + vc->vc_underline = 1; + break; + case 5: + vc->vc_blink = 1; + break; + case 7: + vc->vc_reverse = 1; + break; + case 10: /* ANSI X3.64-1979 (SCO-ish?) + * Select primary font, don't display control chars if + * defined, don't set bit 8 on output. + */ + vc->vc_translate = set_translate(vc->vc_charset == 0 + ? vc->vc_G0_charset + : vc->vc_G1_charset, vc); + vc->vc_disp_ctrl = 0; + vc->vc_toggle_meta = 0; + break; + case 11: /* ANSI X3.64-1979 (SCO-ish?) + * Select first alternate font, lets chars < 32 be + * displayed as ROM chars. + */ + vc->vc_translate = set_translate(IBMPC_MAP, vc); + vc->vc_disp_ctrl = 1; + vc->vc_toggle_meta = 0; + break; + case 12: /* ANSI X3.64-1979 (SCO-ish?) + * Select second alternate font, toggle high bit + * before displaying as ROM char. + */ + vc->vc_translate = set_translate(IBMPC_MAP, vc); + vc->vc_disp_ctrl = 1; + vc->vc_toggle_meta = 1; + break; + case 21: + case 22: + vc->vc_intensity = 1; + break; + case 23: + vc->vc_italic = 0; + break; + case 24: + vc->vc_underline = 0; + break; + case 25: + vc->vc_blink = 0; + break; + case 27: + vc->vc_reverse = 0; + break; + case 38: + i = vc_t416_color(vc, i, rgb_foreground); + break; + case 48: + i = vc_t416_color(vc, i, rgb_background); + break; + case 39: + vc->vc_color = (vc->vc_def_color & 0x0f) | + (vc->vc_color & 0xf0); + break; + case 49: + vc->vc_color = (vc->vc_def_color & 0xf0) | + (vc->vc_color & 0x0f); + break; + default: + if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37) + vc->vc_color = color_table[vc->vc_par[i] - 30] + | (vc->vc_color & 0xf0); + else if (vc->vc_par[i] >= 40 && vc->vc_par[i] <= 47) + vc->vc_color = (color_table[vc->vc_par[i] - 40] << 4) + | (vc->vc_color & 0x0f); + break; } update_attr(vc); } -- cgit v1.2.3 From 6ca8dfd78187d8238abc5b2996848a0c8f07948d Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:35 +0200 Subject: tty: vt, convert more macros to functions Namely convert: * IS_FG -> con_is_fg * DO_UPDATE -> con_should_update * CON_IS_VISIBLE -> con_is_visible DO_UPDATE was a weird name for a yes/no answer, so the new name is con_should_update. Signed-off-by: Jiri Slaby Cc: Thomas Winischhofer Cc: Jean-Christophe Plagniol-Villard Cc: linux-usb@vger.kernel.org Cc: linux-fbdev@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 62 ++++++++++++++++++--------------- drivers/usb/misc/sisusbvga/sisusb_con.c | 4 +-- drivers/video/console/fbcon.c | 26 +++++++------- drivers/video/console/vgacon.c | 8 ++--- include/linux/console_struct.h | 5 ++- 5 files changed, 57 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 8ceabfd20561..26de5c0fc056 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -277,8 +277,15 @@ static void notify_update(struct vc_data *vc) * Low-Level Functions */ -#define IS_FG(vc) ((vc)->vc_num == fg_console) -#define DO_UPDATE(vc) (CON_IS_VISIBLE(vc) && !console_blanked) +static inline bool con_is_fg(const struct vc_data *vc) +{ + return vc->vc_num == fg_console; +} + +static inline bool con_should_update(const struct vc_data *vc) +{ + return con_is_visible(vc) && !console_blanked; +} static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed) { @@ -316,7 +323,7 @@ static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr) nr = b - t - 1; if (b > vc->vc_rows || t >= b || nr < 1) return; - if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_UP, nr)) + if (con_is_visible(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_UP, nr)) return; d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t); s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr)); @@ -334,7 +341,7 @@ static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr) nr = b - t - 1; if (b > vc->vc_rows || t >= b || nr < 1) return; - if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_DOWN, nr)) + if (con_is_visible(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_DOWN, nr)) return; s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t); step = vc->vc_cols * nr; @@ -390,7 +397,7 @@ void update_region(struct vc_data *vc, unsigned long start, int count) { WARN_CONSOLE_UNLOCKED(); - if (DO_UPDATE(vc)) { + if (con_should_update(vc)) { hide_cursor(vc); do_update_region(vc, start, count); set_cursor(vc); @@ -490,7 +497,7 @@ void invert_screen(struct vc_data *vc, int offset, int count, int viewed) } } - if (DO_UPDATE(vc)) + if (con_should_update(vc)) do_update_region(vc, (unsigned long) p, count); notify_update(vc); } @@ -507,7 +514,7 @@ void complement_pos(struct vc_data *vc, int offset) if (old_offset != -1 && old_offset >= 0 && old_offset < vc->vc_screenbuf_size) { scr_writew(old, screenpos(vc, old_offset, 1)); - if (DO_UPDATE(vc)) + if (con_should_update(vc)) vc->vc_sw->con_putc(vc, old, oldy, oldx); notify_update(vc); } @@ -522,7 +529,7 @@ void complement_pos(struct vc_data *vc, int offset) old = scr_readw(p); new = old ^ vc->vc_complement_mask; scr_writew(new, p); - if (DO_UPDATE(vc)) { + if (con_should_update(vc)) { oldx = (offset >> 1) % vc->vc_cols; oldy = (offset >> 1) / vc->vc_cols; vc->vc_sw->con_putc(vc, new, oldy, oldx); @@ -538,7 +545,7 @@ static void insert_char(struct vc_data *vc, unsigned int nr) scr_memmovew(p + nr, p, (vc->vc_cols - vc->vc_x - nr) * 2); scr_memsetw(p, vc->vc_video_erase_char, nr * 2); vc->vc_need_wrap = 0; - if (DO_UPDATE(vc)) + if (con_should_update(vc)) do_update_region(vc, (unsigned long) p, vc->vc_cols - vc->vc_x); } @@ -551,7 +558,7 @@ static void delete_char(struct vc_data *vc, unsigned int nr) scr_memsetw(p + vc->vc_cols - vc->vc_x - nr, vc->vc_video_erase_char, nr * 2); vc->vc_need_wrap = 0; - if (DO_UPDATE(vc)) + if (con_should_update(vc)) do_update_region(vc, (unsigned long) p, vc->vc_cols - vc->vc_x); } @@ -571,7 +578,7 @@ static void add_softcursor(struct vc_data *vc) if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000; if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700; scr_writew(i, (u16 *) vc->vc_pos); - if (DO_UPDATE(vc)) + if (con_should_update(vc)) vc->vc_sw->con_putc(vc, i, vc->vc_y, vc->vc_x); } @@ -579,7 +586,7 @@ static void hide_softcursor(struct vc_data *vc) { if (softcursor_original != -1) { scr_writew(softcursor_original, (u16 *)vc->vc_pos); - if (DO_UPDATE(vc)) + if (con_should_update(vc)) vc->vc_sw->con_putc(vc, softcursor_original, vc->vc_y, vc->vc_x); softcursor_original = -1; @@ -596,8 +603,7 @@ static void hide_cursor(struct vc_data *vc) static void set_cursor(struct vc_data *vc) { - if (!IS_FG(vc) || console_blanked || - vc->vc_mode == KD_GRAPHICS) + if (!con_is_fg(vc) || console_blanked || vc->vc_mode == KD_GRAPHICS) return; if (vc->vc_deccm) { if (vc == sel_cons) @@ -613,7 +619,7 @@ static void set_origin(struct vc_data *vc) { WARN_CONSOLE_UNLOCKED(); - if (!CON_IS_VISIBLE(vc) || + if (!con_is_visible(vc) || !vc->vc_sw->con_set_origin || !vc->vc_sw->con_set_origin(vc)) vc->vc_origin = (unsigned long)vc->vc_screenbuf; @@ -661,12 +667,12 @@ void redraw_screen(struct vc_data *vc, int is_switch) struct vc_data *old_vc = vc_cons[fg_console].d; if (old_vc == vc) return; - if (!CON_IS_VISIBLE(vc)) + if (!con_is_visible(vc)) redraw = 1; *vc->vc_display_fg = vc; fg_console = vc->vc_num; hide_cursor(old_vc); - if (!CON_IS_VISIBLE(old_vc)) { + if (!con_is_visible(old_vc)) { save_screen(old_vc); set_origin(old_vc); } @@ -941,7 +947,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, tty_do_resize(tty, &ws); } - if (CON_IS_VISIBLE(vc)) + if (con_is_visible(vc)) update_screen(vc); vt_event_post(VT_EVENT_RESIZE, vc->vc_num, vc->vc_num); return err; @@ -1171,7 +1177,7 @@ static void csi_J(struct vc_data *vc, int vpar) scr_memsetw(vc->vc_screenbuf, vc->vc_video_erase_char, vc->vc_screenbuf_size >> 1); set_origin(vc); - if (CON_IS_VISIBLE(vc)) + if (con_is_visible(vc)) update_screen(vc); /* fall through */ case 2: /* erase whole display */ @@ -1182,7 +1188,7 @@ static void csi_J(struct vc_data *vc, int vpar) return; } scr_memsetw(start, vc->vc_video_erase_char, 2 * count); - if (DO_UPDATE(vc)) + if (con_should_update(vc)) do_update_region(vc, (unsigned long) start, count); vc->vc_need_wrap = 0; } @@ -1210,7 +1216,7 @@ static void csi_K(struct vc_data *vc, int vpar) } scr_memsetw(start, vc->vc_video_erase_char, 2 * count); vc->vc_need_wrap = 0; - if (DO_UPDATE(vc)) + if (con_should_update(vc)) do_update_region(vc, (unsigned long) start, count); } @@ -1223,7 +1229,7 @@ static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar posi count = (vpar > vc->vc_cols - vc->vc_x) ? (vc->vc_cols - vc->vc_x) : vpar; scr_memsetw((unsigned short *)vc->vc_pos, vc->vc_video_erase_char, 2 * count); - if (DO_UPDATE(vc)) + if (con_should_update(vc)) vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, count); vc->vc_need_wrap = 0; } @@ -2208,7 +2214,7 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co charmask = himask ? 0x1ff : 0xff; /* undraw cursor first */ - if (IS_FG(vc)) + if (con_is_fg(vc)) hide_cursor(vc); param.vc = vc; @@ -2380,7 +2386,7 @@ rescan_last_byte: ((vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) : (vc_attr << 8) + tc, (u16 *) vc->vc_pos); - if (DO_UPDATE(vc) && draw_x < 0) { + if (con_should_update(vc) && draw_x < 0) { draw_x = vc->vc_x; draw_from = vc->vc_pos; } @@ -2564,7 +2570,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count) goto quit; /* undraw cursor first */ - if (IS_FG(vc)) + if (con_is_fg(vc)) hide_cursor(vc); start = (ushort *)vc->vc_pos; @@ -2575,7 +2581,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count) c = *b++; if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) { if (cnt > 0) { - if (CON_IS_VISIBLE(vc)) + if (con_is_visible(vc)) vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x); vc->vc_x += cnt; if (vc->vc_need_wrap) @@ -2607,7 +2613,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count) myx++; } if (cnt > 0) { - if (CON_IS_VISIBLE(vc)) + if (con_is_visible(vc)) vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x); vc->vc_x += cnt; if (vc->vc_x == vc->vc_cols) { @@ -3154,7 +3160,7 @@ static int do_bind_con_driver(const struct consw *csw, int first, int last, j = i; - if (CON_IS_VISIBLE(vc)) { + if (con_is_visible(vc)) { k = i; save_screen(vc); } diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index 52a6da991165..460cebf322e3 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -570,7 +570,7 @@ sisusbcon_set_palette(struct vc_data *c, const unsigned char *table) /* Return value not used by vt */ - if (!CON_IS_VISIBLE(c)) + if (!con_is_visible(c)) return; sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num); @@ -1226,7 +1226,7 @@ sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot, struct vc_data *vc = vc_cons[i].d; if (vc && vc->vc_sw == &sisusb_con) { - if (CON_IS_VISIBLE(vc)) { + if (con_is_visible(vc)) { vc->vc_sw->con_cursor(vc, CM_DRAW); } vc->vc_font.height = fh; diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index eef8a8b7274f..b87f5cfdaea5 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -380,7 +380,7 @@ static void fb_flashcursor(struct work_struct *work) if (ops && ops->currcon != -1) vc = vc_cons[ops->currcon].d; - if (!vc || !CON_IS_VISIBLE(vc) || + if (!vc || !con_is_visible(vc) || registered_fb[con2fb_map[vc->vc_num]] != info || vc->vc_deccm != 1) { console_unlock(); @@ -618,7 +618,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, erase, vc->vc_size_row * logo_lines); - if (CON_IS_VISIBLE(vc) && vc->vc_mode == KD_TEXT) { + if (con_is_visible(vc) && vc->vc_mode == KD_TEXT) { fbcon_clear_margins(vc, 0); update_screen(vc); } @@ -1112,7 +1112,7 @@ static void fbcon_init(struct vc_data *vc, int init) * * We need to do it in fbcon_init() to prevent screen corruption. */ - if (CON_IS_VISIBLE(vc) && vc->vc_mode == KD_TEXT) { + if (con_is_visible(vc) && vc->vc_mode == KD_TEXT) { if (info->fbops->fb_set_par && !(ops->flags & FBCON_FLAGS_INIT)) { ret = info->fbops->fb_set_par(info); @@ -1192,7 +1192,7 @@ static void fbcon_deinit(struct vc_data *vc) if (!ops) goto finished; - if (CON_IS_VISIBLE(vc)) + if (con_is_visible(vc)) fbcon_del_cursor_timer(info); ops->flags &= ~FBCON_FLAGS_INIT; @@ -1397,7 +1397,7 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, rows /= vc->vc_font.height; vc_resize(vc, cols, rows); - if (CON_IS_VISIBLE(vc)) { + if (con_is_visible(vc)) { update_screen(vc); if (softback_buf) fbcon_update_softback(vc); @@ -2145,7 +2145,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, return -EINVAL; DPRINTK("resize now %ix%i\n", var.xres, var.yres); - if (CON_IS_VISIBLE(vc)) { + if (con_is_visible(vc)) { var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE; fb_set_var(info, &var); @@ -2448,7 +2448,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int cnt; char *old_data = NULL; - if (CON_IS_VISIBLE(vc) && softback_lines) + if (con_is_visible(vc) && softback_lines) fbcon_set_origin(vc); resize = (w != vc->vc_font.width) || (h != vc->vc_font.height); @@ -2529,9 +2529,9 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, cols /= w; rows /= h; vc_resize(vc, cols, rows); - if (CON_IS_VISIBLE(vc) && softback_buf) + if (con_is_visible(vc) && softback_buf) fbcon_update_softback(vc); - } else if (CON_IS_VISIBLE(vc) + } else if (con_is_visible(vc) && vc->vc_mode == KD_TEXT) { fbcon_clear_margins(vc, 0); update_screen(vc); @@ -2660,7 +2660,7 @@ static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table) if (fbcon_is_inactive(vc, info)) return; - if (!CON_IS_VISIBLE(vc)) + if (!con_is_visible(vc)) return; depth = fb_get_color_depth(&info->var, &info->fix); @@ -2902,7 +2902,7 @@ static void fbcon_modechanged(struct fb_info *info) p = &fb_display[vc->vc_num]; set_blitting_type(vc, info); - if (CON_IS_VISIBLE(vc)) { + if (con_is_visible(vc)) { var_to_display(p, &info->var, info); cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); @@ -2941,7 +2941,7 @@ static void fbcon_set_all_vcs(struct fb_info *info) registered_fb[con2fb_map[i]] != info) continue; - if (CON_IS_VISIBLE(vc)) { + if (con_is_visible(vc)) { fg = i; continue; } @@ -3180,7 +3180,7 @@ static void fbcon_fb_blanked(struct fb_info *info, int blank) registered_fb[con2fb_map[ops->currcon]] != info) return; - if (CON_IS_VISIBLE(vc)) { + if (con_is_visible(vc)) { if (blank) do_blank_screen(0); else diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index e280b3ceebd9..11576611a974 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -589,7 +589,7 @@ static void vgacon_init(struct vc_data *c, int init) static void vgacon_deinit(struct vc_data *c) { /* When closing the active console, reset video origin */ - if (CON_IS_VISIBLE(c)) { + if (con_is_visible(c)) { c->vc_visible_origin = vga_vram_base; vga_set_mem_top(c); } @@ -860,7 +860,7 @@ static void vgacon_set_palette(struct vc_data *vc, const unsigned char *table) { #ifdef CAN_LOAD_PALETTE if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked - || !CON_IS_VISIBLE(vc)) + || !con_is_visible(vc)) return; vga_set_palette(vc, table); #endif @@ -1248,7 +1248,7 @@ static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight) struct vc_data *c = vc_cons[i].d; if (c && c->vc_sw == &vga_con) { - if (CON_IS_VISIBLE(c)) { + if (con_is_visible(c)) { /* void size to cause regs to be rewritten */ cursor_size_lastfrom = 0; cursor_size_lastto = 0; @@ -1312,7 +1312,7 @@ static int vgacon_resize(struct vc_data *c, unsigned int width, return success */ return (user) ? 0 : -EINVAL; - if (CON_IS_VISIBLE(c) && !vga_is_gfx) /* who knows */ + if (con_is_visible(c) && !vga_is_gfx) /* who knows */ vgacon_doresize(c, width, height); return 0; } diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h index 5fa605c93428..a12d3f2899a8 100644 --- a/include/linux/console_struct.h +++ b/include/linux/console_struct.h @@ -168,6 +168,9 @@ extern void vc_SAK(struct work_struct *work); #define CUR_DEFAULT CUR_UNDERLINE -#define CON_IS_VISIBLE(conp) (*conp->vc_display_fg == conp) +static inline bool con_is_visible(const struct vc_data *vc) +{ + return *vc->vc_display_fg == vc; +} #endif /* _LINUX_CONSOLE_STRUCT_H */ -- cgit v1.2.3 From f8b0c2e688f086d22157afc734755ed370e288dc Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:36 +0200 Subject: tty: vt, ignore PIO_UNIMAPCLR param We do not do hashtables for unicode fonts since 1995 (1.3.28). So it is time to remove the second parameter of con_clear_unimap and ignore the advice from userspace completely. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 13 ++++++------- drivers/tty/vt/vt_ioctl.c | 8 +------- include/linux/vt_kern.h | 5 ++--- 3 files changed, 9 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index c8c91f0476a2..9d7ab7b66a8a 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -499,9 +499,8 @@ con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos) return 0; } -/* ui is a leftover from using a hashtable, but might be used again - Caller must hold the lock */ -static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui) +/* Caller must hold the lock */ +static int con_do_clear_unimap(struct vc_data *vc) { struct uni_pagedir *p, *q; @@ -524,11 +523,11 @@ static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui) return 0; } -int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui) +int con_clear_unimap(struct vc_data *vc) { int ret; console_lock(); - ret = con_do_clear_unimap(vc, ui); + ret = con_do_clear_unimap(vc); console_unlock(); return ret; } @@ -556,7 +555,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) int j, k; u16 **p1, *p2, l; - err1 = con_do_clear_unimap(vc, NULL); + err1 = con_do_clear_unimap(vc); if (err1) { console_unlock(); return err1; @@ -677,7 +676,7 @@ int con_set_default_unimap(struct vc_data *vc) /* The default font is always 256 characters */ - err = con_do_clear_unimap(vc, NULL); + err = con_do_clear_unimap(vc); if (err) return err; diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 97d5a74558a3..f62c598810ff 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -1006,16 +1006,10 @@ int vt_ioctl(struct tty_struct *tty, break; case PIO_UNIMAPCLR: - { struct unimapinit ui; if (!perm) return -EPERM; - ret = copy_from_user(&ui, up, sizeof(struct unimapinit)); - if (ret) - ret = -EFAULT; - else - con_clear_unimap(vc, &ui); + con_clear_unimap(vc); break; - } case PIO_UNIMAP: case GIO_UNIMAP: diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h index 160f81fe3eb8..6abd24f258bc 100644 --- a/include/linux/vt_kern.h +++ b/include/linux/vt_kern.h @@ -59,14 +59,13 @@ int tioclinux(struct tty_struct *tty, unsigned long arg); #ifdef CONFIG_CONSOLE_TRANSLATIONS /* consolemap.c */ -struct unimapinit; struct unipair; int con_set_trans_old(unsigned char __user * table); int con_get_trans_old(unsigned char __user * table); int con_set_trans_new(unsigned short __user * table); int con_get_trans_new(unsigned short __user * table); -int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui); +int con_clear_unimap(struct vc_data *vc); int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list); int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list); int con_set_default_unimap(struct vc_data *vc); @@ -92,7 +91,7 @@ static inline int con_get_trans_new(unsigned short __user *table) { return -EINVAL; } -static inline int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui) +static inline int con_clear_unimap(struct vc_data *vc) { return 0; } -- cgit v1.2.3 From abd530de2a55c1a74271e27d6e8c71c74c25e222 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:37 +0200 Subject: tty: vt, remove unused vc_deccolm vc_deccolm is only set and never read, remove the member from vc_data. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 1 - include/linux/console_struct.h | 1 - 2 files changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 26de5c0fc056..213ce24060b5 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1482,7 +1482,6 @@ static void set_mode(struct vc_data *vc, int on_off) clr_kbd(vc, decckm); break; case 3: /* 80/132 mode switch unimplemented */ - vc->vc_deccolm = on_off; #if 0 vc_resize(deccolm ? 132 : 80, vc->vc_rows); /* this alone does not suffice; some user mode diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h index a12d3f2899a8..6fd3c908a340 100644 --- a/include/linux/console_struct.h +++ b/include/linux/console_struct.h @@ -106,7 +106,6 @@ struct vc_data { unsigned int vc_decawm : 1; /* Autowrap Mode */ unsigned int vc_deccm : 1; /* Cursor Visible */ unsigned int vc_decim : 1; /* Insert Mode */ - unsigned int vc_deccolm : 1; /* 80/132 Column Mode */ /* attribute flags */ unsigned int vc_intensity : 2; /* 0=half-bright, 1=normal, 2=bold */ unsigned int vc_italic:1; -- cgit v1.2.3 From 71e98e0e2aede08d6e0a0f3d94ea28b591ef4306 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 3 Jun 2016 12:00:03 +0200 Subject: serial: sh-sci: Always set TIOCM_CTS in .get_mctrl() callback Documentation/serial/driver clearly states: If the port does not support CTS, DCD or DSR, the driver should indicate that the signal is permanently active. Hence always set TIOCM_CTS, as we currently don't look at the CTS hardware line state at all. FWIW, this fixes the transmit path when hardware-assisted flow control is enabled, and userspace enables CRTSCTS. The receive path is still broken, as RTS is never asserted. Signed-off-by: Geert Uytterhoeven Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 0130feb069ae..135f836642ab 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1835,9 +1835,9 @@ static unsigned int sci_get_mctrl(struct uart_port *port) { /* * CTS/RTS is handled in hardware when supported, while nothing - * else is wired up. Keep it simple and simply assert DSR/CAR. + * else is wired up. Keep it simple and simply assert CTS/DSR/CAR. */ - return TIOCM_DSR | TIOCM_CAR; + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; } static void sci_break_ctl(struct uart_port *port, int break_state) -- cgit v1.2.3 From f907c9ea88355ac9fe065ffbd6acc914408b4232 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 3 Jun 2016 12:00:04 +0200 Subject: serial: sh-sci: Add support for GPIO-controlled modem lines Enhance the Renesas SCI UART driver to add support for GPIO-controlled modem lines (CTS, DSR, DCD, RNG, RTS, DTR), using the serial_mctrl_gpio helpers. GPIO-controlled modem lines can be used when dedicated modem lines are not available. Invalid configurations specifying both GPIO RTS/CTS and dedicated RTS/CTS are rejected. Signed-off-by: Geert Uytterhoeven Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 1 + drivers/tty/serial/sh-sci.c | 46 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 7e3a58c8bb67..b5c8ad1573f4 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -736,6 +736,7 @@ config SERIAL_SH_SCI tristate "SuperH SCI(F) serial port support" depends on SUPERH || ARCH_RENESAS || H8300 || COMPILE_TEST select SERIAL_CORE + select SERIAL_MCTRL_GPIO if GPIOLIB config SERIAL_SH_SCI_NR_UARTS int "Maximum number of SCI(F) serial ports" diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 135f836642ab..bf3780a7f700 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -57,6 +57,7 @@ #include #endif +#include "serial_mctrl_gpio.h" #include "sh-sci.h" /* Offsets into the sci_port->irqs array */ @@ -111,6 +112,7 @@ struct sci_port { unsigned int error_clear; unsigned int sampling_rate_mask; resource_size_t reg_size; + struct mctrl_gpios *gpios; /* Break timer */ struct timer_list break_timer; @@ -1817,6 +1819,8 @@ static unsigned int sci_tx_empty(struct uart_port *port) */ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl) { + struct sci_port *s = to_sci_port(port); + if (mctrl & TIOCM_LOOP) { const struct plat_sci_reg *reg; @@ -1829,15 +1833,35 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl) serial_port_in(port, SCFCR) | SCFCR_LOOP); } + + mctrl_gpio_set(s->gpios, mctrl); } static unsigned int sci_get_mctrl(struct uart_port *port) { + struct sci_port *s = to_sci_port(port); + struct mctrl_gpios *gpios = s->gpios; + unsigned int mctrl = 0; + + mctrl_gpio_get(gpios, &mctrl); + /* * CTS/RTS is handled in hardware when supported, while nothing * else is wired up. Keep it simple and simply assert CTS/DSR/CAR. */ - return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; + if (IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(gpios, UART_GPIO_CTS))) + mctrl |= TIOCM_CTS; + if (IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(gpios, UART_GPIO_DSR))) + mctrl |= TIOCM_DSR; + if (IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(gpios, UART_GPIO_DCD))) + mctrl |= TIOCM_CAR; + + return mctrl; +} + +static void sci_enable_ms(struct uart_port *port) +{ + mctrl_gpio_enable_ms(to_sci_port(port)->gpios); } static void sci_break_ctl(struct uart_port *port, int break_state) @@ -1899,6 +1923,8 @@ static void sci_shutdown(struct uart_port *port) dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); + mctrl_gpio_disable_ms(to_sci_port(port)->gpios); + spin_lock_irqsave(&port->lock, flags); sci_stop_rx(port); sci_stop_tx(port); @@ -2300,6 +2326,9 @@ done: sci_start_rx(port); sci_port_disable(s); + + if (UART_ENABLE_MS(port, termios->c_cflag)) + sci_enable_ms(port); } static void sci_pm(struct uart_port *port, unsigned int state, @@ -2425,6 +2454,7 @@ static struct uart_ops sci_uart_ops = { .start_tx = sci_start_tx, .stop_tx = sci_stop_tx, .stop_rx = sci_stop_rx, + .enable_ms = sci_enable_ms, .break_ctl = sci_break_ctl, .startup = sci_startup, .shutdown = sci_shutdown, @@ -2912,6 +2942,20 @@ static int sci_probe_single(struct platform_device *dev, if (ret) return ret; + sciport->gpios = mctrl_gpio_init(&sciport->port, 0); + if (IS_ERR(sciport->gpios) && PTR_ERR(sciport->gpios) != -ENOSYS) + return PTR_ERR(sciport->gpios); + + if (p->capabilities & SCIx_HAVE_RTSCTS) { + if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(sciport->gpios, + UART_GPIO_CTS)) || + !IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(sciport->gpios, + UART_GPIO_RTS))) { + dev_err(&dev->dev, "Conflicting RTS/CTS config\n"); + return -EINVAL; + } + } + ret = uart_add_one_port(&sci_uart_driver, &sciport->port); if (ret) { sci_cleanup_single(sciport); -- cgit v1.2.3 From abbf121fb6dae6657388a32feac346e5e1debdbd Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 3 Jun 2016 12:00:05 +0200 Subject: serial: sh-sci: Do not open-code sci_getreg() Replace open-coded variants of sci_getreg() by function calls, and drop intermediate variables where appropriate. Signed-off-by: Geert Uytterhoeven Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index bf3780a7f700..ce7bd165929e 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -703,7 +703,6 @@ static void sci_poll_put_char(struct uart_port *port, unsigned char c) static void sci_init_pins(struct uart_port *port, unsigned int cflag) { struct sci_port *s = to_sci_port(port); - const struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR; /* * Use port-specific handler if provided. @@ -717,7 +716,7 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag) * For the generic path SCSPTR is necessary. Bail out if that's * unavailable, too. */ - if (!reg->size) + if (!sci_getreg(port, SCSPTR)->size) return; if ((s->cfg->capabilities & SCIx_HAVE_RTSCTS) && @@ -1866,12 +1865,10 @@ static void sci_enable_ms(struct uart_port *port) static void sci_break_ctl(struct uart_port *port, int break_state) { - struct sci_port *s = to_sci_port(port); - const struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR; unsigned short scscr, scsptr; /* check wheter the port has SCSPTR */ - if (!reg->size) { + if (!sci_getreg(port, SCSPTR)->size) { /* * Not supported by hardware. Most parts couple break and rx * interrupts together, with break detection always enabled. -- cgit v1.2.3 From ef5e90e8ccb7b715c0a1509339f730b2bf9698a2 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 3 Jun 2016 12:00:06 +0200 Subject: serial: sh-sci: Add more Serial Port Register documentation Improve documentation for the (H)SCIF Serial Port Register: - Make it clear the RTS and CTS lines are active-low, - Document the bits related to the serial port's clock pin. Signed-off-by: Geert Uytterhoeven Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h index 7a4fa185b93e..85a2b81ba0a8 100644 --- a/drivers/tty/serial/sh-sci.h +++ b/drivers/tty/serial/sh-sci.h @@ -108,10 +108,12 @@ enum { #define SCLSR_ORER BIT(0) /* Overrun Error */ /* SCSPTR (Serial Port Register), optional */ -#define SCSPTR_RTSIO BIT(7) /* Serial Port RTS Pin Input/Output */ -#define SCSPTR_RTSDT BIT(6) /* Serial Port RTS Pin Data */ -#define SCSPTR_CTSIO BIT(5) /* Serial Port CTS Pin Input/Output */ -#define SCSPTR_CTSDT BIT(4) /* Serial Port CTS Pin Data */ +#define SCSPTR_RTSIO BIT(7) /* Serial Port RTS# Pin Input/Output */ +#define SCSPTR_RTSDT BIT(6) /* Serial Port RTS# Pin Data */ +#define SCSPTR_CTSIO BIT(5) /* Serial Port CTS# Pin Input/Output */ +#define SCSPTR_CTSDT BIT(4) /* Serial Port CTS# Pin Data */ +#define SCSPTR_SCKIO BIT(3) /* Serial Port Clock Pin Input/Output */ +#define SCSPTR_SCKDT BIT(2) /* Serial Port Clock Pin Data */ #define SCSPTR_SPB2IO BIT(1) /* Serial Port Break Input/Output */ #define SCSPTR_SPB2DT BIT(0) /* Serial Port Break Data */ -- cgit v1.2.3 From 4780c09f7a0926674c96c0a40dfeb7469f759c8e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 3 Jun 2016 12:00:07 +0200 Subject: serial: sh-sci: Add more Serial Port Control/Data Register documentation Improve documentation for the SCIFA/SCIFB Serial Port Control and Data Registers: - State clearly that the RTS and CTS lines are active-low, - Document the bits related to the serial port's SCK, RXD, and TXD pins. Signed-off-by: Geert Uytterhoeven Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h index 85a2b81ba0a8..e7d2bc692a58 100644 --- a/drivers/tty/serial/sh-sci.h +++ b/drivers/tty/serial/sh-sci.h @@ -121,12 +121,18 @@ enum { #define HSCIF_SRE BIT(15) /* Sampling Rate Register Enable */ /* SCPCR (Serial Port Control Register), SCIFA/SCIFB only */ -#define SCPCR_RTSC BIT(4) /* Serial Port RTS Pin / Output Pin */ -#define SCPCR_CTSC BIT(3) /* Serial Port CTS Pin / Input Pin */ +#define SCPCR_RTSC BIT(4) /* Serial Port RTS# Pin / Output Pin */ +#define SCPCR_CTSC BIT(3) /* Serial Port CTS# Pin / Input Pin */ +#define SCPCR_SCKC BIT(2) /* Serial Port SCK Pin / Output Pin */ +#define SCPCR_RXDC BIT(1) /* Serial Port RXD Pin / Input Pin */ +#define SCPCR_TXDC BIT(0) /* Serial Port TXD Pin / Output Pin */ /* SCPDR (Serial Port Data Register), SCIFA/SCIFB only */ -#define SCPDR_RTSD BIT(4) /* Serial Port RTS Output Pin Data */ -#define SCPDR_CTSD BIT(3) /* Serial Port CTS Input Pin Data */ +#define SCPDR_RTSD BIT(4) /* Serial Port RTS# Output Pin Data */ +#define SCPDR_CTSD BIT(3) /* Serial Port CTS# Input Pin Data */ +#define SCPDR_SCKD BIT(2) /* Serial Port SCK Output Pin Data */ +#define SCPDR_RXDD BIT(1) /* Serial Port RXD Input Pin Data */ +#define SCPDR_TXDD BIT(0) /* Serial Port TXD Output Pin Data */ /* * BRG Clock Select Register (Some SCIF and HSCIF) -- cgit v1.2.3 From d2b9775d795ec05fb42504c0f47dd06ba5fd709e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 3 Jun 2016 12:00:08 +0200 Subject: serial: sh-sci: Correct pin initialization on (H)SCIF Correct pin initialization on (H)SCIF: - RTS must be deasserted (it's active low), - SCK must be an input, as it may be used as the optional external clock input. Initial pin configuration must always be done: - Regardless of the presence of dedicated RTS and CTS pins: if the register exists, the RTS/CTS bits exist, too, - Regardless of hardware flow control being enabled or not: RTS must be deasserted. Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index ce7bd165929e..c46999f20917 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -712,21 +712,14 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag) return; } - /* - * For the generic path SCSPTR is necessary. Bail out if that's - * unavailable, too. - */ - if (!sci_getreg(port, SCSPTR)->size) - return; - - if ((s->cfg->capabilities & SCIx_HAVE_RTSCTS) && - ((!(cflag & CRTSCTS)))) { - unsigned short status; - - status = serial_port_in(port, SCSPTR); - status &= ~SCSPTR_CTSIO; - status |= SCSPTR_RTSIO; - serial_port_out(port, SCSPTR, status); /* Set RTS = 1 */ + if (sci_getreg(port, SCSPTR)->size) { + u16 status = serial_port_in(port, SCSPTR); + + /* RTS# is output, driven 1 */ + status |= SCSPTR_RTSIO | SCSPTR_RTSDT; + /* CTS# and SCK are inputs */ + status &= ~(SCSPTR_CTSIO | SCSPTR_SCKIO); + serial_port_out(port, SCSPTR, status); } } -- cgit v1.2.3 From e9d7a45a039913497a57887d85f5decfda4679f0 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 3 Jun 2016 12:00:09 +0200 Subject: serial: sh-sci: Add pin initialization for SCIFA/SCIFB Before, the driver relied on initialization by the boot loader, or by implicit reset state. Note that unlike on (H)SCIF, the RTS/CTS bits exist only if dedicated RTS/CTS pins are available, which depends on the SoC and UART instance. Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index c46999f20917..b9d027af0f3e 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -712,7 +712,21 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag) return; } - if (sci_getreg(port, SCSPTR)->size) { + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + u16 ctrl = serial_port_in(port, SCPCR); + + /* Enable RXD and TXD pin functions */ + ctrl &= ~(SCPCR_RXDC | SCPCR_TXDC); + if (to_sci_port(port)->cfg->capabilities & SCIx_HAVE_RTSCTS) { + /* RTS# is output, driven 1 */ + ctrl |= SCPCR_RTSC; + serial_port_out(port, SCPDR, + serial_port_in(port, SCPDR) | SCPDR_RTSD); + /* Enable CTS# pin function */ + ctrl &= ~SCPCR_CTSC; + } + serial_port_out(port, SCPCR, ctrl); + } else if (sci_getreg(port, SCSPTR)->size) { u16 status = serial_port_in(port, SCSPTR); /* RTS# is output, driven 1 */ -- cgit v1.2.3 From 33f50ffc253854cf6cd556786ae893c7454a1a67 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 3 Jun 2016 12:00:10 +0200 Subject: serial: sh-sci: Fix support for hardware-assisted RTS/CTS The existing support for hardware-assisted RTS/CTS is rudimentary and doesn't work. Add support for hardware-assisted RTS/CTS hardware flow control for the (H)SCIF, SCIFA, and SCIFB variants. Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 90 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 83 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index b9d027af0f3e..02b240a02dc6 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -141,6 +141,8 @@ struct sci_port { struct timer_list rx_timer; unsigned int rx_timeout; #endif + + bool autorts; }; #define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS @@ -1811,6 +1813,46 @@ static unsigned int sci_tx_empty(struct uart_port *port) return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0; } +static void sci_set_rts(struct uart_port *port, bool state) +{ + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + u16 data = serial_port_in(port, SCPDR); + + /* Active low */ + if (state) + data &= ~SCPDR_RTSD; + else + data |= SCPDR_RTSD; + serial_port_out(port, SCPDR, data); + + /* RTS# is output */ + serial_port_out(port, SCPCR, + serial_port_in(port, SCPCR) | SCPCR_RTSC); + } else if (sci_getreg(port, SCSPTR)->size) { + u16 ctrl = serial_port_in(port, SCSPTR); + + /* Active low */ + if (state) + ctrl &= ~SCSPTR_RTSDT; + else + ctrl |= SCSPTR_RTSDT; + serial_port_out(port, SCSPTR, ctrl); + } +} + +static bool sci_get_cts(struct uart_port *port) +{ + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + /* Active low */ + return !(serial_port_in(port, SCPDR) & SCPDR_CTSD); + } else if (sci_getreg(port, SCSPTR)->size) { + /* Active low */ + return !(serial_port_in(port, SCSPTR) & SCSPTR_CTSDT); + } + + return true; +} + /* * Modem control is a bit of a mixed bag for SCI(F) ports. Generally * CTS/RTS is supported in hardware by at least one port and controlled @@ -1841,6 +1883,31 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl) } mctrl_gpio_set(s->gpios, mctrl); + + if (!(s->cfg->capabilities & SCIx_HAVE_RTSCTS)) + return; + + if (!(mctrl & TIOCM_RTS)) { + /* Disable Auto RTS */ + serial_port_out(port, SCFCR, + serial_port_in(port, SCFCR) & ~SCFCR_MCE); + + /* Clear RTS */ + sci_set_rts(port, 0); + } else if (s->autorts) { + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + /* Enable RTS# pin function */ + serial_port_out(port, SCPCR, + serial_port_in(port, SCPCR) & ~SCPCR_RTSC); + } + + /* Enable Auto RTS */ + serial_port_out(port, SCFCR, + serial_port_in(port, SCFCR) | SCFCR_MCE); + } else { + /* Set RTS */ + sci_set_rts(port, 1); + } } static unsigned int sci_get_mctrl(struct uart_port *port) @@ -1853,10 +1920,14 @@ static unsigned int sci_get_mctrl(struct uart_port *port) /* * CTS/RTS is handled in hardware when supported, while nothing - * else is wired up. Keep it simple and simply assert CTS/DSR/CAR. + * else is wired up. */ - if (IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(gpios, UART_GPIO_CTS))) + if (s->autorts) { + if (sci_get_cts(port)) + mctrl |= TIOCM_CTS; + } else if (IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(gpios, UART_GPIO_CTS))) { mctrl |= TIOCM_CTS; + } if (IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(gpios, UART_GPIO_DSR))) mctrl |= TIOCM_DSR; if (IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(gpios, UART_GPIO_DCD))) @@ -1927,6 +1998,7 @@ static void sci_shutdown(struct uart_port *port) dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); + s->autorts = false; mctrl_gpio_disable_ms(to_sci_port(port)->gpios); spin_lock_irqsave(&port->lock, flags); @@ -2248,15 +2320,18 @@ done: sci_init_pins(port, termios->c_cflag); + port->status &= ~UPSTAT_AUTOCTS; + s->autorts = false; reg = sci_getreg(port, SCFCR); if (reg->size) { unsigned short ctrl = serial_port_in(port, SCFCR); - if (s->cfg->capabilities & SCIx_HAVE_RTSCTS) { - if (termios->c_cflag & CRTSCTS) - ctrl |= SCFCR_MCE; - else - ctrl &= ~SCFCR_MCE; + if ((port->flags & UPF_HARD_FLOW) && + (termios->c_cflag & CRTSCTS)) { + /* There is no CTS interrupt to restart the hardware */ + port->status |= UPSTAT_AUTOCTS; + /* MCE is enabled when RTS is raised */ + s->autorts = true; } /* @@ -2958,6 +3033,7 @@ static int sci_probe_single(struct platform_device *dev, dev_err(&dev->dev, "Conflicting RTS/CTS config\n"); return -EINVAL; } + sciport->port.flags |= UPF_HARD_FLOW; } ret = uart_add_one_port(&sci_uart_driver, &sciport->port); -- cgit v1.2.3 From 861a70abb483645d4474a6bc006471c2db59a78d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 3 Jun 2016 12:00:11 +0200 Subject: serial: sh-sci: Add DT support for dedicated RTS/CTS Add support for indicating the availability of dedicated lines for RTS/CTS hardware flow control, using the standard "uart-has-rtscts" DT property. Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 02b240a02dc6..d9cb0d70fcee 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -2999,6 +2999,9 @@ sci_parse_dt(struct platform_device *pdev, unsigned int *dev_id) p->regtype = SCI_OF_REGTYPE(match->data); p->scscr = SCSCR_RE | SCSCR_TE; + if (of_find_property(np, "uart-has-rtscts", NULL)) + p->capabilities |= SCIx_HAVE_RTSCTS; + return p; } -- cgit v1.2.3 From 44763d3d301a13523186731b4797b181c78fe8b4 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Jun 2016 16:59:13 +0200 Subject: serial: sh-sci: Do not start transfers from sci_startup() FIFO reset is done in sci_reset(), called from sci_set_termios(), while sci_start_tx() and sci_start_rx() are called before, from sci_startup(). However, starting transfers before the UART's FIFOs have been reset may cause reading of stale data. Remove the calls to sci_start_tx() and sci_start_rx() from sci_startup() to fix this. Transfers are still started when needed: - sci_start_rx() is called from sci_set_termios() after FIFO reset, if the CREAD flag is set, - sci_start_tx() is called from uart_change_speed() immediately thereafter, if transmission is enabled. Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index d9cb0d70fcee..d88c84cd88a4 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1972,7 +1972,6 @@ static void sci_break_ctl(struct uart_port *port, int break_state) static int sci_startup(struct uart_port *port) { struct sci_port *s = to_sci_port(port); - unsigned long flags; int ret; dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); @@ -1983,11 +1982,6 @@ static int sci_startup(struct uart_port *port) sci_request_dma(port); - spin_lock_irqsave(&port->lock, flags); - sci_start_tx(port); - sci_start_rx(port); - spin_unlock_irqrestore(&port->lock, flags); - return 0; } -- cgit v1.2.3 From 2768cf42874ae04bdbc33a9c9db96181dc0bbb8d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Jun 2016 16:59:15 +0200 Subject: serial: sh-sci: Clear RX, error, and break flags during reset Setting the FIFO reset bits is not sufficient to reset the RX FIFO. After this the status register's RDF flag bit may still be set, causing the reception of one stale byte of data. To fix this, clear all status flag bits related to reception, error, and break handling, cfr. the initialization flowchart in the datasheet. Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index d88c84cd88a4..408f706393de 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -2152,6 +2152,10 @@ static void sci_reset(struct uart_port *port) reg = sci_getreg(port, SCFCR); if (reg->size) serial_port_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST); + + sci_clear_SCxSR(port, + SCxSR_RDxF_CLEAR(port) & SCxSR_ERROR_CLEAR(port) & + SCxSR_BREAK_CLEAR(port)); } static void sci_set_termios(struct uart_port *port, struct ktermios *termios, -- cgit v1.2.3 From fc2af3348a4acea0c28db89a8c84660d0baed4aa Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Jun 2016 16:59:16 +0200 Subject: serial: sh-sci: Clear (H)SCIF timeout and overrun during reset Add the missing timeout bit definition for (H)SCIF. Clear the timeout and overrun flag bits during UART reset, cfr. the initialization flowchart in the datasheet. Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 5 +++++ drivers/tty/serial/sh-sci.h | 1 + 2 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 408f706393de..432d9acabf7f 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -2156,6 +2156,11 @@ static void sci_reset(struct uart_port *port) sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port) & SCxSR_ERROR_CLEAR(port) & SCxSR_BREAK_CLEAR(port)); + if (sci_getreg(port, SCLSR)->size) { + status = serial_port_in(port, SCLSR); + status &= ~(SCLSR_TO | SCLSR_ORER); + serial_port_out(port, SCLSR, status); + } } static void sci_set_termios(struct uart_port *port, struct ktermios *termios, diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h index e7d2bc692a58..ffa6d688c335 100644 --- a/drivers/tty/serial/sh-sci.h +++ b/drivers/tty/serial/sh-sci.h @@ -105,6 +105,7 @@ enum { #define SCFCR_LOOP BIT(0) /* Loopback Test */ /* SCLSR (Line Status Register) on (H)SCIF */ +#define SCLSR_TO BIT(2) /* Timeout */ #define SCLSR_ORER BIT(0) /* Overrun Error */ /* SCSPTR (Serial Port Register), optional */ -- cgit v1.2.3 From 01e4d273559715ee6a8b1cfbe07ceda6c8e1a515 Mon Sep 17 00:00:00 2001 From: Kefeng Wang Date: Wed, 11 May 2016 14:06:01 +0800 Subject: serial: 8250_early: Add earlycon support for Synopsys DesignWare ABP UART Some board like Hisilicon D02 uses Synopsys DesignWare ABP UART, declare an OF early console for it, so early console device can be enabled with comand line "earlycon"(without option) via the "stdout-path" property in device-tree. Signed-off-by: Kefeng Wang Tested-by: Jon Mason Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_early.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c index 8d08ff5c4e34..85a12f032402 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -150,6 +150,7 @@ EARLYCON_DECLARE(uart, early_serial8250_setup); OF_EARLYCON_DECLARE(ns16550, "ns16550", early_serial8250_setup); OF_EARLYCON_DECLARE(ns16550a, "ns16550a", early_serial8250_setup); OF_EARLYCON_DECLARE(uart, "nvidia,tegra20-uart", early_serial8250_setup); +OF_EARLYCON_DECLARE(uart, "snps,dw-apb-uart", early_serial8250_setup); #ifdef CONFIG_SERIAL_8250_OMAP -- cgit v1.2.3 From 321737416c72dc3d3dd8753c3684c6eb86d0ea6c Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 11 May 2016 18:02:26 -0700 Subject: tty: serial: msm: Move header file into driver This header file is only used by the driver, so let's merge the two together to reduce files and make it easier to see the whole driver without flipping through two files. This also makes it easier to use the structures defined in msm_serial.c in the functions that are defined in msm_serial.h by placing them in the proper locations. Signed-off-by: Stephen Boyd Acked-by: Andy Gross Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/msm_serial.c | 172 +++++++++++++++++++++++++++++++++++-- drivers/tty/serial/msm_serial.h | 184 ---------------------------------------- 2 files changed, 166 insertions(+), 190 deletions(-) delete mode 100644 drivers/tty/serial/msm_serial.h (limited to 'drivers') diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index b7d80bd57db9..28b8ac423de1 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -40,12 +40,126 @@ #include #include -#include "msm_serial.h" - -#define UARTDM_BURST_SIZE 16 /* in bytes */ -#define UARTDM_TX_AIGN(x) ((x) & ~0x3) /* valid for > 1p3 */ -#define UARTDM_TX_MAX 256 /* in bytes, valid for <= 1p3 */ -#define UARTDM_RX_SIZE (UART_XMIT_SIZE / 4) +#define UART_MR1 0x0000 + +#define UART_MR1_AUTO_RFR_LEVEL0 0x3F +#define UART_MR1_AUTO_RFR_LEVEL1 0x3FF00 +#define UART_DM_MR1_AUTO_RFR_LEVEL1 0xFFFFFF00 +#define UART_MR1_RX_RDY_CTL BIT(7) +#define UART_MR1_CTS_CTL BIT(6) + +#define UART_MR2 0x0004 +#define UART_MR2_ERROR_MODE BIT(6) +#define UART_MR2_BITS_PER_CHAR 0x30 +#define UART_MR2_BITS_PER_CHAR_5 (0x0 << 4) +#define UART_MR2_BITS_PER_CHAR_6 (0x1 << 4) +#define UART_MR2_BITS_PER_CHAR_7 (0x2 << 4) +#define UART_MR2_BITS_PER_CHAR_8 (0x3 << 4) +#define UART_MR2_STOP_BIT_LEN_ONE (0x1 << 2) +#define UART_MR2_STOP_BIT_LEN_TWO (0x3 << 2) +#define UART_MR2_PARITY_MODE_NONE 0x0 +#define UART_MR2_PARITY_MODE_ODD 0x1 +#define UART_MR2_PARITY_MODE_EVEN 0x2 +#define UART_MR2_PARITY_MODE_SPACE 0x3 +#define UART_MR2_PARITY_MODE 0x3 + +#define UART_CSR 0x0008 + +#define UART_TF 0x000C +#define UARTDM_TF 0x0070 + +#define UART_CR 0x0010 +#define UART_CR_CMD_NULL (0 << 4) +#define UART_CR_CMD_RESET_RX (1 << 4) +#define UART_CR_CMD_RESET_TX (2 << 4) +#define UART_CR_CMD_RESET_ERR (3 << 4) +#define UART_CR_CMD_RESET_BREAK_INT (4 << 4) +#define UART_CR_CMD_START_BREAK (5 << 4) +#define UART_CR_CMD_STOP_BREAK (6 << 4) +#define UART_CR_CMD_RESET_CTS (7 << 4) +#define UART_CR_CMD_RESET_STALE_INT (8 << 4) +#define UART_CR_CMD_PACKET_MODE (9 << 4) +#define UART_CR_CMD_MODE_RESET (12 << 4) +#define UART_CR_CMD_SET_RFR (13 << 4) +#define UART_CR_CMD_RESET_RFR (14 << 4) +#define UART_CR_CMD_PROTECTION_EN (16 << 4) +#define UART_CR_CMD_STALE_EVENT_DISABLE (6 << 8) +#define UART_CR_CMD_STALE_EVENT_ENABLE (80 << 4) +#define UART_CR_CMD_FORCE_STALE (4 << 8) +#define UART_CR_CMD_RESET_TX_READY (3 << 8) +#define UART_CR_TX_DISABLE BIT(3) +#define UART_CR_TX_ENABLE BIT(2) +#define UART_CR_RX_DISABLE BIT(1) +#define UART_CR_RX_ENABLE BIT(0) +#define UART_CR_CMD_RESET_RXBREAK_START ((1 << 11) | (2 << 4)) + +#define UART_IMR 0x0014 +#define UART_IMR_TXLEV BIT(0) +#define UART_IMR_RXSTALE BIT(3) +#define UART_IMR_RXLEV BIT(4) +#define UART_IMR_DELTA_CTS BIT(5) +#define UART_IMR_CURRENT_CTS BIT(6) +#define UART_IMR_RXBREAK_START BIT(10) + +#define UART_IPR_RXSTALE_LAST 0x20 +#define UART_IPR_STALE_LSB 0x1F +#define UART_IPR_STALE_TIMEOUT_MSB 0x3FF80 +#define UART_DM_IPR_STALE_TIMEOUT_MSB 0xFFFFFF80 + +#define UART_IPR 0x0018 +#define UART_TFWR 0x001C +#define UART_RFWR 0x0020 +#define UART_HCR 0x0024 + +#define UART_MREG 0x0028 +#define UART_NREG 0x002C +#define UART_DREG 0x0030 +#define UART_MNDREG 0x0034 +#define UART_IRDA 0x0038 +#define UART_MISR_MODE 0x0040 +#define UART_MISR_RESET 0x0044 +#define UART_MISR_EXPORT 0x0048 +#define UART_MISR_VAL 0x004C +#define UART_TEST_CTRL 0x0050 + +#define UART_SR 0x0008 +#define UART_SR_HUNT_CHAR BIT(7) +#define UART_SR_RX_BREAK BIT(6) +#define UART_SR_PAR_FRAME_ERR BIT(5) +#define UART_SR_OVERRUN BIT(4) +#define UART_SR_TX_EMPTY BIT(3) +#define UART_SR_TX_READY BIT(2) +#define UART_SR_RX_FULL BIT(1) +#define UART_SR_RX_READY BIT(0) + +#define UART_RF 0x000C +#define UARTDM_RF 0x0070 +#define UART_MISR 0x0010 +#define UART_ISR 0x0014 +#define UART_ISR_TX_READY BIT(7) + +#define UARTDM_RXFS 0x50 +#define UARTDM_RXFS_BUF_SHIFT 0x7 +#define UARTDM_RXFS_BUF_MASK 0x7 + +#define UARTDM_DMEN 0x3C +#define UARTDM_DMEN_RX_SC_ENABLE BIT(5) +#define UARTDM_DMEN_TX_SC_ENABLE BIT(4) + +#define UARTDM_DMEN_TX_BAM_ENABLE BIT(2) /* UARTDM_1P4 */ +#define UARTDM_DMEN_TX_DM_ENABLE BIT(0) /* < UARTDM_1P4 */ + +#define UARTDM_DMEN_RX_BAM_ENABLE BIT(3) /* UARTDM_1P4 */ +#define UARTDM_DMEN_RX_DM_ENABLE BIT(1) /* < UARTDM_1P4 */ + +#define UARTDM_DMRX 0x34 +#define UARTDM_NCF_TX 0x40 +#define UARTDM_RX_TOTAL_SNAP 0x38 + +#define UARTDM_BURST_SIZE 16 /* in bytes */ +#define UARTDM_TX_AIGN(x) ((x) & ~0x3) /* valid for > 1p3 */ +#define UARTDM_TX_MAX 256 /* in bytes, valid for <= 1p3 */ +#define UARTDM_RX_SIZE (UART_XMIT_SIZE / 4) enum { UARTDM_1P1 = 1, @@ -78,6 +192,52 @@ struct msm_port { struct msm_dma rx_dma; }; +#define UART_TO_MSM(uart_port) container_of(uart_port, struct msm_port, uart) + +static +void msm_write(struct uart_port *port, unsigned int val, unsigned int off) +{ + writel_relaxed(val, port->membase + off); +} + +static +unsigned int msm_read(struct uart_port *port, unsigned int off) +{ + return readl_relaxed(port->membase + off); +} + +/* + * Setup the MND registers to use the TCXO clock. + */ +static void msm_serial_set_mnd_regs_tcxo(struct uart_port *port) +{ + msm_write(port, 0x06, UART_MREG); + msm_write(port, 0xF1, UART_NREG); + msm_write(port, 0x0F, UART_DREG); + msm_write(port, 0x1A, UART_MNDREG); + port->uartclk = 1843200; +} + +/* + * Setup the MND registers to use the TCXO clock divided by 4. + */ +static void msm_serial_set_mnd_regs_tcxoby4(struct uart_port *port) +{ + msm_write(port, 0x18, UART_MREG); + msm_write(port, 0xF6, UART_NREG); + msm_write(port, 0x0F, UART_DREG); + msm_write(port, 0x0A, UART_MNDREG); + port->uartclk = 1843200; +} + +static void msm_serial_set_mnd_regs(struct uart_port *port) +{ + if (port->uartclk == 19200000) + msm_serial_set_mnd_regs_tcxo(port); + else if (port->uartclk == 4800000) + msm_serial_set_mnd_regs_tcxoby4(port); +} + static void msm_handle_tx(struct uart_port *port); static void msm_start_rx_dma(struct msm_port *msm_port); diff --git a/drivers/tty/serial/msm_serial.h b/drivers/tty/serial/msm_serial.h deleted file mode 100644 index 178645826f16..000000000000 --- a/drivers/tty/serial/msm_serial.h +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (C) 2007 Google, Inc. - * Author: Robert Love - * Copyright (c) 2011, Code Aurora Forum. All rights reserved. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef __DRIVERS_SERIAL_MSM_SERIAL_H -#define __DRIVERS_SERIAL_MSM_SERIAL_H - -#define UART_MR1 0x0000 - -#define UART_MR1_AUTO_RFR_LEVEL0 0x3F -#define UART_MR1_AUTO_RFR_LEVEL1 0x3FF00 -#define UART_DM_MR1_AUTO_RFR_LEVEL1 0xFFFFFF00 -#define UART_MR1_RX_RDY_CTL BIT(7) -#define UART_MR1_CTS_CTL BIT(6) - -#define UART_MR2 0x0004 -#define UART_MR2_ERROR_MODE BIT(6) -#define UART_MR2_BITS_PER_CHAR 0x30 -#define UART_MR2_BITS_PER_CHAR_5 (0x0 << 4) -#define UART_MR2_BITS_PER_CHAR_6 (0x1 << 4) -#define UART_MR2_BITS_PER_CHAR_7 (0x2 << 4) -#define UART_MR2_BITS_PER_CHAR_8 (0x3 << 4) -#define UART_MR2_STOP_BIT_LEN_ONE (0x1 << 2) -#define UART_MR2_STOP_BIT_LEN_TWO (0x3 << 2) -#define UART_MR2_PARITY_MODE_NONE 0x0 -#define UART_MR2_PARITY_MODE_ODD 0x1 -#define UART_MR2_PARITY_MODE_EVEN 0x2 -#define UART_MR2_PARITY_MODE_SPACE 0x3 -#define UART_MR2_PARITY_MODE 0x3 - -#define UART_CSR 0x0008 - -#define UART_TF 0x000C -#define UARTDM_TF 0x0070 - -#define UART_CR 0x0010 -#define UART_CR_CMD_NULL (0 << 4) -#define UART_CR_CMD_RESET_RX (1 << 4) -#define UART_CR_CMD_RESET_TX (2 << 4) -#define UART_CR_CMD_RESET_ERR (3 << 4) -#define UART_CR_CMD_RESET_BREAK_INT (4 << 4) -#define UART_CR_CMD_START_BREAK (5 << 4) -#define UART_CR_CMD_STOP_BREAK (6 << 4) -#define UART_CR_CMD_RESET_CTS (7 << 4) -#define UART_CR_CMD_RESET_STALE_INT (8 << 4) -#define UART_CR_CMD_PACKET_MODE (9 << 4) -#define UART_CR_CMD_MODE_RESET (12 << 4) -#define UART_CR_CMD_SET_RFR (13 << 4) -#define UART_CR_CMD_RESET_RFR (14 << 4) -#define UART_CR_CMD_PROTECTION_EN (16 << 4) -#define UART_CR_CMD_STALE_EVENT_DISABLE (6 << 8) -#define UART_CR_CMD_STALE_EVENT_ENABLE (80 << 4) -#define UART_CR_CMD_FORCE_STALE (4 << 8) -#define UART_CR_CMD_RESET_TX_READY (3 << 8) -#define UART_CR_TX_DISABLE BIT(3) -#define UART_CR_TX_ENABLE BIT(2) -#define UART_CR_RX_DISABLE BIT(1) -#define UART_CR_RX_ENABLE BIT(0) -#define UART_CR_CMD_RESET_RXBREAK_START ((1 << 11) | (2 << 4)) - -#define UART_IMR 0x0014 -#define UART_IMR_TXLEV BIT(0) -#define UART_IMR_RXSTALE BIT(3) -#define UART_IMR_RXLEV BIT(4) -#define UART_IMR_DELTA_CTS BIT(5) -#define UART_IMR_CURRENT_CTS BIT(6) -#define UART_IMR_RXBREAK_START BIT(10) - -#define UART_IPR_RXSTALE_LAST 0x20 -#define UART_IPR_STALE_LSB 0x1F -#define UART_IPR_STALE_TIMEOUT_MSB 0x3FF80 -#define UART_DM_IPR_STALE_TIMEOUT_MSB 0xFFFFFF80 - -#define UART_IPR 0x0018 -#define UART_TFWR 0x001C -#define UART_RFWR 0x0020 -#define UART_HCR 0x0024 - -#define UART_MREG 0x0028 -#define UART_NREG 0x002C -#define UART_DREG 0x0030 -#define UART_MNDREG 0x0034 -#define UART_IRDA 0x0038 -#define UART_MISR_MODE 0x0040 -#define UART_MISR_RESET 0x0044 -#define UART_MISR_EXPORT 0x0048 -#define UART_MISR_VAL 0x004C -#define UART_TEST_CTRL 0x0050 - -#define UART_SR 0x0008 -#define UART_SR_HUNT_CHAR BIT(7) -#define UART_SR_RX_BREAK BIT(6) -#define UART_SR_PAR_FRAME_ERR BIT(5) -#define UART_SR_OVERRUN BIT(4) -#define UART_SR_TX_EMPTY BIT(3) -#define UART_SR_TX_READY BIT(2) -#define UART_SR_RX_FULL BIT(1) -#define UART_SR_RX_READY BIT(0) - -#define UART_RF 0x000C -#define UARTDM_RF 0x0070 -#define UART_MISR 0x0010 -#define UART_ISR 0x0014 -#define UART_ISR_TX_READY BIT(7) - -#define UARTDM_RXFS 0x50 -#define UARTDM_RXFS_BUF_SHIFT 0x7 -#define UARTDM_RXFS_BUF_MASK 0x7 - -#define UARTDM_DMEN 0x3C -#define UARTDM_DMEN_RX_SC_ENABLE BIT(5) -#define UARTDM_DMEN_TX_SC_ENABLE BIT(4) - -#define UARTDM_DMEN_TX_BAM_ENABLE BIT(2) /* UARTDM_1P4 */ -#define UARTDM_DMEN_TX_DM_ENABLE BIT(0) /* < UARTDM_1P4 */ - -#define UARTDM_DMEN_RX_BAM_ENABLE BIT(3) /* UARTDM_1P4 */ -#define UARTDM_DMEN_RX_DM_ENABLE BIT(1) /* < UARTDM_1P4 */ - -#define UARTDM_DMRX 0x34 -#define UARTDM_NCF_TX 0x40 -#define UARTDM_RX_TOTAL_SNAP 0x38 - -#define UART_TO_MSM(uart_port) ((struct msm_port *) uart_port) - -static inline -void msm_write(struct uart_port *port, unsigned int val, unsigned int off) -{ - writel_relaxed(val, port->membase + off); -} - -static inline -unsigned int msm_read(struct uart_port *port, unsigned int off) -{ - return readl_relaxed(port->membase + off); -} - -/* - * Setup the MND registers to use the TCXO clock. - */ -static inline void msm_serial_set_mnd_regs_tcxo(struct uart_port *port) -{ - msm_write(port, 0x06, UART_MREG); - msm_write(port, 0xF1, UART_NREG); - msm_write(port, 0x0F, UART_DREG); - msm_write(port, 0x1A, UART_MNDREG); - port->uartclk = 1843200; -} - -/* - * Setup the MND registers to use the TCXO clock divided by 4. - */ -static inline void msm_serial_set_mnd_regs_tcxoby4(struct uart_port *port) -{ - msm_write(port, 0x18, UART_MREG); - msm_write(port, 0xF6, UART_NREG); - msm_write(port, 0x0F, UART_DREG); - msm_write(port, 0x0A, UART_MNDREG); - port->uartclk = 1843200; -} - -static inline -void msm_serial_set_mnd_regs_from_uartclk(struct uart_port *port) -{ - if (port->uartclk == 19200000) - msm_serial_set_mnd_regs_tcxo(port); - else if (port->uartclk == 4800000) - msm_serial_set_mnd_regs_tcxoby4(port); -} - -#define msm_serial_set_mnd_regs msm_serial_set_mnd_regs_from_uartclk - -#endif /* __DRIVERS_SERIAL_MSM_SERIAL_H */ -- cgit v1.2.3 From 2a31f094553125e0353b9f7e7b6e9aeea752fed3 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 11 May 2016 18:02:27 -0700 Subject: tty: serial: msm: Only configure MND registers on hw that has it The registers that msm_serial_set_mnd_regs() writes only exist on the non-uartdm hardware, so let's return early here if this function is called on uartdm hardware. This also prevents us from messing up the uartclk variable if the uartclk rate happens to be 19.2 or 4.8 MHz. Signed-off-by: Stephen Boyd Acked-by: Andy Gross Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/msm_serial.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 28b8ac423de1..a051dc5def24 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -232,6 +232,15 @@ static void msm_serial_set_mnd_regs_tcxoby4(struct uart_port *port) static void msm_serial_set_mnd_regs(struct uart_port *port) { + struct msm_port *msm_port = UART_TO_MSM(port); + + /* + * These registers don't exist so we change the clk input rate + * on uartdm hardware instead + */ + if (msm_port->is_uartdm) + return; + if (port->uartclk == 19200000) msm_serial_set_mnd_regs_tcxo(port); else if (port->uartclk == 4800000) -- cgit v1.2.3 From e4276ff8a08116f22589b4f52974cf82cd3207db Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 11 May 2016 18:02:28 -0700 Subject: tty: serial: msm: Cleanup include usage The hrtimer include isn't used and neither is serial. Drop those ones. The irq.h header really should be interrupt.h because this is an interrupt user and not an interrupt chip. Finally add wait.h for the wake_up*() usage in this driver and kernel.h for container_of(). Signed-off-by: Stephen Boyd Acked-by: Andy Gross Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/msm_serial.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index a051dc5def24..88af5a3d21dd 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -19,26 +19,26 @@ # define SUPPORT_SYSRQ #endif +#include #include #include #include -#include #include #include #include -#include +#include #include #include #include #include #include -#include #include #include #include #include #include #include +#include #define UART_MR1 0x0000 -- cgit v1.2.3 From 002eb41f303e007011aecba25ea6de25a4ed475f Mon Sep 17 00:00:00 2001 From: Charanya Venkatraman Date: Tue, 7 Jun 2016 15:58:41 +0530 Subject: tty:serial:msm:Do not restore Rx interrupts in DMA Avoid data corruption issues that result in CRC errors during file transfers over serial ports at higher baud rates. The current msm_serial driver masks the FIFO Rx interrupts in msm_start_rx_dma() since Rx FIFO interrupts are not required in DMA mode. However, msm_complete_rx_dma() re-enables the Rx FIFO interrupts which could cause RXSTALE event to be processed when a TXLEV interrupt occurs. The following is the sequence of events that could occur resulting in data corruption. msm_start_rx_dma -> msm_complete_rx_dma --> spin_unlock_irqrestore(&port->lock) --> msm_uart_irq()(For TXLEV interrupt) --> msm_handle_rx_dm() (Read from FIFO resulting in data corruption) The patch fixes the issue by not restoring the RXLEV and RXSTALE interrupts in msm_complete_rx_dma(). These interrupts are required only in FIFO mode. Signed-off-by: Charanya Venkatraman Acked-by: Andy Gross Reviewed-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/msm_serial.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 88af5a3d21dd..d0384d4cccb1 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -557,10 +557,6 @@ static void msm_complete_rx_dma(void *args) val &= ~dma->enable_bit; msm_write(port, val, UARTDM_DMEN); - /* Restore interrupts */ - msm_port->imr |= UART_IMR_RXLEV | UART_IMR_RXSTALE; - msm_write(port, msm_port->imr, UART_IMR); - if (msm_read(port, UART_SR) & UART_SR_OVERRUN) { port->icount.overrun++; tty_insert_flip_char(tport, 0, TTY_OVERRUN); -- cgit v1.2.3 From 30acf549ca1e81859a67590ab9ecfce3d1050a0b Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Thu, 2 Jun 2016 17:48:28 -0700 Subject: tty: serial: msm: Don't read off end of tx fifo For dm uarts in pio mode tx data is transferred to the fifo register 4 bytes at a time, but care is not taken when these 4 bytes spans the end of the xmit buffer so the loop might read up to 3 bytes past the buffer and then skip the actual data at the beginning of the buffer. Fix this by, analogous to the DMA case, make sure the chunk doesn't wrap the xmit buffer. Fixes: 3a878c430fd6 ("tty: serial: msm: Add TX DMA support") Cc: Ivan Ivanov Cc: stable@vger.kernel.org Reported-by: Frank Rowand Reported-by: Nicolas Dechesne Signed-off-by: Bjorn Andersson Acked-by: Andy Gross Tested-by: Frank Rowand Reviewed-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/msm_serial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index d0384d4cccb1..2c30aaee3e93 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -891,7 +891,7 @@ static void msm_handle_tx(struct uart_port *port) return; } - pio_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE); + pio_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); dma_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); dma_min = 1; /* Always DMA */ -- cgit v1.2.3 From 9a3f5bf275e68b6651a2bc935beaac938cf27adc Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 7 Jun 2016 19:11:52 +0100 Subject: tty: serial: msm: fix definition of msm_stop_dma The msm_stop_dma() is not exported from the driver, so make it static to stop the following warning: drivers/tty/serial/msm_serial.c:84:6: warning: symbol 'msm_stop_dma' was not declared. Should it be static? Signed-off-by: Ben Dooks Acked-by: Andy Gross Reviewed-by: Bjorn Andersson Reviewed-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/msm_serial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 2c30aaee3e93..7312e7e01b7e 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -250,7 +250,7 @@ static void msm_serial_set_mnd_regs(struct uart_port *port) static void msm_handle_tx(struct uart_port *port); static void msm_start_rx_dma(struct msm_port *msm_port); -void msm_stop_dma(struct uart_port *port, struct msm_dma *dma) +static void msm_stop_dma(struct uart_port *port, struct msm_dma *dma) { struct device *dev = port->dev; unsigned int mapped; -- cgit v1.2.3 From 3e5af8e04a3b104b6a8ccca4ff33644b5bcc21f0 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 10 May 2016 20:56:10 +0200 Subject: serial: Make SERIAL_MPS2_UART depend on ARCH_MPS2 Enabling support for the UART on the ARM MPS2 platform only make sense when compiling for the ARM MPS2 platform, unless compile-testing. Signed-off-by: Geert Uytterhoeven Reviewed-by: Vladimir Murzin Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index b5c8ad1573f4..518db24a5b36 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1478,7 +1478,7 @@ config SERIAL_MPS2_UART_CONSOLE config SERIAL_MPS2_UART bool "MPS2 UART port" - depends on ARM || COMPILE_TEST + depends on ARCH_MPS2 || COMPILE_TEST select SERIAL_CORE help This driver support the UART ports on ARM MPS2. -- cgit v1.2.3 From a7cfaf165ed0f0b1e5e8636f9f28843b2b90139a Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 20 May 2016 01:59:54 -0300 Subject: serial: serial_core: Perform NULL checks for release/request_port ops Doing the following UART bind/unbind sequence on a i.mx platform causes a kernel crash due to NULL pointer dereference: echo 21f4000.serial > /sys/bus/platform/drivers/imx-uart/bind echo 21f4000.serial > /sys/bus/platform/drivers/imx-uart/unbind Fix this problem by adding NULL checks prior to calling release/request_port ops. Reported-by: Fugang Duan Signed-off-by: Fabio Estevam Tested-by: Fugang Duan Acked-by: Fugang Duan Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index a333c59cba2c..9fc15335c8c5 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -887,7 +887,7 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port, /* * Free and release old regions */ - if (old_type != PORT_UNKNOWN) + if (old_type != PORT_UNKNOWN && uport->ops->release_port) uport->ops->release_port(uport); uport->iobase = new_port; @@ -900,7 +900,7 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port, /* * Claim and map the new regions */ - if (uport->type != PORT_UNKNOWN) { + if (uport->type != PORT_UNKNOWN && uport->ops->request_port) { retval = uport->ops->request_port(uport); } else { /* Always success - Jean II */ @@ -1125,7 +1125,7 @@ static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state) * If we already have a port type configured, * we must release its resources. */ - if (uport->type != PORT_UNKNOWN) + if (uport->type != PORT_UNKNOWN && uport->ops->release_port) uport->ops->release_port(uport); flags = UART_CONFIG_TYPE; @@ -2897,7 +2897,7 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport) /* * Free the port IO and memory resources, if any. */ - if (uport->type != PORT_UNKNOWN) + if (uport->type != PORT_UNKNOWN && uport->ops->release_port) uport->ops->release_port(uport); kfree(uport->tty_groups); -- cgit v1.2.3 From 9b6519009dbe2b361a73284ea0fd2e9b86aeef4d Mon Sep 17 00:00:00 2001 From: Muhammad Falak R Wani Date: Fri, 20 May 2016 17:53:28 +0530 Subject: tty/vt/keyboard: use memdup_user(). Use memdup_user to duplicate a memory region from user-space to kernel-space, instead of open coding using kmalloc & copy_from_user. Signed-off-by: Muhammad Falak R Wani Reviewed-by: Samuel Thibault Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/keyboard.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index cd08c103eb47..89a7ab007ff4 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -1745,16 +1745,10 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm) return -EINVAL; if (ct) { - buf = kmalloc(ct * sizeof(struct kbdiacruc), - GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - if (copy_from_user(buf, a->kbdiacruc, - ct * sizeof(struct kbdiacruc))) { - kfree(buf); - return -EFAULT; - } + buf = memdup_user(a->kbdiacruc, + ct * sizeof(struct kbdiacruc)); + if (IS_ERR(buf)) + return PTR_ERR(buf); } spin_lock_irqsave(&kbd_event_lock, flags); if (ct) -- cgit v1.2.3 From 9205218e491d70bf45f4527cd3bcb5cd3734ae17 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Fri, 17 Jun 2016 12:05:46 +0200 Subject: tty/serial: atmel: re-integrate status check in irq handler The IRQ status check and related actions was done in the tasklet without benefit. So, move it back to the IRQ context to simplify IRQ handling and having the possibility to split the tasklet in two separated ones for receive and transmit actions. Signed-off-by: Nicolas Ferre Signed-off-by: Ludovic Desroches Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 43 ++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 954941dd8124..8854ac6f383d 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -146,9 +146,7 @@ struct atmel_uart_port { struct scatterlist sg_tx; struct scatterlist sg_rx; struct tasklet_struct tasklet; - unsigned int irq_status; unsigned int irq_status_prev; - unsigned int status_change; unsigned int tx_len; struct circ_buf rx_ring; @@ -1237,14 +1235,27 @@ atmel_handle_status(struct uart_port *port, unsigned int pending, unsigned int status) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + unsigned int status_change; if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC | ATMEL_US_CTSIC)) { - atmel_port->irq_status = status; - atmel_port->status_change = atmel_port->irq_status ^ - atmel_port->irq_status_prev; + status_change = status ^ atmel_port->irq_status_prev; atmel_port->irq_status_prev = status; - tasklet_schedule(&atmel_port->tasklet); + + if (status_change & (ATMEL_US_RI | ATMEL_US_DSR + | ATMEL_US_DCD | ATMEL_US_CTS)) { + /* TODO: All reads to CSR will clear these interrupts! */ + if (status_change & ATMEL_US_RI) + port->icount.rng++; + if (status_change & ATMEL_US_DSR) + port->icount.dsr++; + if (status_change & ATMEL_US_DCD) + uart_handle_dcd_change(port, !(status & ATMEL_US_DCD)); + if (status_change & ATMEL_US_CTS) + uart_handle_cts_change(port, !(status & ATMEL_US_CTS)); + + wake_up_interruptible(&port->state->port.delta_msr_wait); + } } } @@ -1575,31 +1586,12 @@ static void atmel_tasklet_func(unsigned long data) { struct uart_port *port = (struct uart_port *)data; struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - unsigned int status = atmel_port->irq_status; - unsigned int status_change = atmel_port->status_change; /* The interrupt handler does not take the lock */ spin_lock(&port->lock); atmel_port->schedule_tx(port); - if (status_change & (ATMEL_US_RI | ATMEL_US_DSR - | ATMEL_US_DCD | ATMEL_US_CTS)) { - /* TODO: All reads to CSR will clear these interrupts! */ - if (status_change & ATMEL_US_RI) - port->icount.rng++; - if (status_change & ATMEL_US_DSR) - port->icount.dsr++; - if (status_change & ATMEL_US_DCD) - uart_handle_dcd_change(port, !(status & ATMEL_US_DCD)); - if (status_change & ATMEL_US_CTS) - uart_handle_cts_change(port, !(status & ATMEL_US_CTS)); - - wake_up_interruptible(&port->state->port.delta_msr_wait); - - atmel_port->status_change = 0; - } - atmel_port->schedule_rx(port); spin_unlock(&port->lock); @@ -1833,7 +1825,6 @@ static int atmel_startup(struct uart_port *port) /* Save current CSR for comparison in atmel_tasklet_func() */ atmel_port->irq_status_prev = atmel_get_lines_status(port); - atmel_port->irq_status = atmel_port->irq_status_prev; /* * Finally, enable the serial port -- cgit v1.2.3 From 00e8e65870cc581a0a8496e95480ea1b39aec58b Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Fri, 17 Jun 2016 12:05:47 +0200 Subject: tty/serial: atmel: split tx and rx paths Split TX and RX paths to not schedule RX tasklet on TX events and vice versa. Signed-off-by: Nicolas Ferre Signed-off-by: Ludovic Desroches Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 53 +++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 8854ac6f383d..6c1ec7d0d497 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -145,7 +145,8 @@ struct atmel_uart_port { dma_cookie_t cookie_rx; struct scatterlist sg_tx; struct scatterlist sg_rx; - struct tasklet_struct tasklet; + struct tasklet_struct tasklet_rx; + struct tasklet_struct tasklet_tx; unsigned int irq_status_prev; unsigned int tx_len; @@ -708,7 +709,7 @@ static void atmel_rx_chars(struct uart_port *port) status = atmel_uart_readl(port, ATMEL_US_CSR); } - tasklet_schedule(&atmel_port->tasklet); + tasklet_schedule(&atmel_port->tasklet_rx); } /* @@ -779,7 +780,7 @@ static void atmel_complete_tx_dma(void *arg) * remaining data from the beginning of xmit->buf to xmit->head. */ if (!uart_circ_empty(xmit)) - tasklet_schedule(&atmel_port->tasklet); + tasklet_schedule(&atmel_port->tasklet_tx); spin_unlock_irqrestore(&port->lock, flags); } @@ -964,7 +965,7 @@ static void atmel_complete_rx_dma(void *arg) struct uart_port *port = arg; struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - tasklet_schedule(&atmel_port->tasklet); + tasklet_schedule(&atmel_port->tasklet_rx); } static void atmel_release_rx_dma(struct uart_port *port) @@ -1004,7 +1005,7 @@ static void atmel_rx_from_dma(struct uart_port *port) if (dmastat == DMA_ERROR) { dev_dbg(port->dev, "Get residue error, restart tasklet\n"); atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_TIMEOUT); - tasklet_schedule(&atmel_port->tasklet); + tasklet_schedule(&atmel_port->tasklet_rx); return; } @@ -1158,7 +1159,7 @@ static void atmel_uart_timer_callback(unsigned long data) struct uart_port *port = (void *)data; struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - tasklet_schedule(&atmel_port->tasklet); + tasklet_schedule(&atmel_port->tasklet_rx); mod_timer(&atmel_port->uart_timer, jiffies + uart_poll_timeout(port)); } @@ -1181,7 +1182,7 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending) if (pending & (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)) { atmel_uart_writel(port, ATMEL_US_IDR, (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)); - tasklet_schedule(&atmel_port->tasklet); + tasklet_schedule(&atmel_port->tasklet_rx); } if (pending & (ATMEL_US_RXBRK | ATMEL_US_OVRE | @@ -1193,7 +1194,7 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending) if (pending & ATMEL_US_TIMEOUT) { atmel_uart_writel(port, ATMEL_US_IDR, ATMEL_US_TIMEOUT); - tasklet_schedule(&atmel_port->tasklet); + tasklet_schedule(&atmel_port->tasklet_rx); } } @@ -1223,7 +1224,7 @@ atmel_handle_transmit(struct uart_port *port, unsigned int pending) /* Either PDC or interrupt transmission */ atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask); - tasklet_schedule(&atmel_port->tasklet); + tasklet_schedule(&atmel_port->tasklet_tx); } } @@ -1582,18 +1583,25 @@ static int atmel_prepare_rx_pdc(struct uart_port *port) /* * tasklet handling tty stuff outside the interrupt handler. */ -static void atmel_tasklet_func(unsigned long data) +static void atmel_tasklet_rx_func(unsigned long data) { struct uart_port *port = (struct uart_port *)data; struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); /* The interrupt handler does not take the lock */ spin_lock(&port->lock); - - atmel_port->schedule_tx(port); - atmel_port->schedule_rx(port); + spin_unlock(&port->lock); +} +static void atmel_tasklet_tx_func(unsigned long data) +{ + struct uart_port *port = (struct uart_port *)data; + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + /* The interrupt handler does not take the lock */ + spin_lock(&port->lock); + atmel_port->schedule_tx(port); spin_unlock(&port->lock); } @@ -1777,7 +1785,8 @@ static int atmel_startup(struct uart_port *port) return retval; } - tasklet_enable(&atmel_port->tasklet); + tasklet_enable(&atmel_port->tasklet_rx); + tasklet_enable(&atmel_port->tasklet_tx); /* * Initialize DMA (if necessary) @@ -1906,8 +1915,10 @@ static void atmel_shutdown(struct uart_port *port) * Clear out any scheduled tasklets before * we destroy the buffers */ - tasklet_disable(&atmel_port->tasklet); - tasklet_kill(&atmel_port->tasklet); + tasklet_disable(&atmel_port->tasklet_rx); + tasklet_disable(&atmel_port->tasklet_tx); + tasklet_kill(&atmel_port->tasklet_rx); + tasklet_kill(&atmel_port->tasklet_tx); /* * Ensure everything is stopped and @@ -2302,9 +2313,12 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port, port->irq = pdev->resource[1].start; port->rs485_config = atmel_config_rs485; - tasklet_init(&atmel_port->tasklet, atmel_tasklet_func, + tasklet_init(&atmel_port->tasklet_rx, atmel_tasklet_rx_func, + (unsigned long)port); + tasklet_init(&atmel_port->tasklet_tx, atmel_tasklet_tx_func, (unsigned long)port); - tasklet_disable(&atmel_port->tasklet); + tasklet_disable(&atmel_port->tasklet_rx); + tasklet_disable(&atmel_port->tasklet_tx); memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring)); @@ -2786,7 +2800,8 @@ static int atmel_serial_remove(struct platform_device *pdev) struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); int ret = 0; - tasklet_kill(&atmel_port->tasklet); + tasklet_kill(&atmel_port->tasklet_rx); + tasklet_kill(&atmel_port->tasklet_tx); device_init_wakeup(&pdev->dev, 0); -- cgit v1.2.3 From 637ba54f6051903e1f0011b75ee36b2a29696c6d Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Fri, 17 Jun 2016 12:05:48 +0200 Subject: tty/serial: atmel: add comment for the ring buffer size macro There is a macro named ATMEL_SERIAL_RINGSIZE which suggesting that it corresponds to the real size of the ring buffer. Let warn people that there is a factor of four since allocation size is sizeof(struct atmel_uart_char) * ATMEL_SERIAL_RINGSIZE. Signed-off-by: Ludovic Desroches Signed-off-by: Nicolas Ferre Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 6c1ec7d0d497..857016367a7a 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -108,6 +108,12 @@ struct atmel_uart_char { u16 ch; }; +/* + * Be careful, the real size of the ring buffer is + * sizeof(atmel_uart_char) * ATMEL_SERIAL_RINGSIZE. It means that ring buffer + * can contain up to 1024 characters in PIO mode and up to 4096 characters in + * DMA mode. + */ #define ATMEL_SERIAL_RINGSIZE 1024 /* -- cgit v1.2.3 From 0058f0871efe7b01c6f2b3046c68196ab73e96da Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sat, 28 May 2016 00:54:08 +0200 Subject: tty/serial: atmel: fix RS485 half duplex with DMA When using DMA, half duplex doesn't work properly because rx is not stopped before starting tx. Ensure we call atmel_stop_rx() in the DMA case. Signed-off-by: Alexandre Belloni Acked-by: Nicolas Ferre Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 857016367a7a..f887c1df23e6 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -487,19 +487,21 @@ static void atmel_start_tx(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - if (atmel_use_pdc_tx(port)) { - if (atmel_uart_readl(port, ATMEL_PDC_PTSR) & ATMEL_PDC_TXTEN) - /* The transmitter is already running. Yes, we - really need this.*/ - return; + if (atmel_use_pdc_tx(port) && (atmel_uart_readl(port, ATMEL_PDC_PTSR) + & ATMEL_PDC_TXTEN)) + /* The transmitter is already running. Yes, we + really need this.*/ + return; + if (atmel_use_pdc_tx(port) || atmel_use_dma_tx(port)) if ((port->rs485.flags & SER_RS485_ENABLED) && !(port->rs485.flags & SER_RS485_RX_DURING_TX)) atmel_stop_rx(port); + if (atmel_use_pdc_tx(port)) /* re-enable PDC transmit */ atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); - } + /* Enable interrupts */ atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask); } -- cgit v1.2.3 From 210417ce836aa3f0ededcc8f541f5e4a05d2e880 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti Datta Date: Fri, 27 May 2016 15:05:19 +0530 Subject: tty: xuartps: disable clocks when not used Currently the clocks are enabled at probe and disabled at remove. Instead enable the clocks when used. Signed-off-by: Shubhrajyoti Datta Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/xilinx_uartps.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index cd46e64c4255..9ca1a4d1b66a 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -976,6 +976,23 @@ static void cdns_uart_poll_put_char(struct uart_port *port, unsigned char c) } #endif +static void cdns_uart_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) +{ + struct cdns_uart *cdns_uart = port->private_data; + + switch (state) { + case UART_PM_STATE_OFF: + clk_disable(cdns_uart->uartclk); + clk_disable(cdns_uart->pclk); + break; + default: + clk_enable(cdns_uart->pclk); + clk_enable(cdns_uart->uartclk); + break; + } +} + static struct uart_ops cdns_uart_ops = { .set_mctrl = cdns_uart_set_mctrl, .get_mctrl = cdns_uart_get_mctrl, @@ -987,6 +1004,7 @@ static struct uart_ops cdns_uart_ops = { .set_termios = cdns_uart_set_termios, .startup = cdns_uart_startup, .shutdown = cdns_uart_shutdown, + .pm = cdns_uart_pm, .type = cdns_uart_type, .verify_port = cdns_uart_verify_port, .request_port = cdns_uart_request_port, @@ -1350,12 +1368,12 @@ static int cdns_uart_probe(struct platform_device *pdev) return PTR_ERR(cdns_uart_data->uartclk); } - rc = clk_prepare_enable(cdns_uart_data->pclk); + rc = clk_prepare(cdns_uart_data->pclk); if (rc) { dev_err(&pdev->dev, "Unable to enable pclk clock.\n"); return rc; } - rc = clk_prepare_enable(cdns_uart_data->uartclk); + rc = clk_prepare(cdns_uart_data->uartclk); if (rc) { dev_err(&pdev->dev, "Unable to enable device clock.\n"); goto err_out_clk_dis_pclk; @@ -1422,9 +1440,9 @@ err_out_notif_unreg: &cdns_uart_data->clk_rate_change_nb); #endif err_out_clk_disable: - clk_disable_unprepare(cdns_uart_data->uartclk); + clk_unprepare(cdns_uart_data->uartclk); err_out_clk_dis_pclk: - clk_disable_unprepare(cdns_uart_data->pclk); + clk_unprepare(cdns_uart_data->pclk); return rc; } @@ -1448,8 +1466,8 @@ static int cdns_uart_remove(struct platform_device *pdev) #endif rc = uart_remove_one_port(&cdns_uart_uart_driver, port); port->mapbase = 0; - clk_disable_unprepare(cdns_uart_data->uartclk); - clk_disable_unprepare(cdns_uart_data->pclk); + clk_unprepare(cdns_uart_data->uartclk); + clk_unprepare(cdns_uart_data->pclk); return rc; } -- cgit v1.2.3 From 24a6a3037e0b47168f9b3bb9db7ad60c89dad7ba Mon Sep 17 00:00:00 2001 From: Purna Chandra Mandal Date: Tue, 17 May 2016 10:35:54 +0530 Subject: serial: pic32_uart: Fix double free of 'sport->irq_fault_name'. Allocated memory for 'sport->irq_fault_name' is freed twice, first in error check of 'if(!sport->irq_rx_name)' and other in fallback handler. Signed-off-by: Purna Chandra Mandal Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pic32_uart.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/pic32_uart.c b/drivers/tty/serial/pic32_uart.c index 62a43bf5698e..7f8e99bbcb73 100644 --- a/drivers/tty/serial/pic32_uart.c +++ b/drivers/tty/serial/pic32_uart.c @@ -445,7 +445,6 @@ static int pic32_uart_startup(struct uart_port *port) sport->idx); if (!sport->irq_rx_name) { dev_err(port->dev, "%s: kasprintf err!", __func__); - kfree(sport->irq_fault_name); ret = -ENOMEM; goto out_f; } -- cgit v1.2.3 From 4da22f1418cb6f09e974499794db2f5e59fe8090 Mon Sep 17 00:00:00 2001 From: Ji-Ze Hong (Peter Hong) Date: Fri, 27 May 2016 10:02:51 +0800 Subject: serial: 8250_fintek: fix the mismatched IRQ mode Some BIOS only use _OSI("Linux") to distinguish between Linux & Windows. Apply Level/Low to UART trigger mode if Windows, Edge/High mode otherwise. But since 2.6.23 the mainline kernel no longer returns true for _OSI(“Linux”). The default IRQ0~15 trigger mode in Linux is Edge/High mode without ACPI MADT override. It mismatches IRQ mode and makes UART malfunctional on such motherboard. This patch will check the current IRQ mode and apply correct mode to UART. The following link is F81216AD spec PDF: http://html.alldatasheet.com/html-pdf/257956/FINTEK/F81216AD/5569/ 25/F81216AD.html LDN0~3 70h: IRQ channel & Mode register Bit 6~5 : 00 : Active low level mode 01 : Active high edge mode Bit 4 : Sharing Flag (0: not share/1: share) Bit 3~0 : IRQ channel Signed-off-by: Ji-Ze Hong (Peter Hong) Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_fintek.c | 36 ++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c index 870981dd9e39..737b4b3957b0 100644 --- a/drivers/tty/serial/8250/8250_fintek.c +++ b/drivers/tty/serial/8250/8250_fintek.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "8250.h" #define ADDR_PORT 0 @@ -30,6 +31,12 @@ #define IO_ADDR2 0x60 #define LDN 0x7 +#define IRQ_MODE 0x70 +#define IRQ_SHARE BIT(4) +#define IRQ_MODE_MASK (BIT(6) | BIT(5)) +#define IRQ_LEVEL_LOW 0 +#define IRQ_EDGE_HIGH BIT(5) + #define RS485 0xF0 #define RTS_INVERT BIT(5) #define RS485_URA BIT(4) @@ -176,10 +183,37 @@ static int find_base_port(struct fintek_8250 *pdata, u16 io_address) return -ENODEV; } +static int fintek_8250_set_irq_mode(struct fintek_8250 *pdata, bool level_mode) +{ + int status; + u8 tmp; + + status = fintek_8250_enter_key(pdata->base_port, pdata->key); + if (status) + return status; + + outb(LDN, pdata->base_port + ADDR_PORT); + outb(pdata->index, pdata->base_port + DATA_PORT); + + outb(IRQ_MODE, pdata->base_port + ADDR_PORT); + tmp = inb(pdata->base_port + DATA_PORT); + + tmp &= ~IRQ_MODE_MASK; + tmp |= IRQ_SHARE; + if (!level_mode) + tmp |= IRQ_EDGE_HIGH; + + outb(tmp, pdata->base_port + DATA_PORT); + fintek_8250_exit_key(pdata->base_port); + return 0; +} + int fintek_8250_probe(struct uart_8250_port *uart) { struct fintek_8250 *pdata; struct fintek_8250 probe_data; + struct irq_data *irq_data = irq_get_irq_data(uart->port.irq); + bool level_mode = irqd_is_level_type(irq_data); if (find_base_port(&probe_data, uart->port.iobase)) return -ENODEV; @@ -192,5 +226,5 @@ int fintek_8250_probe(struct uart_8250_port *uart) uart->port.rs485_config = fintek_8250_rs485_config; uart->port.private_data = pdata; - return 0; + return fintek_8250_set_irq_mode(pdata, level_mode); } -- cgit v1.2.3 From e51e4d8a185de90424b03f30181b35f29c46a25a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 16 Jun 2016 08:27:35 +0200 Subject: serial: samsung: Fix ERR pointer dereference on deferred probe When the clk_get() of "uart" clock returns EPROBE_DEFER, the next re-probe finishes with success but uses invalid (ERR_PTR) values. This leads to dereferencing of ERR_PTR stored under ourport->clk: 12c30000.serial: Controller clock not found (...) 12c30000.serial: ttySAC3 at MMIO 0x12c30000 (irq = 61, base_baud = 0) is a S3C6400/10 Unable to handle kernel paging request at virtual address fffffdfb (clk_prepare) from [] (s3c24xx_serial_pm+0x20/0x128) (s3c24xx_serial_pm) from [] (uart_change_pm+0x38/0x40) (uart_change_pm) from [] (uart_add_one_port+0x31c/0x44c) (uart_add_one_port) from [] (s3c24xx_serial_probe+0x2a8/0x418) (s3c24xx_serial_probe) from [] (platform_drv_probe+0x50/0xb0) (platform_drv_probe) from [] (driver_probe_device+0x1f4/0x2b0) (driver_probe_device) from [] (bus_for_each_drv+0x44/0x8c) (bus_for_each_drv) from [] (__device_attach+0x9c/0x100) (__device_attach) from [] (bus_probe_device+0x84/0x8c) (bus_probe_device) from [] (deferred_probe_work_func+0x60/0x8c) (deferred_probe_work_func) from [] (process_one_work+0x120/0x328) (process_one_work) from [] (worker_thread+0x2c/0x4ac) (worker_thread) from [] (kthread+0xd8/0xf4) (kthread) from [] (ret_from_fork+0x14/0x3c) The first unsuccessful clk_get() causes s3c24xx_serial_init_port() to exit with failure but the s3c24xx_uart_port is left half-configured (e.g. port->mapbase is set, clk contains ERR_PTR). On next re-probe, the function s3c24xx_serial_init_port() will exit early with success because of configured port->mapbase and driver will use old values, including the ERR_PTR as clock. Fix this by cleaning the port->mapbase on error path so each re-probe will initialize all of the port settings. Fixes: 60e93575476f ("serial: samsung: enable clock before clearing pending interrupts during init") Cc: Signed-off-by: Krzysztof Kozlowski Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Tested-by: Kevin Hilman Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 99bb23161dd6..f0bd2ec0db59 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -1684,7 +1684,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, return -ENODEV; if (port->mapbase != 0) - return 0; + return -EINVAL; /* setup info for port */ port->dev = &platdev->dev; @@ -1738,22 +1738,25 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, ourport->dma = devm_kzalloc(port->dev, sizeof(*ourport->dma), GFP_KERNEL); - if (!ourport->dma) - return -ENOMEM; + if (!ourport->dma) { + ret = -ENOMEM; + goto err; + } } ourport->clk = clk_get(&platdev->dev, "uart"); if (IS_ERR(ourport->clk)) { pr_err("%s: Controller clock not found\n", dev_name(&platdev->dev)); - return PTR_ERR(ourport->clk); + ret = PTR_ERR(ourport->clk); + goto err; } ret = clk_prepare_enable(ourport->clk); if (ret) { pr_err("uart: clock failed to prepare+enable: %d\n", ret); clk_put(ourport->clk); - return ret; + goto err; } /* Keep all interrupts masked and cleared */ @@ -1769,7 +1772,12 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, /* reset the fifos (and setup the uart) */ s3c24xx_serial_resetport(port, cfg); + return 0; + +err: + port->mapbase = 0; + return ret; } /* Device driver serial port probe */ -- cgit v1.2.3 From 926b7b5122c96e1f18cd20e85a286c7ec8d18c97 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 16 Jun 2016 08:27:36 +0200 Subject: serial: samsung: Fix possible out of bounds access on non-DT platform On non-DeviceTree platforms, the index of serial device is a static variable incremented on each probe. It is incremented even if deferred probe happens when getting the clock in s3c24xx_serial_init_port(). This index is used for referencing elements of statically allocated s3c24xx_serial_ports array. In case of re-probe, the index will point outside of this array leading to memory corruption. Increment the index only on successful probe. Reported-by: Bartlomiej Zolnierkiewicz Fixes: b497549a035c ("[ARM] S3C24XX: Split serial driver into core and per-cpu drivers") Signed-off-by: Krzysztof Kozlowski Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index f0bd2ec0db59..4d2924f61e0b 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -1844,8 +1844,6 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) ourport->min_dma_size = max_t(int, ourport->port.fifosize, dma_get_cache_alignment()); - probe_index++; - dbg("%s: initialising port %p...\n", __func__, ourport); ret = s3c24xx_serial_init_port(ourport, pdev); @@ -1875,6 +1873,8 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) if (ret < 0) dev_err(&pdev->dev, "failed to add cpufreq notifier\n"); + probe_index++; + return 0; } -- cgit v1.2.3 From 55c368cb760f08ba1f15718086696754e593504a Mon Sep 17 00:00:00 2001 From: Alexandr Petrenko Date: Mon, 23 May 2016 10:04:54 +0300 Subject: 8250_pci: Adds support for the WCH CH355 4S card Adds support for the WCH CH355 4S card in the 8250 serial driver. Signed-off-by: Alexandr Petrenko Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 3d6287a8981e..20ebaea5c414 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1864,6 +1864,16 @@ pci_wch_ch353_setup(struct serial_private *priv, return pci_default_setup(priv, board, port, idx); } +static int +pci_wch_ch355_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + port->port.flags |= UPF_FIXED_TYPE; + port->port.type = PORT_16550A; + return pci_default_setup(priv, board, port, idx); +} + static int pci_wch_ch38x_setup(struct serial_private *priv, const struct pciserial_board *board, @@ -1915,6 +1925,7 @@ pci_wch_ch38x_setup(struct serial_private *priv, #define PCI_DEVICE_ID_WCH_CH353_2S1PF 0x5046 #define PCI_DEVICE_ID_WCH_CH353_1S1P 0x5053 #define PCI_DEVICE_ID_WCH_CH353_2S1P 0x7053 +#define PCI_DEVICE_ID_WCH_CH355_4S 0x7173 #define PCI_VENDOR_ID_AGESTAR 0x5372 #define PCI_DEVICE_ID_AGESTAR_9375 0x6872 #define PCI_VENDOR_ID_ASIX 0x9710 @@ -2618,6 +2629,14 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .setup = pci_wch_ch353_setup, }, + /* WCH CH355 4S card (16550 clone) */ + { + .vendor = PCI_VENDOR_ID_WCH, + .device = PCI_DEVICE_ID_WCH_CH355_4S, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_wch_ch355_setup, + }, /* WCH CH382 2S card (16850 clone) */ { .vendor = PCIE_VENDOR_ID_WCH, @@ -3812,6 +3831,7 @@ static const struct pci_device_id blacklist[] = { /* multi-io cards handled by parport_serial */ { PCI_DEVICE(0x4348, 0x7053), }, /* WCH CH353 2S1P */ { PCI_DEVICE(0x4348, 0x5053), }, /* WCH CH353 1S1P */ + { PCI_DEVICE(0x4348, 0x7173), }, /* WCH CH355 4S */ { PCI_DEVICE(0x1c00, 0x3250), }, /* WCH CH382 2S1P */ { PCI_DEVICE(0x1c00, 0x3470), }, /* WCH CH384 4S */ @@ -5567,6 +5587,10 @@ static struct pci_device_id serial_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_bt_2_115200 }, + { PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH355_4S, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, pbn_b0_bt_4_115200 }, + { PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH382_2S, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_wch382_2 }, -- cgit v1.2.3 From 5bdb48b501e8366d5fd361cd402816aa3e525895 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Tue, 7 Jun 2016 18:59:21 +0300 Subject: serial: max310x: Fix RS485 handling RS485 IOCTLs uses spinlocks, so move regmap functions into a separate work queue. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 3f6e0ab725fe..bf6e3e08ec67 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -262,6 +262,7 @@ struct max310x_one { struct uart_port port; struct work_struct tx_work; struct work_struct md_work; + struct work_struct rs_work; }; struct max310x_port { @@ -877,36 +878,45 @@ static void max310x_set_termios(struct uart_port *port, uart_update_timeout(port, termios->c_cflag, baud); } -static int max310x_rs485_config(struct uart_port *port, - struct serial_rs485 *rs485) +static void max310x_rs_proc(struct work_struct *ws) { + struct max310x_one *one = container_of(ws, struct max310x_one, rs_work); unsigned int val; - if (rs485->delay_rts_before_send > 0x0f || - rs485->delay_rts_after_send > 0x0f) - return -ERANGE; + val = (one->port.rs485.delay_rts_before_send << 4) | + one->port.rs485.delay_rts_after_send; + max310x_port_write(&one->port, MAX310X_HDPIXDELAY_REG, val); - val = (rs485->delay_rts_before_send << 4) | - rs485->delay_rts_after_send; - max310x_port_write(port, MAX310X_HDPIXDELAY_REG, val); - if (rs485->flags & SER_RS485_ENABLED) { - max310x_port_update(port, MAX310X_MODE1_REG, + if (one->port.rs485.flags & SER_RS485_ENABLED) { + max310x_port_update(&one->port, MAX310X_MODE1_REG, MAX310X_MODE1_TRNSCVCTRL_BIT, MAX310X_MODE1_TRNSCVCTRL_BIT); - max310x_port_update(port, MAX310X_MODE2_REG, + max310x_port_update(&one->port, MAX310X_MODE2_REG, MAX310X_MODE2_ECHOSUPR_BIT, MAX310X_MODE2_ECHOSUPR_BIT); } else { - max310x_port_update(port, MAX310X_MODE1_REG, + max310x_port_update(&one->port, MAX310X_MODE1_REG, MAX310X_MODE1_TRNSCVCTRL_BIT, 0); - max310x_port_update(port, MAX310X_MODE2_REG, + max310x_port_update(&one->port, MAX310X_MODE2_REG, MAX310X_MODE2_ECHOSUPR_BIT, 0); } +} + +static int max310x_rs485_config(struct uart_port *port, + struct serial_rs485 *rs485) +{ + struct max310x_one *one = container_of(port, struct max310x_one, port); + + if ((rs485->delay_rts_before_send > 0x0f) || + (rs485->delay_rts_after_send > 0x0f)) + return -ERANGE; rs485->flags &= SER_RS485_RTS_ON_SEND | SER_RS485_ENABLED; memset(rs485->padding, 0, sizeof(rs485->padding)); port->rs485 = *rs485; + schedule_work(&one->rs_work); + return 0; } @@ -1214,8 +1224,10 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, MAX310X_MODE1_IRQSEL_BIT); /* Initialize queue for start TX */ INIT_WORK(&s->p[i].tx_work, max310x_wq_proc); - /* Initialize queue for changing mode */ + /* Initialize queue for changing LOOPBACK mode */ INIT_WORK(&s->p[i].md_work, max310x_md_proc); + /* Initialize queue for changing RS485 mode */ + INIT_WORK(&s->p[i].rs_work, max310x_rs_proc); /* Register port */ uart_add_one_port(&s->uart, &s->p[i].port); /* Go to suspend mode */ @@ -1257,6 +1269,7 @@ static int max310x_remove(struct device *dev) for (i = 0; i < s->uart.nr; i++) { cancel_work_sync(&s->p[i].tx_work); cancel_work_sync(&s->p[i].md_work); + cancel_work_sync(&s->p[i].rs_work); uart_remove_one_port(&s->uart, &s->p[i].port); s->devtype->power(&s->p[i].port, 0); } -- cgit v1.2.3 From 0e8cc7c2ea025b96b4ed57b52c61f2d982a95ddb Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Tue, 7 Jun 2016 18:59:23 +0300 Subject: serial: max310x: Using resource-managed function for GPIO Use resource managed functions devm_gpiochip_add_data() to make error & exit path a bit simpler. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index bf6e3e08ec67..6e2edbb942d6 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1193,9 +1193,11 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, s->gpio.base = -1; s->gpio.ngpio = devtype->nr * 4; s->gpio.can_sleep = 1; - ret = gpiochip_add_data(&s->gpio, s); - if (ret) - goto out_uart; + ret = devm_gpiochip_add_data(dev, &s->gpio, s); + if (ret) { + uart_unregister_driver(&s->uart); + goto out_clk; + } #endif mutex_init(&s->mutex); @@ -1244,11 +1246,6 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, mutex_destroy(&s->mutex); -#ifdef CONFIG_GPIOLIB - gpiochip_remove(&s->gpio); - -out_uart: -#endif uart_unregister_driver(&s->uart); out_clk: @@ -1262,10 +1259,6 @@ static int max310x_remove(struct device *dev) struct max310x_port *s = dev_get_drvdata(dev); int i; -#ifdef CONFIG_GPIOLIB - gpiochip_remove(&s->gpio); -#endif - for (i = 0; i < s->uart.nr; i++) { cancel_work_sync(&s->p[i].tx_work); cancel_work_sync(&s->p[i].md_work); -- cgit v1.2.3 From 6286767ad3afc886ec6473409aa02191cb54f97b Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Tue, 7 Jun 2016 18:59:24 +0300 Subject: serial: max310x: Register UART driver at module_init This patch moves UART registration at module_init initcall, so this should helps to add multiple chip support in the future. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 79 +++++++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 6e2edbb942d6..66dd3e24f3d6 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1,7 +1,7 @@ /* * Maxim (Dallas) MAX3107/8/9, MAX14830 serial driver * - * Copyright (C) 2012-2014 Alexander Shiyan + * Copyright (C) 2012-2016 Alexander Shiyan * * Based on max3100.c, by Christian Pellegrin * Based on max3110.c, by Feng Tang @@ -32,6 +32,7 @@ #define MAX310X_NAME "max310x" #define MAX310X_MAJOR 204 #define MAX310X_MINOR 209 +#define MAX310X_UART_NR 4 /* MAX310X register definitions */ #define MAX310X_RHR_REG (0x00) /* RX FIFO */ @@ -266,7 +267,6 @@ struct max310x_one { }; struct max310x_port { - struct uart_driver uart; struct max310x_devtype *devtype; struct regmap *regmap; struct mutex mutex; @@ -277,6 +277,15 @@ struct max310x_port { struct max310x_one p[0]; }; +static struct uart_driver max310x_uart = { + .owner = THIS_MODULE, + .driver_name = MAX310X_NAME, + .dev_name = "ttyMAX", + .major = MAX310X_MAJOR, + .minor = MAX310X_MINOR, + .nr = MAX310X_UART_NR, +}; + static u8 max310x_port_read(struct uart_port *port, u8 reg) { struct max310x_port *s = dev_get_drvdata(port->dev); @@ -716,13 +725,13 @@ static irqreturn_t max310x_ist(int irq, void *dev_id) { struct max310x_port *s = (struct max310x_port *)dev_id; - if (s->uart.nr > 1) { + if (s->devtype->nr > 1) { do { unsigned int val = ~0; WARN_ON_ONCE(regmap_read(s->regmap, MAX310X_GLOBALIRQ_REG, &val)); - val = ((1 << s->uart.nr) - 1) & ~val; + val = ((1 << s->devtype->nr) - 1) & ~val; if (!val) break; max310x_port_irq(s, fls(val) - 1); @@ -1019,8 +1028,8 @@ static int __maybe_unused max310x_suspend(struct device *dev) struct max310x_port *s = dev_get_drvdata(dev); int i; - for (i = 0; i < s->uart.nr; i++) { - uart_suspend_port(&s->uart, &s->p[i].port); + for (i = 0; i < s->devtype->nr; i++) { + uart_suspend_port(&max310x_uart, &s->p[i].port); s->devtype->power(&s->p[i].port, 0); } @@ -1032,9 +1041,9 @@ static int __maybe_unused max310x_resume(struct device *dev) struct max310x_port *s = dev_get_drvdata(dev); int i; - for (i = 0; i < s->uart.nr; i++) { + for (i = 0; i < s->devtype->nr; i++) { s->devtype->power(&s->p[i].port, 1); - uart_resume_port(&s->uart, &s->p[i].port); + uart_resume_port(&max310x_uart, &s->p[i].port); } return 0; @@ -1169,18 +1178,6 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, uartclk = max310x_set_ref_clk(s, freq, xtal); dev_dbg(dev, "Reference clock set to %i Hz\n", uartclk); - /* Register UART driver */ - s->uart.owner = THIS_MODULE; - s->uart.dev_name = "ttyMAX"; - s->uart.major = MAX310X_MAJOR; - s->uart.minor = MAX310X_MINOR; - s->uart.nr = devtype->nr; - ret = uart_register_driver(&s->uart); - if (ret) { - dev_err(dev, "Registering UART driver failed\n"); - goto out_clk; - } - #ifdef CONFIG_GPIOLIB /* Setup GPIO cotroller */ s->gpio.owner = THIS_MODULE; @@ -1194,10 +1191,8 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, s->gpio.ngpio = devtype->nr * 4; s->gpio.can_sleep = 1; ret = devm_gpiochip_add_data(dev, &s->gpio, s); - if (ret) { - uart_unregister_driver(&s->uart); + if (ret) goto out_clk; - } #endif mutex_init(&s->mutex); @@ -1231,7 +1226,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, /* Initialize queue for changing RS485 mode */ INIT_WORK(&s->p[i].rs_work, max310x_rs_proc); /* Register port */ - uart_add_one_port(&s->uart, &s->p[i].port); + uart_add_one_port(&max310x_uart, &s->p[i].port); /* Go to suspend mode */ devtype->power(&s->p[i].port, 0); } @@ -1246,8 +1241,6 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, mutex_destroy(&s->mutex); - uart_unregister_driver(&s->uart); - out_clk: clk_disable_unprepare(s->clk); @@ -1259,16 +1252,15 @@ static int max310x_remove(struct device *dev) struct max310x_port *s = dev_get_drvdata(dev); int i; - for (i = 0; i < s->uart.nr; i++) { + for (i = 0; i < s->devtype->nr; i++) { cancel_work_sync(&s->p[i].tx_work); cancel_work_sync(&s->p[i].md_work); cancel_work_sync(&s->p[i].rs_work); - uart_remove_one_port(&s->uart, &s->p[i].port); + uart_remove_one_port(&max310x_uart, &s->p[i].port); s->devtype->power(&s->p[i].port, 0); } mutex_destroy(&s->mutex); - uart_unregister_driver(&s->uart); clk_disable_unprepare(s->clk); return 0; @@ -1341,7 +1333,7 @@ static const struct spi_device_id max310x_id_table[] = { }; MODULE_DEVICE_TABLE(spi, max310x_id_table); -static struct spi_driver max310x_uart_driver = { +static struct spi_driver max310x_spi_driver = { .driver = { .name = MAX310X_NAME, .of_match_table = of_match_ptr(max310x_dt_ids), @@ -1351,9 +1343,34 @@ static struct spi_driver max310x_uart_driver = { .remove = max310x_spi_remove, .id_table = max310x_id_table, }; -module_spi_driver(max310x_uart_driver); #endif +static int __init max310x_uart_init(void) +{ + int ret; + + ret = uart_register_driver(&max310x_uart); + if (ret) + return ret; + +#ifdef CONFIG_SPI_MASTER + spi_register_driver(&max310x_spi_driver); +#endif + + return 0; +} +module_init(max310x_uart_init); + +static void __exit max310x_uart_exit(void) +{ +#ifdef CONFIG_SPI_MASTER + spi_unregister_driver(&max310x_spi_driver); +#endif + + uart_unregister_driver(&max310x_uart); +} +module_exit(max310x_uart_exit); + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Alexander Shiyan "); MODULE_DESCRIPTION("MAX310X serial driver"); -- cgit v1.2.3 From e940e817a701dcaf0d218571c251af0cb6d1bbfb Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Tue, 7 Jun 2016 18:59:25 +0300 Subject: serial: max310x: Remove duplicate bits definition Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 66dd3e24f3d6..e73ae6e79b64 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -156,10 +156,6 @@ #define MAX310X_LCR_FORCEPARITY_BIT (1 << 5) /* 9-bit multidrop parity */ #define MAX310X_LCR_TXBREAK_BIT (1 << 6) /* TX break enable */ #define MAX310X_LCR_RTS_BIT (1 << 7) /* RTS pin control */ -#define MAX310X_LCR_WORD_LEN_5 (0x00) -#define MAX310X_LCR_WORD_LEN_6 (0x01) -#define MAX310X_LCR_WORD_LEN_7 (0x02) -#define MAX310X_LCR_WORD_LEN_8 (0x03) /* IRDA register bits */ #define MAX310X_IRDA_IRDAEN_BIT (1 << 0) /* IRDA mode enable */ @@ -806,7 +802,7 @@ static void max310x_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { - unsigned int lcr, flow = 0; + unsigned int lcr = 0, flow = 0; int baud; /* Mask termios capabilities we don't support */ @@ -815,17 +811,16 @@ static void max310x_set_termios(struct uart_port *port, /* Word size */ switch (termios->c_cflag & CSIZE) { case CS5: - lcr = MAX310X_LCR_WORD_LEN_5; break; case CS6: - lcr = MAX310X_LCR_WORD_LEN_6; + lcr = MAX310X_LCR_LENGTH0_BIT; break; case CS7: - lcr = MAX310X_LCR_WORD_LEN_7; + lcr = MAX310X_LCR_LENGTH1_BIT; break; case CS8: default: - lcr = MAX310X_LCR_WORD_LEN_8; + lcr = MAX310X_LCR_LENGTH1_BIT | MAX310X_LCR_LENGTH0_BIT; break; } -- cgit v1.2.3 From c8246fefe2c995e128345614fb98b5ed5014318b Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Tue, 7 Jun 2016 18:59:26 +0300 Subject: serial: max310x: Unregister UARTs on error Add uart_remove_one_port() for error path. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index e73ae6e79b64..347f6e8dae39 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1234,6 +1234,9 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, dev_err(dev, "Unable to reguest IRQ %i\n", irq); + for (i = 0; i < devtype->nr; i++) + uart_remove_one_port(&max310x_uart, &s->p[i].port); + mutex_destroy(&s->mutex); out_clk: -- cgit v1.2.3 From 78adccac1ff9f485ccf427f337982799ce68738e Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Tue, 7 Jun 2016 18:59:27 +0300 Subject: serial: max310x: Assign port line automatically This patch makes assignment of port line automatically, so now user allow to use several MAX310X chips. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 41 ++++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 347f6e8dae39..9360801df3c4 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -32,7 +32,7 @@ #define MAX310X_NAME "max310x" #define MAX310X_MAJOR 204 #define MAX310X_MINOR 209 -#define MAX310X_UART_NR 4 +#define MAX310X_UART_NRMAX 16 /* MAX310X register definitions */ #define MAX310X_RHR_REG (0x00) /* RX FIFO */ @@ -279,9 +279,11 @@ static struct uart_driver max310x_uart = { .dev_name = "ttyMAX", .major = MAX310X_MAJOR, .minor = MAX310X_MINOR, - .nr = MAX310X_UART_NR, + .nr = MAX310X_UART_NRMAX, }; +static DECLARE_BITMAP(max310x_lines, MAX310X_UART_NRMAX); + static u8 max310x_port_read(struct uart_port *port, u8 reg) { struct max310x_port *s = dev_get_drvdata(port->dev); @@ -600,9 +602,7 @@ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen) unsigned int sts, ch, flag; if (unlikely(rxlen >= port->fifosize)) { - dev_warn_ratelimited(port->dev, - "Port %i: Possible RX FIFO overrun\n", - port->line); + dev_warn_ratelimited(port->dev, "Possible RX FIFO overrun\n"); port->icount.buf_overrun++; /* Ensure sanity of RX level */ rxlen = port->fifosize; @@ -1193,8 +1193,16 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, mutex_init(&s->mutex); for (i = 0; i < devtype->nr; i++) { + unsigned int line; + + line = find_first_zero_bit(max310x_lines, MAX310X_UART_NRMAX); + if (line == MAX310X_UART_NRMAX) { + ret = -ERANGE; + goto out_uart; + } + /* Initialize port data */ - s->p[i].port.line = i; + s->p[i].port.line = line; s->p[i].port.dev = dev; s->p[i].port.irq = irq; s->p[i].port.type = PORT_MAX310X; @@ -1220,8 +1228,15 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, INIT_WORK(&s->p[i].md_work, max310x_md_proc); /* Initialize queue for changing RS485 mode */ INIT_WORK(&s->p[i].rs_work, max310x_rs_proc); + /* Register port */ - uart_add_one_port(&max310x_uart, &s->p[i].port); + ret = uart_add_one_port(&max310x_uart, &s->p[i].port); + if (ret) { + s->p[i].port.dev = NULL; + goto out_uart; + } + set_bit(line, max310x_lines); + /* Go to suspend mode */ devtype->power(&s->p[i].port, 0); } @@ -1234,8 +1249,13 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, dev_err(dev, "Unable to reguest IRQ %i\n", irq); - for (i = 0; i < devtype->nr; i++) - uart_remove_one_port(&max310x_uart, &s->p[i].port); +out_uart: + for (i = 0; i < devtype->nr; i++) { + if (s->p[i].port.dev) { + uart_remove_one_port(&max310x_uart, &s->p[i].port); + clear_bit(s->p[i].port.line, max310x_lines); + } + } mutex_destroy(&s->mutex); @@ -1255,6 +1275,7 @@ static int max310x_remove(struct device *dev) cancel_work_sync(&s->p[i].md_work); cancel_work_sync(&s->p[i].rs_work); uart_remove_one_port(&max310x_uart, &s->p[i].port); + clear_bit(s->p[i].port.line, max310x_lines); s->devtype->power(&s->p[i].port, 0); } @@ -1347,6 +1368,8 @@ static int __init max310x_uart_init(void) { int ret; + bitmap_zero(max310x_lines, MAX310X_UART_NRMAX); + ret = uart_register_driver(&max310x_uart); if (ret) return ret; -- cgit v1.2.3 From 8d6d544cfb52a28d5c75d17552fa3d3f1cfe4a8c Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 6 Jun 2016 13:30:25 +0900 Subject: serial: 8250_uniphier: add COMPILE_TEST option Add COMPILE_TEST for the compilation test coverage. Signed-off-by: Masahiro Yamada Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index e46761d20f7b..b5a0f2e76f08 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -387,7 +387,8 @@ config SERIAL_8250_MT6577 config SERIAL_8250_UNIPHIER tristate "Support for UniPhier on-chip UART" - depends on SERIAL_8250 && ARCH_UNIPHIER + depends on SERIAL_8250 + depends on ARCH_UNIPHIER || COMPILE_TEST help If you have a UniPhier based board and want to use the on-chip serial ports, say Y to this option. If unsure, say N. -- cgit v1.2.3 From ca16c5a300c33fd9d0cda48ef08166f32b35a56d Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Mon, 20 Jun 2016 18:55:03 -0400 Subject: serial: pxa: make it explicitly non-modular The Kconfig currently controlling compilation of this code is: drivers/tty/serial/Kconfig:config SERIAL_PXA drivers/tty/serial/Kconfig: bool "PXA serial port support" ...meaning that it currently is not being built as a module by anyone. Lets remove the modular code that is essentially orphaned, so that when reading the driver there is no doubt it is builtin-only. We explicitly disallow a driver unbind, since that doesn't have a sensible use case anyway, and it allows us to drop the ".remove" code for non-modular drivers. Since module_init translates to device_initcall in the non-modular case, the init ordering remains unchanged with this commit. Also note that MODULE_DEVICE_TABLE and MODULE_ALIAS are both a no-op for non-modular builds. We also delete the MODULE_LICENSE tag since that information is already contained at the top of the file in the comments. Cc: Greg Kroah-Hartman Cc: Jiri Slaby Cc: linux-serial@vger.kernel.org Signed-off-by: Paul Gortmaker Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pxa.c | 30 ++---------------------------- 1 file changed, 2 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c index 41eab75ba2af..cd9d9e878475 100644 --- a/drivers/tty/serial/pxa.c +++ b/drivers/tty/serial/pxa.c @@ -27,7 +27,6 @@ #define SUPPORT_SYSRQ #endif -#include #include #include #include @@ -829,7 +828,6 @@ static const struct of_device_id serial_pxa_dt_ids[] = { { .compatible = "mrvl,mmp-uart", }, {} }; -MODULE_DEVICE_TABLE(of, serial_pxa_dt_ids); static int serial_pxa_probe_dt(struct platform_device *pdev, struct uart_pxa_port *sport) @@ -914,28 +912,15 @@ static int serial_pxa_probe(struct platform_device *dev) return ret; } -static int serial_pxa_remove(struct platform_device *dev) -{ - struct uart_pxa_port *sport = platform_get_drvdata(dev); - - uart_remove_one_port(&serial_pxa_reg, &sport->port); - - clk_unprepare(sport->clk); - clk_put(sport->clk); - kfree(sport); - - return 0; -} - static struct platform_driver serial_pxa_driver = { .probe = serial_pxa_probe, - .remove = serial_pxa_remove, .driver = { .name = "pxa2xx-uart", #ifdef CONFIG_PM .pm = &serial_pxa_pm_ops, #endif + .suppress_bind_attrs = true, .of_match_table = serial_pxa_dt_ids, }, }; @@ -954,15 +939,4 @@ static int __init serial_pxa_init(void) return ret; } - -static void __exit serial_pxa_exit(void) -{ - platform_driver_unregister(&serial_pxa_driver); - uart_unregister_driver(&serial_pxa_reg); -} - -module_init(serial_pxa_init); -module_exit(serial_pxa_exit); - -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:pxa2xx-uart"); +device_initcall(serial_pxa_init); -- cgit v1.2.3 From 03ba5d5187b009e01215b3f74e508d986b912efb Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Mon, 20 Jun 2016 18:55:04 -0400 Subject: serial: vt8500_serial: make it explicitly non-modular The Kconfig currently controlling compilation of this code is: drivers/tty/serial/Kconfig:config SERIAL_VT8500 drivers/tty/serial/Kconfig: bool "VIA VT8500 on-chip serial port support" ...meaning that it currently is not being built as a module by anyone. Lets remove the modular code that is essentially orphaned, so that when reading the driver there is no doubt it is builtin-only. We explicitly disallow a driver unbind, since that doesn't have a sensible use case anyway, and it allows us to drop the ".remove" code for non-modular drivers. Since module_init translates to device_initcall in the non-modular case, the init ordering remains unchanged with this commit. We don't replace module.h with init.h since the file already has that. We also delete the MODULE_LICENSE tag etc. since all that information is already contained at the top of the file in the comments. Cc: Tony Prisk Cc: Greg Kroah-Hartman Cc: Jiri Slaby Cc: Alexey Charkov Cc: linux-serial@vger.kernel.org Signed-off-by: Paul Gortmaker Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/vt8500_serial.c | 30 ++---------------------------- 1 file changed, 2 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c index b384060e3b1f..23cfc5e16b45 100644 --- a/drivers/tty/serial/vt8500_serial.c +++ b/drivers/tty/serial/vt8500_serial.c @@ -21,7 +21,6 @@ #include #include -#include #include #include #include @@ -730,22 +729,12 @@ static int vt8500_serial_probe(struct platform_device *pdev) return 0; } -static int vt8500_serial_remove(struct platform_device *pdev) -{ - struct vt8500_port *vt8500_port = platform_get_drvdata(pdev); - - clk_disable_unprepare(vt8500_port->clk); - uart_remove_one_port(&vt8500_uart_driver, &vt8500_port->uart); - - return 0; -} - static struct platform_driver vt8500_platform_driver = { .probe = vt8500_serial_probe, - .remove = vt8500_serial_remove, .driver = { .name = "vt8500_serial", .of_match_table = wmt_dt_ids, + .suppress_bind_attrs = true, }, }; @@ -764,19 +753,4 @@ static int __init vt8500_serial_init(void) return ret; } - -static void __exit vt8500_serial_exit(void) -{ -#ifdef CONFIG_SERIAL_VT8500_CONSOLE - unregister_console(&vt8500_console); -#endif - platform_driver_unregister(&vt8500_platform_driver); - uart_unregister_driver(&vt8500_uart_driver); -} - -module_init(vt8500_serial_init); -module_exit(vt8500_serial_exit); - -MODULE_AUTHOR("Alexey Charkov "); -MODULE_DESCRIPTION("Driver for vt8500 serial device"); -MODULE_LICENSE("GPL v2"); +device_initcall(vt8500_serial_init); -- cgit v1.2.3 From a10aebe2cd8dfeebc83a0d1790a429d0fe789fd5 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Mon, 20 Jun 2016 18:55:05 -0400 Subject: serial: m32r_sio: make it explicitly non-modular The Kconfig currently controlling compilation of this code is: drivers/tty/serial/Kconfig:config SERIAL_M32R_SIO drivers/tty/serial/Kconfig: bool "M32R SIO I/F" ...meaning that it currently is not being built as a module by anyone. Lets remove the modular code that is essentially orphaned, so that when reading the driver there is no doubt it is builtin-only. Since module_init translates to device_initcall in the non-modular case, the init ordering remains unchanged with this commit. We also delete the MODULE_LICENSE tag etc. since all that information is already contained at the top of the file in the comments. We don't replace module.h with init.h since the file already has that. Cc: Greg Kroah-Hartman Cc: Jiri Slaby Cc: linux-serial@vger.kernel.org Signed-off-by: Paul Gortmaker Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/m32r_sio.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/m32r_sio.c b/drivers/tty/serial/m32r_sio.c index 1b01504cf306..218b7118e85d 100644 --- a/drivers/tty/serial/m32r_sio.c +++ b/drivers/tty/serial/m32r_sio.c @@ -30,7 +30,6 @@ #define SUPPORT_SYSRQ #endif -#include #include #include #include @@ -1057,19 +1056,4 @@ static int __init m32r_sio_init(void) return ret; } - -static void __exit m32r_sio_exit(void) -{ - int i; - - for (i = 0; i < UART_NR; i++) - uart_remove_one_port(&m32r_sio_reg, &m32r_sio_ports[i].port); - - uart_unregister_driver(&m32r_sio_reg); -} - -module_init(m32r_sio_init); -module_exit(m32r_sio_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Generic M32R SIO serial driver"); +device_initcall(m32r_sio_init); -- cgit v1.2.3 From a59388668d0ce19dadea909e09f4eb905a27b1ce Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Wed, 8 Jun 2016 12:08:43 +0200 Subject: serial/bcm63xx_uart: use correct alias naming The bcm63xx_uart driver uses the of alias for determing its id. Recent changes in dts files changed the expected 'uartX' to the recommended 'serialX', breaking serial output. Fix this by checking for a 'serialX' alias as well. Fixes: e3b992d028f8 ("MIPS: BMIPS: Improve BCM6328 device tree") Fixes: 2d52ee82b475 ("MIPS: BMIPS: Improve BCM6368 device tree") Fixes: 7537d273e2f3 ("MIPS: BMIPS: Add device tree example for BCM6358") Signed-off-by: Jonas Gorski Acked-by: Florian Fainelli Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/bcm63xx_uart.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c index c28e5c24da16..5108fab953aa 100644 --- a/drivers/tty/serial/bcm63xx_uart.c +++ b/drivers/tty/serial/bcm63xx_uart.c @@ -813,8 +813,12 @@ static int bcm_uart_probe(struct platform_device *pdev) struct clk *clk; int ret; - if (pdev->dev.of_node) - pdev->id = of_alias_get_id(pdev->dev.of_node, "uart"); + if (pdev->dev.of_node) { + pdev->id = of_alias_get_id(pdev->dev.of_node, "serial"); + + if (pdev->id < 0) + pdev->id = of_alias_get_id(pdev->dev.of_node, "uart"); + } if (pdev->id < 0 || pdev->id >= BCM63XX_NR_UARTS) return -EINVAL; -- cgit v1.2.3 From c2c1659b4f8f9e19fe82a4fd06cca4b3d59090ce Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 16 Jun 2016 16:48:52 +0200 Subject: serial: mvebu-uart: free the IRQ in ->shutdown() As suggested by the serial port infrastructure documentation, the IRQ is requested in ->startup(). However, it is never freed in the ->shutdown() hook. With simple systems that open the serial port once for all and always have at least one process that keep the serial port opened, there was no problem. But with a more complicated system (*cough* systemd *cough*), the serial port is opened/closed many times, which at some point no processes having the serial port open at all. Due to this ->startup() gets called again, tries to request_irq() again, which fails. Fixes: 30530791a7a0 ("serial: mvebu-uart: initial support for Armada-3700 serial port") Cc: Cc: Ofer Heifetz Signed-off-by: Thomas Petazzoni Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/mvebu-uart.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c index ce362bd51de7..45b57c294d13 100644 --- a/drivers/tty/serial/mvebu-uart.c +++ b/drivers/tty/serial/mvebu-uart.c @@ -300,6 +300,8 @@ static int mvebu_uart_startup(struct uart_port *port) static void mvebu_uart_shutdown(struct uart_port *port) { writel(0, port->membase + UART_CTRL); + + free_irq(port->irq, port); } static void mvebu_uart_set_termios(struct uart_port *port, -- cgit v1.2.3 From ce87122911f8db59d3c2bc355c694c7a38940804 Mon Sep 17 00:00:00 2001 From: Vladimir Murzin Date: Tue, 7 Jun 2016 16:02:37 +0100 Subject: serial: mps2-uart: make driver explicitly non-modular The Kconfig currently controlling compilation of mps2-uart is: config SERIAL_MPS2_UART bool "MPS2 UART port" depends on ARM || COMPILE_TEST ...meaning that it currently is not being built as a module by anyone. Follow commit 89ebc2742769 ("drivers/tty: make serial/mvebu-uart.c explicitly non-modular") as an example of moving modular code to non-modular: - remove the modular code that is essentially orphaned, so that when reading the driver there is no doubt it is builtin-only. - explicitly disallow a driver unbind, since that doesn't have a sensible use case anyway, and it allows us to drop the ".remove" code for non-modular drivers. - use arch_initcall instead of module_init and remove module_exit. Also note that MODULE_DEVICE_TABLE is a no-op for non-modular code. We also delete the MODULE_LICENSE tag etc. since all that information was (or is now) contained at the top of the file in the comments. Reported-by: Paul Gortmaker Signed-off-by: Vladimir Murzin Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/mps2-uart.c | 29 ++++------------------------- 1 file changed, 4 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/mps2-uart.c b/drivers/tty/serial/mps2-uart.c index da9e27d3c263..492ec4b375a0 100644 --- a/drivers/tty/serial/mps2-uart.c +++ b/drivers/tty/serial/mps2-uart.c @@ -1,4 +1,6 @@ /* + * MPS2 UART driver + * * Copyright (C) 2015 ARM Limited * * Author: Vladimir Murzin @@ -17,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -569,30 +570,20 @@ static int mps2_serial_probe(struct platform_device *pdev) return 0; } -static int mps2_serial_remove(struct platform_device *pdev) -{ - struct mps2_uart_port *mps_port = platform_get_drvdata(pdev); - - uart_remove_one_port(&mps2_uart_driver, &mps_port->port); - - return 0; -} - #ifdef CONFIG_OF static const struct of_device_id mps2_match[] = { { .compatible = "arm,mps2-uart", }, {}, }; -MODULE_DEVICE_TABLE(of, mps2_match); #endif static struct platform_driver mps2_serial_driver = { .probe = mps2_serial_probe, - .remove = mps2_serial_remove, .driver = { .name = DRIVER_NAME, .of_match_table = of_match_ptr(mps2_match), + .suppress_bind_attrs = true, }, }; @@ -610,16 +601,4 @@ static int __init mps2_uart_init(void) return ret; } -module_init(mps2_uart_init); - -static void __exit mps2_uart_exit(void) -{ - platform_driver_unregister(&mps2_serial_driver); - uart_unregister_driver(&mps2_uart_driver); -} -module_exit(mps2_uart_exit); - -MODULE_AUTHOR("Vladimir Murzin "); -MODULE_DESCRIPTION("MPS2 UART driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" DRIVER_NAME); +arch_initcall(mps2_uart_init); -- cgit v1.2.3 From 3548e45c71881eb6c9d324f04ae32b28ce7439e9 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 7 Jun 2016 19:06:11 +0100 Subject: serial: sirf: make fifo functions static The fifo mask functions should be static as they are not used outside of the driver. Fix the following warnings by making them static: drivers/tty/serial/sirfsoc_uart.h:109:5: warning: symbol 'uart_usp_ff_full_mask' was not declared. Should it be static? drivers/tty/serial/sirfsoc_uart.h:117:5: warning: symbol 'uart_usp_ff_empty_mask' was not declared. Should it be static? Signed-off-by: Ben Dooks Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sirfsoc_uart.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sirfsoc_uart.h b/drivers/tty/serial/sirfsoc_uart.h index c3a885b4d76a..43756bd9111c 100644 --- a/drivers/tty/serial/sirfsoc_uart.h +++ b/drivers/tty/serial/sirfsoc_uart.h @@ -106,7 +106,7 @@ struct sirfsoc_uart_register { enum sirfsoc_uart_type uart_type; }; -u32 uart_usp_ff_full_mask(struct uart_port *port) +static u32 uart_usp_ff_full_mask(struct uart_port *port) { u32 full_bit; @@ -114,7 +114,7 @@ u32 uart_usp_ff_full_mask(struct uart_port *port) return (1 << full_bit); } -u32 uart_usp_ff_empty_mask(struct uart_port *port) +static u32 uart_usp_ff_empty_mask(struct uart_port *port) { u32 empty_bit; -- cgit v1.2.3 From e37697b3f75464dbf86ecb0f480eb11581cc75d2 Mon Sep 17 00:00:00 2001 From: Matthew Leach Date: Wed, 22 Jun 2016 17:57:02 +0100 Subject: tty: serial: samsung: fixup accessors for endian Fix the serial access code to deal with kernels built for big endian operation. Signed-off-by: Matthew Leach Acked-by: Ben Dooks Reviewed-by: Krzysztof Kozlowski Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/samsung.h b/drivers/tty/serial/samsung.h index fc5deaa4f382..8f96b715a7b0 100644 --- a/drivers/tty/serial/samsung.h +++ b/drivers/tty/serial/samsung.h @@ -117,10 +117,10 @@ struct s3c24xx_uart_port { #define portaddrl(port, reg) \ ((unsigned long *)(unsigned long)((port)->membase + (reg))) -#define rd_regb(port, reg) (__raw_readb(portaddr(port, reg))) -#define rd_regl(port, reg) (__raw_readl(portaddr(port, reg))) +#define rd_regb(port, reg) (readb_relaxed(portaddr(port, reg))) +#define rd_regl(port, reg) (readl_relaxed(portaddr(port, reg))) -#define wr_regb(port, reg, val) __raw_writeb(val, portaddr(port, reg)) -#define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg)) +#define wr_regb(port, reg, val) writeb_relaxed(val, portaddr(port, reg)) +#define wr_regl(port, reg, val) writel_relaxed(val, portaddr(port, reg)) #endif -- cgit v1.2.3 From bbb5ff91225dfbf3e5c27619552e41661048ed61 Mon Sep 17 00:00:00 2001 From: Matthew Leach Date: Wed, 22 Jun 2016 17:57:03 +0100 Subject: tty: serial: samsung: add byte-order aware bit functions This driver makes use of the __set_bit() and __clear_bit() functions. When running under big-endian, these functions don't convert the bit indexes when working with peripheral registers, leading to the incorrect bits being set and cleared when running big-endian. Add two new driver functions for setting and clearing bits that are byte-order aware. Signed-off-by: Matthew Leach Reviewed-by: Krzysztof Kozlowski Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung.c | 16 +++++++--------- drivers/tty/serial/samsung.h | 28 ++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 4d2924f61e0b..ae2095a66708 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -169,8 +169,7 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port) return; if (s3c24xx_serial_has_interrupt_mask(port)) - __set_bit(S3C64XX_UINTM_TXD, - portaddrl(port, S3C64XX_UINTM)); + s3c24xx_set_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM); else disable_irq_nosync(ourport->tx_irq); @@ -235,8 +234,7 @@ static void enable_tx_dma(struct s3c24xx_uart_port *ourport) /* Mask Tx interrupt */ if (s3c24xx_serial_has_interrupt_mask(port)) - __set_bit(S3C64XX_UINTM_TXD, - portaddrl(port, S3C64XX_UINTM)); + s3c24xx_set_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM); else disable_irq_nosync(ourport->tx_irq); @@ -269,8 +267,8 @@ static void enable_tx_pio(struct s3c24xx_uart_port *ourport) /* Unmask Tx interrupt */ if (s3c24xx_serial_has_interrupt_mask(port)) - __clear_bit(S3C64XX_UINTM_TXD, - portaddrl(port, S3C64XX_UINTM)); + s3c24xx_clear_bit(port, S3C64XX_UINTM_TXD, + S3C64XX_UINTM); else enable_irq(ourport->tx_irq); @@ -397,8 +395,8 @@ static void s3c24xx_serial_stop_rx(struct uart_port *port) if (rx_enabled(port)) { dbg("s3c24xx_serial_stop_rx: port=%p\n", port); if (s3c24xx_serial_has_interrupt_mask(port)) - __set_bit(S3C64XX_UINTM_RXD, - portaddrl(port, S3C64XX_UINTM)); + s3c24xx_set_bit(port, S3C64XX_UINTM_RXD, + S3C64XX_UINTM); else disable_irq_nosync(ourport->rx_irq); rx_enabled(port) = 0; @@ -1069,7 +1067,7 @@ static int s3c64xx_serial_startup(struct uart_port *port) spin_unlock_irqrestore(&port->lock, flags); /* Enable Rx Interrupt */ - __clear_bit(S3C64XX_UINTM_RXD, portaddrl(port, S3C64XX_UINTM)); + s3c24xx_clear_bit(port, S3C64XX_UINTM_RXD, S3C64XX_UINTM); dbg("s3c64xx_serial_startup ok\n"); return ret; diff --git a/drivers/tty/serial/samsung.h b/drivers/tty/serial/samsung.h index 8f96b715a7b0..2ae4fcee1814 100644 --- a/drivers/tty/serial/samsung.h +++ b/drivers/tty/serial/samsung.h @@ -123,4 +123,32 @@ struct s3c24xx_uart_port { #define wr_regb(port, reg, val) writeb_relaxed(val, portaddr(port, reg)) #define wr_regl(port, reg, val) writel_relaxed(val, portaddr(port, reg)) +/* Byte-order aware bit setting/clearing functions. */ + +static inline void s3c24xx_set_bit(struct uart_port *port, int idx, + unsigned int reg) +{ + unsigned long flags; + u32 val; + + local_irq_save(flags); + val = rd_regl(port, reg); + val |= (1 << idx); + wr_regl(port, reg, val); + local_irq_restore(flags); +} + +static inline void s3c24xx_clear_bit(struct uart_port *port, int idx, + unsigned int reg) +{ + unsigned long flags; + u32 val; + + local_irq_save(flags); + val = rd_regl(port, reg); + val &= ~(1 << idx); + wr_regl(port, reg, val); + local_irq_restore(flags); +} + #endif -- cgit v1.2.3 From d03516df837587368fc6e75591f6329c072b9eb5 Mon Sep 17 00:00:00 2001 From: Matthew Leach Date: Tue, 21 Jun 2016 16:19:49 +0100 Subject: tty: serial: 8250: add CON_CONSDEV to flags When using the 8250 as a boot console and the main console results in messages being printed twice. The console framework will only unregister boot consoles if a new console is registered with the CON_CONSDEV flag set. Set this flag for the univ8250 console to prevent double-registration. Signed-off-by: Matthew Leach Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index fa823a54cf35..dcf43f66404f 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -675,7 +675,7 @@ static struct console univ8250_console = { .device = uart_console_device, .setup = univ8250_console_setup, .match = univ8250_console_match, - .flags = CON_PRINTBUFFER | CON_ANYTIME, + .flags = CON_PRINTBUFFER | CON_ANYTIME | CON_CONSDEV, .index = -1, .data = &serial8250_reg, }; -- cgit v1.2.3 From c6f82787a5a193a5c4c49ddaeb362d320efa5fba Mon Sep 17 00:00:00 2001 From: Chuah, Kim Tatt Date: Wed, 15 Jun 2016 13:44:11 +0800 Subject: dmaengine: hsu: Export hsu_dma_get_status() To allow other code to safely read DMA Channel Status Register (where the register attribute for Channel Error, Descriptor Time Out & Descriptor Done fields are read-clear), export hsu_dma_get_status(). hsu_dma_irq() is renamed to hsu_dma_do_irq() and requires Status Register value to be passed in. Signed-off-by: Chuah, Kim Tatt Acked-by: Andy Shevchenko Reviewed-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/dma/hsu/hsu.c | 90 +++++++++++++++++++++++++++++--------- drivers/dma/hsu/pci.c | 11 ++++- drivers/tty/serial/8250/8250_mid.c | 22 +++++++--- include/linux/dma/hsu.h | 14 ++++-- 4 files changed, 106 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/hsu/hsu.c b/drivers/dma/hsu/hsu.c index f8c5cd53307c..c5f21efd6090 100644 --- a/drivers/dma/hsu/hsu.c +++ b/drivers/dma/hsu/hsu.c @@ -126,28 +126,33 @@ static void hsu_dma_start_transfer(struct hsu_dma_chan *hsuc) hsu_dma_start_channel(hsuc); } -static u32 hsu_dma_chan_get_sr(struct hsu_dma_chan *hsuc) -{ - unsigned long flags; - u32 sr; - - spin_lock_irqsave(&hsuc->vchan.lock, flags); - sr = hsu_chan_readl(hsuc, HSU_CH_SR); - spin_unlock_irqrestore(&hsuc->vchan.lock, flags); - - return sr & ~(HSU_CH_SR_DESCE_ANY | HSU_CH_SR_CDESC_ANY); -} - -irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr) +/* + * hsu_dma_get_status() - get DMA channel status + * @chip: HSUART DMA chip + * @nr: DMA channel number + * @status: pointer for DMA Channel Status Register value + * + * Description: + * The function reads and clears the DMA Channel Status Register, checks + * if it was a timeout interrupt and returns a corresponding value. + * + * Caller should provide a valid pointer for the DMA Channel Status + * Register value that will be returned in @status. + * + * Return: + * 1 for DMA timeout status, 0 for other DMA status, or error code for + * invalid parameters or no interrupt pending. + */ +int hsu_dma_get_status(struct hsu_dma_chip *chip, unsigned short nr, + u32 *status) { struct hsu_dma_chan *hsuc; - struct hsu_dma_desc *desc; unsigned long flags; u32 sr; /* Sanity check */ if (nr >= chip->hsu->nr_channels) - return IRQ_NONE; + return -EINVAL; hsuc = &chip->hsu->chan[nr]; @@ -155,22 +160,65 @@ irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr) * No matter what situation, need read clear the IRQ status * There is a bug, see Errata 5, HSD 2900918 */ - sr = hsu_dma_chan_get_sr(hsuc); + spin_lock_irqsave(&hsuc->vchan.lock, flags); + sr = hsu_chan_readl(hsuc, HSU_CH_SR); + spin_unlock_irqrestore(&hsuc->vchan.lock, flags); + + /* Check if any interrupt is pending */ + sr &= ~(HSU_CH_SR_DESCE_ANY | HSU_CH_SR_CDESC_ANY); if (!sr) - return IRQ_NONE; + return -EIO; /* Timeout IRQ, need wait some time, see Errata 2 */ if (sr & HSU_CH_SR_DESCTO_ANY) udelay(2); + /* + * At this point, at least one of Descriptor Time Out, Channel Error + * or Descriptor Done bits must be set. Clear the Descriptor Time Out + * bits and if sr is still non-zero, it must be channel error or + * descriptor done which are higher priority than timeout and handled + * in hsu_dma_do_irq(). Else, it must be a timeout. + */ sr &= ~HSU_CH_SR_DESCTO_ANY; - if (!sr) - return IRQ_HANDLED; + + *status = sr; + + return sr ? 0 : 1; +} +EXPORT_SYMBOL_GPL(hsu_dma_get_status); + +/* + * hsu_dma_do_irq() - DMA interrupt handler + * @chip: HSUART DMA chip + * @nr: DMA channel number + * @status: Channel Status Register value + * + * Description: + * This function handles Channel Error and Descriptor Done interrupts. + * This function should be called after determining that the DMA interrupt + * is not a normal timeout interrupt, ie. hsu_dma_get_status() returned 0. + * + * Return: + * IRQ_NONE for invalid channel number, IRQ_HANDLED otherwise. + */ +irqreturn_t hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr, + u32 status) +{ + struct hsu_dma_chan *hsuc; + struct hsu_dma_desc *desc; + unsigned long flags; + + /* Sanity check */ + if (nr >= chip->hsu->nr_channels) + return IRQ_NONE; + + hsuc = &chip->hsu->chan[nr]; spin_lock_irqsave(&hsuc->vchan.lock, flags); desc = hsuc->desc; if (desc) { - if (sr & HSU_CH_SR_CHE) { + if (status & HSU_CH_SR_CHE) { desc->status = DMA_ERROR; } else if (desc->active < desc->nents) { hsu_dma_start_channel(hsuc); @@ -184,7 +232,7 @@ irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr) return IRQ_HANDLED; } -EXPORT_SYMBOL_GPL(hsu_dma_irq); +EXPORT_SYMBOL_GPL(hsu_dma_do_irq); static struct hsu_dma_desc *hsu_dma_alloc_desc(unsigned int nents) { diff --git a/drivers/dma/hsu/pci.c b/drivers/dma/hsu/pci.c index e2db76bd56d8..9916058531d9 100644 --- a/drivers/dma/hsu/pci.c +++ b/drivers/dma/hsu/pci.c @@ -27,13 +27,20 @@ static irqreturn_t hsu_pci_irq(int irq, void *dev) { struct hsu_dma_chip *chip = dev; u32 dmaisr; + u32 status; unsigned short i; irqreturn_t ret = IRQ_NONE; + int err; dmaisr = readl(chip->regs + HSU_PCI_DMAISR); for (i = 0; i < chip->hsu->nr_channels; i++) { - if (dmaisr & 0x1) - ret |= hsu_dma_irq(chip, i); + if (dmaisr & 0x1) { + err = hsu_dma_get_status(chip, i, &status); + if (err > 0) + ret |= IRQ_HANDLED; + else if (err == 0) + ret |= hsu_dma_do_irq(chip, i, status); + } dmaisr >>= 1; } diff --git a/drivers/tty/serial/8250/8250_mid.c b/drivers/tty/serial/8250/8250_mid.c index 86379a79a6a3..b218ff528df7 100644 --- a/drivers/tty/serial/8250/8250_mid.c +++ b/drivers/tty/serial/8250/8250_mid.c @@ -97,12 +97,24 @@ static int dnv_handle_irq(struct uart_port *p) { struct mid8250 *mid = p->private_data; unsigned int fisr = serial_port_in(p, INTEL_MID_UART_DNV_FISR); + u32 status; int ret = IRQ_NONE; - - if (fisr & BIT(2)) - ret |= hsu_dma_irq(&mid->dma_chip, 1); - if (fisr & BIT(1)) - ret |= hsu_dma_irq(&mid->dma_chip, 0); + int err; + + if (fisr & BIT(2)) { + err = hsu_dma_get_status(&mid->dma_chip, 1, &status); + if (err > 0) + ret |= IRQ_HANDLED; + else if (err == 0) + ret |= hsu_dma_do_irq(&mid->dma_chip, 1, status); + } + if (fisr & BIT(1)) { + err = hsu_dma_get_status(&mid->dma_chip, 0, &status); + if (err > 0) + ret |= IRQ_HANDLED; + else if (err == 0) + ret |= hsu_dma_do_irq(&mid->dma_chip, 0, status); + } if (fisr & BIT(0)) ret |= serial8250_handle_irq(p, serial_port_in(p, UART_IIR)); return ret; diff --git a/include/linux/dma/hsu.h b/include/linux/dma/hsu.h index 79df69dc629c..aaff68efba5d 100644 --- a/include/linux/dma/hsu.h +++ b/include/linux/dma/hsu.h @@ -39,14 +39,22 @@ struct hsu_dma_chip { #if IS_ENABLED(CONFIG_HSU_DMA) /* Export to the internal users */ -irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr); +int hsu_dma_get_status(struct hsu_dma_chip *chip, unsigned short nr, + u32 *status); +irqreturn_t hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr, + u32 status); /* Export to the platform drivers */ int hsu_dma_probe(struct hsu_dma_chip *chip); int hsu_dma_remove(struct hsu_dma_chip *chip); #else -static inline irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, - unsigned short nr) +static inline int hsu_dma_get_status(struct hsu_dma_chip *chip, + unsigned short nr, u32 *status) +{ + return 0; +} +static inline irqreturn_t hsu_dma_do_irq(struct hsu_dma_chip *chip, + unsigned short nr, u32 status) { return IRQ_NONE; } -- cgit v1.2.3 From fd9e516d83108ad82d2c0c30097a6143c779f9c0 Mon Sep 17 00:00:00 2001 From: Chuah, Kim Tatt Date: Wed, 15 Jun 2016 13:44:12 +0800 Subject: serial: 8250_dma: Export serial8250_rx_dma_flush() Export serial8250_rx_dma_flush() for use by SOC UART drivers. Signed-off-by: Chuah, Kim Tatt Acked-by: Andy Shevchenko Reviewed-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dma.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c index 7f33d1c8d1a9..3590d012001f 100644 --- a/drivers/tty/serial/8250/8250_dma.c +++ b/drivers/tty/serial/8250/8250_dma.c @@ -145,6 +145,7 @@ void serial8250_rx_dma_flush(struct uart_8250_port *p) dmaengine_terminate_all(dma->rxchan); } } +EXPORT_SYMBOL_GPL(serial8250_rx_dma_flush); int serial8250_request_dma(struct uart_8250_port *p) { -- cgit v1.2.3 From 692aa1905679bd72f84115986235d214f6096a98 Mon Sep 17 00:00:00 2001 From: Chuah, Kim Tatt Date: Wed, 15 Jun 2016 13:44:13 +0800 Subject: serial: 8250_mid: Read RX buffer on RX DMA timeout for DNV In DNV, when RX DMA is used and number of bytes received is less than transfer size, only RX DMA timeout interrupt is sent. When this happens, read the RX buffer. Signed-off-by: Chuah, Kim Tatt Acked-by: Andy Shevchenko Reviewed-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_mid.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_mid.c b/drivers/tty/serial/8250/8250_mid.c index b218ff528df7..339de9cd0866 100644 --- a/drivers/tty/serial/8250/8250_mid.c +++ b/drivers/tty/serial/8250/8250_mid.c @@ -96,6 +96,7 @@ static int tng_setup(struct mid8250 *mid, struct uart_port *p) static int dnv_handle_irq(struct uart_port *p) { struct mid8250 *mid = p->private_data; + struct uart_8250_port *up = up_to_u8250p(p); unsigned int fisr = serial_port_in(p, INTEL_MID_UART_DNV_FISR); u32 status; int ret = IRQ_NONE; @@ -103,9 +104,10 @@ static int dnv_handle_irq(struct uart_port *p) if (fisr & BIT(2)) { err = hsu_dma_get_status(&mid->dma_chip, 1, &status); - if (err > 0) + if (err > 0) { + serial8250_rx_dma_flush(up); ret |= IRQ_HANDLED; - else if (err == 0) + } else if (err == 0) ret |= hsu_dma_do_irq(&mid->dma_chip, 1, status); } if (fisr & BIT(1)) { -- cgit v1.2.3 From 36fd95b17e9c1c41836632d95f2be5cff93b3df8 Mon Sep 17 00:00:00 2001 From: Yegor Yefremov Date: Tue, 31 May 2016 10:59:15 +0200 Subject: tty/serial/8250: make UART_MCR register access consistent Introduce serial8250_out_MCR() and serial8250_in_MCR() routines, that replace following calls: serial_out(port, UART_MCR, val) serial_port_out(up, UART_MCR, val) serial_in(port, UART_MCR) This patch is needed in order to integrate reading/writing of MCR signals via SERIAL_MCTRL_GPIO infrastructure later. Reviewed-by: Peter Hurley Signed-off-by: Yegor Yefremov Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250.h | 10 ++++++++ drivers/tty/serial/8250/8250_omap.c | 4 ++-- drivers/tty/serial/8250/8250_port.c | 47 ++++++++++++++++++------------------- 3 files changed, 35 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 31b3d55211d0..1a16feac9a36 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -129,6 +129,16 @@ void serial8250_rpm_put(struct uart_8250_port *p); int serial8250_em485_init(struct uart_8250_port *p); void serial8250_em485_destroy(struct uart_8250_port *p); +static inline void serial8250_out_MCR(struct uart_8250_port *up, int value) +{ + serial_out(up, UART_MCR, value); +} + +static inline int serial8250_in_MCR(struct uart_8250_port *up) +{ + return serial_in(up, UART_MCR); +} + #if defined(__alpha__) && !defined(CONFIG_PCI) /* * Digital did something really horribly wrong with the OUT1 and OUT2 diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 2c44c792d586..61ad6c3b20a0 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -280,7 +280,7 @@ static void omap8250_restore_regs(struct uart_8250_port *up) serial_out(up, UART_EFR, UART_EFR_ECB); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); - serial_out(up, UART_MCR, UART_MCR_TCRTLR); + serial8250_out_MCR(up, UART_MCR_TCRTLR); serial_out(up, UART_FCR, up->fcr); omap8250_update_scr(up, priv); @@ -296,7 +296,7 @@ static void omap8250_restore_regs(struct uart_8250_port *up) serial_out(up, UART_LCR, 0); /* drop TCR + TLR access, we setup XON/XOFF later */ - serial_out(up, UART_MCR, up->mcr); + serial8250_out_MCR(up, up->mcr); serial_out(up, UART_IER, up->ier); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index c8d8d245350b..bdfa659b9606 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -527,13 +527,13 @@ static void serial8250_clear_fifos(struct uart_8250_port *p) static inline void serial8250_em485_rts_after_send(struct uart_8250_port *p) { - unsigned char mcr = serial_in(p, UART_MCR); + unsigned char mcr = serial8250_in_MCR(p); if (p->port.rs485.flags & SER_RS485_RTS_AFTER_SEND) mcr |= UART_MCR_RTS; else mcr &= ~UART_MCR_RTS; - serial_out(p, UART_MCR, mcr); + serial8250_out_MCR(p, mcr); } static void serial8250_em485_handle_start_tx(unsigned long arg); @@ -785,10 +785,10 @@ static int size_fifo(struct uart_8250_port *up) old_lcr = serial_in(up, UART_LCR); serial_out(up, UART_LCR, 0); old_fcr = serial_in(up, UART_FCR); - old_mcr = serial_in(up, UART_MCR); + old_mcr = serial8250_in_MCR(up); serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - serial_out(up, UART_MCR, UART_MCR_LOOP); + serial8250_out_MCR(up, UART_MCR_LOOP); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); old_dl = serial_dl_read(up); serial_dl_write(up, 0x0001); @@ -800,7 +800,7 @@ static int size_fifo(struct uart_8250_port *up) (count < 256); count++) serial_in(up, UART_RX); serial_out(up, UART_FCR, old_fcr); - serial_out(up, UART_MCR, old_mcr); + serial8250_out_MCR(up, old_mcr); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); serial_dl_write(up, old_dl); serial_out(up, UART_LCR, old_lcr); @@ -1040,17 +1040,17 @@ static void autoconfig_16550a(struct uart_8250_port *up) * it's changed. If so, set baud_base in EXCR2 to 921600. -- dwmw2 */ serial_out(up, UART_LCR, 0); - status1 = serial_in(up, UART_MCR); + status1 = serial8250_in_MCR(up); serial_out(up, UART_LCR, 0xE0); status2 = serial_in(up, 0x02); /* EXCR1 */ if (!((status2 ^ status1) & UART_MCR_LOOP)) { serial_out(up, UART_LCR, 0); - serial_out(up, UART_MCR, status1 ^ UART_MCR_LOOP); + serial8250_out_MCR(up, status1 ^ UART_MCR_LOOP); serial_out(up, UART_LCR, 0xE0); status2 = serial_in(up, 0x02); /* EXCR1 */ serial_out(up, UART_LCR, 0); - serial_out(up, UART_MCR, status1); + serial8250_out_MCR(up, status1); if ((status2 ^ status1) & UART_MCR_LOOP) { unsigned short quot; @@ -1224,7 +1224,7 @@ static void autoconfig(struct uart_8250_port *up) } } - save_mcr = serial_in(up, UART_MCR); + save_mcr = serial8250_in_MCR(up); save_lcr = serial_in(up, UART_LCR); /* @@ -1237,9 +1237,9 @@ static void autoconfig(struct uart_8250_port *up) * that conflicts with COM 1-4 --- we hope! */ if (!(port->flags & UPF_SKIP_TEST)) { - serial_out(up, UART_MCR, UART_MCR_LOOP | 0x0A); + serial8250_out_MCR(up, UART_MCR_LOOP | 0x0A); status1 = serial_in(up, UART_MSR) & 0xF0; - serial_out(up, UART_MCR, save_mcr); + serial8250_out_MCR(up, save_mcr); if (status1 != 0x90) { spin_unlock_irqrestore(&port->lock, flags); DEBUG_AUTOCONF("LOOP test failed (%02x) ", @@ -1305,7 +1305,7 @@ static void autoconfig(struct uart_8250_port *up) if (port->type == PORT_RSA) serial_out(up, UART_RSA_FRR, 0); #endif - serial_out(up, UART_MCR, save_mcr); + serial8250_out_MCR(up, save_mcr); serial8250_clear_fifos(up); serial_in(up, UART_RX); if (up->capabilities & UART_CAP_UUE) @@ -1353,19 +1353,18 @@ static void autoconfig_irq(struct uart_8250_port *up) /* forget possible initially masked and pending IRQ */ probe_irq_off(probe_irq_on()); - save_mcr = serial_in(up, UART_MCR); + save_mcr = serial8250_in_MCR(up); save_ier = serial_in(up, UART_IER); - serial_out(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2); + serial8250_out_MCR(up, UART_MCR_OUT1 | UART_MCR_OUT2); irqs = probe_irq_on(); - serial_out(up, UART_MCR, 0); + serial8250_out_MCR(up, 0); udelay(10); if (port->flags & UPF_FOURPORT) { - serial_out(up, UART_MCR, - UART_MCR_DTR | UART_MCR_RTS); + serial8250_out_MCR(up, UART_MCR_DTR | UART_MCR_RTS); } else { - serial_out(up, UART_MCR, - UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); + serial8250_out_MCR(up, + UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); } serial_out(up, UART_IER, 0x0f); /* enable all intrs */ serial_in(up, UART_LSR); @@ -1376,7 +1375,7 @@ static void autoconfig_irq(struct uart_8250_port *up) udelay(20); irq = probe_irq_off(irqs); - serial_out(up, UART_MCR, save_mcr); + serial8250_out_MCR(up, save_mcr); serial_out(up, UART_IER, save_ier); if (port->flags & UPF_FOURPORT) @@ -1549,14 +1548,14 @@ static inline void start_tx_rs485(struct uart_port *port) del_timer(&em485->stop_tx_timer); em485->active_timer = NULL; - mcr = serial_in(up, UART_MCR); + mcr = serial8250_in_MCR(up); if (!!(up->port.rs485.flags & SER_RS485_RTS_ON_SEND) != !!(mcr & UART_MCR_RTS)) { if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND) mcr |= UART_MCR_RTS; else mcr &= ~UART_MCR_RTS; - serial_out(up, UART_MCR, mcr); + serial8250_out_MCR(up, mcr); if (up->port.rs485.delay_rts_before_send > 0) { em485->active_timer = &em485->start_tx_timer; @@ -1943,7 +1942,7 @@ void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl) mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr; - serial_port_out(port, UART_MCR, mcr); + serial8250_out_MCR(up, mcr); } EXPORT_SYMBOL_GPL(serial8250_do_set_mctrl); @@ -3090,7 +3089,7 @@ static void serial8250_console_restore(struct uart_8250_port *up) serial8250_set_divisor(port, baud, quot, frac); serial_port_out(port, UART_LCR, up->lcr); - serial_port_out(port, UART_MCR, UART_MCR_DTR | UART_MCR_RTS); + serial8250_out_MCR(up, UART_MCR_DTR | UART_MCR_RTS); } /* -- cgit v1.2.3 From bf5cee681e57babde5358a71e59b75151eb02c1a Mon Sep 17 00:00:00 2001 From: Yegor Yefremov Date: Tue, 31 May 2016 10:59:16 +0200 Subject: serial: mctrl_gpio: add modem control read routine mctrl_gpio_get_outputs() returns the state of following signals: RTS, DTR While defining the routine for reading outputs, fix the comment for mctrl_gpio_get() routine as it returns only the state of the input signals. Signed-off-by: Yegor Yefremov Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_mctrl_gpio.c | 18 ++++++++++++++++++ drivers/tty/serial/serial_mctrl_gpio.h | 15 ++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c index e8dd5097dc56..a868595beab0 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.c +++ b/drivers/tty/serial/serial_mctrl_gpio.c @@ -86,6 +86,24 @@ unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl) } EXPORT_SYMBOL_GPL(mctrl_gpio_get); +unsigned int +mctrl_gpio_get_outputs(struct mctrl_gpios *gpios, unsigned int *mctrl) +{ + enum mctrl_gpio_idx i; + + for (i = 0; i < UART_GPIO_MAX; i++) { + if (gpios->gpio[i] && mctrl_gpios_desc[i].dir_out) { + if (gpiod_get_value(gpios->gpio[i])) + *mctrl |= mctrl_gpios_desc[i].mctrl; + else + *mctrl &= ~mctrl_gpios_desc[i].mctrl; + } + } + + return *mctrl; +} +EXPORT_SYMBOL_GPL(mctrl_gpio_get_outputs); + struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx) { struct mctrl_gpios *gpios; diff --git a/drivers/tty/serial/serial_mctrl_gpio.h b/drivers/tty/serial/serial_mctrl_gpio.h index 332a33ab0647..fa000bcff217 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.h +++ b/drivers/tty/serial/serial_mctrl_gpio.h @@ -48,11 +48,18 @@ struct mctrl_gpios; void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl); /* - * Get state of the modem control output lines from GPIOs. + * Get state of the modem control input lines from GPIOs. * The mctrl flags are updated and returned. */ unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl); +/* + * Get state of the modem control output lines from GPIOs. + * The mctrl flags are updated and returned. + */ +unsigned int +mctrl_gpio_get_outputs(struct mctrl_gpios *gpios, unsigned int *mctrl); + /* * Returns the associated struct gpio_desc to the modem line gidx */ @@ -107,6 +114,12 @@ unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl) return *mctrl; } +static inline unsigned int +mctrl_gpio_get_outputs(struct mctrl_gpios *gpios, unsigned int *mctrl) +{ + return *mctrl; +} + static inline struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios, enum mctrl_gpio_idx gidx) -- cgit v1.2.3 From 434be0ae7aa746f481c3a22139e472dbc3f4f817 Mon Sep 17 00:00:00 2001 From: Yegor Yefremov Date: Tue, 31 May 2016 10:59:17 +0200 Subject: serial: mctrl_gpio: enable API usage only for initialized mctrl_gpios struct This workaround is needed for the cases, where mctrl_gpio API is used before mctrl_gpio_init() was invoked. This happens in 8250 during console initialization, as the driver sets DTR signal. Signed-off-by: Yegor Yefremov Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_mctrl_gpio.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c index a868595beab0..d2da6aa7f27d 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.c +++ b/drivers/tty/serial/serial_mctrl_gpio.c @@ -52,6 +52,9 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl) int value_array[UART_GPIO_MAX]; unsigned int count = 0; + if (gpios == NULL) + return; + for (i = 0; i < UART_GPIO_MAX; i++) if (gpios->gpio[i] && mctrl_gpios_desc[i].dir_out) { desc_array[count] = gpios->gpio[i]; @@ -73,6 +76,9 @@ unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl) { enum mctrl_gpio_idx i; + if (gpios == NULL) + return *mctrl; + for (i = 0; i < UART_GPIO_MAX; i++) { if (gpios->gpio[i] && !mctrl_gpios_desc[i].dir_out) { if (gpiod_get_value(gpios->gpio[i])) @@ -91,6 +97,9 @@ mctrl_gpio_get_outputs(struct mctrl_gpios *gpios, unsigned int *mctrl) { enum mctrl_gpio_idx i; + if (gpios == NULL) + return *mctrl; + for (i = 0; i < UART_GPIO_MAX; i++) { if (gpios->gpio[i] && mctrl_gpios_desc[i].dir_out) { if (gpiod_get_value(gpios->gpio[i])) @@ -221,6 +230,9 @@ void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios) { enum mctrl_gpio_idx i; + if (gpios == NULL) + return; + for (i = 0; i < UART_GPIO_MAX; i++) { if (gpios->irq[i]) devm_free_irq(gpios->port->dev, gpios->irq[i], gpios); @@ -236,6 +248,9 @@ void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios) { enum mctrl_gpio_idx i; + if (gpios == NULL) + return; + /* .enable_ms may be called multiple times */ if (gpios->mctrl_on) return; @@ -258,6 +273,9 @@ void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios) { enum mctrl_gpio_idx i; + if (gpios == NULL) + return; + if (!gpios->mctrl_on) return; -- cgit v1.2.3 From 4ef03d328769eddbfeca1f1c958fdb181a69c341 Mon Sep 17 00:00:00 2001 From: Yegor Yefremov Date: Tue, 31 May 2016 10:59:18 +0200 Subject: tty/serial/8250: use mctrl_gpio helpers This patch permits the usage for GPIOs to control the CTS/RTS/DTR/DSR/DCD/RI signals. Signed-off-by: Yegor Yefremov Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/8250.txt | 19 ++++++++++++ drivers/tty/serial/8250/8250.h | 35 ++++++++++++++++++++++- drivers/tty/serial/8250/8250_core.c | 9 ++++++ drivers/tty/serial/8250/8250_omap.c | 31 +++++++++++--------- drivers/tty/serial/8250/8250_port.c | 7 ++++- drivers/tty/serial/8250/Kconfig | 1 + include/linux/serial_8250.h | 1 + 7 files changed, 88 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/serial/8250.txt b/Documentation/devicetree/bindings/serial/8250.txt index 936ab5b87324..f5561ac7e17e 100644 --- a/Documentation/devicetree/bindings/serial/8250.txt +++ b/Documentation/devicetree/bindings/serial/8250.txt @@ -42,6 +42,9 @@ Optional properties: - auto-flow-control: one way to enable automatic flow control support. The driver is allowed to detect support for the capability even without this property. +- {rts,cts,dtr,dsr,rng,dcd}-gpios: specify a GPIO for RTS/CTS/DTR/DSR/RI/DCD + line respectively. It will use specified GPIO instead of the peripheral + function pin for the UART feature. If unsure, don't specify this property. Note: * fsl,ns16550: @@ -63,3 +66,19 @@ Example: interrupts = <10>; reg-shift = <2>; }; + +Example for OMAP UART using GPIO-based modem control signals: + + uart4: serial@49042000 { + compatible = "ti,omap3-uart"; + reg = <0x49042000 0x400>; + interrupts = <80>; + ti,hwmods = "uart4"; + clock-frequency = <48000000>; + cts-gpios = <&gpio3 5 GPIO_ACTIVE_LOW>; + rts-gpios = <&gpio3 6 GPIO_ACTIVE_LOW>; + dtr-gpios = <&gpio1 12 GPIO_ACTIVE_LOW>; + dsr-gpios = <&gpio1 13 GPIO_ACTIVE_LOW>; + dcd-gpios = <&gpio1 14 GPIO_ACTIVE_LOW>; + rng-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>; + }; diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 1a16feac9a36..122e0e4029fe 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -15,6 +15,8 @@ #include #include +#include "../serial_mctrl_gpio.h" + struct uart_8250_dma { int (*tx_dma)(struct uart_8250_port *p); int (*rx_dma)(struct uart_8250_port *p); @@ -131,12 +133,43 @@ void serial8250_em485_destroy(struct uart_8250_port *p); static inline void serial8250_out_MCR(struct uart_8250_port *up, int value) { + int mctrl_gpio = 0; + serial_out(up, UART_MCR, value); + + if (value & UART_MCR_RTS) + mctrl_gpio |= TIOCM_RTS; + if (value & UART_MCR_DTR) + mctrl_gpio |= TIOCM_DTR; + + mctrl_gpio_set(up->gpios, mctrl_gpio); } static inline int serial8250_in_MCR(struct uart_8250_port *up) { - return serial_in(up, UART_MCR); + int mctrl, mctrl_gpio = 0; + + mctrl = serial_in(up, UART_MCR); + + /* save current MCR values */ + if (mctrl & UART_MCR_RTS) + mctrl_gpio |= TIOCM_RTS; + if (mctrl & UART_MCR_DTR) + mctrl_gpio |= TIOCM_DTR; + + mctrl_gpio = mctrl_gpio_get_outputs(up->gpios, &mctrl_gpio); + + if (mctrl_gpio & TIOCM_RTS) + mctrl |= UART_MCR_RTS; + else + mctrl &= ~UART_MCR_RTS; + + if (mctrl_gpio & TIOCM_DTR) + mctrl |= UART_MCR_DTR; + else + mctrl &= ~UART_MCR_DTR; + + return mctrl; } #if defined(__alpha__) && !defined(CONFIG_PCI) diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index dcf43f66404f..13ad5c3d2e68 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -974,6 +974,8 @@ int serial8250_register_8250_port(struct uart_8250_port *up) uart = serial8250_find_match_or_unused(&up->port); if (uart && uart->port.type != PORT_8250_CIR) { + struct mctrl_gpios *gpios; + if (uart->port.dev) uart_remove_one_port(&serial8250_reg, &uart->port); @@ -1011,6 +1013,13 @@ int serial8250_register_8250_port(struct uart_8250_port *up) if (up->port.flags & UPF_FIXED_TYPE) uart->port.type = up->port.type; + gpios = mctrl_gpio_init(&uart->port, 0); + if (IS_ERR(gpios)) { + if (PTR_ERR(gpios) != -ENOSYS) + return PTR_ERR(gpios); + } else + uart->gpios = gpios; + serial8250_set_defaults(uart); /* Possibly override default I/O functions. */ diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 61ad6c3b20a0..e14982f36a04 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -134,18 +134,21 @@ static void omap8250_set_mctrl(struct uart_port *port, unsigned int mctrl) serial8250_do_set_mctrl(port, mctrl); - /* - * Turn off autoRTS if RTS is lowered and restore autoRTS setting - * if RTS is raised - */ - lcr = serial_in(up, UART_LCR); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS)) - priv->efr |= UART_EFR_RTS; - else - priv->efr &= ~UART_EFR_RTS; - serial_out(up, UART_EFR, priv->efr); - serial_out(up, UART_LCR, lcr); + if (IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(up->gpios, + UART_GPIO_RTS))) { + /* + * Turn off autoRTS if RTS is lowered and restore autoRTS + * setting if RTS is raised + */ + lcr = serial_in(up, UART_LCR); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS)) + priv->efr |= UART_EFR_RTS; + else + priv->efr &= ~UART_EFR_RTS; + serial_out(up, UART_EFR, priv->efr); + serial_out(up, UART_LCR, lcr); + } } /* @@ -446,7 +449,9 @@ static void omap_8250_set_termios(struct uart_port *port, priv->efr = 0; up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF); - if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) { + if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW + && IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(up->gpios, + UART_GPIO_RTS))) { /* Enable AUTOCTS (autoRTS is enabled when RTS is raised) */ up->port.status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS; priv->efr |= UART_EFR_CTS; diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index bdfa659b9606..7481b95c6d84 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1618,6 +1618,8 @@ static void serial8250_disable_ms(struct uart_port *port) if (up->bugs & UART_BUG_NOMSR) return; + mctrl_gpio_disable_ms(up->gpios); + up->ier &= ~UART_IER_MSI; serial_port_out(port, UART_IER, up->ier); } @@ -1630,6 +1632,8 @@ static void serial8250_enable_ms(struct uart_port *port) if (up->bugs & UART_BUG_NOMSR) return; + mctrl_gpio_enable_ms(up->gpios); + up->ier |= UART_IER_MSI; serial8250_rpm_get(up); @@ -1913,7 +1917,8 @@ unsigned int serial8250_do_get_mctrl(struct uart_port *port) ret |= TIOCM_DSR; if (status & UART_MSR_CTS) ret |= TIOCM_CTS; - return ret; + + return mctrl_gpio_get(up->gpios, &ret); } EXPORT_SYMBOL_GPL(serial8250_do_get_mctrl); diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index b5a0f2e76f08..b1c73dec7eda 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -6,6 +6,7 @@ config SERIAL_8250 tristate "8250/16550 and compatible serial support" select SERIAL_CORE + select SERIAL_MCTRL_GPIO if GPIOLIB ---help--- This selects whether you want to include the driver for the standard serial ports. The standard answer is Y. People who might say N diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index 48ec7651989b..923266cd294a 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -111,6 +111,7 @@ struct uart_8250_port { * if no_console_suspend */ unsigned char probe; + struct mctrl_gpios *gpios; #define UART_PROBE_RSA (1 << 0) /* -- cgit v1.2.3 From 68b780598d75fb2be80d70034ec7b46e4fe712da Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 6 Jun 2016 18:41:01 +0900 Subject: serial: 8250_uniphier: drop !defined(MODULE) conditional The !defined(MODULE) conditional has been added to the OF_EARLYCON_DECLARE() define. Now we can revert commit a2d3ea2f2399 ("serial: 8250/uniphier: fix modular build"). Signed-off-by: Masahiro Yamada Acked-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_uniphier.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c index efd1f9c047b1..b8d9c8c9d02a 100644 --- a/drivers/tty/serial/8250/8250_uniphier.c +++ b/drivers/tty/serial/8250/8250_uniphier.c @@ -35,7 +35,7 @@ struct uniphier8250_priv { spinlock_t atomic_write_lock; }; -#if defined(CONFIG_SERIAL_8250_CONSOLE) && !defined(MODULE) +#ifdef CONFIG_SERIAL_8250_CONSOLE static int __init uniphier_early_console_setup(struct earlycon_device *device, const char *options) { -- cgit v1.2.3 From ae73975f193547cf50e61480b92781b199574b83 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 6 Jun 2016 18:41:02 +0900 Subject: serial: 8250_mtk: drop !defined(MODULE) conditional The !defined(MODULE) conditional has been added to the OF_EARLYCON_DECLARE() define. This commit partially reverts commit 3f5921a60f74 ("serial: 8250/mediatek: fix building with SERIAL_8250=m"). Signed-off-by: Masahiro Yamada Acked-by: Matthias Brugger Acked-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_mtk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c index 3489fbcb7313..3611ec9bb4fa 100644 --- a/drivers/tty/serial/8250/8250_mtk.c +++ b/drivers/tty/serial/8250/8250_mtk.c @@ -301,7 +301,7 @@ static struct platform_driver mtk8250_platform_driver = { }; module_platform_driver(mtk8250_platform_driver); -#if defined(CONFIG_SERIAL_8250_CONSOLE) && !defined(MODULE) +#ifdef CONFIG_SERIAL_8250_CONSOLE static int __init early_mtk8250_setup(struct earlycon_device *device, const char *options) { -- cgit v1.2.3 From 755dd8aa12d162e40f3c5bd0031ad2f29ce6bc68 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 6 Jun 2016 18:41:03 +0900 Subject: serial: 8250_ingenic: drop #if conditional surrounding earlycon code The #if defined(CONFIG_SERIAL_EARLYCON) && !defined(MODULE) conditional has been added to the OF_EARLYCON_DECLARE() define. The same conditional can be dropped from 8250_ingenic.c because the unused symbols will be marked as __maybe_unsed. Also, the Kconfig dependency can become much simpler. Signed-off-by: Masahiro Yamada Acked-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_ingenic.c | 2 -- drivers/tty/serial/8250/Kconfig | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c index b0677f610863..4d9dc10e265c 100644 --- a/drivers/tty/serial/8250/8250_ingenic.c +++ b/drivers/tty/serial/8250/8250_ingenic.c @@ -48,7 +48,6 @@ static const struct of_device_id of_match[]; #define UART_MCR_MDCE BIT(7) #define UART_MCR_FCM BIT(6) -#if defined(CONFIG_SERIAL_EARLYCON) && !defined(MODULE) static struct earlycon_device *early_device; static uint8_t __init early_in(struct uart_port *port, int offset) @@ -141,7 +140,6 @@ OF_EARLYCON_DECLARE(jz4775_uart, "ingenic,jz4775-uart", EARLYCON_DECLARE(jz4780_uart, ingenic_early_console_setup); OF_EARLYCON_DECLARE(jz4780_uart, "ingenic,jz4780-uart", ingenic_early_console_setup); -#endif /* CONFIG_SERIAL_EARLYCON */ static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value) { diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index b1c73dec7eda..c9ec839a5ddf 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -397,7 +397,7 @@ config SERIAL_8250_UNIPHIER config SERIAL_8250_INGENIC tristate "Support for Ingenic SoC serial ports" depends on SERIAL_8250 - depends on (OF_FLATTREE && SERIAL_8250_CONSOLE) || !SERIAL_EARLYCON + depends on OF_FLATTREE depends on MIPS || COMPILE_TEST help If you have a system using an Ingenic SoC and wish to make use of -- cgit v1.2.3 From 5fd2b6ee7a319e0955acff96948fae57321b1f5a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 26 Jun 2016 11:20:21 +0200 Subject: serial: sh-sci: Stop transfers in sci_shutdown() Make sure the transmitter and receiver are stopped when shutting down the port, and related interrupts are disabled. Without this: - New input data may be received into the RX FIFO, possibly triggering a new RX DMA completion, - Transfers will still be enabled on a subsequent startup of the UART, before the UART's FIFOs have been reset, causing reading of stale data. Inspired by a patch in the BSP by Koji Matsuoka . Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 432d9acabf7f..d86eee38aae6 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1989,6 +1989,7 @@ static void sci_shutdown(struct uart_port *port) { struct sci_port *s = to_sci_port(port); unsigned long flags; + u16 scr; dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); @@ -1998,6 +1999,9 @@ static void sci_shutdown(struct uart_port *port) spin_lock_irqsave(&port->lock, flags); sci_stop_rx(port); sci_stop_tx(port); + /* Stop RX and TX, disable related interrupts, keep clock source */ + scr = serial_port_in(port, SCSCR); + serial_port_out(port, SCSCR, scr & (SCSCR_CKE1 | SCSCR_CKE0)); spin_unlock_irqrestore(&port->lock, flags); #ifdef CONFIG_SERIAL_SH_SCI_DMA -- cgit v1.2.3 From 98f2082c3ac4042189723c120553310700b583bb Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Sun, 26 Jun 2016 09:44:49 +0200 Subject: tty/serial: atmel: enforce tasklet init and termination sequences As some race conditions are identified in the termination process of tasklets, enforce the atmel_shutdown() sequence. This way we make sure that no new tasklets or software timer are scheduled during shutdown process. An atomic flag is positioned to give this information throughout the code. We also remove tasklet_disable() calls that were leading to deadlocks while stopping the driver. A simpler init/kill sequence is used. Signed-off-by: Nicolas Ferre Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 61 ++++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index f887c1df23e6..2eaa18ddef61 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -153,6 +153,7 @@ struct atmel_uart_port { struct scatterlist sg_rx; struct tasklet_struct tasklet_rx; struct tasklet_struct tasklet_tx; + atomic_t tasklet_shutdown; unsigned int irq_status_prev; unsigned int tx_len; @@ -286,6 +287,13 @@ static bool atmel_use_fifo(struct uart_port *port) return atmel_port->fifo_size; } +static void atmel_tasklet_schedule(struct atmel_uart_port *atmel_port, + struct tasklet_struct *t) +{ + if (!atomic_read(&atmel_port->tasklet_shutdown)) + tasklet_schedule(t); +} + static unsigned int atmel_get_lines_status(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); @@ -717,7 +725,7 @@ static void atmel_rx_chars(struct uart_port *port) status = atmel_uart_readl(port, ATMEL_US_CSR); } - tasklet_schedule(&atmel_port->tasklet_rx); + atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_rx); } /* @@ -788,7 +796,7 @@ static void atmel_complete_tx_dma(void *arg) * remaining data from the beginning of xmit->buf to xmit->head. */ if (!uart_circ_empty(xmit)) - tasklet_schedule(&atmel_port->tasklet_tx); + atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx); spin_unlock_irqrestore(&port->lock, flags); } @@ -973,7 +981,7 @@ static void atmel_complete_rx_dma(void *arg) struct uart_port *port = arg; struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - tasklet_schedule(&atmel_port->tasklet_rx); + atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_rx); } static void atmel_release_rx_dma(struct uart_port *port) @@ -1013,7 +1021,7 @@ static void atmel_rx_from_dma(struct uart_port *port) if (dmastat == DMA_ERROR) { dev_dbg(port->dev, "Get residue error, restart tasklet\n"); atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_TIMEOUT); - tasklet_schedule(&atmel_port->tasklet_rx); + atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_rx); return; } @@ -1167,8 +1175,11 @@ static void atmel_uart_timer_callback(unsigned long data) struct uart_port *port = (void *)data; struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - tasklet_schedule(&atmel_port->tasklet_rx); - mod_timer(&atmel_port->uart_timer, jiffies + uart_poll_timeout(port)); + if (!atomic_read(&atmel_port->tasklet_shutdown)) { + tasklet_schedule(&atmel_port->tasklet_rx); + mod_timer(&atmel_port->uart_timer, + jiffies + uart_poll_timeout(port)); + } } /* @@ -1190,7 +1201,8 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending) if (pending & (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)) { atmel_uart_writel(port, ATMEL_US_IDR, (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)); - tasklet_schedule(&atmel_port->tasklet_rx); + atmel_tasklet_schedule(atmel_port, + &atmel_port->tasklet_rx); } if (pending & (ATMEL_US_RXBRK | ATMEL_US_OVRE | @@ -1202,7 +1214,8 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending) if (pending & ATMEL_US_TIMEOUT) { atmel_uart_writel(port, ATMEL_US_IDR, ATMEL_US_TIMEOUT); - tasklet_schedule(&atmel_port->tasklet_rx); + atmel_tasklet_schedule(atmel_port, + &atmel_port->tasklet_rx); } } @@ -1232,7 +1245,7 @@ atmel_handle_transmit(struct uart_port *port, unsigned int pending) /* Either PDC or interrupt transmission */ atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask); - tasklet_schedule(&atmel_port->tasklet_tx); + atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx); } } @@ -1793,8 +1806,11 @@ static int atmel_startup(struct uart_port *port) return retval; } - tasklet_enable(&atmel_port->tasklet_rx); - tasklet_enable(&atmel_port->tasklet_tx); + atomic_set(&atmel_port->tasklet_shutdown, 0); + tasklet_init(&atmel_port->tasklet_rx, atmel_tasklet_rx_func, + (unsigned long)port); + tasklet_init(&atmel_port->tasklet_tx, atmel_tasklet_tx_func, + (unsigned long)port); /* * Initialize DMA (if necessary) @@ -1913,31 +1929,36 @@ static void atmel_shutdown(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + /* Disable interrupts at device level */ + atmel_uart_writel(port, ATMEL_US_IDR, -1); + + /* Prevent spurious interrupts from scheduling the tasklet */ + atomic_inc(&atmel_port->tasklet_shutdown); + /* * Prevent any tasklets being scheduled during * cleanup */ del_timer_sync(&atmel_port->uart_timer); + /* Make sure that no interrupt is on the fly */ + synchronize_irq(port->irq); + /* * Clear out any scheduled tasklets before * we destroy the buffers */ - tasklet_disable(&atmel_port->tasklet_rx); - tasklet_disable(&atmel_port->tasklet_tx); tasklet_kill(&atmel_port->tasklet_rx); tasklet_kill(&atmel_port->tasklet_tx); /* * Ensure everything is stopped and - * disable all interrupts, port and break condition. + * disable port and break condition. */ atmel_stop_rx(port); atmel_stop_tx(port); atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA); - atmel_uart_writel(port, ATMEL_US_IDR, -1); - /* * Shut-down the DMA. @@ -2321,13 +2342,6 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port, port->irq = pdev->resource[1].start; port->rs485_config = atmel_config_rs485; - tasklet_init(&atmel_port->tasklet_rx, atmel_tasklet_rx_func, - (unsigned long)port); - tasklet_init(&atmel_port->tasklet_tx, atmel_tasklet_tx_func, - (unsigned long)port); - tasklet_disable(&atmel_port->tasklet_rx); - tasklet_disable(&atmel_port->tasklet_tx); - memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring)); if (pdata && pdata->regs) { @@ -2712,6 +2726,7 @@ static int atmel_serial_probe(struct platform_device *pdev) atmel_port->uart.line = ret; atmel_serial_probe_fifos(atmel_port, pdev); + atomic_set(&atmel_port->tasklet_shutdown, 0); spin_lock_init(&atmel_port->lock_suspended); ret = atmel_init_port(atmel_port, pdev); -- cgit v1.2.3