diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-03-17 13:53:25 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-03-17 13:53:25 -0700 |
commit | 96b9b1c95660d4bc5510c5d798d3817ae9f0b391 (patch) | |
tree | c34e96557f5c2350e32bb418f5548d4b477940cd | |
parent | 8eee93e2576c303b6071368456dcd6c9a5a021c9 (diff) | |
parent | a95fc9c8e576dc238ad849f65c67e4fd33c01d3b (diff) | |
download | linux-stable-96b9b1c95660d4bc5510c5d798d3817ae9f0b391.tar.gz linux-stable-96b9b1c95660d4bc5510c5d798d3817ae9f0b391.tar.bz2 linux-stable-96b9b1c95660d4bc5510c5d798d3817ae9f0b391.zip |
Merge tag 'tty-4.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty/serial updates from Greg KH:
"Here's the big tty/serial driver pull request for 4.6-rc1.
Lots of changes in here, Peter has been on a tear again, with lots of
refactoring and bugs fixes, many thanks to the great work he has been
doing. Lots of driver updates and fixes as well, full details in the
shortlog.
All have been in linux-next for a while with no reported issues"
* tag 'tty-4.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (220 commits)
serial: 8250: describe CONFIG_SERIAL_8250_RSA
serial: samsung: optimize UART rx fifo access routine
serial: pl011: add mark/space parity support
serial: sa1100: make sa1100_register_uart_fns a function
tty: serial: 8250: add MOXA Smartio MUE boards support
serial: 8250: convert drivers to use up_to_u8250p()
serial: 8250/mediatek: fix building with SERIAL_8250=m
serial: 8250/ingenic: fix building with SERIAL_8250=m
serial: 8250/uniphier: fix modular build
Revert "drivers/tty/serial: make 8250/8250_ingenic.c explicitly non-modular"
Revert "drivers/tty/serial: make 8250/8250_mtk.c explicitly non-modular"
serial: mvebu-uart: initial support for Armada-3700 serial port
serial: mctrl_gpio: Add missing module license
serial: ifx6x60: avoid uninitialized variable use
tty/serial: at91: fix bad offset for UART timeout register
tty/serial: at91: restore dynamic driver binding
serial: 8250: Add hardware dependency to RT288X option
TTY, devpts: document pty count limiting
tty: goldfish: support platform_device with id -1
drivers: tty: goldfish: Add device tree bindings
...
139 files changed, 3447 insertions, 3701 deletions
diff --git a/Documentation/devicetree/bindings/goldfish/tty.txt b/Documentation/devicetree/bindings/goldfish/tty.txt new file mode 100644 index 000000000000..82648278da77 --- /dev/null +++ b/Documentation/devicetree/bindings/goldfish/tty.txt @@ -0,0 +1,17 @@ +Android Goldfish TTY + +Android goldfish tty device generated by android emulator. + +Required properties: + +- compatible : should contain "google,goldfish-tty" to match emulator +- reg : <registers mapping> +- interrupts : <interrupt mapping> + +Example: + + goldfish_tty@1f004000 { + compatible = "google,goldfish-tty"; + reg = <0x1f004000 0x1000>; + interrupts = <0xc>; + }; diff --git a/Documentation/devicetree/bindings/serial/brcm,bcm2835-aux-uart.txt b/Documentation/devicetree/bindings/serial/brcm,bcm2835-aux-uart.txt new file mode 100644 index 000000000000..b5cc6297cd1b --- /dev/null +++ b/Documentation/devicetree/bindings/serial/brcm,bcm2835-aux-uart.txt @@ -0,0 +1,18 @@ +* BCM2835 AUXILIAR UART + +Required properties: + +- compatible: "brcm,bcm2835-aux-uart" +- reg: The base address of the UART register bank. +- interrupts: A single interrupt specifier. +- clocks: Clock driving the hardware; used to figure out the baud rate + divisor. + +Example: + + uart1: serial@7e215040 { + compatible = "brcm,bcm2835-aux-uart"; + reg = <0x7e215040 0x40>; + interrupts = <1 29>; + clocks = <&aux BCM2835_AUX_CLOCK_UART>; + }; diff --git a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt index 401b1b33c2c4..528c3b90f23c 100644 --- a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt +++ b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt @@ -19,6 +19,8 @@ Required properties: - "renesas,scifa-r8a7791" for R8A7791 (R-Car M2-W) SCIFA compatible UART. - "renesas,scifb-r8a7791" for R8A7791 (R-Car M2-W) SCIFB compatible UART. - "renesas,hscif-r8a7791" for R8A7791 (R-Car M2-W) HSCIF compatible UART. + - "renesas,scif-r8a7792" for R8A7792 (R-Car V2H) SCIF compatible UART. + - "renesas,hscif-r8a7792" for R8A7792 (R-Car V2H) HSCIF compatible UART. - "renesas,scif-r8a7793" for R8A7793 (R-Car M2-N) SCIF compatible UART. - "renesas,scifa-r8a7793" for R8A7793 (R-Car M2-N) SCIFA compatible UART. - "renesas,scifb-r8a7793" for R8A7793 (R-Car M2-N) SCIFB compatible UART. diff --git a/Documentation/devicetree/bindings/tty/serial/mvebu-uart.txt b/Documentation/devicetree/bindings/tty/serial/mvebu-uart.txt new file mode 100644 index 000000000000..6087defd9f93 --- /dev/null +++ b/Documentation/devicetree/bindings/tty/serial/mvebu-uart.txt @@ -0,0 +1,13 @@ +* Marvell UART : Non standard UART used in some of Marvell EBU SoCs (e.g., Armada-3700) + +Required properties: +- compatible: "marvell,armada-3700-uart" +- reg: offset and length of the register set for the device. +- interrupts: device interrupt + +Example: + serial@12000 { + compatible = "marvell,armada-3700-uart"; + reg = <0x12000 0x400>; + interrupts = <43>; + }; diff --git a/Documentation/filesystems/devpts.txt b/Documentation/filesystems/devpts.txt index 68dffd87f9b7..30d2fcb32f72 100644 --- a/Documentation/filesystems/devpts.txt +++ b/Documentation/filesystems/devpts.txt @@ -51,6 +51,15 @@ where 'ns_exec -cm /bin/bash' calls clone() with CLONE_NEWNS flag and execs /bin/bash in the child process. A pty created by the sshd is not visible in the original mount of /dev/pts. +Total count of pty pairs in all instances is limited by sysctls: +kernel.pty.max = 4096 - global limit +kernel.pty.reserve = 1024 - reserve for initial instance +kernel.pty.nr - current count of ptys + +Per-instance limit could be set by adding mount option "max=<count>". +This feature was added in kernel 3.4 together with sysctl kernel.pty.reserve. +In kernels older than 3.4 sysctl kernel.pty.max works as per-instance limit. + User-space changes ------------------ diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index def479154d59..85b280de7aa8 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1064,6 +1064,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted. A valid base address must be provided, and the serial port must already be setup and configured. + armada3700_uart,<addr> + Start an early, polled-mode console on the + Armada 3700 serial port at the specified + address. The serial port must already be setup + and configured. Options are not yet supported. + earlyprintk= [X86,SH,BLACKFIN,ARM,M68k] earlyprintk=vga earlyprintk=efi diff --git a/Documentation/serial/tty.txt b/Documentation/serial/tty.txt index bc3842dc323a..798cba82c762 100644 --- a/Documentation/serial/tty.txt +++ b/Documentation/serial/tty.txt @@ -72,9 +72,6 @@ flush_buffer() - (optional) May be called at any point between open and close, and instructs the line discipline to empty its input buffer. -chars_in_buffer() - (optional) Report the number of bytes in the input - buffer. - set_termios() - (optional) Called on termios structure changes. The caller passes the old termios data and the current data is in the tty. Called under the diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index f4444c94ff28..57653a44b128 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -66,6 +66,7 @@ show up in /proc/sys/kernel: - printk_delay - printk_ratelimit - printk_ratelimit_burst +- pty ==> Documentation/filesystems/devpts.txt - randomize_va_space - real-root-dev ==> Documentation/initrd.txt - reboot-cmd [ SPARC only ] diff --git a/MAINTAINERS b/MAINTAINERS index 543dd219de80..5dc9d90c4048 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6068,7 +6068,7 @@ S: Maintained F: drivers/media/platform/rcar_jpu.c JSM Neo PCI based serial card -M: Thadeu Lima de Souza Cascardo <cascardo@linux.vnet.ibm.com> +M: Gabriel Krisman Bertazi <krisman@linux.vnet.ibm.com> L: linux-serial@vger.kernel.org S: Maintained F: drivers/tty/serial/jsm/ diff --git a/arch/alpha/include/asm/serial.h b/arch/alpha/include/asm/serial.h index 22909b83f473..e31557fc06cc 100644 --- a/arch/alpha/include/asm/serial.h +++ b/arch/alpha/include/asm/serial.h @@ -14,11 +14,11 @@ /* Standard COM flags (except for COM4, because of the 8514 problem) */ #ifdef CONFIG_SERIAL_8250_DETECT_IRQ -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ) -#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ) +#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ) +#define STD_COM4_FLAGS (UPF_BOOT_AUTOCONF | UPF_AUTO_IRQ) #else -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) -#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF +#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST) +#define STD_COM4_FLAGS UPF_BOOT_AUTOCONF #endif #define SERIAL_PORT_DFNS \ diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index f164c6b32ce2..8e072de89fed 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -252,7 +252,7 @@ void __init omap_serial_init_port(struct omap_board_data *bdata, info = omap_serial_default_info; oh = uart->oh; - name = DRIVER_NAME; + name = OMAP_SERIAL_DRIVER_NAME; omap_up.dma_enabled = info->dma_enabled; omap_up.uartclk = OMAP24XX_BASE_BAUD * 16; diff --git a/arch/frv/include/asm/serial.h b/arch/frv/include/asm/serial.h index dbb825998689..bce0d0d07e60 100644 --- a/arch/frv/include/asm/serial.h +++ b/arch/frv/include/asm/serial.h @@ -13,6 +13,6 @@ */ #define BASE_BAUD 0 -#define STD_COM_FLAGS ASYNC_BOOT_AUTOCONF +#define STD_COM_FLAGS UPF_BOOT_AUTOCONF #define SERIAL_PORT_DFNS diff --git a/arch/ia64/kernel/unaligned.c b/arch/ia64/kernel/unaligned.c index 622772b7fb6c..e7ae6088350a 100644 --- a/arch/ia64/kernel/unaligned.c +++ b/arch/ia64/kernel/unaligned.c @@ -1336,8 +1336,11 @@ ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs) * Don't call tty_write_message() if we're in the kernel; we might * be holding locks... */ - if (user_mode(regs)) - tty_write_message(current->signal->tty, buf); + if (user_mode(regs)) { + struct tty_struct *tty = get_current_tty(); + tty_write_message(tty, buf); + tty_kref_put(tty); + } buf[len-1] = '\0'; /* drop '\r' */ /* watch for command names containing %s */ printk(KERN_WARNING "%s", buf); diff --git a/arch/m68k/include/asm/serial.h b/arch/m68k/include/asm/serial.h index 06d0cb19b4e1..6d4497049b4b 100644 --- a/arch/m68k/include/asm/serial.h +++ b/arch/m68k/include/asm/serial.h @@ -18,11 +18,11 @@ /* Standard COM flags (except for COM4, because of the 8514 problem) */ #ifdef CONFIG_SERIAL_8250_DETECT_IRQ -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ) -#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ) +#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ) +#define STD_COM4_FLAGS (UPF_BOOT_AUTOCONF | UPF_AUTO_IRQ) #else -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) -#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF +#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST) +#define STD_COM4_FLAGS UPF_BOOT_AUTOCONF #endif #ifdef CONFIG_ISA diff --git a/arch/mips/pmcs-msp71xx/msp_serial.c b/arch/mips/pmcs-msp71xx/msp_serial.c index d304be22b963..8e6e8db8dd5f 100644 --- a/arch/mips/pmcs-msp71xx/msp_serial.c +++ b/arch/mips/pmcs-msp71xx/msp_serial.c @@ -110,7 +110,7 @@ void __init msp_serial_setup(void) up.uartclk = uartclk; up.regshift = 2; up.iotype = UPIO_MEM; - up.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST; + up.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; up.type = PORT_16550A; up.line = 0; up.serial_out = msp_serial_out; diff --git a/arch/mn10300/include/asm/serial.h b/arch/mn10300/include/asm/serial.h index c1990218f18c..594ebff15d3f 100644 --- a/arch/mn10300/include/asm/serial.h +++ b/arch/mn10300/include/asm/serial.h @@ -14,15 +14,15 @@ /* Standard COM flags (except for COM4, because of the 8514 problem) */ #ifdef CONFIG_SERIAL_8250_DETECT_IRQ -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ) -#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ) +#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ) +#define STD_COM4_FLAGS (UPF_BOOT_AUTOCONF | UPF_AUTO_IRQ) #else -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) -#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF +#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST) +#define STD_COM4_FLAGS UPF_BOOT_AUTOCONF #endif #ifdef CONFIG_SERIAL_8250_MANY_PORTS -#define FOURPORT_FLAGS ASYNC_FOURPORT +#define FOURPORT_FLAGS UPF_FOURPORT #define ACCENT_FLAGS 0 #define BOCA_FLAGS 0 #define HUB6_FLAGS 0 diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c index 70cb408bc20d..c54505dcf4db 100644 --- a/arch/xtensa/platforms/iss/console.c +++ b/arch/xtensa/platforms/iss/console.c @@ -28,10 +28,6 @@ #include <linux/tty.h> #include <linux/tty_flip.h> -#ifdef SERIAL_INLINE -#define _INLINE_ inline -#endif - #define SERIAL_MAX_NUM_LINES 1 #define SERIAL_TIMER_VALUE (HZ / 10) diff --git a/arch/xtensa/platforms/xt2000/setup.c b/arch/xtensa/platforms/xt2000/setup.c index 87678961a8c8..5f4bd71971d6 100644 --- a/arch/xtensa/platforms/xt2000/setup.c +++ b/arch/xtensa/platforms/xt2000/setup.c @@ -113,7 +113,7 @@ void platform_heartbeat(void) } //#define RS_TABLE_SIZE 2 -//#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST) +//#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF|UPF_SKIP_TEST) #define _SERIAL_PORT(_base,_irq) \ { \ diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 45df4bf914f8..22c27652e46a 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -1349,7 +1349,7 @@ static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty) /* TODO:disable interrupts instead of reset to preserve signal states */ reset_device(info); - if (!tty || tty->termios.c_cflag & HUPCL) { + if (!tty || C_HUPCL(tty)) { info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR); set_signals(info); } @@ -1390,7 +1390,7 @@ static void mgslpc_program_hw(MGSLPC_INFO *info, struct tty_struct *tty) port_irq_enable(info, (unsigned char) PVR_DSR | PVR_RI); get_signals(info); - if (info->netcount || (tty && (tty->termios.c_cflag & CREAD))) + if (info->netcount || (tty && C_CREAD(tty))) rx_start(info); spin_unlock_irqrestore(&info->lock, flags); @@ -1733,7 +1733,7 @@ static void mgslpc_throttle(struct tty_struct * tty) if (I_IXOFF(tty)) mgslpc_send_xchar(tty, STOP_CHAR(tty)); - if (tty->termios.c_cflag & CRTSCTS) { + if (C_CRTSCTS(tty)) { spin_lock_irqsave(&info->lock, flags); info->serial_signals &= ~SerialSignal_RTS; set_signals(info); @@ -1762,7 +1762,7 @@ static void mgslpc_unthrottle(struct tty_struct * tty) mgslpc_send_xchar(tty, START_CHAR(tty)); } - if (tty->termios.c_cflag & CRTSCTS) { + if (C_CRTSCTS(tty)) { spin_lock_irqsave(&info->lock, flags); info->serial_signals |= SerialSignal_RTS; set_signals(info); @@ -2306,8 +2306,7 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term mgslpc_change_params(info, tty); /* Handle transition to B0 status */ - if (old_termios->c_cflag & CBAUD && - !(tty->termios.c_cflag & CBAUD)) { + if ((old_termios->c_cflag & CBAUD) && !C_BAUD(tty)) { info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR); spin_lock_irqsave(&info->lock, flags); set_signals(info); @@ -2315,21 +2314,17 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term } /* Handle transition away from B0 status */ - if (!(old_termios->c_cflag & CBAUD) && - tty->termios.c_cflag & CBAUD) { + if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) { info->serial_signals |= SerialSignal_DTR; - if (!(tty->termios.c_cflag & CRTSCTS) || - !test_bit(TTY_THROTTLED, &tty->flags)) { + if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags)) info->serial_signals |= SerialSignal_RTS; - } spin_lock_irqsave(&info->lock, flags); set_signals(info); spin_unlock_irqrestore(&info->lock, flags); } /* Handle turning off CRTSCTS */ - if (old_termios->c_cflag & CRTSCTS && - !(tty->termios.c_cflag & CRTSCTS)) { + if (old_termios->c_cflag & CRTSCTS && !C_CRTSCTS(tty)) { tty->hw_stopped = 0; tx_release(tty); } diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c index a15ce4ef39cd..b098d2d0b7c4 100644 --- a/drivers/char/ttyprintk.c +++ b/drivers/char/ttyprintk.c @@ -171,7 +171,7 @@ static const struct tty_operations ttyprintk_ops = { .ioctl = tpk_ioctl, }; -static struct tty_port_operations null_ops = { }; +static const struct tty_port_operations null_ops = { }; static struct tty_driver *ttyprintk_driver; diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index 2175225af742..947d5c978b8f 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -1572,7 +1572,7 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp) #endif return; } - port->flags |= ASYNC_CLOSING; + info->closing = 1; tty->closing = 1; /* @@ -1603,6 +1603,7 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp) info->ncarrier = 0; tty_port_close_end(port, tty); + info->closing = 0; #ifdef ISDN_DEBUG_MODEM_OPEN printk(KERN_DEBUG "isdn_tty_close normal exit\n"); #endif @@ -2236,7 +2237,7 @@ isdn_tty_at_cout(char *msg, modem_info *info) l = strlen(msg); spin_lock_irqsave(&info->readlock, flags); - if (port->flags & ASYNC_CLOSING) { + if (info->closing) { spin_unlock_irqrestore(&info->readlock, flags); return; } @@ -2386,13 +2387,12 @@ isdn_tty_modem_result(int code, modem_info *info) case RESULT_NO_CARRIER: #ifdef ISDN_DEBUG_MODEM_HUP printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n", - (info->port.flags & ASYNC_CLOSING), - (!info->port.tty)); + info->closing, !info->port.tty); #endif m->mdmreg[REG_RINGCNT] = 0; del_timer(&info->nc_timer); info->ncarrier = 0; - if ((info->port.flags & ASYNC_CLOSING) || (!info->port.tty)) + if (info->closing || !info->port.tty) return; #ifdef CONFIG_ISDN_AUDIO @@ -2525,7 +2525,7 @@ isdn_tty_modem_result(int code, modem_info *info) } } if (code == RESULT_NO_CARRIER) { - if ((info->port.flags & ASYNC_CLOSING) || (!info->port.tty)) + if (info->closing || (!info->port.tty)) return; if (info->port.flags & ASYNC_CHECK_CD) diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c index d2de5925b73e..5415056f9aa5 100644 --- a/drivers/mmc/card/sdio_uart.c +++ b/drivers/mmc/card/sdio_uart.c @@ -493,7 +493,7 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port) if (status & UART_MSR_DCTS) { port->icount.cts++; tty = tty_port_tty_get(&port->port); - if (tty && (tty->termios.c_cflag & CRTSCTS)) { + if (tty && C_CRTSCTS(tty)) { int cts = (status & UART_MSR_CTS); if (tty->hw_stopped) { if (cts) { @@ -648,10 +648,10 @@ static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty) sdio_uart_change_speed(port, &tty->termios, NULL); - if (tty->termios.c_cflag & CBAUD) + if (C_BAUD(tty)) sdio_uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR); - if (tty->termios.c_cflag & CRTSCTS) + if (C_CRTSCTS(tty)) if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS)) tty->hw_stopped = 1; @@ -833,7 +833,7 @@ static void sdio_uart_throttle(struct tty_struct *tty) { struct sdio_uart_port *port = tty->driver_data; - if (!I_IXOFF(tty) && !(tty->termios.c_cflag & CRTSCTS)) + if (!I_IXOFF(tty) && !C_CRTSCTS(tty)) return; if (sdio_uart_claim_func(port) != 0) @@ -844,7 +844,7 @@ static void sdio_uart_throttle(struct tty_struct *tty) sdio_uart_start_tx(port); } - if (tty->termios.c_cflag & CRTSCTS) + if (C_CRTSCTS(tty)) sdio_uart_clear_mctrl(port, TIOCM_RTS); sdio_uart_irq(port->func); @@ -855,7 +855,7 @@ static void sdio_uart_unthrottle(struct tty_struct *tty) { struct sdio_uart_port *port = tty->driver_data; - if (!I_IXOFF(tty) && !(tty->termios.c_cflag & CRTSCTS)) + if (!I_IXOFF(tty) && !C_CRTSCTS(tty)) return; if (sdio_uart_claim_func(port) != 0) @@ -870,7 +870,7 @@ static void sdio_uart_unthrottle(struct tty_struct *tty) } } - if (tty->termios.c_cflag & CRTSCTS) + if (C_CRTSCTS(tty)) sdio_uart_set_mctrl(port, TIOCM_RTS); sdio_uart_irq(port->func); diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c index 696852eb23c3..7a3f990c1935 100644 --- a/drivers/net/irda/irtty-sir.c +++ b/drivers/net/irda/irtty-sir.c @@ -430,16 +430,6 @@ static int irtty_open(struct tty_struct *tty) /* Module stuff handled via irda_ldisc.owner - Jean II */ - /* First make sure we're not already connected. */ - if (tty->disc_data != NULL) { - priv = tty->disc_data; - if (priv && priv->magic == IRTTY_MAGIC) { - ret = -EEXIST; - goto out; - } - tty->disc_data = NULL; /* ### */ - } - /* stop the underlying driver */ irtty_stop_receiver(tty, TRUE); if (tty->ops->stop) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 655f79db7899..e2295b2c9836 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -796,14 +796,13 @@ static inline void early_init_dt_check_for_initrd(unsigned long node) #endif /* CONFIG_BLK_DEV_INITRD */ #ifdef CONFIG_SERIAL_EARLYCON -extern struct of_device_id __earlycon_of_table[]; static int __init early_init_dt_scan_chosen_serial(void) { int offset; - const char *p; + const char *p, *q, *options = NULL; int l; - const struct of_device_id *match = __earlycon_of_table; + const struct earlycon_id *match; const void *fdt = initial_boot_params; offset = fdt_path_offset(fdt, "/chosen"); @@ -818,27 +817,26 @@ static int __init early_init_dt_scan_chosen_serial(void) if (!p || !l) return -ENOENT; - /* Remove console options if present */ - l = strchrnul(p, ':') - p; + q = strchrnul(p, ':'); + if (*q != '\0') + options = q + 1; + l = q - p; /* Get the node specified by stdout-path */ offset = fdt_path_offset_namelen(fdt, p, l); - if (offset < 0) - return -ENODEV; - - while (match->compatible[0]) { - u64 addr; + if (offset < 0) { + pr_warn("earlycon: stdout-path %.*s not found\n", l, p); + return 0; + } - if (fdt_node_check_compatible(fdt, offset, match->compatible)) { - match++; + for (match = __earlycon_table; match < __earlycon_table_end; match++) { + if (!match->compatible[0]) continue; - } - addr = fdt_translate_address(fdt, offset); - if (addr == OF_BAD_ADDR) - return -ENXIO; + if (fdt_node_check_compatible(fdt, offset, match->compatible)) + continue; - of_setup_earlycon(addr, match->data); + of_setup_earlycon(match, offset, options); return 0; } return -ENODEV; diff --git a/drivers/of/fdt_address.c b/drivers/of/fdt_address.c index 8d3dc6fbdb7a..dca8f9b93745 100644 --- a/drivers/of/fdt_address.c +++ b/drivers/of/fdt_address.c @@ -161,7 +161,7 @@ static int __init fdt_translate_one(const void *blob, int parent, * that can be mapped to a cpu physical address). This is not really specified * that way, but this is traditionally the way IBM at least do things */ -u64 __init fdt_translate_address(const void *blob, int node_offset) +static u64 __init fdt_translate_address(const void *blob, int node_offset) { int parent, len; const struct of_bus *bus, *pbus; @@ -239,3 +239,12 @@ u64 __init fdt_translate_address(const void *blob, int node_offset) bail: return result; } + +/** + * of_flat_dt_translate_address - translate DT addr into CPU phys addr + * @node: node in the flat blob + */ +u64 __init of_flat_dt_translate_address(unsigned long node) +{ + return fdt_translate_address(initial_boot_params, node); +} diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 7d82bbcb12df..e7e078b3c7e6 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -643,7 +643,6 @@ static void raw3215_shutdown(struct raw3215_info *raw) if ((raw->flags & RAW3215_WORKING) || raw->queued_write != NULL || raw->queued_read != NULL) { - raw->port.flags |= ASYNC_CLOSING; add_wait_queue(&raw->empty_wait, &wait); set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); @@ -651,7 +650,7 @@ static void raw3215_shutdown(struct raw3215_info *raw) spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); remove_wait_queue(&raw->empty_wait, &wait); set_current_state(TASK_RUNNING); - raw->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_CLOSING); + raw->port.flags &= ~ASYNC_INITIALIZED; } spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); } diff --git a/drivers/staging/dgap/dgap.c b/drivers/staging/dgap/dgap.c index bad355100825..294c1c83aa4d 100644 --- a/drivers/staging/dgap/dgap.c +++ b/drivers/staging/dgap/dgap.c @@ -1530,7 +1530,7 @@ static void dgap_input(struct channel_t *ch) if ((bd->state != BOARD_READY) || !tp || (tp->magic != TTY_MAGIC) || !(ch->ch_tun.un_flags & UN_ISOPEN) || - !(tp->termios.c_cflag & CREAD) || + !C_CREAD(tp) || (ch->ch_tun.un_flags & UN_CLOSING)) { writew(head, &bs->rx_tail); writeb(1, &bs->idata); @@ -1665,9 +1665,7 @@ static void dgap_input(struct channel_t *ch) } static void dgap_write_wakeup(struct board_t *bd, struct channel_t *ch, - struct un_t *un, u32 mask, - unsigned long *irq_flags1, - unsigned long *irq_flags2) + struct un_t *un, u32 mask) { if (!(un->un_flags & mask)) return; @@ -1677,17 +1675,7 @@ static void dgap_write_wakeup(struct board_t *bd, struct channel_t *ch, if (!(un->un_flags & UN_ISOPEN)) return; - if ((un->un_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - un->un_tty->ldisc->ops->write_wakeup) { - spin_unlock_irqrestore(&ch->ch_lock, *irq_flags2); - spin_unlock_irqrestore(&bd->bd_lock, *irq_flags1); - - (un->un_tty->ldisc->ops->write_wakeup)(un->un_tty); - - spin_lock_irqsave(&bd->bd_lock, *irq_flags1); - spin_lock_irqsave(&ch->ch_lock, *irq_flags2); - } - wake_up_interruptible(&un->un_tty->write_wait); + tty_wakeup(un->un_tty); wake_up_interruptible(&un->un_flags_wait); } @@ -1952,10 +1940,8 @@ static int dgap_event(struct board_t *bd) * Process Transmit low. */ if (reason & IFTLW) { - dgap_write_wakeup(bd, ch, &ch->ch_tun, UN_LOW, - &lock_flags, &lock_flags2); - dgap_write_wakeup(bd, ch, &ch->ch_pun, UN_LOW, - &lock_flags, &lock_flags2); + dgap_write_wakeup(bd, ch, &ch->ch_tun, UN_LOW); + dgap_write_wakeup(bd, ch, &ch->ch_pun, UN_LOW); if (ch->ch_flags & CH_WLOW) { ch->ch_flags &= ~CH_WLOW; wake_up_interruptible(&ch->ch_flags_wait); @@ -1966,10 +1952,8 @@ static int dgap_event(struct board_t *bd) * Process Transmit empty. */ if (reason & IFTEM) { - dgap_write_wakeup(bd, ch, &ch->ch_tun, UN_EMPTY, - &lock_flags, &lock_flags2); - dgap_write_wakeup(bd, ch, &ch->ch_pun, UN_EMPTY, - &lock_flags, &lock_flags2); + dgap_write_wakeup(bd, ch, &ch->ch_tun, UN_EMPTY); + dgap_write_wakeup(bd, ch, &ch->ch_pun, UN_EMPTY); if (ch->ch_flags & CH_WEMPTY) { ch->ch_flags &= ~CH_WEMPTY; wake_up_interruptible(&ch->ch_flags_wait); @@ -3171,8 +3155,6 @@ static void dgap_tty_flush_buffer(struct tty_struct *tty) spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); spin_unlock_irqrestore(&bd->bd_lock, lock_flags); - if (waitqueue_active(&tty->write_wait)) - wake_up_interruptible(&tty->write_wait); tty_wakeup(tty); } @@ -4969,10 +4951,6 @@ static int dgap_tty_ioctl(struct tty_struct *tty, unsigned int cmd, ch->ch_pun.un_flags &= ~(UN_LOW | UN_EMPTY); wake_up_interruptible(&ch->ch_pun.un_flags_wait); } - if (waitqueue_active(&tty->write_wait)) - wake_up_interruptible(&tty->write_wait); - - /* Can't hold any locks when calling tty_wakeup! */ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); spin_unlock_irqrestore(&bd->bd_lock, lock_flags); tty_wakeup(tty); diff --git a/drivers/staging/dgnc/dgnc_tty.c b/drivers/staging/dgnc/dgnc_tty.c index b79eab084c02..8b1ba65a6984 100644 --- a/drivers/staging/dgnc/dgnc_tty.c +++ b/drivers/staging/dgnc/dgnc_tty.c @@ -541,7 +541,7 @@ void dgnc_input(struct channel_t *ch) */ if (!tp || (tp->magic != TTY_MAGIC) || !(ch->ch_tun.un_flags & UN_ISOPEN) || - !(tp->termios.c_cflag & CREAD) || + !C_CREAD(tp) || (ch->ch_tun.un_flags & UN_CLOSING)) { ch->ch_r_head = tail; @@ -933,14 +933,7 @@ void dgnc_wakeup_writes(struct channel_t *ch) } if (ch->ch_tun.un_flags & UN_ISOPEN) { - if ((ch->ch_tun.un_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - ch->ch_tun.un_tty->ldisc->ops->write_wakeup) { - spin_unlock_irqrestore(&ch->ch_lock, flags); - ch->ch_tun.un_tty->ldisc->ops->write_wakeup(ch->ch_tun.un_tty); - spin_lock_irqsave(&ch->ch_lock, flags); - } - - wake_up_interruptible(&ch->ch_tun.un_tty->write_wait); + tty_wakeup(ch->ch_tun.un_tty); /* * If unit is set to wait until empty, check to make sure @@ -975,14 +968,7 @@ void dgnc_wakeup_writes(struct channel_t *ch) } if (ch->ch_pun.un_flags & UN_ISOPEN) { - if ((ch->ch_pun.un_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - ch->ch_pun.un_tty->ldisc->ops->write_wakeup) { - spin_unlock_irqrestore(&ch->ch_lock, flags); - ch->ch_pun.un_tty->ldisc->ops->write_wakeup(ch->ch_pun.un_tty); - spin_lock_irqsave(&ch->ch_lock, flags); - } - - wake_up_interruptible(&ch->ch_pun.un_tty->write_wait); + tty_wakeup(ch->ch_pun.un_tty); /* * If unit is set to wait until empty, check to make sure diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index c01f45095877..82c4d2e45319 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -226,7 +226,7 @@ config CYCLADES config CYZ_INTR bool "Cyclades-Z interrupt mode operation" - depends on CYCLADES + depends on CYCLADES && PCI help The Cyclades-Z family of multiport cards allows 2 (two) driver op modes: polling and interrupt. In polling mode, the driver will check diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 2caaf5a2516d..eacf4c9f3b29 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -639,7 +639,7 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info) custom.adkcon = AC_UARTBRK; mb(); - if (tty->termios.c_cflag & HUPCL) + if (C_HUPCL(tty)) info->MCR &= ~(SER_DTR|SER_RTS); rtsdtr_ctrl(info->MCR); @@ -965,8 +965,7 @@ static void rs_throttle(struct tty_struct * tty) struct serial_state *info = tty->driver_data; unsigned long flags; #ifdef SERIAL_DEBUG_THROTTLE - printk("throttle %s: %d....\n", tty_name(tty), - tty->ldisc.chars_in_buffer(tty)); + printk("throttle %s ....\n", tty_name(tty)); #endif if (serial_paranoia_check(info, tty->name, "rs_throttle")) @@ -975,7 +974,7 @@ static void rs_throttle(struct tty_struct * tty) if (I_IXOFF(tty)) rs_send_xchar(tty, STOP_CHAR(tty)); - if (tty->termios.c_cflag & CRTSCTS) + if (C_CRTSCTS(tty)) info->MCR &= ~SER_RTS; local_irq_save(flags); @@ -988,8 +987,7 @@ static void rs_unthrottle(struct tty_struct * tty) struct serial_state *info = tty->driver_data; unsigned long flags; #ifdef SERIAL_DEBUG_THROTTLE - printk("unthrottle %s: %d....\n", tty_name(tty), - tty->ldisc.chars_in_buffer(tty)); + printk("unthrottle %s ....\n", tty_name(tty)); #endif if (serial_paranoia_check(info, tty->name, "rs_unthrottle")) @@ -1001,7 +999,7 @@ static void rs_unthrottle(struct tty_struct * tty) else rs_send_xchar(tty, START_CHAR(tty)); } - if (tty->termios.c_cflag & CRTSCTS) + if (C_CRTSCTS(tty)) info->MCR |= SER_RTS; local_irq_save(flags); rtsdtr_ctrl(info->MCR); @@ -1334,8 +1332,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) change_speed(tty, info, old_termios); /* Handle transition to B0 status */ - if ((old_termios->c_cflag & CBAUD) && - !(cflag & CBAUD)) { + if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) { info->MCR &= ~(SER_DTR|SER_RTS); local_irq_save(flags); rtsdtr_ctrl(info->MCR); @@ -1343,21 +1340,17 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) } /* Handle transition away from B0 status */ - if (!(old_termios->c_cflag & CBAUD) && - (cflag & CBAUD)) { + if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) { info->MCR |= SER_DTR; - if (!(tty->termios.c_cflag & CRTSCTS) || - !test_bit(TTY_THROTTLED, &tty->flags)) { + if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags)) info->MCR |= SER_RTS; - } local_irq_save(flags); rtsdtr_ctrl(info->MCR); local_irq_restore(flags); } /* Handle turning off CRTSCTS */ - if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios.c_cflag & CRTSCTS)) { + if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) { tty->hw_stopped = 0; rs_start(tty); } @@ -1369,8 +1362,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) * XXX It's not clear whether the current behavior is correct * or not. Hence, this may change..... */ - if (!(old_termios->c_cflag & CLOCAL) && - (tty->termios.c_cflag & CLOCAL)) + if (!(old_termios->c_cflag & CLOCAL) && C_CLOCAL(tty)) wake_up_interruptible(&info->open_wait); #endif } diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index abbed201dc74..d67e542bab1c 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -1440,7 +1440,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty) info->port.xmit_buf = NULL; free_page((unsigned long)temp); } - if (tty->termios.c_cflag & HUPCL) + if (C_HUPCL(tty)) cyy_change_rts_dtr(info, 0, TIOCM_RTS | TIOCM_DTR); cyy_issue_cmd(info, CyCHAN_CTL | CyDIS_RCVR); @@ -1469,7 +1469,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty) free_page((unsigned long)temp); } - if (tty->termios.c_cflag & HUPCL) + if (C_HUPCL(tty)) tty_port_lower_dtr_rts(&info->port); set_bit(TTY_IO_ERROR, &tty->flags); @@ -2795,8 +2795,7 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios) cy_set_line_char(info, tty); - if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios.c_cflag & CRTSCTS)) { + if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) { tty->hw_stopped = 0; cy_start(tty); } @@ -2807,8 +2806,7 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios) * XXX It's not clear whether the current behavior is correct * or not. Hence, this may change..... */ - if (!(old_termios->c_cflag & CLOCAL) && - (tty->termios.c_cflag & CLOCAL)) + if (!(old_termios->c_cflag & CLOCAL) && C_CLOCAL(tty)) wake_up_interruptible(&info->port.open_wait); #endif } /* cy_set_termios */ @@ -2852,8 +2850,8 @@ static void cy_throttle(struct tty_struct *tty) unsigned long flags; #ifdef CY_DEBUG_THROTTLE - printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty), - tty->ldisc.chars_in_buffer(tty), info->line); + printk(KERN_DEBUG "cyc:throttle %s ...ttyC%d\n", tty_name(tty), + info->line); #endif if (serial_paranoia_check(info, tty->name, "cy_throttle")) @@ -2868,7 +2866,7 @@ static void cy_throttle(struct tty_struct *tty) info->throttle = 1; } - if (tty->termios.c_cflag & CRTSCTS) { + if (C_CRTSCTS(tty)) { if (!cy_is_Z(card)) { spin_lock_irqsave(&card->card_lock, flags); cyy_change_rts_dtr(info, 0, TIOCM_RTS); @@ -2891,8 +2889,8 @@ static void cy_unthrottle(struct tty_struct *tty) unsigned long flags; #ifdef CY_DEBUG_THROTTLE - printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n", - tty_name(tty), tty_chars_in_buffer(tty), info->line); + printk(KERN_DEBUG "cyc:unthrottle %s ...ttyC%d\n", + tty_name(tty), info->line); #endif if (serial_paranoia_check(info, tty->name, "cy_unthrottle")) @@ -2905,7 +2903,7 @@ static void cy_unthrottle(struct tty_struct *tty) cy_send_xchar(tty, START_CHAR(tty)); } - if (tty->termios.c_cflag & CRTSCTS) { + if (C_CRTSCTS(tty)) { card = info->card; if (!cy_is_Z(card)) { spin_lock_irqsave(&card->card_lock, flags); diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c index 342b36b9ad35..7ac9bcdf1e61 100644 --- a/drivers/tty/ehv_bytechan.c +++ b/drivers/tty/ehv_bytechan.c @@ -23,7 +23,6 @@ * byte channel used for the console is designated as the default tty. */ -#include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/err.h> @@ -719,19 +718,6 @@ error: return ret; } -static int ehv_bc_tty_remove(struct platform_device *pdev) -{ - struct ehv_bc_data *bc = dev_get_drvdata(&pdev->dev); - - tty_unregister_device(ehv_bc_driver, bc - bcs); - - tty_port_destroy(&bc->port); - irq_dispose_mapping(bc->tx_irq); - irq_dispose_mapping(bc->rx_irq); - - return 0; -} - static const struct of_device_id ehv_bc_tty_of_ids[] = { { .compatible = "epapr,hv-byte-channel" }, {} @@ -741,15 +727,15 @@ static struct platform_driver ehv_bc_tty_driver = { .driver = { .name = "ehv-bc", .of_match_table = ehv_bc_tty_of_ids, + .suppress_bind_attrs = true, }, .probe = ehv_bc_tty_probe, - .remove = ehv_bc_tty_remove, }; /** * ehv_bc_init - ePAPR hypervisor byte channel driver initialization * - * This function is called when this module is loaded. + * This function is called when this driver is loaded. */ static int __init ehv_bc_init(void) { @@ -814,24 +800,4 @@ error: return ret; } - - -/** - * ehv_bc_exit - ePAPR hypervisor byte channel driver termination - * - * This function is called when this driver is unloaded. - */ -static void __exit ehv_bc_exit(void) -{ - platform_driver_unregister(&ehv_bc_tty_driver); - tty_unregister_driver(ehv_bc_driver); - put_tty_driver(ehv_bc_driver); - kfree(bcs); -} - -module_init(ehv_bc_init); -module_exit(ehv_bc_exit); - -MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); -MODULE_DESCRIPTION("ePAPR hypervisor byte channel driver"); -MODULE_LICENSE("GPL v2"); +device_initcall(ehv_bc_init); diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c index 0f82c0b146f6..3fc912373adf 100644 --- a/drivers/tty/goldfish.c +++ b/drivers/tty/goldfish.c @@ -68,8 +68,7 @@ static void goldfish_tty_do_write(int line, const char *buf, unsigned count) static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id) { - struct platform_device *pdev = dev_id; - struct goldfish_tty *qtty = &goldfish_ttys[pdev->id]; + struct goldfish_tty *qtty = dev_id; void __iomem *base = qtty->base; unsigned long irq_flags; unsigned char *buf; @@ -162,7 +161,7 @@ static int goldfish_tty_console_setup(struct console *co, char *options) return 0; } -static struct tty_port_operations goldfish_port_ops = { +static const struct tty_port_operations goldfish_port_ops = { .activate = goldfish_tty_activate, .shutdown = goldfish_tty_shutdown }; @@ -233,6 +232,7 @@ static int goldfish_tty_probe(struct platform_device *pdev) struct device *ttydev; void __iomem *base; u32 irq; + unsigned int line; r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (r == NULL) @@ -248,10 +248,16 @@ static int goldfish_tty_probe(struct platform_device *pdev) irq = r->start; - if (pdev->id >= goldfish_tty_line_count) - goto err_unmap; - mutex_lock(&goldfish_tty_lock); + + if (pdev->id == PLATFORM_DEVID_NONE) + line = goldfish_tty_current_line_count; + else + line = pdev->id; + + if (line >= goldfish_tty_line_count) + goto err_create_driver_failed; + if (goldfish_tty_current_line_count == 0) { ret = goldfish_tty_create_driver(); if (ret) @@ -259,7 +265,7 @@ static int goldfish_tty_probe(struct platform_device *pdev) } goldfish_tty_current_line_count++; - qtty = &goldfish_ttys[pdev->id]; + qtty = &goldfish_ttys[line]; spin_lock_init(&qtty->lock); tty_port_init(&qtty->port); qtty->port.ops = &goldfish_port_ops; @@ -269,13 +275,13 @@ static int goldfish_tty_probe(struct platform_device *pdev) writel(GOLDFISH_TTY_CMD_INT_DISABLE, base + GOLDFISH_TTY_CMD); ret = request_irq(irq, goldfish_tty_interrupt, IRQF_SHARED, - "goldfish_tty", pdev); + "goldfish_tty", qtty); if (ret) goto err_request_irq_failed; ttydev = tty_port_register_device(&qtty->port, goldfish_tty_driver, - pdev->id, &pdev->dev); + line, &pdev->dev); if (IS_ERR(ttydev)) { ret = PTR_ERR(ttydev); goto err_tty_register_device_failed; @@ -286,8 +292,9 @@ static int goldfish_tty_probe(struct platform_device *pdev) qtty->console.device = goldfish_tty_console_device; qtty->console.setup = goldfish_tty_console_setup; qtty->console.flags = CON_PRINTBUFFER; - qtty->console.index = pdev->id; + qtty->console.index = line; register_console(&qtty->console); + platform_set_drvdata(pdev, qtty); mutex_unlock(&goldfish_tty_lock); return 0; @@ -307,13 +314,12 @@ err_unmap: static int goldfish_tty_remove(struct platform_device *pdev) { - struct goldfish_tty *qtty; + struct goldfish_tty *qtty = platform_get_drvdata(pdev); mutex_lock(&goldfish_tty_lock); - qtty = &goldfish_ttys[pdev->id]; unregister_console(&qtty->console); - tty_unregister_device(goldfish_tty_driver, pdev->id); + tty_unregister_device(goldfish_tty_driver, qtty->console.index); iounmap(qtty->base); qtty->base = NULL; free_irq(qtty->irq, pdev); @@ -324,11 +330,19 @@ static int goldfish_tty_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id goldfish_tty_of_match[] = { + { .compatible = "google,goldfish-tty", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, goldfish_tty_of_match); + static struct platform_driver goldfish_tty_platform_driver = { .probe = goldfish_tty_probe, .remove = goldfish_tty_remove, .driver = { - .name = "goldfish_tty" + .name = "goldfish_tty", + .of_match_table = goldfish_tty_of_match, } }; diff --git a/drivers/tty/hvc/hvc_vio.c b/drivers/tty/hvc/hvc_vio.c index f575a9b5ede7..b05dc5086627 100644 --- a/drivers/tty/hvc/hvc_vio.c +++ b/drivers/tty/hvc/hvc_vio.c @@ -41,7 +41,6 @@ #include <linux/delay.h> #include <linux/slab.h> #include <linux/console.h> -#include <linux/module.h> #include <asm/hvconsole.h> #include <asm/vio.h> @@ -61,7 +60,6 @@ static struct vio_device_id hvc_driver_table[] = { #endif { "", "" } }; -MODULE_DEVICE_TABLE(vio, hvc_driver_table); typedef enum hv_protocol { HV_PROTOCOL_RAW, @@ -363,26 +361,13 @@ static int hvc_vio_probe(struct vio_dev *vdev, return 0; } -static int hvc_vio_remove(struct vio_dev *vdev) -{ - struct hvc_struct *hp = dev_get_drvdata(&vdev->dev); - int rc, termno; - - termno = hp->vtermno; - rc = hvc_remove(hp); - if (rc == 0) { - if (hvterm_privs[termno] != &hvterm_priv0) - kfree(hvterm_privs[termno]); - hvterm_privs[termno] = NULL; - } - return rc; -} - static struct vio_driver hvc_vio_driver = { .id_table = hvc_driver_table, .probe = hvc_vio_probe, - .remove = hvc_vio_remove, .name = hvc_driver_name, + .driver = { + .suppress_bind_attrs = true, + }, }; static int __init hvc_vio_init(void) @@ -394,13 +379,7 @@ static int __init hvc_vio_init(void) return rc; } -module_init(hvc_vio_init); /* after drivers/char/hvc_console.c */ - -static void __exit hvc_vio_exit(void) -{ - vio_unregister_driver(&hvc_vio_driver); -} -module_exit(hvc_vio_exit); +device_initcall(hvc_vio_init); /* after drivers/tty/hvc/hvc_console.c */ void __init hvc_vio_init_early(void) { diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index fa816b7193b6..f417fa1ee47c 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c @@ -162,7 +162,7 @@ static int domU_read_console(uint32_t vtermno, char *buf, int len) return recv; } -static struct hv_ops domU_hvc_ops = { +static const struct hv_ops domU_hvc_ops = { .get_chars = domU_read_console, .put_chars = domU_write_console, .notifier_add = notifier_add_irq, @@ -188,7 +188,7 @@ static int dom0_write_console(uint32_t vtermno, const char *str, int len) return len; } -static struct hv_ops dom0_hvc_ops = { +static const struct hv_ops dom0_hvc_ops = { .get_chars = dom0_read_console, .put_chars = dom0_write_console, .notifier_add = notifier_add_irq, @@ -323,6 +323,7 @@ void xen_console_resume(void) } } +#ifdef CONFIG_HVC_XEN_FRONTEND static void xencons_disconnect_backend(struct xencons_info *info) { if (info->irq > 0) @@ -363,7 +364,6 @@ static int xen_console_remove(struct xencons_info *info) return 0; } -#ifdef CONFIG_HVC_XEN_FRONTEND static int xencons_remove(struct xenbus_device *dev) { return xen_console_remove(dev_get_drvdata(&dev->dev)); diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c index 99875949bfb7..8bf67630018b 100644 --- a/drivers/tty/isicom.c +++ b/drivers/tty/isicom.c @@ -1204,8 +1204,7 @@ static void isicom_set_termios(struct tty_struct *tty, isicom_config_port(tty); spin_unlock_irqrestore(&port->card->card_lock, flags); - if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios.c_cflag & CRTSCTS)) { + if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) { tty->hw_stopped = 0; isicom_start(tty); } diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 4c4a23674569..2f12bb9f4336 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -254,6 +254,7 @@ struct mxser_port { int xmit_head; int xmit_tail; int xmit_cnt; + int closing; struct ktermios normal_termios; @@ -1081,6 +1082,7 @@ static void mxser_close(struct tty_struct *tty, struct file *filp) return; if (tty_port_close_start(port, tty, filp) == 0) return; + info->closing = 1; mutex_lock(&port->mutex); mxser_close_port(port); mxser_flush_buffer(tty); @@ -1091,6 +1093,7 @@ static void mxser_close(struct tty_struct *tty, struct file *filp) mxser_shutdown_port(port); clear_bit(ASYNCB_INITIALIZED, &port->flags); mutex_unlock(&port->mutex); + info->closing = 0; /* Right now the tty_port set is done outside of the close_end helper as we don't yet have everyone using refcounts */ tty_port_close_end(port, tty); @@ -1864,7 +1867,7 @@ static void mxser_stoprx(struct tty_struct *tty) } } - if (tty->termios.c_cflag & CRTSCTS) { + if (C_CRTSCTS(tty)) { info->MCR &= ~UART_MCR_RTS; outb(info->MCR, info->ioaddr + UART_MCR); } @@ -1901,7 +1904,7 @@ static void mxser_unthrottle(struct tty_struct *tty) } } - if (tty->termios.c_cflag & CRTSCTS) { + if (C_CRTSCTS(tty)) { info->MCR |= UART_MCR_RTS; outb(info->MCR, info->ioaddr + UART_MCR); } @@ -1949,15 +1952,13 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi mxser_change_speed(tty, old_termios); spin_unlock_irqrestore(&info->slock, flags); - if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios.c_cflag & CRTSCTS)) { + if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) { tty->hw_stopped = 0; mxser_start(tty); } /* Handle sw stopped */ - if ((old_termios->c_iflag & IXON) && - !(tty->termios.c_iflag & IXON)) { + if ((old_termios->c_iflag & IXON) && !I_IXON(tty)) { tty->stopped = 0; if (info->board->chip_flag) { @@ -2255,10 +2256,8 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id) break; iir &= MOXA_MUST_IIR_MASK; tty = tty_port_tty_get(&port->port); - if (!tty || - (port->port.flags & ASYNC_CLOSING) || - !(port->port.flags & - ASYNC_INITIALIZED)) { + if (!tty || port->closing || + !(port->port.flags & ASYNC_INITIALIZED)) { status = inb(port->ioaddr + UART_LSR); outb(0x27, port->ioaddr + UART_FCR); inb(port->ioaddr + UART_MSR); @@ -2337,7 +2336,7 @@ static const struct tty_operations mxser_ops = { .get_icount = mxser_get_icount, }; -static struct tty_port_operations mxser_port_ops = { +static const struct tty_port_operations mxser_port_ops = { .carrier_raised = mxser_carrier_raised, .dtr_rts = mxser_dtr_rts, .activate = mxser_activate, diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index c3fe026d3168..c01620780f5b 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -1066,7 +1066,7 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci, /* Carrier drop -> hangup */ if (tty) { if ((mlines & TIOCM_CD) == 0 && (dlci->modem_rx & TIOCM_CD)) - if (!(tty->termios.c_cflag & CLOCAL)) + if (!C_CLOCAL(tty)) tty_hangup(tty); } if (brk & 0x01) @@ -2304,21 +2304,6 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp, } /** - * gsmld_chars_in_buffer - report available bytes - * @tty: tty device - * - * Report the number of characters buffered to be delivered to user - * at this instant in time. - * - * Locking: gsm lock - */ - -static ssize_t gsmld_chars_in_buffer(struct tty_struct *tty) -{ - return 0; -} - -/** * gsmld_flush_buffer - clean input queue * @tty: terminal device * @@ -2830,7 +2815,6 @@ static struct tty_ldisc_ops tty_ldisc_packet = { .open = gsmld_open, .close = gsmld_close, .flush_buffer = gsmld_flush_buffer, - .chars_in_buffer = gsmld_chars_in_buffer, .read = gsmld_read, .write = gsmld_write, .ioctl = gsmld_ioctl, @@ -3132,7 +3116,7 @@ static void gsmtty_throttle(struct tty_struct *tty) struct gsm_dlci *dlci = tty->driver_data; if (dlci->state == DLCI_CLOSED) return; - if (tty->termios.c_cflag & CRTSCTS) + if (C_CRTSCTS(tty)) dlci->modem_tx &= ~TIOCM_DTR; dlci->throttled = 1; /* Send an MSC with DTR cleared */ @@ -3144,7 +3128,7 @@ static void gsmtty_unthrottle(struct tty_struct *tty) struct gsm_dlci *dlci = tty->driver_data; if (dlci->state == DLCI_CLOSED) return; - if (tty->termios.c_cflag & CRTSCTS) + if (C_CRTSCTS(tty)) dlci->modem_tx |= TIOCM_DTR; dlci->throttled = 0; /* Send an MSC with DTR set */ diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index bbc4ce66c2c1..bcaba17688f6 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -159,7 +159,6 @@ struct n_hdlc { /* * HDLC buffer list manipulation functions */ -static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list); static void n_hdlc_buf_put(struct n_hdlc_buf_list *list, struct n_hdlc_buf *buf); static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *list); @@ -853,10 +852,10 @@ static struct n_hdlc *n_hdlc_alloc(void) if (!n_hdlc) return NULL; - n_hdlc_buf_list_init(&n_hdlc->rx_free_buf_list); - n_hdlc_buf_list_init(&n_hdlc->tx_free_buf_list); - n_hdlc_buf_list_init(&n_hdlc->rx_buf_list); - n_hdlc_buf_list_init(&n_hdlc->tx_buf_list); + spin_lock_init(&n_hdlc->rx_free_buf_list.spinlock); + spin_lock_init(&n_hdlc->tx_free_buf_list.spinlock); + spin_lock_init(&n_hdlc->rx_buf_list.spinlock); + spin_lock_init(&n_hdlc->tx_buf_list.spinlock); /* allocate free rx buffer list */ for(i=0;i<DEFAULT_RX_BUF_COUNT;i++) { @@ -885,16 +884,6 @@ static struct n_hdlc *n_hdlc_alloc(void) } /* end of n_hdlc_alloc() */ /** - * n_hdlc_buf_list_init - initialize specified HDLC buffer list - * @list - pointer to buffer list - */ -static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list) -{ - memset(list, 0, sizeof(*list)); - spin_lock_init(&list->spinlock); -} /* end of n_hdlc_buf_list_init() */ - -/** * n_hdlc_buf_put - add specified HDLC buffer to tail of specified list * @list - pointer to buffer list * @buf - pointer to buffer diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index b280abaad91b..fb76a7d80e7e 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -113,8 +113,6 @@ struct n_tty_data { DECLARE_BITMAP(read_flags, N_TTY_BUF_SIZE); unsigned char echo_buf[N_TTY_BUF_SIZE]; - int minimum_to_wake; - /* consumer-published */ size_t read_tail; size_t line_start; @@ -153,15 +151,6 @@ static inline unsigned char *echo_buf_addr(struct n_tty_data *ldata, size_t i) return &ldata->echo_buf[i & (N_TTY_BUF_SIZE - 1)]; } -static inline int tty_put_user(struct tty_struct *tty, unsigned char x, - unsigned char __user *ptr) -{ - struct n_tty_data *ldata = tty->disc_data; - - tty_audit_add_data(tty, &x, 1, ldata->icanon); - return put_user(x, ptr); -} - static int tty_copy_to_user(struct tty_struct *tty, void __user *to, size_t tail, size_t n) { @@ -171,7 +160,7 @@ static int tty_copy_to_user(struct tty_struct *tty, void __user *to, int uncopied; if (n > size) { - tty_audit_add_data(tty, from, size, ldata->icanon); + tty_audit_add_data(tty, from, size); uncopied = copy_to_user(to, from, size); if (uncopied) return uncopied; @@ -180,7 +169,7 @@ static int tty_copy_to_user(struct tty_struct *tty, void __user *to, from = ldata->read_buf; } - tty_audit_add_data(tty, from, n, ldata->icanon); + tty_audit_add_data(tty, from, n); return copy_to_user(to, from, n); } @@ -239,8 +228,8 @@ static ssize_t chars_in_buffer(struct tty_struct *tty) static void n_tty_write_wakeup(struct tty_struct *tty) { - if (tty->fasync && test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) - kill_fasync(&tty->fasync, SIGIO, POLL_OUT); + clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); + kill_fasync(&tty->fasync, SIGIO, POLL_OUT); } static void n_tty_check_throttle(struct tty_struct *tty) @@ -272,8 +261,6 @@ static void n_tty_check_unthrottle(struct tty_struct *tty) if (tty->driver->type == TTY_DRIVER_TYPE_PTY) { if (chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE) return; - if (!tty->count) - return; n_tty_kick_worker(tty); tty_wakeup(tty->link); return; @@ -292,8 +279,6 @@ static void n_tty_check_unthrottle(struct tty_struct *tty) tty_set_flow_change(tty, TTY_UNTHROTTLE_SAFE); if (chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE) break; - if (!tty->count) - break; n_tty_kick_worker(tty); unthrottled = tty_unthrottle_safe(tty); if (!unthrottled) @@ -381,28 +366,6 @@ static void n_tty_flush_buffer(struct tty_struct *tty) } /** - * n_tty_chars_in_buffer - report available bytes - * @tty: tty device - * - * Report the number of characters buffered to be delivered to user - * at this instant in time. - * - * Locking: exclusive termios_rwsem - */ - -static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty) -{ - ssize_t n; - - WARN_ONCE(1, "%s is deprecated and scheduled for removal.", __func__); - - down_write(&tty->termios_rwsem); - n = chars_in_buffer(tty); - up_write(&tty->termios_rwsem); - return n; -} - -/** * is_utf8_continuation - utf8 multibyte check * @c: byte to check * @@ -1561,8 +1524,6 @@ n_tty_receive_buf_closing(struct tty_struct *tty, const unsigned char *cp, flag = *fp++; if (likely(flag == TTY_NORMAL)) n_tty_receive_char_closing(tty, *cp++); - else - n_tty_receive_char_flagged(tty, *cp++, flag); } } @@ -1664,7 +1625,7 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp, /* publish read_head to consumer */ smp_store_release(&ldata->commit_head, ldata->read_head); - if ((read_cnt(ldata) >= ldata->minimum_to_wake) || L_EXTPROC(tty)) { + if (read_cnt(ldata)) { kill_fasync(&tty->fasync, SIGIO, POLL_IN); wake_up_interruptible_poll(&tty->read_wait, POLLIN); } @@ -1785,12 +1746,6 @@ static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp, return n_tty_receive_buf_common(tty, cp, fp, count, 1); } -int is_ignored(int sig) -{ - return (sigismember(¤t->blocked, sig) || - current->sighand->action[sig-1].sa.sa_handler == SIG_IGN); -} - /** * n_tty_set_termios - termios data changed * @tty: terminal @@ -1937,7 +1892,6 @@ static int n_tty_open(struct tty_struct *tty) reset_buffer_flags(tty->disc_data); ldata->column = 0; ldata->canon_column = 0; - ldata->minimum_to_wake = 1; ldata->num_overrun = 0; ldata->no_room = 0; ldata->lnext = 0; @@ -2015,7 +1969,7 @@ static int copy_from_read_buf(struct tty_struct *tty, retval = copy_to_user(*b, from, n); n -= retval; is_eof = n == 1 && *from == EOF_CHAR(tty); - tty_audit_add_data(tty, from, n, ldata->icanon); + tty_audit_add_data(tty, from, n); smp_store_release(&ldata->read_tail, ldata->read_tail + n); /* Turn single EOF into zero-length read */ if (L_EXTPROC(tty) && ldata->icanon && is_eof && @@ -2109,7 +2063,7 @@ static int canon_copy_from_read_buf(struct tty_struct *tty, ldata->line_start = ldata->read_tail; else ldata->push = 0; - tty_audit_push(tty); + tty_audit_push(); } return 0; } @@ -2200,14 +2154,9 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, minimum = MIN_CHAR(tty); if (minimum) { time = (HZ / 10) * TIME_CHAR(tty); - if (time) - ldata->minimum_to_wake = 1; - else if (!waitqueue_active(&tty->read_wait) || - (ldata->minimum_to_wake > minimum)) - ldata->minimum_to_wake = minimum; } else { timeout = (HZ / 10) * TIME_CHAR(tty); - ldata->minimum_to_wake = minimum = 1; + minimum = 1; } } @@ -2225,19 +2174,15 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, cs = tty->link->ctrl_status; tty->link->ctrl_status = 0; spin_unlock_irq(&tty->link->ctrl_lock); - if (tty_put_user(tty, cs, b++)) { + if (put_user(cs, b)) { retval = -EFAULT; - b--; break; } + b++; nr--; break; } - if (((minimum - (b - buf)) < ldata->minimum_to_wake) && - ((minimum - (b - buf)) >= 1)) - ldata->minimum_to_wake = (minimum - (b - buf)); - done = check_other_done(tty); if (!input_available_p(tty, 0)) { @@ -2275,11 +2220,11 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, /* Deal with packet mode. */ if (packet && b == buf) { - if (tty_put_user(tty, TIOCPKT_DATA, b++)) { + if (put_user(TIOCPKT_DATA, b)) { retval = -EFAULT; - b--; break; } + b++; nr--; } @@ -2303,9 +2248,6 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, up_read(&tty->termios_rwsem); remove_wait_queue(&tty->read_wait, &wait); - if (!waitqueue_active(&tty->read_wait)) - ldata->minimum_to_wake = minimum; - mutex_unlock(&ldata->atomic_read_lock); if (b - buf) @@ -2417,7 +2359,7 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, } break_out: remove_wait_queue(&tty->write_wait, &wait); - if (b - buf != nr && tty->fasync) + if (nr && tty->fasync) set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); up_read(&tty->termios_rwsem); return (b - buf) ? b - buf : retval; @@ -2440,7 +2382,6 @@ break_out: static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file, poll_table *wait) { - struct n_tty_data *ldata = tty->disc_data; unsigned int mask = 0; poll_wait(file, &tty->read_wait, wait); @@ -2453,12 +2394,6 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file, mask |= POLLPRI | POLLIN | POLLRDNORM; if (tty_hung_up_p(file)) mask |= POLLHUP; - if (!(mask & (POLLHUP | POLLIN | POLLRDNORM))) { - if (MIN_CHAR(tty) && !TIME_CHAR(tty)) - ldata->minimum_to_wake = MIN_CHAR(tty); - else - ldata->minimum_to_wake = 1; - } if (tty->ops->write && !tty_is_writelocked(tty) && tty_chars_in_buffer(tty) < WAKEUP_CHARS && tty_write_room(tty) > 0) @@ -2507,25 +2442,12 @@ static int n_tty_ioctl(struct tty_struct *tty, struct file *file, } } -static void n_tty_fasync(struct tty_struct *tty, int on) -{ - struct n_tty_data *ldata = tty->disc_data; - - if (!waitqueue_active(&tty->read_wait)) { - if (on) - ldata->minimum_to_wake = 1; - else if (!tty->fasync) - ldata->minimum_to_wake = N_TTY_BUF_SIZE; - } -} - -struct tty_ldisc_ops tty_ldisc_N_TTY = { +static struct tty_ldisc_ops n_tty_ops = { .magic = TTY_LDISC_MAGIC, .name = "n_tty", .open = n_tty_open, .close = n_tty_close, .flush_buffer = n_tty_flush_buffer, - .chars_in_buffer = n_tty_chars_in_buffer, .read = n_tty_read, .write = n_tty_write, .ioctl = n_tty_ioctl, @@ -2533,7 +2455,6 @@ struct tty_ldisc_ops tty_ldisc_N_TTY = { .poll = n_tty_poll, .receive_buf = n_tty_receive_buf, .write_wakeup = n_tty_write_wakeup, - .fasync = n_tty_fasync, .receive_buf2 = n_tty_receive_buf2, }; @@ -2541,14 +2462,18 @@ struct tty_ldisc_ops tty_ldisc_N_TTY = { * n_tty_inherit_ops - inherit N_TTY methods * @ops: struct tty_ldisc_ops where to save N_TTY methods * - * Enables a 'subclass' line discipline to 'inherit' N_TTY - * methods. + * Enables a 'subclass' line discipline to 'inherit' N_TTY methods. */ void n_tty_inherit_ops(struct tty_ldisc_ops *ops) { - *ops = tty_ldisc_N_TTY; + *ops = n_tty_ops; ops->owner = NULL; ops->refcount = ops->flags = 0; } EXPORT_SYMBOL_GPL(n_tty_inherit_ops); + +void __init n_tty_init(void) +{ + tty_register_ldisc(N_TTY, &n_tty_ops); +} diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c index 80f9de907563..5cc80b80c82b 100644 --- a/drivers/tty/nozomi.c +++ b/drivers/tty/nozomi.c @@ -823,7 +823,7 @@ static int receive_data(enum port_type index, struct nozomi *dc) struct tty_struct *tty = tty_port_tty_get(&port->port); int i, ret; - read_mem32((u32 *) &size, addr, 4); + size = __le32_to_cpu(readl(addr)); /* DBG1( "%d bytes port: %d", size, index); */ if (tty && test_bit(TTY_THROTTLED, &tty->flags)) { diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 2348fa613707..e16a49b507ef 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -263,8 +263,7 @@ static void pty_set_termios(struct tty_struct *tty, { /* See if packet mode change of state. */ if (tty->link && tty->link->packet) { - int extproc = (old_termios->c_lflag & EXTPROC) | - (tty->termios.c_lflag & EXTPROC); + int extproc = (old_termios->c_lflag & EXTPROC) | L_EXTPROC(tty); int old_flow = ((old_termios->c_iflag & IXON) && (old_termios->c_cc[VSTOP] == '\023') && (old_termios->c_cc[VSTART] == '\021')); @@ -406,13 +405,8 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty, if (legacy) { /* We always use new tty termios data so we can do this the easy way .. */ - retval = tty_init_termios(tty); - if (retval) - goto err_deinit_tty; - - retval = tty_init_termios(o_tty); - if (retval) - goto err_free_termios; + tty_init_termios(tty); + tty_init_termios(o_tty); driver->other->ttys[idx] = o_tty; driver->ttys[idx] = tty; @@ -444,12 +438,7 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty, tty->count++; o_tty->count++; return 0; -err_free_termios: - if (legacy) - tty_free_termios(tty); -err_deinit_tty: - deinitialize_tty_struct(o_tty); - free_tty_struct(o_tty); + err_put_module: module_put(driver->other->owner); err: @@ -666,20 +655,13 @@ static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver, return tty; } -/* We have no need to install and remove our tty objects as devpts does all - the work for us */ - static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty) { return pty_common_install(driver, tty, false); } -static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty) -{ -} - /* this is called once with whichever end is closed last */ -static void pty_unix98_shutdown(struct tty_struct *tty) +static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty) { struct inode *ptmx_inode; @@ -704,7 +686,6 @@ static const struct tty_operations ptm_unix98_ops = { .unthrottle = pty_unthrottle, .ioctl = pty_unix98_ioctl, .resize = pty_resize, - .shutdown = pty_unix98_shutdown, .cleanup = pty_cleanup }; @@ -722,7 +703,6 @@ static const struct tty_operations pty_unix98_ops = { .set_termios = pty_set_termios, .start = pty_start, .stop = pty_stop, - .shutdown = pty_unix98_shutdown, .cleanup = pty_cleanup, }; diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c index 802eac7e561b..0b802cdd70d0 100644 --- a/drivers/tty/rocket.c +++ b/drivers/tty/rocket.c @@ -643,7 +643,6 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev) info->chan = chan; tty_port_init(&info->port); info->port.ops = &rocket_port_ops; - init_completion(&info->close_wait); info->flags &= ~ROCKET_MODE_MASK; switch (pc104[board][line]) { case 422: @@ -960,7 +959,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp) tty->alt_speed = 460800; configure_r_port(tty, info, NULL); - if (tty->termios.c_cflag & CBAUD) { + if (C_BAUD(tty)) { sSetDTR(cp); sSetRTS(cp); } @@ -1043,13 +1042,12 @@ static void rp_close(struct tty_struct *tty, struct file *filp) } } spin_lock_irq(&port->lock); - info->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_CLOSING | ASYNC_NORMAL_ACTIVE); + info->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_NORMAL_ACTIVE); tty->closing = 0; spin_unlock_irq(&port->lock); mutex_unlock(&port->mutex); tty_port_tty_set(port, NULL); - complete_all(&info->close_wait); atomic_dec(&rp_num_ports_open); #ifdef ROCKET_DEBUG_OPEN @@ -1086,18 +1084,18 @@ static void rp_set_termios(struct tty_struct *tty, cp = &info->channel; /* Handle transition to B0 status */ - if ((old_termios->c_cflag & CBAUD) && !(tty->termios.c_cflag & CBAUD)) { + if ((old_termios->c_cflag & CBAUD) && !C_BAUD(tty)) { sClrDTR(cp); sClrRTS(cp); } /* Handle transition away from B0 status */ - if (!(old_termios->c_cflag & CBAUD) && (tty->termios.c_cflag & CBAUD)) { + if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) { sSetRTS(cp); sSetDTR(cp); } - if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios.c_cflag & CRTSCTS)) + if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) rp_start(tty); } @@ -1360,8 +1358,7 @@ static void rp_throttle(struct tty_struct *tty) struct r_port *info = tty->driver_data; #ifdef ROCKET_DEBUG_THROTTLE - printk(KERN_INFO "throttle %s: %d....\n", tty->name, - tty->ldisc.chars_in_buffer(tty)); + printk(KERN_INFO "throttle %s ....\n", tty->name); #endif if (rocket_paranoia_check(info, "rp_throttle")) @@ -1377,8 +1374,7 @@ static void rp_unthrottle(struct tty_struct *tty) { struct r_port *info = tty->driver_data; #ifdef ROCKET_DEBUG_THROTTLE - printk(KERN_INFO "unthrottle %s: %d....\n", tty->name, - tty->ldisc.chars_in_buffer(tty)); + printk(KERN_INFO "unthrottle %s ....\n", tty->name); #endif if (rocket_paranoia_check(info, "rp_unthrottle")) diff --git a/drivers/tty/rocket_int.h b/drivers/tty/rocket_int.h index 67e0f1e778a2..ef1e1be6b26d 100644 --- a/drivers/tty/rocket_int.h +++ b/drivers/tty/rocket_int.h @@ -1144,7 +1144,6 @@ struct r_port { int read_status_mask; int cps; - struct completion close_wait; /* Not yet matching the core */ spinlock_t slock; struct mutex write_mtx; }; diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c deleted file mode 100644 index 0982c1a44187..000000000000 --- a/drivers/tty/serial/68328serial.c +++ /dev/null @@ -1,1322 +0,0 @@ -/* 68328serial.c: Serial port driver for 68328 microcontroller - * - * Copyright (C) 1995 David S. Miller <davem@caip.rutgers.edu> - * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com> - * Copyright (C) 1998, 1999 D. Jeff Dionne <jeff@uclinux.org> - * Copyright (C) 1999 Vladimir Gurevich <vgurevic@cisco.com> - * Copyright (C) 2002-2003 David McCullough <davidm@snapgear.com> - * Copyright (C) 2002 Greg Ungerer <gerg@snapgear.com> - * - * VZ Support/Fixes Evan Stawnyczy <e@lineo.ca> - * Multiple UART support Daniel Potts <danielp@cse.unsw.edu.au> - * Power management support Daniel Potts <danielp@cse.unsw.edu.au> - * VZ Second Serial Port enable Phil Wilshire - * 2.4/2.5 port David McCullough - */ - -#include <linux/module.h> -#include <linux/errno.h> -#include <linux/serial.h> -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/timer.h> -#include <linux/interrupt.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/major.h> -#include <linux/string.h> -#include <linux/fcntl.h> -#include <linux/mm.h> -#include <linux/kernel.h> -#include <linux/console.h> -#include <linux/reboot.h> -#include <linux/keyboard.h> -#include <linux/init.h> -#include <linux/pm.h> -#include <linux/bitops.h> -#include <linux/delay.h> -#include <linux/gfp.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/delay.h> -#include <asm/uaccess.h> - -/* (es) */ -/* note: perhaps we can murge these files, so that you can just - * define 1 of them, and they can sort that out for themselves - */ -#if defined(CONFIG_M68EZ328) -#include <asm/MC68EZ328.h> -#else -#if defined(CONFIG_M68VZ328) -#include <asm/MC68VZ328.h> -#else -#include <asm/MC68328.h> -#endif /* CONFIG_M68VZ328 */ -#endif /* CONFIG_M68EZ328 */ - -/* Turn off usage of real serial interrupt code, to "support" Copilot */ -#ifdef CONFIG_XCOPILOT_BUGS -#undef USE_INTS -#else -#define USE_INTS -#endif - -/* - * I believe this is the optimal setting that reduces the number of interrupts. - * At high speeds the output might become a little "bursted" (use USTCNT_TXHE - * if that bothers you), but in most cases it will not, since we try to - * transmit characters every time rs_interrupt is called. Thus, quite often - * you'll see that a receive interrupt occures before the transmit one. - * -- Vladimir Gurevich - */ -#define USTCNT_TX_INTR_MASK (USTCNT_TXEE) - -/* - * 68328 and 68EZ328 UARTS are a little bit different. EZ328 has special - * "Old data interrupt" which occures whenever the data stay in the FIFO - * longer than 30 bits time. This allows us to use FIFO without compromising - * latency. '328 does not have this feature and without the real 328-based - * board I would assume that RXRE is the safest setting. - * - * For EZ328 I use RXHE (Half empty) interrupt to reduce the number of - * interrupts. RXFE (receive queue full) causes the system to lose data - * at least at 115200 baud - * - * If your board is busy doing other stuff, you might consider to use - * RXRE (data ready intrrupt) instead. - * - * The other option is to make these INTR masks run-time configurable, so - * that people can dynamically adapt them according to the current usage. - * -- Vladimir Gurevich - */ - -/* (es) */ -#if defined(CONFIG_M68EZ328) || defined(CONFIG_M68VZ328) -#define USTCNT_RX_INTR_MASK (USTCNT_RXHE | USTCNT_ODEN) -#elif defined(CONFIG_M68328) -#define USTCNT_RX_INTR_MASK (USTCNT_RXRE) -#else -#error Please, define the Rx interrupt events for your CPU -#endif -/* (/es) */ - -/* - * This is our internal structure for each serial port's state. - */ -struct m68k_serial { - struct tty_port tport; - char is_cons; /* Is this our console. */ - int magic; - int baud_base; - int port; - int irq; - int type; /* UART type */ - int custom_divisor; - int x_char; /* xon/xoff character */ - int line; - unsigned char *xmit_buf; - int xmit_head; - int xmit_tail; - int xmit_cnt; -}; - -#define SERIAL_MAGIC 0x5301 - -/* - * Define the number of ports supported and their irqs. - */ -#define NR_PORTS 1 - -static struct m68k_serial m68k_soft[NR_PORTS]; - -static unsigned int uart_irqs[NR_PORTS] = { UART_IRQ_NUM }; - -/* multiple ports are contiguous in memory */ -m68328_uart *uart_addr = (m68328_uart *)USTCNT_ADDR; - -struct tty_driver *serial_driver; - -static void change_speed(struct m68k_serial *info, struct tty_struct *tty); - -/* - * Setup for console. Argument comes from the boot command line. - */ - -/* note: this is messy, but it works, again, perhaps defined somewhere else?*/ -#ifdef CONFIG_M68VZ328 -#define CONSOLE_BAUD_RATE 19200 -#define DEFAULT_CBAUD B19200 -#endif - - -#ifndef CONSOLE_BAUD_RATE -#define CONSOLE_BAUD_RATE 9600 -#define DEFAULT_CBAUD B9600 -#endif - - -static int m68328_console_initted; -static int m68328_console_baud = CONSOLE_BAUD_RATE; -static int m68328_console_cbaud = DEFAULT_CBAUD; - - -static inline int serial_paranoia_check(struct m68k_serial *info, - char *name, const char *routine) -{ -#ifdef SERIAL_PARANOIA_CHECK - static const char *badmagic = - "Warning: bad magic number for serial struct %s in %s\n"; - static const char *badinfo = - "Warning: null m68k_serial for %s in %s\n"; - - if (!info) { - printk(badinfo, name, routine); - return 1; - } - if (info->magic != SERIAL_MAGIC) { - printk(badmagic, name, routine); - return 1; - } -#endif - return 0; -} - -/* - * This is used to figure out the divisor speeds and the timeouts - */ -static int baud_table[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200, 0 }; - -/* Utility routines */ -static inline int get_baud(struct m68k_serial *ss) -{ - unsigned long result = 115200; - unsigned short int baud = uart_addr[ss->line].ubaud; - if (GET_FIELD(baud, UBAUD_PRESCALER) == 0x38) result = 38400; - result >>= GET_FIELD(baud, UBAUD_DIVIDE); - - return result; -} - -/* - * ------------------------------------------------------------ - * rs_stop() and rs_start() - * - * This routines are called before setting or resetting tty->stopped. - * They enable or disable transmitter interrupts, as necessary. - * ------------------------------------------------------------ - */ -static void rs_stop(struct tty_struct *tty) -{ - struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; - m68328_uart *uart = &uart_addr[info->line]; - unsigned long flags; - - if (serial_paranoia_check(info, tty->name, "rs_stop")) - return; - - local_irq_save(flags); - uart->ustcnt &= ~USTCNT_TXEN; - local_irq_restore(flags); -} - -static int rs_put_char(char ch) -{ - unsigned long flags; - int loops = 0; - - local_irq_save(flags); - - while (!(UTX & UTX_TX_AVAIL) && (loops < 1000)) { - loops++; - udelay(5); - } - - UTX_TXDATA = ch; - udelay(5); - local_irq_restore(flags); - return 1; -} - -static void rs_start(struct tty_struct *tty) -{ - struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; - m68328_uart *uart = &uart_addr[info->line]; - unsigned long flags; - - if (serial_paranoia_check(info, tty->name, "rs_start")) - return; - - local_irq_save(flags); - if (info->xmit_cnt && info->xmit_buf && !(uart->ustcnt & USTCNT_TXEN)) { -#ifdef USE_INTS - uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK; -#else - uart->ustcnt |= USTCNT_TXEN; -#endif - } - local_irq_restore(flags); -} - -static void receive_chars(struct m68k_serial *info, unsigned short rx) -{ - m68328_uart *uart = &uart_addr[info->line]; - unsigned char ch, flag; - - /* - * This do { } while() loop will get ALL chars out of Rx FIFO - */ -#ifndef CONFIG_XCOPILOT_BUGS - do { -#endif - ch = GET_FIELD(rx, URX_RXDATA); - - if (info->is_cons) { - if (URX_BREAK & rx) { /* whee, break received */ - return; -#ifdef CONFIG_MAGIC_SYSRQ - } else if (ch == 0x10) { /* ^P */ - show_state(); - show_free_areas(0); - show_buffers(); -/* show_net_buffers(); */ - return; - } else if (ch == 0x12) { /* ^R */ - emergency_restart(); - return; -#endif /* CONFIG_MAGIC_SYSRQ */ - } - } - - flag = TTY_NORMAL; - - if (rx & URX_PARITY_ERROR) - flag = TTY_PARITY; - else if (rx & URX_OVRUN) - flag = TTY_OVERRUN; - else if (rx & URX_FRAME_ERROR) - flag = TTY_FRAME; - - tty_insert_flip_char(&info->tport, ch, flag); -#ifndef CONFIG_XCOPILOT_BUGS - } while ((rx = uart->urx.w) & URX_DATA_READY); -#endif - - tty_schedule_flip(&info->tport); -} - -static void transmit_chars(struct m68k_serial *info, struct tty_struct *tty) -{ - m68328_uart *uart = &uart_addr[info->line]; - - if (info->x_char) { - /* Send next char */ - uart->utx.b.txdata = info->x_char; - info->x_char = 0; - goto clear_and_return; - } - - if ((info->xmit_cnt <= 0) || !tty || tty->stopped) { - /* That's peculiar... TX ints off */ - uart->ustcnt &= ~USTCNT_TX_INTR_MASK; - goto clear_and_return; - } - - /* Send char */ - uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++]; - info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); - info->xmit_cnt--; - - if (info->xmit_cnt <= 0) { - /* All done for now... TX ints off */ - uart->ustcnt &= ~USTCNT_TX_INTR_MASK; - goto clear_and_return; - } - -clear_and_return: - /* Clear interrupt (should be auto)*/ - return; -} - -/* - * This is the serial driver's generic interrupt routine - */ -irqreturn_t rs_interrupt(int irq, void *dev_id) -{ - struct m68k_serial *info = dev_id; - struct tty_struct *tty = tty_port_tty_get(&info->tport); - m68328_uart *uart; - unsigned short rx; - unsigned short tx; - - uart = &uart_addr[info->line]; - rx = uart->urx.w; - -#ifdef USE_INTS - tx = uart->utx.w; - - if (rx & URX_DATA_READY) - receive_chars(info, rx); - if (tx & UTX_TX_AVAIL) - transmit_chars(info, tty); -#else - receive_chars(info, rx); -#endif - tty_kref_put(tty); - - return IRQ_HANDLED; -} - -static int startup(struct m68k_serial *info, struct tty_struct *tty) -{ - m68328_uart *uart = &uart_addr[info->line]; - unsigned long flags; - - if (info->tport.flags & ASYNC_INITIALIZED) - return 0; - - if (!info->xmit_buf) { - info->xmit_buf = (unsigned char *) __get_free_page(GFP_KERNEL); - if (!info->xmit_buf) - return -ENOMEM; - } - - local_irq_save(flags); - - /* - * Clear the FIFO buffers and disable them - * (they will be reenabled in change_speed()) - */ - - uart->ustcnt = USTCNT_UEN; - uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_TXEN; - (void)uart->urx.w; - - /* - * Finally, enable sequencing and interrupts - */ -#ifdef USE_INTS - uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | - USTCNT_RX_INTR_MASK | USTCNT_TX_INTR_MASK; -#else - uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK; -#endif - - if (tty) - clear_bit(TTY_IO_ERROR, &tty->flags); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - - /* - * and set the speed of the serial port - */ - - change_speed(info, tty); - - info->tport.flags |= ASYNC_INITIALIZED; - local_irq_restore(flags); - return 0; -} - -/* - * This routine will shutdown a serial port; interrupts are disabled, and - * DTR is dropped if the hangup on close termio flag is on. - */ -static void shutdown(struct m68k_serial *info, struct tty_struct *tty) -{ - m68328_uart *uart = &uart_addr[info->line]; - unsigned long flags; - - uart->ustcnt = 0; /* All off! */ - if (!(info->tport.flags & ASYNC_INITIALIZED)) - return; - - local_irq_save(flags); - - if (info->xmit_buf) { - free_page((unsigned long) info->xmit_buf); - info->xmit_buf = 0; - } - - if (tty) - set_bit(TTY_IO_ERROR, &tty->flags); - - info->tport.flags &= ~ASYNC_INITIALIZED; - local_irq_restore(flags); -} - -struct { - int divisor, prescale; -} -#ifndef CONFIG_M68VZ328 - hw_baud_table[18] = { - {0, 0}, /* 0 */ - {0, 0}, /* 50 */ - {0, 0}, /* 75 */ - {0, 0}, /* 110 */ - {0, 0}, /* 134 */ - {0, 0}, /* 150 */ - {0, 0}, /* 200 */ - {7, 0x26}, /* 300 */ - {6, 0x26}, /* 600 */ - {5, 0x26}, /* 1200 */ - {0, 0}, /* 1800 */ - {4, 0x26}, /* 2400 */ - {3, 0x26}, /* 4800 */ - {2, 0x26}, /* 9600 */ - {1, 0x26}, /* 19200 */ - {0, 0x26}, /* 38400 */ - {1, 0x38}, /* 57600 */ - {0, 0x38}, /* 115200 */ -}; -#else - hw_baud_table[18] = { - {0, 0}, /* 0 */ - {0, 0}, /* 50 */ - {0, 0}, /* 75 */ - {0, 0}, /* 110 */ - {0, 0}, /* 134 */ - {0, 0}, /* 150 */ - {0, 0}, /* 200 */ - {0, 0}, /* 300 */ - {7, 0x26}, /* 600 */ - {6, 0x26}, /* 1200 */ - {0, 0}, /* 1800 */ - {5, 0x26}, /* 2400 */ - {4, 0x26}, /* 4800 */ - {3, 0x26}, /* 9600 */ - {2, 0x26}, /* 19200 */ - {1, 0x26}, /* 38400 */ - {0, 0x26}, /* 57600 */ - {1, 0x38}, /* 115200 */ -}; -#endif -/* rate = 1036800 / ((65 - prescale) * (1<<divider)) */ - -/* - * This routine is called to set the UART divisor registers to match - * the specified baud rate for a serial port. - */ -static void change_speed(struct m68k_serial *info, struct tty_struct *tty) -{ - m68328_uart *uart = &uart_addr[info->line]; - unsigned short port; - unsigned short ustcnt; - unsigned cflag; - int i; - - cflag = tty->termios.c_cflag; - port = info->port; - if (!port) - return; - - ustcnt = uart->ustcnt; - uart->ustcnt = ustcnt & ~USTCNT_TXEN; - - i = cflag & CBAUD; - if (i & CBAUDEX) { - i = (i & ~CBAUDEX) + B38400; - } - - uart->ubaud = PUT_FIELD(UBAUD_DIVIDE, hw_baud_table[i].divisor) | - PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale); - - ustcnt &= ~(USTCNT_PARITYEN | USTCNT_ODD_EVEN | USTCNT_STOP | USTCNT_8_7); - - if ((cflag & CSIZE) == CS8) - ustcnt |= USTCNT_8_7; - - if (cflag & CSTOPB) - ustcnt |= USTCNT_STOP; - - if (cflag & PARENB) - ustcnt |= USTCNT_PARITYEN; - if (cflag & PARODD) - ustcnt |= USTCNT_ODD_EVEN; - -#ifdef CONFIG_SERIAL_68328_RTS_CTS - if (cflag & CRTSCTS) { - uart->utx.w &= ~UTX_NOCTS; - } else { - uart->utx.w |= UTX_NOCTS; - } -#endif - - ustcnt |= USTCNT_TXEN; - - uart->ustcnt = ustcnt; - return; -} - -/* - * Fair output driver allows a process to speak. - */ -static void rs_fair_output(void) -{ - int left; /* Output no more than that */ - unsigned long flags; - struct m68k_serial *info = &m68k_soft[0]; - char c; - - if (info == NULL) return; - if (info->xmit_buf == NULL) return; - - local_irq_save(flags); - left = info->xmit_cnt; - while (left != 0) { - c = info->xmit_buf[info->xmit_tail]; - info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1); - info->xmit_cnt--; - local_irq_restore(flags); - - rs_put_char(c); - - local_irq_save(flags); - left = min(info->xmit_cnt, left-1); - } - - /* Last character is being transmitted now (hopefully). */ - udelay(5); - - local_irq_restore(flags); - return; -} - -/* - * m68k_console_print is registered for printk. - */ -void console_print_68328(const char *p) -{ - char c; - - while ((c = *(p++)) != 0) { - if (c == '\n') - rs_put_char('\r'); - rs_put_char(c); - } - - /* Comment this if you want to have a strict interrupt-driven output */ - rs_fair_output(); - - return; -} - -static void rs_set_ldisc(struct tty_struct *tty) -{ - struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; - - if (serial_paranoia_check(info, tty->name, "rs_set_ldisc")) - return; - - info->is_cons = (tty->termios.c_line == N_TTY); - - printk("ttyS%d console mode %s\n", info->line, info->is_cons ? "on" : "off"); -} - -static void rs_flush_chars(struct tty_struct *tty) -{ - struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; - m68328_uart *uart = &uart_addr[info->line]; - unsigned long flags; - - if (serial_paranoia_check(info, tty->name, "rs_flush_chars")) - return; -#ifndef USE_INTS - for (;;) { -#endif - - /* Enable transmitter */ - local_irq_save(flags); - - if (info->xmit_cnt <= 0 || tty->stopped || !info->xmit_buf) { - local_irq_restore(flags); - return; - } - -#ifdef USE_INTS - uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK; -#else - uart->ustcnt |= USTCNT_TXEN; -#endif - -#ifdef USE_INTS - if (uart->utx.w & UTX_TX_AVAIL) { -#else - if (1) { -#endif - /* Send char */ - uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++]; - info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); - info->xmit_cnt--; - } - -#ifndef USE_INTS - while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5); - } -#endif - local_irq_restore(flags); -} - -extern void console_printn(const char *b, int count); - -static int rs_write(struct tty_struct *tty, - const unsigned char *buf, int count) -{ - int c, total = 0; - struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; - m68328_uart *uart = &uart_addr[info->line]; - unsigned long flags; - - if (serial_paranoia_check(info, tty->name, "rs_write")) - return 0; - - if (!tty || !info->xmit_buf) - return 0; - - local_save_flags(flags); - while (1) { - local_irq_disable(); - c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); - local_irq_restore(flags); - - if (c <= 0) - break; - - memcpy(info->xmit_buf + info->xmit_head, buf, c); - - local_irq_disable(); - info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); - info->xmit_cnt += c; - local_irq_restore(flags); - buf += c; - count -= c; - total += c; - } - - if (info->xmit_cnt && !tty->stopped) { - /* Enable transmitter */ - local_irq_disable(); -#ifndef USE_INTS - while (info->xmit_cnt) { -#endif - - uart->ustcnt |= USTCNT_TXEN; -#ifdef USE_INTS - uart->ustcnt |= USTCNT_TX_INTR_MASK; -#else - while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5); -#endif - if (uart->utx.w & UTX_TX_AVAIL) { - uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++]; - info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); - info->xmit_cnt--; - } - -#ifndef USE_INTS - } -#endif - local_irq_restore(flags); - } - - return total; -} - -static int rs_write_room(struct tty_struct *tty) -{ - struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; - int ret; - - if (serial_paranoia_check(info, tty->name, "rs_write_room")) - return 0; - ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; - if (ret < 0) - ret = 0; - return ret; -} - -static int rs_chars_in_buffer(struct tty_struct *tty) -{ - struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; - - if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer")) - return 0; - return info->xmit_cnt; -} - -static void rs_flush_buffer(struct tty_struct *tty) -{ - struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; - unsigned long flags; - - if (serial_paranoia_check(info, tty->name, "rs_flush_buffer")) - return; - local_irq_save(flags); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - local_irq_restore(flags); - tty_wakeup(tty); -} - -/* - * ------------------------------------------------------------ - * rs_throttle() - * - * This routine is called by the upper-layer tty layer to signal that - * incoming characters should be throttled. - * ------------------------------------------------------------ - */ -static void rs_throttle(struct tty_struct *tty) -{ - struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; - - if (serial_paranoia_check(info, tty->name, "rs_throttle")) - return; - - if (I_IXOFF(tty)) - info->x_char = STOP_CHAR(tty); - - /* Turn off RTS line (do this atomic) */ -} - -static void rs_unthrottle(struct tty_struct *tty) -{ - struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; - - if (serial_paranoia_check(info, tty->name, "rs_unthrottle")) - return; - - if (I_IXOFF(tty)) { - if (info->x_char) - info->x_char = 0; - else - info->x_char = START_CHAR(tty); - } - - /* Assert RTS line (do this atomic) */ -} - -/* - * ------------------------------------------------------------ - * rs_ioctl() and friends - * ------------------------------------------------------------ - */ - -static int get_serial_info(struct m68k_serial *info, - struct serial_struct *retinfo) -{ - struct serial_struct tmp; - - if (!retinfo) - return -EFAULT; - memset(&tmp, 0, sizeof(tmp)); - tmp.type = info->type; - tmp.line = info->line; - tmp.port = info->port; - tmp.irq = info->irq; - tmp.flags = info->tport.flags; - tmp.baud_base = info->baud_base; - tmp.close_delay = info->tport.close_delay; - tmp.closing_wait = info->tport.closing_wait; - tmp.custom_divisor = info->custom_divisor; - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; - - return 0; -} - -static int set_serial_info(struct m68k_serial *info, struct tty_struct *tty, - struct serial_struct *new_info) -{ - struct tty_port *port = &info->tport; - struct serial_struct new_serial; - struct m68k_serial old_info; - int retval = 0; - - if (!new_info) - return -EFAULT; - if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) - return -EFAULT; - old_info = *info; - - if (!capable(CAP_SYS_ADMIN)) { - if ((new_serial.baud_base != info->baud_base) || - (new_serial.type != info->type) || - (new_serial.close_delay != port->close_delay) || - ((new_serial.flags & ~ASYNC_USR_MASK) != - (port->flags & ~ASYNC_USR_MASK))) - return -EPERM; - port->flags = ((port->flags & ~ASYNC_USR_MASK) | - (new_serial.flags & ASYNC_USR_MASK)); - info->custom_divisor = new_serial.custom_divisor; - goto check_and_exit; - } - - if (port->count > 1) - return -EBUSY; - - /* - * OK, past this point, all the error checking has been done. - * At this point, we start making changes..... - */ - - info->baud_base = new_serial.baud_base; - port->flags = ((port->flags & ~ASYNC_FLAGS) | - (new_serial.flags & ASYNC_FLAGS)); - info->type = new_serial.type; - port->close_delay = new_serial.close_delay; - port->closing_wait = new_serial.closing_wait; - -check_and_exit: - retval = startup(info, tty); - return retval; -} - -/* - * get_lsr_info - get line status register info - * - * Purpose: Let user call ioctl() to get info when the UART physically - * is emptied. On bus types like RS485, the transmitter must - * release the bus after transmitting. This must be done when - * the transmit shift register is empty, not be done when the - * transmit holding register is empty. This functionality - * allows an RS485 driver to be written in user space. - */ -static int get_lsr_info(struct m68k_serial *info, unsigned int *value) -{ -#ifdef CONFIG_SERIAL_68328_RTS_CTS - m68328_uart *uart = &uart_addr[info->line]; -#endif - unsigned char status; - unsigned long flags; - - local_irq_save(flags); -#ifdef CONFIG_SERIAL_68328_RTS_CTS - status = (uart->utx.w & UTX_CTS_STAT) ? 1 : 0; -#else - status = 0; -#endif - local_irq_restore(flags); - return put_user(status, value); -} - -/* - * This routine sends a break character out the serial port. - */ -static void send_break(struct m68k_serial *info, unsigned int duration) -{ - m68328_uart *uart = &uart_addr[info->line]; - unsigned long flags; - if (!info->port) - return; - local_irq_save(flags); -#ifdef USE_INTS - uart->utx.w |= UTX_SEND_BREAK; - msleep_interruptible(duration); - uart->utx.w &= ~UTX_SEND_BREAK; -#endif - local_irq_restore(flags); -} - -static int rs_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; - int retval; - - if (serial_paranoia_check(info, tty->name, "rs_ioctl")) - return -ENODEV; - - if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && - (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && - (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) { - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; - } - - switch (cmd) { - case TCSBRK: /* SVID version: non-zero arg --> no break */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - if (!arg) - send_break(info, 250); /* 1/4 second */ - return 0; - case TCSBRKP: /* support for POSIX tcsendbreak() */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - send_break(info, arg ? arg*(100) : 250); - return 0; - case TIOCGSERIAL: - return get_serial_info(info, - (struct serial_struct *) arg); - case TIOCSSERIAL: - return set_serial_info(info, tty, - (struct serial_struct *) arg); - case TIOCSERGETLSR: /* Get line status register */ - return get_lsr_info(info, (unsigned int *) arg); - case TIOCSERGSTRUCT: - if (copy_to_user((struct m68k_serial *) arg, - info, sizeof(struct m68k_serial))) - return -EFAULT; - return 0; - default: - return -ENOIOCTLCMD; - } - return 0; -} - -static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) -{ - struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; - - change_speed(info, tty); - - if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios.c_cflag & CRTSCTS)) - rs_start(tty); - -} - -/* - * ------------------------------------------------------------ - * rs_close() - * - * This routine is called when the serial port gets closed. First, we - * wait for the last remaining data to be sent. Then, we unlink its - * S structure from the interrupt chain if necessary, and we free - * that IRQ if nothing is left in the chain. - * ------------------------------------------------------------ - */ -static void rs_close(struct tty_struct *tty, struct file *filp) -{ - struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; - struct tty_port *port = &info->tport; - m68328_uart *uart = &uart_addr[info->line]; - unsigned long flags; - - if (serial_paranoia_check(info, tty->name, "rs_close")) - return; - - local_irq_save(flags); - - if (tty_hung_up_p(filp)) { - local_irq_restore(flags); - return; - } - - if ((tty->count == 1) && (port->count != 1)) { - /* - * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. Info->count should always - * be one in these conditions. If it's greater than - * one, we've got real problems, since it means the - * serial port won't be shutdown. - */ - printk("rs_close: bad serial port count; tty->count is 1, " - "port->count is %d\n", port->count); - port->count = 1; - } - if (--port->count < 0) { - printk("rs_close: bad serial port count for ttyS%d: %d\n", - info->line, port->count); - port->count = 0; - } - if (port->count) { - local_irq_restore(flags); - return; - } - port->flags |= ASYNC_CLOSING; - /* - * Now we wait for the transmit buffer to clear; and we notify - * the line discipline to only process XON/XOFF characters. - */ - tty->closing = 1; - if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, port->closing_wait); - /* - * At this point we stop accepting input. To do this, we - * disable the receive line status interrupts, and tell the - * interrupt driver to stop checking the data ready bit in the - * line status register. - */ - - uart->ustcnt &= ~USTCNT_RXEN; - uart->ustcnt &= ~(USTCNT_RXEN | USTCNT_RX_INTR_MASK); - - shutdown(info, tty); - rs_flush_buffer(tty); - - tty_ldisc_flush(tty); - tty->closing = 0; - tty_port_tty_set(&info->tport, NULL); -#warning "This is not and has never been valid so fix it" -#if 0 - if (tty->ldisc.num != ldiscs[N_TTY].num) { - if (tty->ldisc.close) - (tty->ldisc.close)(tty); - tty->ldisc = ldiscs[N_TTY]; - tty->termios.c_line = N_TTY; - if (tty->ldisc.open) - (tty->ldisc.open)(tty); - } -#endif - if (port->blocked_open) { - if (port->close_delay) - msleep_interruptible(jiffies_to_msecs(port->close_delay)); - wake_up_interruptible(&port->open_wait); - } - port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); - local_irq_restore(flags); -} - -/* - * rs_hangup() --- called by tty_hangup() when a hangup is signaled. - */ -void rs_hangup(struct tty_struct *tty) -{ - struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; - - if (serial_paranoia_check(info, tty->name, "rs_hangup")) - return; - - rs_flush_buffer(tty); - shutdown(info, tty); - info->tport.count = 0; - info->tport.flags &= ~ASYNC_NORMAL_ACTIVE; - tty_port_tty_set(&info->tport, NULL); - wake_up_interruptible(&info->tport.open_wait); -} - -/* - * This routine is called whenever a serial port is opened. It - * enables interrupts for a serial port, linking in its S structure into - * the IRQ chain. It also performs the serial-specific - * initialization for the tty structure. - */ -int rs_open(struct tty_struct *tty, struct file *filp) -{ - struct m68k_serial *info; - int retval; - - info = &m68k_soft[tty->index]; - - if (serial_paranoia_check(info, tty->name, "rs_open")) - return -ENODEV; - - info->tport.count++; - tty->driver_data = info; - tty_port_tty_set(&info->tport, tty); - - /* - * Start up serial port - */ - retval = startup(info, tty); - if (retval) - return retval; - - return tty_port_block_til_ready(&info->tport, tty, filp); -} - -/* Finally, routines used to initialize the serial driver. */ - -static void show_serial_version(void) -{ - printk("MC68328 serial driver version 1.00\n"); -} - -static const struct tty_operations rs_ops = { - .open = rs_open, - .close = rs_close, - .write = rs_write, - .flush_chars = rs_flush_chars, - .write_room = rs_write_room, - .chars_in_buffer = rs_chars_in_buffer, - .flush_buffer = rs_flush_buffer, - .ioctl = rs_ioctl, - .throttle = rs_throttle, - .unthrottle = rs_unthrottle, - .set_termios = rs_set_termios, - .stop = rs_stop, - .start = rs_start, - .hangup = rs_hangup, - .set_ldisc = rs_set_ldisc, -}; - -static const struct tty_port_operations rs_port_ops = { -}; - -/* rs_init inits the driver */ -static int __init -rs68328_init(void) -{ - unsigned long flags; - int i; - struct m68k_serial *info; - - serial_driver = alloc_tty_driver(NR_PORTS); - if (!serial_driver) - return -ENOMEM; - - show_serial_version(); - - /* Initialize the tty_driver structure */ - /* SPARC: Not all of this is exactly right for us. */ - - serial_driver->name = "ttyS"; - serial_driver->major = TTY_MAJOR; - serial_driver->minor_start = 64; - serial_driver->type = TTY_DRIVER_TYPE_SERIAL; - serial_driver->subtype = SERIAL_TYPE_NORMAL; - serial_driver->init_termios = tty_std_termios; - serial_driver->init_termios.c_cflag = - m68328_console_cbaud | CS8 | CREAD | HUPCL | CLOCAL; - serial_driver->flags = TTY_DRIVER_REAL_RAW; - tty_set_operations(serial_driver, &rs_ops); - - local_irq_save(flags); - - for (i = 0; i < NR_PORTS; i++) { - - info = &m68k_soft[i]; - tty_port_init(&info->tport); - info->tport.ops = &rs_port_ops; - info->magic = SERIAL_MAGIC; - info->port = (int) &uart_addr[i]; - info->irq = uart_irqs[i]; - info->custom_divisor = 16; - info->x_char = 0; - info->line = i; - info->is_cons = 1; /* Means shortcuts work */ - - printk("%s%d at 0x%08x (irq = %d)", serial_driver->name, info->line, - info->port, info->irq); - printk(" is a builtin MC68328 UART\n"); - -#ifdef CONFIG_M68VZ328 - if (i > 0) - PJSEL &= 0xCF; /* PSW enable second port output */ -#endif - - if (request_irq(uart_irqs[i], - rs_interrupt, - 0, - "M68328_UART", info)) - panic("Unable to attach 68328 serial interrupt\n"); - - tty_port_link_device(&info->tport, serial_driver, i); - } - local_irq_restore(flags); - - if (tty_register_driver(serial_driver)) { - put_tty_driver(serial_driver); - for (i = 0; i < NR_PORTS; i++) - tty_port_destroy(&m68k_soft[i].tport); - printk(KERN_ERR "Couldn't register serial driver\n"); - return -ENOMEM; - } - - return 0; -} - -module_init(rs68328_init); - - - -static void m68328_set_baud(void) -{ - unsigned short ustcnt; - int i; - - ustcnt = USTCNT; - USTCNT = ustcnt & ~USTCNT_TXEN; - -again: - for (i = 0; i < ARRAY_SIZE(baud_table); i++) - if (baud_table[i] == m68328_console_baud) - break; - if (i >= ARRAY_SIZE(baud_table)) { - m68328_console_baud = 9600; - goto again; - } - - UBAUD = PUT_FIELD(UBAUD_DIVIDE, hw_baud_table[i].divisor) | - PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale); - ustcnt &= ~(USTCNT_PARITYEN | USTCNT_ODD_EVEN | USTCNT_STOP | USTCNT_8_7); - ustcnt |= USTCNT_8_7; - ustcnt |= USTCNT_TXEN; - USTCNT = ustcnt; - m68328_console_initted = 1; - return; -} - - -int m68328_console_setup(struct console *cp, char *arg) -{ - int i, n = CONSOLE_BAUD_RATE; - - if (!cp) - return(-1); - - if (arg) - n = simple_strtoul(arg, NULL, 0); - - for (i = 0; i < ARRAY_SIZE(baud_table); i++) - if (baud_table[i] == n) - break; - if (i < ARRAY_SIZE(baud_table)) { - m68328_console_baud = n; - m68328_console_cbaud = 0; - if (i > 15) { - m68328_console_cbaud |= CBAUDEX; - i -= 15; - } - m68328_console_cbaud |= i; - } - - m68328_set_baud(); /* make sure baud rate changes */ - return 0; -} - - -static struct tty_driver *m68328_console_device(struct console *c, int *index) -{ - *index = c->index; - return serial_driver; -} - - -void m68328_console_write (struct console *co, const char *str, - unsigned int count) -{ - if (!m68328_console_initted) - m68328_set_baud(); - while (count--) { - if (*str == '\n') - rs_put_char('\r'); - rs_put_char(*str++); - } -} - - -static struct console m68328_driver = { - .name = "ttyS", - .write = m68328_console_write, - .device = m68328_console_device, - .setup = m68328_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, -}; - - -static int __init m68328_console_init(void) -{ - register_console(&m68328_driver); - return 0; -} - -console_initcall(m68328_console_init); diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index d54dcd87c67e..047a7ba6796a 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -92,6 +92,18 @@ struct serial8250_config { #define SERIAL8250_SHARE_IRQS 0 #endif +#define SERIAL8250_PORT_FLAGS(_base, _irq, _flags) \ + { \ + .iobase = _base, \ + .irq = _irq, \ + .uartclk = 1843200, \ + .iotype = UPIO_PORT, \ + .flags = UPF_BOOT_AUTOCONF | (_flags), \ + } + +#define SERIAL8250_PORT(_base, _irq) SERIAL8250_PORT_FLAGS(_base, _irq, 0) + + static inline int serial_in(struct uart_8250_port *up, int offset) { return up->port.serial_in(&up->port, offset); @@ -117,6 +129,8 @@ static inline void serial_dl_write(struct uart_8250_port *up, int value) struct uart_8250_port *serial8250_get_port(int line); void serial8250_rpm_get(struct uart_8250_port *p); 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); #if defined(__alpha__) && !defined(CONFIG_PCI) /* diff --git a/drivers/tty/serial/8250/8250_accent.c b/drivers/tty/serial/8250/8250_accent.c index 34b51c651192..522aeae05192 100644 --- a/drivers/tty/serial/8250/8250_accent.c +++ b/drivers/tty/serial/8250/8250_accent.c @@ -10,18 +10,11 @@ #include <linux/init.h> #include <linux/serial_8250.h> -#define PORT(_base,_irq) \ - { \ - .iobase = _base, \ - .irq = _irq, \ - .uartclk = 1843200, \ - .iotype = UPIO_PORT, \ - .flags = UPF_BOOT_AUTOCONF, \ - } +#include "8250.h" static struct plat_serial8250_port accent_data[] = { - PORT(0x330, 4), - PORT(0x338, 4), + SERIAL8250_PORT(0x330, 4), + SERIAL8250_PORT(0x338, 4), { }, }; diff --git a/drivers/tty/serial/8250/8250_acorn.c b/drivers/tty/serial/8250/8250_acorn.c index 549aa07c0d27..402dfdd4940e 100644 --- a/drivers/tty/serial/8250/8250_acorn.c +++ b/drivers/tty/serial/8250/8250_acorn.c @@ -70,7 +70,7 @@ serial_card_probe(struct expansion_card *ec, const struct ecard_id *id) uart.port.regshift = 2; uart.port.dev = &ec->dev; - for (i = 0; i < info->num_ports; i ++) { + for (i = 0; i < info->num_ports; i++) { uart.port.membase = info->vaddr + type->offset[i]; uart.port.mapbase = bus_addr + type->offset[i]; diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c new file mode 100644 index 000000000000..e10f1244409b --- /dev/null +++ b/drivers/tty/serial/8250/8250_bcm2835aux.c @@ -0,0 +1,146 @@ +/* + * Serial port driver for BCM2835AUX UART + * + * Copyright (C) 2016 Martin Sperl <kernel@martin.sperl.org> + * + * Based on 8250_lpc18xx.c: + * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +#include "8250.h" + +struct bcm2835aux_data { + struct uart_8250_port uart; + struct clk *clk; + int line; +}; + +static int bcm2835aux_serial_probe(struct platform_device *pdev) +{ + struct bcm2835aux_data *data; + struct resource *res; + int ret; + + /* allocate the custom structure */ + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + /* initialize data */ + spin_lock_init(&data->uart.port.lock); + data->uart.capabilities = UART_CAP_FIFO; + data->uart.port.dev = &pdev->dev; + data->uart.port.regshift = 2; + data->uart.port.type = PORT_16550; + data->uart.port.iotype = UPIO_MEM; + data->uart.port.fifosize = 8; + data->uart.port.flags = UPF_SHARE_IRQ | + UPF_FIXED_PORT | + UPF_FIXED_TYPE | + UPF_SKIP_TEST; + + /* get the clock - this also enables the HW */ + data->clk = devm_clk_get(&pdev->dev, NULL); + ret = PTR_ERR_OR_ZERO(data->clk); + if (ret) { + dev_err(&pdev->dev, "could not get clk: %d\n", ret); + return ret; + } + + /* get the interrupt */ + ret = platform_get_irq(pdev, 0); + if (ret < 0) { + dev_err(&pdev->dev, "irq not found - %i", ret); + return ret; + } + data->uart.port.irq = ret; + + /* map the main registers */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "memory resource not found"); + return -EINVAL; + } + data->uart.port.membase = devm_ioremap_resource(&pdev->dev, res); + ret = PTR_ERR_OR_ZERO(data->uart.port.membase); + if (ret) + return ret; + + /* Check for a fixed line number */ + ret = of_alias_get_id(pdev->dev.of_node, "serial"); + if (ret >= 0) + data->uart.port.line = ret; + + /* enable the clock as a last step */ + ret = clk_prepare_enable(data->clk); + if (ret) { + dev_err(&pdev->dev, "unable to enable uart clock - %d\n", + ret); + return ret; + } + + /* the HW-clock divider for bcm2835aux is 8, + * but 8250 expects a divider of 16, + * so we have to multiply the actual clock by 2 + * to get identical baudrates. + */ + data->uart.port.uartclk = clk_get_rate(data->clk) * 2; + + /* register the port */ + ret = serial8250_register_8250_port(&data->uart); + if (ret < 0) { + dev_err(&pdev->dev, "unable to register 8250 port - %d\n", + ret); + goto dis_clk; + } + data->line = ret; + + platform_set_drvdata(pdev, data); + + return 0; + +dis_clk: + clk_disable_unprepare(data->clk); + return ret; +} + +static int bcm2835aux_serial_remove(struct platform_device *pdev) +{ + struct bcm2835aux_data *data = platform_get_drvdata(pdev); + + serial8250_unregister_port(data->uart.port.line); + clk_disable_unprepare(data->clk); + + return 0; +} + +static const struct of_device_id bcm2835aux_serial_match[] = { + { .compatible = "brcm,bcm2835-aux-uart" }, + { }, +}; +MODULE_DEVICE_TABLE(of, bcm2835aux_serial_match); + +static struct platform_driver bcm2835aux_serial_driver = { + .driver = { + .name = "bcm2835-aux-uart", + .of_match_table = bcm2835aux_serial_match, + }, + .probe = bcm2835aux_serial_probe, + .remove = bcm2835aux_serial_remove, +}; +module_platform_driver(bcm2835aux_serial_driver); + +MODULE_DESCRIPTION("BCM2835 auxiliar UART driver"); +MODULE_AUTHOR("Martin Sperl <kernel@martin.sperl.org>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/tty/serial/8250/8250_boca.c b/drivers/tty/serial/8250/8250_boca.c index d125dc107985..a63b5998e383 100644 --- a/drivers/tty/serial/8250/8250_boca.c +++ b/drivers/tty/serial/8250/8250_boca.c @@ -10,32 +10,25 @@ #include <linux/init.h> #include <linux/serial_8250.h> -#define PORT(_base,_irq) \ - { \ - .iobase = _base, \ - .irq = _irq, \ - .uartclk = 1843200, \ - .iotype = UPIO_PORT, \ - .flags = UPF_BOOT_AUTOCONF, \ - } +#include "8250.h" static struct plat_serial8250_port boca_data[] = { - PORT(0x100, 12), - PORT(0x108, 12), - PORT(0x110, 12), - PORT(0x118, 12), - PORT(0x120, 12), - PORT(0x128, 12), - PORT(0x130, 12), - PORT(0x138, 12), - PORT(0x140, 12), - PORT(0x148, 12), - PORT(0x150, 12), - PORT(0x158, 12), - PORT(0x160, 12), - PORT(0x168, 12), - PORT(0x170, 12), - PORT(0x178, 12), + SERIAL8250_PORT(0x100, 12), + SERIAL8250_PORT(0x108, 12), + SERIAL8250_PORT(0x110, 12), + SERIAL8250_PORT(0x118, 12), + SERIAL8250_PORT(0x120, 12), + SERIAL8250_PORT(0x128, 12), + SERIAL8250_PORT(0x130, 12), + SERIAL8250_PORT(0x138, 12), + SERIAL8250_PORT(0x140, 12), + SERIAL8250_PORT(0x148, 12), + SERIAL8250_PORT(0x150, 12), + SERIAL8250_PORT(0x158, 12), + SERIAL8250_PORT(0x160, 12), + SERIAL8250_PORT(0x168, 12), + SERIAL8250_PORT(0x170, 12), + SERIAL8250_PORT(0x178, 12), { }, }; diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index c9720a97a977..2f4f5ee651db 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -597,6 +597,7 @@ static void univ8250_console_write(struct console *co, const char *s, static int univ8250_console_setup(struct console *co, char *options) { struct uart_port *port; + int retval; /* * Check whether an invalid uart number has been specified, and @@ -609,7 +610,10 @@ static int univ8250_console_setup(struct console *co, char *options) /* link port to console */ port->cons = co; - return serial8250_console_setup(port, options, false); + retval = serial8250_console_setup(port, options, false); + if (retval != 0) + port->cons = NULL; + return retval; } /** @@ -687,7 +691,7 @@ static int __init univ8250_console_init(void) } console_initcall(univ8250_console_init); -#define SERIAL8250_CONSOLE &univ8250_console +#define SERIAL8250_CONSOLE (&univ8250_console) #else #define SERIAL8250_CONSOLE NULL #endif @@ -764,6 +768,7 @@ void serial8250_suspend_port(int line) uart_suspend_port(&serial8250_reg, port); } +EXPORT_SYMBOL(serial8250_suspend_port); /** * serial8250_resume_port - resume one serial port @@ -789,6 +794,7 @@ void serial8250_resume_port(int line) } uart_resume_port(&serial8250_reg, port); } +EXPORT_SYMBOL(serial8250_resume_port); /* * Register a set of serial devices attached to a platform device. The @@ -1068,6 +1074,15 @@ void serial8250_unregister_port(int line) struct uart_8250_port *uart = &serial8250_ports[line]; mutex_lock(&serial_mutex); + + if (uart->em485) { + unsigned long flags; + + spin_lock_irqsave(&uart->port.lock, flags); + serial8250_em485_destroy(uart); + spin_unlock_irqrestore(&uart->port.lock, flags); + } + uart_remove_one_port(&serial8250_reg, &uart->port); if (serial8250_isa_devs) { uart->port.flags &= ~UPF_BOOT_AUTOCONF; @@ -1093,9 +1108,8 @@ static int __init serial8250_init(void) serial8250_isa_init_ports(); - printk(KERN_INFO "Serial: 8250/16550 driver, " - "%d ports, IRQ sharing %sabled\n", nr_uarts, - share_irqs ? "en" : "dis"); + pr_info("Serial: 8250/16550 driver, %d ports, IRQ sharing %sabled\n", + nr_uarts, share_irqs ? "en" : "dis"); #ifdef CONFIG_SPARC ret = sunserial_register_minors(&serial8250_reg, UART_NR); @@ -1168,15 +1182,11 @@ static void __exit serial8250_exit(void) module_init(serial8250_init); module_exit(serial8250_exit); -EXPORT_SYMBOL(serial8250_suspend_port); -EXPORT_SYMBOL(serial8250_resume_port); - MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Generic 8250/16x50 serial driver"); module_param(share_irqs, uint, 0644); -MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices" - " (unsafe)"); +MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices (unsafe)"); module_param(nr_uarts, uint, 0644); MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")"); diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index a5d319e4aae6..a3fb95d85d7c 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -68,12 +68,6 @@ struct dw8250_data { unsigned int uart_16550_compatible:1; }; -#define BYT_PRV_CLK 0x800 -#define BYT_PRV_CLK_EN (1 << 0) -#define BYT_PRV_CLK_M_VAL_SHIFT 1 -#define BYT_PRV_CLK_N_VAL_SHIFT 16 -#define BYT_PRV_CLK_UPDATE (1 << 31) - static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value) { struct dw8250_data *d = p->private_data; @@ -95,25 +89,45 @@ static void dw8250_force_idle(struct uart_port *p) (void)p->serial_in(p, UART_RX); } -static void dw8250_serial_out(struct uart_port *p, int offset, int value) +static void dw8250_check_lcr(struct uart_port *p, int value) { - writeb(value, p->membase + (offset << p->regshift)); + void __iomem *offset = p->membase + (UART_LCR << p->regshift); + int tries = 1000; /* Make sure LCR write wasn't ignored */ - if (offset == UART_LCR) { - int tries = 1000; - while (tries--) { - unsigned int lcr = p->serial_in(p, UART_LCR); - if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR)) - return; - dw8250_force_idle(p); - writeb(value, p->membase + (UART_LCR << p->regshift)); - } - /* - * FIXME: this deadlocks if port->lock is already held - * dev_err(p->dev, "Couldn't set LCR to %d\n", value); - */ + while (tries--) { + unsigned int lcr = p->serial_in(p, UART_LCR); + + if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR)) + return; + + dw8250_force_idle(p); + +#ifdef CONFIG_64BIT + __raw_writeq(value & 0xff, offset); +#else + if (p->iotype == UPIO_MEM32) + writel(value, offset); + else if (p->iotype == UPIO_MEM32BE) + iowrite32be(value, offset); + else + writeb(value, offset); +#endif } + /* + * FIXME: this deadlocks if port->lock is already held + * dev_err(p->dev, "Couldn't set LCR to %d\n", value); + */ +} + +static void dw8250_serial_out(struct uart_port *p, int offset, int value) +{ + struct dw8250_data *d = p->private_data; + + writeb(value, p->membase + (offset << p->regshift)); + + if (offset == UART_LCR && !d->uart_16550_compatible) + dw8250_check_lcr(p, value); } static unsigned int dw8250_serial_in(struct uart_port *p, int offset) @@ -135,49 +149,26 @@ static unsigned int dw8250_serial_inq(struct uart_port *p, int offset) static void dw8250_serial_outq(struct uart_port *p, int offset, int value) { + struct dw8250_data *d = p->private_data; + value &= 0xff; __raw_writeq(value, p->membase + (offset << p->regshift)); /* Read back to ensure register write ordering. */ __raw_readq(p->membase + (UART_LCR << p->regshift)); - /* Make sure LCR write wasn't ignored */ - if (offset == UART_LCR) { - int tries = 1000; - while (tries--) { - unsigned int lcr = p->serial_in(p, UART_LCR); - if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR)) - return; - dw8250_force_idle(p); - __raw_writeq(value & 0xff, - p->membase + (UART_LCR << p->regshift)); - } - /* - * FIXME: this deadlocks if port->lock is already held - * dev_err(p->dev, "Couldn't set LCR to %d\n", value); - */ - } + if (offset == UART_LCR && !d->uart_16550_compatible) + dw8250_check_lcr(p, value); } #endif /* CONFIG_64BIT */ static void dw8250_serial_out32(struct uart_port *p, int offset, int value) { + struct dw8250_data *d = p->private_data; + writel(value, p->membase + (offset << p->regshift)); - /* Make sure LCR write wasn't ignored */ - if (offset == UART_LCR) { - int tries = 1000; - while (tries--) { - unsigned int lcr = p->serial_in(p, UART_LCR); - if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR)) - return; - dw8250_force_idle(p); - writel(value, p->membase + (UART_LCR << p->regshift)); - } - /* - * FIXME: this deadlocks if port->lock is already held - * dev_err(p->dev, "Couldn't set LCR to %d\n", value); - */ - } + if (offset == UART_LCR && !d->uart_16550_compatible) + dw8250_check_lcr(p, value); } static unsigned int dw8250_serial_in32(struct uart_port *p, int offset) @@ -187,14 +178,33 @@ static unsigned int dw8250_serial_in32(struct uart_port *p, int offset) return dw8250_modify_msr(p, offset, value); } +static void dw8250_serial_out32be(struct uart_port *p, int offset, int value) +{ + struct dw8250_data *d = p->private_data; + + iowrite32be(value, p->membase + (offset << p->regshift)); + + if (offset == UART_LCR && !d->uart_16550_compatible) + dw8250_check_lcr(p, value); +} + +static unsigned int dw8250_serial_in32be(struct uart_port *p, int offset) +{ + unsigned int value = ioread32be(p->membase + (offset << p->regshift)); + + return dw8250_modify_msr(p, offset, value); +} + + static int dw8250_handle_irq(struct uart_port *p) { struct dw8250_data *d = p->private_data; unsigned int iir = p->serial_in(p, UART_IIR); - if (serial8250_handle_irq(p, iir)) { + if (serial8250_handle_irq(p, iir)) return 1; - } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) { + + if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) { /* Clear the USR */ (void)p->serial_in(p, d->usr_reg); @@ -281,6 +291,11 @@ static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data) data->skip_autocfg = true; } #endif + if (of_device_is_big_endian(p->dev->of_node)) { + p->iotype = UPIO_MEM32BE; + p->serial_in = dw8250_serial_in32be; + p->serial_out = dw8250_serial_out32be; + } } else if (has_acpi_companion(p->dev)) { p->iotype = UPIO_MEM32; p->regshift = 2; @@ -309,14 +324,20 @@ static void dw8250_setup_port(struct uart_port *p) * If the Component Version Register returns zero, we know that * ADDITIONAL_FEATURES are not enabled. No need to go any further. */ - reg = readl(p->membase + DW_UART_UCV); + if (p->iotype == UPIO_MEM32BE) + reg = ioread32be(p->membase + DW_UART_UCV); + else + reg = readl(p->membase + DW_UART_UCV); if (!reg) return; dev_dbg(p->dev, "Designware UART version %c.%c%c\n", (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff); - reg = readl(p->membase + DW_UART_CPR); + if (p->iotype == UPIO_MEM32BE) + reg = ioread32be(p->membase + DW_UART_CPR); + else + reg = readl(p->membase + DW_UART_CPR); if (!reg) return; @@ -463,10 +484,8 @@ static int dw8250_probe(struct platform_device *pdev) dw8250_quirks(p, data); /* If the Busy Functionality is not implemented, don't handle it */ - if (data->uart_16550_compatible) { - p->serial_out = NULL; + if (data->uart_16550_compatible) p->handle_irq = NULL; - } if (!data->skip_autocfg) dw8250_setup_port(p); diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c index af62131af21e..8d08ff5c4e34 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -39,15 +39,17 @@ static unsigned int __init serial8250_early_in(struct uart_port *port, int offset) { + offset <<= port->regshift; + switch (port->iotype) { case UPIO_MEM: return readb(port->membase + offset); case UPIO_MEM16: - return readw(port->membase + (offset << 1)); + return readw(port->membase + offset); case UPIO_MEM32: - return readl(port->membase + (offset << 2)); + return readl(port->membase + offset); case UPIO_MEM32BE: - return ioread32be(port->membase + (offset << 2)); + return ioread32be(port->membase + offset); case UPIO_PORT: return inb(port->iobase + offset); default: @@ -57,18 +59,20 @@ static unsigned int __init serial8250_early_in(struct uart_port *port, int offse static void __init serial8250_early_out(struct uart_port *port, int offset, int value) { + offset <<= port->regshift; + switch (port->iotype) { case UPIO_MEM: writeb(value, port->membase + offset); break; case UPIO_MEM16: - writew(value, port->membase + (offset << 1)); + writew(value, port->membase + offset); break; case UPIO_MEM32: - writel(value, port->membase + (offset << 2)); + writel(value, port->membase + offset); break; case UPIO_MEM32BE: - iowrite32be(value, port->membase + (offset << 2)); + iowrite32be(value, port->membase + offset); break; case UPIO_PORT: outb(value, port->iobase + offset); @@ -145,3 +149,25 @@ EARLYCON_DECLARE(uart8250, early_serial8250_setup); 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); + +#ifdef CONFIG_SERIAL_8250_OMAP + +static int __init early_omap8250_setup(struct earlycon_device *device, + const char *options) +{ + struct uart_port *port = &device->port; + + if (!(device->port.membase || device->port.iobase)) + return -ENODEV; + + port->regshift = 2; + device->con->write = early_serial8250_write; + return 0; +} + +OF_EARLYCON_DECLARE(omap8250, "ti,omap2-uart", early_omap8250_setup); +OF_EARLYCON_DECLARE(omap8250, "ti,omap3-uart", early_omap8250_setup); +OF_EARLYCON_DECLARE(omap8250, "ti,omap4-uart", early_omap8250_setup); + +#endif diff --git a/drivers/tty/serial/8250/8250_exar_st16c554.c b/drivers/tty/serial/8250/8250_exar_st16c554.c index bf53aabf9b5e..3a7cb8262bb9 100644 --- a/drivers/tty/serial/8250/8250_exar_st16c554.c +++ b/drivers/tty/serial/8250/8250_exar_st16c554.c @@ -13,20 +13,13 @@ #include <linux/init.h> #include <linux/serial_8250.h> -#define PORT(_base,_irq) \ - { \ - .iobase = _base, \ - .irq = _irq, \ - .uartclk = 1843200, \ - .iotype = UPIO_PORT, \ - .flags = UPF_BOOT_AUTOCONF, \ - } +#include "8250.h" static struct plat_serial8250_port exar_data[] = { - PORT(0x100, 5), - PORT(0x108, 5), - PORT(0x110, 5), - PORT(0x118, 5), + SERIAL8250_PORT(0x100, 5), + SERIAL8250_PORT(0x108, 5), + SERIAL8250_PORT(0x110, 5), + SERIAL8250_PORT(0x118, 5), { }, }; diff --git a/drivers/tty/serial/8250/8250_fourport.c b/drivers/tty/serial/8250/8250_fourport.c index be1582609626..4045180a8cfc 100644 --- a/drivers/tty/serial/8250/8250_fourport.c +++ b/drivers/tty/serial/8250/8250_fourport.c @@ -10,24 +10,20 @@ #include <linux/init.h> #include <linux/serial_8250.h> -#define PORT(_base,_irq) \ - { \ - .iobase = _base, \ - .irq = _irq, \ - .uartclk = 1843200, \ - .iotype = UPIO_PORT, \ - .flags = UPF_BOOT_AUTOCONF | UPF_FOURPORT, \ - } +#include "8250.h" + +#define SERIAL8250_FOURPORT(_base, _irq) \ + SERIAL8250_PORT_FLAGS(_base, _irq, UPF_FOURPORT) static struct plat_serial8250_port fourport_data[] = { - PORT(0x1a0, 9), - PORT(0x1a8, 9), - PORT(0x1b0, 9), - PORT(0x1b8, 9), - PORT(0x2a0, 5), - PORT(0x2a8, 5), - PORT(0x2b0, 5), - PORT(0x2b8, 5), + SERIAL8250_FOURPORT(0x1a0, 9), + SERIAL8250_FOURPORT(0x1a8, 9), + SERIAL8250_FOURPORT(0x1b0, 9), + SERIAL8250_FOURPORT(0x1b8, 9), + SERIAL8250_FOURPORT(0x2a0, 5), + SERIAL8250_FOURPORT(0x2a8, 5), + SERIAL8250_FOURPORT(0x2b0, 5), + SERIAL8250_FOURPORT(0x2b8, 5), { }, }; diff --git a/drivers/tty/serial/8250/8250_gsc.c b/drivers/tty/serial/8250/8250_gsc.c index 2e3ea1a70d7b..b1e6ae9f1ff9 100644 --- a/drivers/tty/serial/8250/8250_gsc.c +++ b/drivers/tty/serial/8250/8250_gsc.c @@ -42,7 +42,7 @@ static int __init serial_init_chip(struct parisc_device *dev) * the user what they're missing. */ if (parisc_parent(dev)->id.hw_type != HPHW_IOA) - printk(KERN_INFO + dev_info(&dev->dev, "Serial: device 0x%llx not configured.\n" "Enable support for Wax, Lasi, Asp or Dino.\n", (unsigned long long)dev->hpa.start); @@ -66,8 +66,9 @@ static int __init serial_init_chip(struct parisc_device *dev) err = serial8250_register_8250_port(&uart); if (err < 0) { - printk(KERN_WARNING - "serial8250_register_8250_port returned error %d\n", err); + dev_warn(&dev->dev, + "serial8250_register_8250_port returned error %d\n", + err); iounmap(uart.port.membase); return err; } diff --git a/drivers/tty/serial/8250/8250_hp300.c b/drivers/tty/serial/8250/8250_hp300.c index 2891958cd842..38166db2b824 100644 --- a/drivers/tty/serial/8250/8250_hp300.c +++ b/drivers/tty/serial/8250/8250_hp300.c @@ -24,8 +24,7 @@ #endif #ifdef CONFIG_HPAPCI -struct hp300_port -{ +struct hp300_port { struct hp300_port *next; /* next port */ int line; /* line (tty) number */ }; @@ -111,7 +110,7 @@ int __init hp300_setup_serial_console(void) /* Check for APCI console */ if (scode == 256) { #ifdef CONFIG_HPAPCI - printk(KERN_INFO "Serial console is HP APCI 1\n"); + pr_info("Serial console is HP APCI 1\n"); port.uartclk = HPAPCI_BAUD_BASE * 16; port.mapbase = (FRODO_BASE + FRODO_APCI_OFFSET(1)); @@ -119,7 +118,7 @@ int __init hp300_setup_serial_console(void) port.regshift = 2; add_preferred_console("ttyS", port.line, "9600n8"); #else - printk(KERN_WARNING "Serial console is APCI but support is disabled (CONFIG_HPAPCI)!\n"); + pr_warn("Serial console is APCI but support is disabled (CONFIG_HPAPCI)!\n"); return 0; #endif } else { @@ -128,7 +127,7 @@ int __init hp300_setup_serial_console(void) if (!pa) return 0; - printk(KERN_INFO "Serial console is HP DCA at select code %d\n", scode); + pr_info("Serial console is HP DCA at select code %d\n", scode); port.uartclk = HPDCA_BAUD_BASE * 16; port.mapbase = (pa + UART_OFFSET); @@ -142,13 +141,13 @@ int __init hp300_setup_serial_console(void) if (DIO_ID(pa + DIO_VIRADDRBASE) & 0x80) add_preferred_console("ttyS", port.line, "9600n8"); #else - printk(KERN_WARNING "Serial console is DCA but support is disabled (CONFIG_HPDCA)!\n"); + pr_warn("Serial console is DCA but support is disabled (CONFIG_HPDCA)!\n"); return 0; #endif } if (early_serial_setup(&port) < 0) - printk(KERN_WARNING "hp300_setup_serial_console(): early_serial_setup() failed.\n"); + pr_warn("%s: early_serial_setup() failed.\n", __func__); return 0; } #endif /* CONFIG_SERIAL_8250_CONSOLE */ @@ -180,8 +179,9 @@ static int hpdca_init_one(struct dio_dev *d, line = serial8250_register_8250_port(&uart); if (line < 0) { - printk(KERN_NOTICE "8250_hp300: register_serial() DCA scode %d" - " irq %d failed\n", d->scode, uart.port.irq); + dev_notice(&d->dev, + "8250_hp300: register_serial() DCA scode %d irq %d failed\n", + d->scode, uart.port.irq); return -ENOMEM; } @@ -249,8 +249,8 @@ static int __init hp300_8250_init(void) /* Memory mapped I/O */ uart.port.iotype = UPIO_MEM; - uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ \ - | UPF_BOOT_AUTOCONF; + uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ + | UPF_BOOT_AUTOCONF; /* XXX - no interrupt support yet */ uart.port.irq = 0; uart.port.uartclk = HPAPCI_BAUD_BASE * 16; @@ -261,8 +261,9 @@ static int __init hp300_8250_init(void) line = serial8250_register_8250_port(&uart); if (line < 0) { - printk(KERN_NOTICE "8250_hp300: register_serial() APCI" - " %d irq %d failed\n", i, uart.port.irq); + dev_notice(uart.port.dev, + "8250_hp300: register_serial() APCI %d irq %d failed\n", + i, uart.port.irq); kfree(port); continue; } diff --git a/drivers/tty/serial/8250/8250_hub6.c b/drivers/tty/serial/8250/8250_hub6.c index a5c778e83de0..27124e21eb96 100644 --- a/drivers/tty/serial/8250/8250_hub6.c +++ b/drivers/tty/serial/8250/8250_hub6.c @@ -10,7 +10,7 @@ #include <linux/init.h> #include <linux/serial_8250.h> -#define HUB6(card,port) \ +#define HUB6(card, port) \ { \ .iobase = 0x302, \ .irq = 3, \ diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c index d6e1ec9b4fde..b0677f610863 100644 --- a/drivers/tty/serial/8250/8250_ingenic.c +++ b/drivers/tty/serial/8250/8250_ingenic.c @@ -48,7 +48,7 @@ static const struct of_device_id of_match[]; #define UART_MCR_MDCE BIT(7) #define UART_MCR_FCM BIT(6) -#ifdef CONFIG_SERIAL_EARLYCON +#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) @@ -154,14 +154,18 @@ static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value) break; case UART_IER: - /* Enable receive timeout interrupt with the - * receive line status interrupt */ + /* + * Enable receive timeout interrupt with the receive line + * status interrupt. + */ value |= (value & 0x4) << 2; break; case UART_MCR: - /* If we have enabled modem status IRQs we should enable modem - * mode. */ + /* + * If we have enabled modem status IRQs we should enable + * modem mode. + */ ier = p->serial_in(p, UART_IER); if (ier & UART_IER_MSI) diff --git a/drivers/tty/serial/8250/8250_moxa.c b/drivers/tty/serial/8250/8250_moxa.c new file mode 100644 index 000000000000..26eb5393a263 --- /dev/null +++ b/drivers/tty/serial/8250/8250_moxa.c @@ -0,0 +1,157 @@ +/* + * 8250_moxa.c - MOXA Smartio/Industio MUE multiport serial driver. + * + * Author: Mathieu OTHACEHE <m.othacehe@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/pci.h> + +#include "8250.h" + +#define PCI_DEVICE_ID_MOXA_CP102E 0x1024 +#define PCI_DEVICE_ID_MOXA_CP102EL 0x1025 +#define PCI_DEVICE_ID_MOXA_CP104EL_A 0x1045 +#define PCI_DEVICE_ID_MOXA_CP114EL 0x1144 +#define PCI_DEVICE_ID_MOXA_CP116E_A_A 0x1160 +#define PCI_DEVICE_ID_MOXA_CP116E_A_B 0x1161 +#define PCI_DEVICE_ID_MOXA_CP118EL_A 0x1182 +#define PCI_DEVICE_ID_MOXA_CP118E_A_I 0x1183 +#define PCI_DEVICE_ID_MOXA_CP132EL 0x1322 +#define PCI_DEVICE_ID_MOXA_CP134EL_A 0x1342 +#define PCI_DEVICE_ID_MOXA_CP138E_A 0x1381 +#define PCI_DEVICE_ID_MOXA_CP168EL_A 0x1683 + +#define MOXA_BASE_BAUD 921600 +#define MOXA_UART_OFFSET 0x200 +#define MOXA_BASE_BAR 1 + +struct moxa8250_board { + unsigned int num_ports; + int line[0]; +}; + +enum { + moxa8250_2p = 0, + moxa8250_4p, + moxa8250_8p +}; + +static struct moxa8250_board moxa8250_boards[] = { + [moxa8250_2p] = { .num_ports = 2}, + [moxa8250_4p] = { .num_ports = 4}, + [moxa8250_8p] = { .num_ports = 8}, +}; + +static int moxa8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct uart_8250_port uart; + struct moxa8250_board *brd; + void __iomem *ioaddr; + resource_size_t baseaddr; + unsigned int i, nr_ports; + unsigned int offset; + int ret; + + brd = &moxa8250_boards[id->driver_data]; + nr_ports = brd->num_ports; + + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + brd = devm_kzalloc(&pdev->dev, sizeof(struct moxa8250_board) + + sizeof(unsigned int) * nr_ports, GFP_KERNEL); + if (!brd) + return -ENOMEM; + + memset(&uart, 0, sizeof(struct uart_8250_port)); + + uart.port.dev = &pdev->dev; + uart.port.irq = pdev->irq; + uart.port.uartclk = MOXA_BASE_BAUD * 16; + uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ; + + baseaddr = pci_resource_start(pdev, MOXA_BASE_BAR); + ioaddr = pcim_iomap(pdev, MOXA_BASE_BAR, 0); + if (!ioaddr) + return -ENOMEM; + + for (i = 0; i < nr_ports; i++) { + + /* + * MOXA Smartio MUE boards with 4 ports have + * a different offset for port #3 + */ + if (nr_ports == 4 && i == 3) + offset = 7 * MOXA_UART_OFFSET; + else + offset = i * MOXA_UART_OFFSET; + + uart.port.iotype = UPIO_MEM; + uart.port.iobase = 0; + uart.port.mapbase = baseaddr + offset; + uart.port.membase = ioaddr + offset; + uart.port.regshift = 0; + + dev_dbg(&pdev->dev, "Setup PCI port: port %lx, irq %d, type %d\n", + uart.port.iobase, uart.port.irq, uart.port.iotype); + + brd->line[i] = serial8250_register_8250_port(&uart); + if (brd->line[i] < 0) { + dev_err(&pdev->dev, + "Couldn't register serial port %lx, irq %d, type %d, error %d\n", + uart.port.iobase, uart.port.irq, + uart.port.iotype, brd->line[i]); + break; + } + } + + pci_set_drvdata(pdev, brd); + return 0; +} + +static void moxa8250_remove(struct pci_dev *pdev) +{ + struct moxa8250_board *brd = pci_get_drvdata(pdev); + unsigned int i; + + for (i = 0; i < brd->num_ports; i++) + serial8250_unregister_port(brd->line[i]); +} + +#define MOXA_DEVICE(id, data) { PCI_VDEVICE(MOXA, id), (kernel_ulong_t)data } + +static const struct pci_device_id pci_ids[] = { + MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP102E, moxa8250_2p), + MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP102EL, moxa8250_2p), + MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP104EL_A, moxa8250_4p), + MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP114EL, moxa8250_4p), + MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP116E_A_A, moxa8250_8p), + MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP116E_A_B, moxa8250_8p), + MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP118EL_A, moxa8250_8p), + MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP118E_A_I, moxa8250_8p), + MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP132EL, moxa8250_2p), + MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP134EL_A, moxa8250_4p), + MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP138E_A, moxa8250_8p), + MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP168EL_A, moxa8250_8p), + {0} +}; +MODULE_DEVICE_TABLE(pci, pci_ids); + +static struct pci_driver moxa8250_pci_driver = { + .name = "8250_moxa", + .id_table = pci_ids, + .probe = moxa8250_probe, + .remove = moxa8250_remove, +}; + +module_pci_driver(moxa8250_pci_driver); + +MODULE_AUTHOR("Mathieu OTHACEHE"); +MODULE_DESCRIPTION("MOXA SmartIO MUE driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c index 0e590b233f03..3489fbcb7313 100644 --- a/drivers/tty/serial/8250/8250_mtk.c +++ b/drivers/tty/serial/8250/8250_mtk.c @@ -16,7 +16,7 @@ */ #include <linux/clk.h> #include <linux/io.h> -#include <linux/init.h> +#include <linux/module.h> #include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/platform_device.h> @@ -41,12 +41,10 @@ static void mtk8250_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { + struct uart_8250_port *up = up_to_u8250p(port); unsigned long flags; unsigned int baud, quot; - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - serial8250_do_set_termios(port, termios, old); /* @@ -116,7 +114,7 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios, tty_termios_encode_baud_rate(termios, baud, baud); } -static int mtk8250_runtime_suspend(struct device *dev) +static int __maybe_unused mtk8250_runtime_suspend(struct device *dev) { struct mtk8250_data *data = dev_get_drvdata(dev); @@ -126,7 +124,7 @@ static int mtk8250_runtime_suspend(struct device *dev) return 0; } -static int mtk8250_runtime_resume(struct device *dev) +static int __maybe_unused mtk8250_runtime_resume(struct device *dev) { struct mtk8250_data *data = dev_get_drvdata(dev); int err; @@ -245,8 +243,24 @@ static int mtk8250_probe(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP -static int mtk8250_suspend(struct device *dev) +static int mtk8250_remove(struct platform_device *pdev) +{ + struct mtk8250_data *data = platform_get_drvdata(pdev); + + pm_runtime_get_sync(&pdev->dev); + + serial8250_unregister_port(data->line); + + pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + + if (!pm_runtime_status_suspended(&pdev->dev)) + mtk8250_runtime_suspend(&pdev->dev); + + return 0; +} + +static int __maybe_unused mtk8250_suspend(struct device *dev) { struct mtk8250_data *data = dev_get_drvdata(dev); @@ -255,7 +269,7 @@ static int mtk8250_suspend(struct device *dev) return 0; } -static int mtk8250_resume(struct device *dev) +static int __maybe_unused mtk8250_resume(struct device *dev) { struct mtk8250_data *data = dev_get_drvdata(dev); @@ -263,7 +277,6 @@ static int mtk8250_resume(struct device *dev) return 0; } -#endif /* CONFIG_PM_SLEEP */ static const struct dev_pm_ops mtk8250_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(mtk8250_suspend, mtk8250_resume) @@ -275,20 +288,20 @@ static const struct of_device_id mtk8250_of_match[] = { { .compatible = "mediatek,mt6577-uart" }, { /* Sentinel */ } }; +MODULE_DEVICE_TABLE(of, mtk8250_of_match); static struct platform_driver mtk8250_platform_driver = { .driver = { - .name = "mt6577-uart", - .pm = &mtk8250_pm_ops, - .of_match_table = mtk8250_of_match, - .suppress_bind_attrs = true, - + .name = "mt6577-uart", + .pm = &mtk8250_pm_ops, + .of_match_table = mtk8250_of_match, }, .probe = mtk8250_probe, + .remove = mtk8250_remove, }; -builtin_platform_driver(mtk8250_platform_driver); +module_platform_driver(mtk8250_platform_driver); -#ifdef CONFIG_SERIAL_8250_CONSOLE +#if defined(CONFIG_SERIAL_8250_CONSOLE) && !defined(MODULE) static int __init early_mtk8250_setup(struct earlycon_device *device, const char *options) { @@ -302,3 +315,7 @@ static int __init early_mtk8250_setup(struct earlycon_device *device, OF_EARLYCON_DECLARE(mtk8250, "mediatek,mt6577-uart", early_mtk8250_setup); #endif + +MODULE_AUTHOR("Matthias Brugger"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Mediatek 8250 serial port driver"); diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c index 33021c1f7d55..c7ed3d2bc8b2 100644 --- a/drivers/tty/serial/8250/8250_of.c +++ b/drivers/tty/serial/8250/8250_of.c @@ -335,6 +335,7 @@ static struct platform_driver of_platform_serial_driver = { .driver = { .name = "of_serial", .of_match_table = of_platform_serial_table, + .pm = &of_serial_pm_ops, }, .probe = of_platform_serial_probe, .remove = of_platform_serial_remove, diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index a2c0734c76e2..6f760510e46d 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -318,8 +318,7 @@ static void omap_8250_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); + struct uart_8250_port *up = up_to_u8250p(port); struct omap8250_priv *priv = up->port.private_data; unsigned char cval = 0; unsigned int baud; @@ -682,9 +681,8 @@ static void omap_8250_shutdown(struct uart_port *port) static void omap_8250_throttle(struct uart_port *port) { + struct uart_8250_port *up = up_to_u8250p(port); unsigned long flags; - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); pm_runtime_get_sync(port->dev); @@ -697,11 +695,40 @@ static void omap_8250_throttle(struct uart_port *port) pm_runtime_put_autosuspend(port->dev); } +static int omap_8250_rs485_config(struct uart_port *port, + struct serial_rs485 *rs485) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + /* Clamp the delays to [0, 100ms] */ + rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U); + rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U); + + port->rs485 = *rs485; + + /* + * Both serial8250_em485_init and serial8250_em485_destroy + * are idempotent + */ + if (rs485->flags & SER_RS485_ENABLED) { + int ret = serial8250_em485_init(up); + + if (ret) { + rs485->flags &= ~SER_RS485_ENABLED; + port->rs485.flags &= ~SER_RS485_ENABLED; + } + return ret; + } + + serial8250_em485_destroy(up); + + return 0; +} + static void omap_8250_unthrottle(struct uart_port *port) { + struct uart_8250_port *up = up_to_u8250p(port); unsigned long flags; - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); pm_runtime_get_sync(port->dev); @@ -1146,6 +1173,7 @@ static int omap8250_probe(struct platform_device *pdev) up.port.shutdown = omap_8250_shutdown; up.port.throttle = omap_8250_throttle; up.port.unthrottle = omap_8250_unthrottle; + up.port.rs485_config = omap_8250_rs485_config; if (pdev->dev.of_node) { const struct of_device_id *id; diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 7cd6f9a90542..98862aa5bb58 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -55,7 +55,6 @@ struct pci_serial_quirk { struct serial_private { struct pci_dev *dev; unsigned int nr; - void __iomem *remapped_bar[PCI_NUM_BAR_RESOURCES]; struct pci_serial_quirk *quirk; int line[0]; }; @@ -85,15 +84,13 @@ setup_port(struct serial_private *priv, struct uart_8250_port *port, return -EINVAL; if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) { - if (!priv->remapped_bar[bar]) - priv->remapped_bar[bar] = pci_ioremap_bar(dev, bar); - if (!priv->remapped_bar[bar]) + if (!pcim_iomap(dev, bar, 0) && !pcim_iomap_table(dev)) return -ENOMEM; port->port.iotype = UPIO_MEM; port->port.iobase = 0; port->port.mapbase = pci_resource_start(dev, bar) + offset; - port->port.membase = priv->remapped_bar[bar] + offset; + port->port.membase = pcim_iomap_table(dev)[bar] + offset; port->port.regshift = regshift; } else { port->port.iotype = UPIO_PORT; @@ -721,7 +718,7 @@ static int pci_ni8430_init(struct pci_dev *dev) */ pcibios_resource_to_bus(dev->bus, ®ion, &dev->resource[bar]); device_window = ((region.start + MITE_IOWBSR1_WIN_OFFSET) & 0xffffff00) - | MITE_IOWBSR1_WENAB | MITE_IOWBSR1_WSIZE; + | MITE_IOWBSR1_WENAB | MITE_IOWBSR1_WSIZE; writel(device_window, p + MITE_IOWBSR1); /* Set window access to go to RAMSEL IO address space */ @@ -803,12 +800,12 @@ static int pci_netmos_9900_numports(struct pci_dev *dev) unsigned int pi; unsigned short sub_serports; - pi = (c & 0xff); + pi = c & 0xff; - if (pi == 2) { + if (pi == 2) return 1; - } else if ((pi == 0) && - (dev->device == PCI_DEVICE_ID_NETMOS_9900)) { + + if ((pi == 0) && (dev->device == PCI_DEVICE_ID_NETMOS_9900)) { /* two possibilities: 0x30ps encodes number of parallel and * serial ports, or 0x1000 indicates *something*. This is not * immediately obvious, since the 2s1p+4s configuration seems @@ -816,12 +813,12 @@ static int pci_netmos_9900_numports(struct pci_dev *dev) * advertising the same function 3 as the 4s+2s1p config. */ sub_serports = dev->subsystem_device & 0xf; - if (sub_serports > 0) { + if (sub_serports > 0) return sub_serports; - } else { - dev_err(&dev->dev, "NetMos/Mostech serial driver ignoring port on ambiguous config.\n"); - return 0; - } + + dev_err(&dev->dev, + "NetMos/Mostech serial driver ignoring port on ambiguous config.\n"); + return 0; } moan_device("unknown NetMos/Mostech program interface", dev); @@ -842,21 +839,21 @@ static int pci_netmos_init(struct pci_dev *dev) return 0; switch (dev->device) { /* FALLTHROUGH on all */ - case PCI_DEVICE_ID_NETMOS_9904: - case PCI_DEVICE_ID_NETMOS_9912: - case PCI_DEVICE_ID_NETMOS_9922: - case PCI_DEVICE_ID_NETMOS_9900: - num_serial = pci_netmos_9900_numports(dev); - break; + case PCI_DEVICE_ID_NETMOS_9904: + case PCI_DEVICE_ID_NETMOS_9912: + case PCI_DEVICE_ID_NETMOS_9922: + case PCI_DEVICE_ID_NETMOS_9900: + num_serial = pci_netmos_9900_numports(dev); + break; - default: - if (num_serial == 0 ) { - moan_device("unknown NetMos/Mostech device", dev); - } + default: + break; } - if (num_serial == 0) + if (num_serial == 0) { + moan_device("unknown NetMos/Mostech device", dev); return -ENODEV; + } return num_serial; } @@ -1198,8 +1195,9 @@ static int pci_quatech_has_qmcr(struct uart_8250_port *port) static int pci_quatech_test(struct uart_8250_port *port) { - u8 reg; - u8 qopr = pci_quatech_rqopr(port); + u8 reg, qopr; + + qopr = pci_quatech_rqopr(port); pci_quatech_wqopr(port, qopr & QPCR_TEST_FOR1); reg = pci_quatech_rqopr(port) & 0xC0; if (reg != QPCR_TEST_GET1) @@ -1286,6 +1284,7 @@ static int pci_quatech_init(struct pci_dev *dev) unsigned long base = pci_resource_start(dev, 0); if (base) { u32 tmp; + outl(inl(base + 0x38) | 0x00002000, base + 0x38); tmp = inl(base + 0x3c); outl(tmp | 0x01000000, base + 0x3c); @@ -1334,29 +1333,6 @@ static int pci_default_setup(struct serial_private *priv, return setup_port(priv, port, bar, offset, board->reg_shift); } -static int pci_pericom_setup(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_8250_port *port, int idx) -{ - unsigned int bar, offset = board->first_offset, maxnr; - - bar = FL_GET_BASE(board->flags); - if (board->flags & FL_BASE_BARS) - bar += idx; - else - offset += idx * board->uart_offset; - - maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) >> - (board->reg_shift + 3); - - if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr) - return 1; - - port->port.uartclk = 14745600; - - return setup_port(priv, port, bar, offset, board->reg_shift); -} - static int ce4100_serial_setup(struct serial_private *priv, const struct pciserial_board *board, @@ -1541,10 +1517,9 @@ pci_brcm_trumanage_setup(struct serial_private *priv, static int pci_fintek_rs485_config(struct uart_port *port, struct serial_rs485 *rs485) { + struct pci_dev *pci_dev = to_pci_dev(port->dev); u8 setting; u8 *index = (u8 *) port->private_data; - struct pci_dev *pci_dev = container_of(port->dev, struct pci_dev, - dev); pci_read_config_byte(pci_dev, 0x40 + 8 * *index + 7, &setting); @@ -1766,7 +1741,7 @@ xr17v35x_has_slave(struct serial_private *priv) const int dev_id = priv->dev->device; return ((dev_id == PCI_DEVICE_ID_EXAR_XR17V4358) || - (dev_id == PCI_DEVICE_ID_EXAR_XR17V8358)); + (dev_id == PCI_DEVICE_ID_EXAR_XR17V8358)); } static int @@ -1866,8 +1841,8 @@ pci_fastcom335_setup(struct serial_private *priv, static int pci_wch_ch353_setup(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_8250_port *port, int idx) + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) { port->port.flags |= UPF_FIXED_TYPE; port->port.type = PORT_16550A; @@ -1876,8 +1851,8 @@ pci_wch_ch353_setup(struct serial_private *priv, static int pci_wch_ch38x_setup(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_8250_port *port, int idx) + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) { port->port.flags |= UPF_FIXED_TYPE; port->port.type = PORT_16850; @@ -2246,16 +2221,6 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .exit = pci_plx9050_exit, }, /* - * Pericom - */ - { - .vendor = PCI_VENDOR_ID_PERICOM, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup, - }, - /* * PLX */ { @@ -3733,15 +3698,10 @@ static struct pciserial_board pci_boards[] = { .base_baud = 921600, .reg_shift = 2, }, - /* - * Intel BayTrail HSUART reference clock is 44.2368 MHz at power-on, - * but is overridden by byt_set_termios. - */ [pbn_byt] = { .flags = FL_BASE0, .num_ports = 1, .base_baud = 2764800, - .uart_offset = 0x80, .reg_shift = 2, }, [pbn_qrk] = { @@ -3840,6 +3800,20 @@ static const struct pci_device_id blacklist[] = { { PCI_DEVICE(0x1c00, 0x3250), }, /* WCH CH382 2S1P */ { PCI_DEVICE(0x1c00, 0x3470), }, /* WCH CH384 4S */ + /* Moxa Smartio MUE boards handled by 8250_moxa */ + { PCI_VDEVICE(MOXA, 0x1024), }, + { PCI_VDEVICE(MOXA, 0x1025), }, + { PCI_VDEVICE(MOXA, 0x1045), }, + { PCI_VDEVICE(MOXA, 0x1144), }, + { PCI_VDEVICE(MOXA, 0x1160), }, + { PCI_VDEVICE(MOXA, 0x1161), }, + { PCI_VDEVICE(MOXA, 0x1182), }, + { PCI_VDEVICE(MOXA, 0x1183), }, + { PCI_VDEVICE(MOXA, 0x1322), }, + { PCI_VDEVICE(MOXA, 0x1342), }, + { PCI_VDEVICE(MOXA, 0x1381), }, + { PCI_VDEVICE(MOXA, 0x1683), }, + /* Intel platforms with MID UART */ { PCI_VDEVICE(INTEL, 0x081b), }, { PCI_VDEVICE(INTEL, 0x081c), }, @@ -4027,12 +4001,6 @@ void pciserial_remove_ports(struct serial_private *priv) for (i = 0; i < priv->nr; i++) serial8250_unregister_port(priv->line[i]); - for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) { - if (priv->remapped_bar[i]) - iounmap(priv->remapped_bar[i]); - priv->remapped_bar[i] = NULL; - } - /* * Find the exit quirks. */ @@ -4104,7 +4072,7 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) board = &pci_boards[ent->driver_data]; - rc = pci_enable_device(dev); + rc = pcim_enable_device(dev); pci_save_state(dev); if (rc) return rc; @@ -4123,7 +4091,7 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) */ rc = serial_pci_guess_board(dev, &tmp); if (rc) - goto disable; + return rc; } else { /* * We matched an explicit entry. If we are able to @@ -4139,16 +4107,11 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) } priv = pciserial_init_ports(dev, board); - if (!IS_ERR(priv)) { - pci_set_drvdata(dev, priv); - return 0; - } + if (IS_ERR(priv)) + return PTR_ERR(priv); - rc = PTR_ERR(priv); - - disable: - pci_disable_device(dev); - return rc; + pci_set_drvdata(dev, priv); + return 0; } static void pciserial_remove_one(struct pci_dev *dev) @@ -4156,8 +4119,6 @@ static void pciserial_remove_one(struct pci_dev *dev) struct serial_private *priv = pci_get_drvdata(dev); pciserial_remove_ports(priv); - - pci_disable_device(dev); } #ifdef CONFIG_PM_SLEEP @@ -4538,7 +4499,7 @@ static struct pci_device_id serial_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_bt_2_921600 }, { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI958, - PCI_ANY_ID , PCI_ANY_ID, 0, 0, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b2_8_1152000 }, /* diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c index 658b392d1170..34f05ed78b68 100644 --- a/drivers/tty/serial/8250/8250_pnp.c +++ b/drivers/tty/serial/8250/8250_pnp.c @@ -357,8 +357,8 @@ static const struct pnp_device_id pnp_dev_table[] = { /* Fujitsu Wacom 1FGT Tablet PC device */ { "FUJ02E9", 0 }, /* - * LG C1 EXPRESS DUAL (C1-PB11A3) touch screen (actually a FUJ02E6 in - * disguise) + * LG C1 EXPRESS DUAL (C1-PB11A3) touch screen (actually a FUJ02E6 + * in disguise). */ { "LTS0001", 0 }, /* Rockwell's (PORALiNK) 33600 INT PNP */ @@ -367,12 +367,14 @@ static const struct pnp_device_id pnp_dev_table[] = { { "PNPCXXX", UNKNOWN_DEV }, /* More unknown PnP modems */ { "PNPDXXX", UNKNOWN_DEV }, - /* Winbond CIR port, should not be probed. We should keep track - of it to prevent the legacy serial driver from probing it */ + /* + * Winbond CIR port, should not be probed. We should keep track of + * it to prevent the legacy serial driver from probing it. + */ { "WEC1022", CIR_PORT }, /* - * SMSC IrCC SIR/FIR port, should not be probed by serial driver - * as well so its own driver can bind to it. + * SMSC IrCC SIR/FIR port, should not be probed by serial driver as + * well so its own driver can bind to it. */ { "SMCF010", CIR_PORT }, { "", 0 } @@ -380,35 +382,35 @@ static const struct pnp_device_id pnp_dev_table[] = { MODULE_DEVICE_TABLE(pnp, pnp_dev_table); -static char *modem_names[] = { +static const char *modem_names[] = { "MODEM", "Modem", "modem", "FAX", "Fax", "fax", "56K", "56k", "K56", "33.6", "28.8", "14.4", "33,600", "28,800", "14,400", "33.600", "28.800", "14.400", "33600", "28800", "14400", "V.90", "V.34", "V.32", NULL }; -static int check_name(char *name) +static bool check_name(const char *name) { - char **tmp; + const char **tmp; for (tmp = modem_names; *tmp; tmp++) if (strstr(name, *tmp)) - return 1; + return true; - return 0; + return false; } -static int check_resources(struct pnp_dev *dev) +static bool check_resources(struct pnp_dev *dev) { - resource_size_t base[] = {0x2f8, 0x3f8, 0x2e8, 0x3e8}; - int i; + static const resource_size_t base[] = {0x2f8, 0x3f8, 0x2e8, 0x3e8}; + unsigned int i; for (i = 0; i < ARRAY_SIZE(base); i++) { if (pnp_possible_config(dev, IORESOURCE_IO, base[i], 8)) - return 1; + return true; } - return 0; + return false; } /* @@ -425,8 +427,8 @@ static int check_resources(struct pnp_dev *dev) static int serial_pnp_guess_board(struct pnp_dev *dev) { if (!(check_name(pnp_dev_name(dev)) || - (dev->card && check_name(dev->card->name)))) - return -ENODEV; + (dev->card && check_name(dev->card->name)))) + return -ENODEV; if (check_resources(dev)) return 0; @@ -462,11 +464,11 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) } else return -ENODEV; -#ifdef SERIAL_DEBUG_PNP - printk(KERN_DEBUG - "Setup PNP port: port %x, mem 0x%lx, irq %d, type %d\n", - uart.port.iobase, uart.port.mapbase, uart.port.irq, uart.port.iotype); -#endif + dev_dbg(&dev->dev, + "Setup PNP port: port %lx, mem %pa, irq %d, type %d\n", + uart.port.iobase, &uart.port.mapbase, + uart.port.irq, uart.port.iotype); + if (flags & CIR_PORT) { uart.port.flags |= UPF_FIXED_PORT | UPF_FIXED_TYPE; uart.port.type = PORT_8250_CIR; diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 8d262bce97e4..e213da01a3d7 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -37,6 +37,7 @@ #include <linux/slab.h> #include <linux/uaccess.h> #include <linux/pm_runtime.h> +#include <linux/timer.h> #include <asm/io.h> #include <asm/irq.h> @@ -52,7 +53,7 @@ #define DEBUG_AUTOCONF(fmt...) do { } while (0) #endif -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) /* * Here we define the default xmit fifo size used for each type of UART. @@ -250,9 +251,11 @@ static const struct serial8250_config uart_config[] = { .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, .flags = UART_CAP_FIFO | UART_CAP_AFE, }, -/* tx_loadsz is set to 63-bytes instead of 64-bytes to implement -workaround of errata A-008006 which states that tx_loadsz should be -configured less than Maximum supported fifo bytes */ + /* + * tx_loadsz is set to 63-bytes instead of 64-bytes to implement + * workaround of errata A-008006 which states that tx_loadsz should + * be configured less than Maximum supported fifo bytes. + */ [PORT_16550A_FSL64] = { .name = "16550A_FSL64", .fifo_size = 64, @@ -522,6 +525,20 @@ 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); + + 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); +} + +static void serial8250_em485_handle_start_tx(unsigned long arg); +static void serial8250_em485_handle_stop_tx(unsigned long arg); + void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p) { serial8250_clear_fifos(p); @@ -546,6 +563,73 @@ void serial8250_rpm_put(struct uart_8250_port *p) } EXPORT_SYMBOL_GPL(serial8250_rpm_put); +/** + * serial8250_em485_init() - put uart_8250_port into rs485 emulating + * @p: uart_8250_port port instance + * + * The function is used to start rs485 software emulating on the + * &struct uart_8250_port* @p. Namely, RTS is switched before/after + * transmission. The function is idempotent, so it is safe to call it + * multiple times. + * + * The caller MUST enable interrupt on empty shift register before + * calling serial8250_em485_init(). This interrupt is not a part of + * 8250 standard, but implementation defined. + * + * The function is supposed to be called from .rs485_config callback + * or from any other callback protected with p->port.lock spinlock. + * + * See also serial8250_em485_destroy() + * + * Return 0 - success, -errno - otherwise + */ +int serial8250_em485_init(struct uart_8250_port *p) +{ + if (p->em485 != NULL) + return 0; + + p->em485 = kmalloc(sizeof(struct uart_8250_em485), GFP_ATOMIC); + if (p->em485 == NULL) + return -ENOMEM; + + setup_timer(&p->em485->stop_tx_timer, + serial8250_em485_handle_stop_tx, (unsigned long)p); + setup_timer(&p->em485->start_tx_timer, + serial8250_em485_handle_start_tx, (unsigned long)p); + p->em485->active_timer = NULL; + + serial8250_em485_rts_after_send(p); + + return 0; +} +EXPORT_SYMBOL_GPL(serial8250_em485_init); + +/** + * serial8250_em485_destroy() - put uart_8250_port into normal state + * @p: uart_8250_port port instance + * + * The function is used to stop rs485 software emulating on the + * &struct uart_8250_port* @p. The function is idempotent, so it is safe to + * call it multiple times. + * + * The function is supposed to be called from .rs485_config callback + * or from any other callback protected with p->port.lock spinlock. + * + * See also serial8250_em485_init() + */ +void serial8250_em485_destroy(struct uart_8250_port *p) +{ + if (p->em485 == NULL) + return; + + del_timer(&p->em485->start_tx_timer); + del_timer(&p->em485->stop_tx_timer); + + kfree(p->em485); + p->em485 = NULL; +} +EXPORT_SYMBOL_GPL(serial8250_em485_destroy); + /* * These two wrappers ensure that enable_runtime_pm_tx() can be called more than * once and disable_runtime_pm_tx() will still disable RPM because the fifo is @@ -731,22 +815,16 @@ static int size_fifo(struct uart_8250_port *up) */ static unsigned int autoconfig_read_divisor_id(struct uart_8250_port *p) { - unsigned char old_dll, old_dlm, old_lcr; - unsigned int id; + unsigned char old_lcr; + unsigned int id, old_dl; old_lcr = serial_in(p, UART_LCR); serial_out(p, UART_LCR, UART_LCR_CONF_MODE_A); + old_dl = serial_dl_read(p); + serial_dl_write(p, 0); + id = serial_dl_read(p); + serial_dl_write(p, old_dl); - old_dll = serial_in(p, UART_DLL); - old_dlm = serial_in(p, UART_DLM); - - serial_out(p, UART_DLL, 0); - serial_out(p, UART_DLM, 0); - - id = serial_in(p, UART_DLL) | serial_in(p, UART_DLM) << 8; - - serial_out(p, UART_DLL, old_dll); - serial_out(p, UART_DLM, old_dlm); serial_out(p, UART_LCR, old_lcr); return id; @@ -1238,8 +1316,7 @@ static void autoconfig(struct uart_8250_port *up) out_lock: spin_unlock_irqrestore(&port->lock, flags); if (up->capabilities != old_capabilities) { - printk(KERN_WARNING - "ttyS%d: detected caps %08x should be %08x\n", + pr_warn("ttyS%d: detected caps %08x should be %08x\n", serial_index(port), old_capabilities, up->capabilities); } @@ -1304,7 +1381,69 @@ static void autoconfig_irq(struct uart_8250_port *up) port->irq = (irq > 0) ? irq : 0; } -static inline void __stop_tx(struct uart_8250_port *p) +static void serial8250_stop_rx(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + serial8250_rpm_get(up); + + up->ier &= ~(UART_IER_RLSI | UART_IER_RDI); + up->port.read_status_mask &= ~UART_LSR_DR; + serial_port_out(port, UART_IER, up->ier); + + serial8250_rpm_put(up); +} + +static void __do_stop_tx_rs485(struct uart_8250_port *p) +{ + if (!p->em485) + return; + + serial8250_em485_rts_after_send(p); + /* + * Empty the RX FIFO, we are not interested in anything + * received during the half-duplex transmission. + */ + if (!(p->port.rs485.flags & SER_RS485_RX_DURING_TX)) + serial8250_clear_fifos(p); +} + +static void serial8250_em485_handle_stop_tx(unsigned long arg) +{ + struct uart_8250_port *p = (struct uart_8250_port *)arg; + struct uart_8250_em485 *em485 = p->em485; + unsigned long flags; + + spin_lock_irqsave(&p->port.lock, flags); + if (em485 && + em485->active_timer == &em485->stop_tx_timer) { + __do_stop_tx_rs485(p); + em485->active_timer = NULL; + } + spin_unlock_irqrestore(&p->port.lock, flags); +} + +static void __stop_tx_rs485(struct uart_8250_port *p) +{ + struct uart_8250_em485 *em485 = p->em485; + + if (!em485) + return; + + /* + * __do_stop_tx_rs485 is going to set RTS according to config + * AND flush RX FIFO if required. + */ + if (p->port.rs485.delay_rts_after_send > 0) { + em485->active_timer = &em485->stop_tx_timer; + mod_timer(&em485->stop_tx_timer, jiffies + + p->port.rs485.delay_rts_after_send * HZ / 1000); + } else { + __do_stop_tx_rs485(p); + } +} + +static inline void __do_stop_tx(struct uart_8250_port *p) { if (p->ier & UART_IER_THRI) { p->ier &= ~UART_IER_THRI; @@ -1313,6 +1452,28 @@ static inline void __stop_tx(struct uart_8250_port *p) } } +static inline void __stop_tx(struct uart_8250_port *p) +{ + struct uart_8250_em485 *em485 = p->em485; + + if (em485) { + unsigned char lsr = serial_in(p, UART_LSR); + /* + * To provide required timeing and allow FIFO transfer, + * __stop_tx_rs485 must be called only when both FIFO and + * shift register are empty. It is for device driver to enable + * interrupt on TEMT. + */ + if ((lsr & BOTH_EMPTY) != BOTH_EMPTY) + return; + + del_timer(&em485->start_tx_timer); + em485->active_timer = NULL; + } + __do_stop_tx(p); + __stop_tx_rs485(p); +} + static void serial8250_stop_tx(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); @@ -1330,12 +1491,10 @@ static void serial8250_stop_tx(struct uart_port *port) serial8250_rpm_put(up); } -static void serial8250_start_tx(struct uart_port *port) +static inline void __start_tx(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); - serial8250_rpm_get_tx(up); - if (up->dma && !up->dma->tx_dma(up)) return; @@ -1345,6 +1504,7 @@ static void serial8250_start_tx(struct uart_port *port) if (up->bugs & UART_BUG_TXEN) { unsigned char lsr; + lsr = serial_in(up, UART_LSR); up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; if (lsr & UART_LSR_THRE) @@ -1361,33 +1521,83 @@ static void serial8250_start_tx(struct uart_port *port) } } -static void serial8250_throttle(struct uart_port *port) +static inline void start_tx_rs485(struct uart_port *port) { - port->throttle(port); + struct uart_8250_port *up = up_to_u8250p(port); + struct uart_8250_em485 *em485 = up->em485; + unsigned char mcr; + + if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) + serial8250_stop_rx(&up->port); + + del_timer(&em485->stop_tx_timer); + em485->active_timer = NULL; + + mcr = serial_in(up, UART_MCR); + 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); + + if (up->port.rs485.delay_rts_before_send > 0) { + em485->active_timer = &em485->start_tx_timer; + mod_timer(&em485->start_tx_timer, jiffies + + up->port.rs485.delay_rts_before_send * HZ / 1000); + return; + } + } + + __start_tx(port); } -static void serial8250_unthrottle(struct uart_port *port) +static void serial8250_em485_handle_start_tx(unsigned long arg) { - port->unthrottle(port); + struct uart_8250_port *p = (struct uart_8250_port *)arg; + struct uart_8250_em485 *em485 = p->em485; + unsigned long flags; + + spin_lock_irqsave(&p->port.lock, flags); + if (em485 && + em485->active_timer == &em485->start_tx_timer) { + __start_tx(&p->port); + em485->active_timer = NULL; + } + spin_unlock_irqrestore(&p->port.lock, flags); } -static void serial8250_stop_rx(struct uart_port *port) +static void serial8250_start_tx(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); + struct uart_8250_em485 *em485 = up->em485; - serial8250_rpm_get(up); + serial8250_rpm_get_tx(up); - up->ier &= ~(UART_IER_RLSI | UART_IER_RDI); - up->port.read_status_mask &= ~UART_LSR_DR; - serial_port_out(port, UART_IER, up->ier); + if (em485 && + em485->active_timer == &em485->start_tx_timer) + return; - serial8250_rpm_put(up); + if (em485) + start_tx_rs485(port); + else + __start_tx(port); +} + +static void serial8250_throttle(struct uart_port *port) +{ + port->throttle(port); +} + +static void serial8250_unthrottle(struct uart_port *port) +{ + port->unthrottle(port); } static void serial8250_disable_ms(struct uart_port *port) { - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); + struct uart_8250_port *up = up_to_u8250p(port); /* no MSR capabilities */ if (up->bugs & UART_BUG_NOMSR) @@ -1412,81 +1622,85 @@ static void serial8250_enable_ms(struct uart_port *port) serial8250_rpm_put(up); } +static void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr) +{ + struct uart_port *port = &up->port; + unsigned char ch; + char flag = TTY_NORMAL; + + if (likely(lsr & UART_LSR_DR)) + ch = serial_in(up, UART_RX); + else + /* + * Intel 82571 has a Serial Over Lan device that will + * set UART_LSR_BI without setting UART_LSR_DR when + * it receives a break. To avoid reading from the + * receive buffer without UART_LSR_DR bit set, we + * just force the read character to be 0 + */ + ch = 0; + + port->icount.rx++; + + lsr |= up->lsr_saved_flags; + up->lsr_saved_flags = 0; + + if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) { + if (lsr & UART_LSR_BI) { + lsr &= ~(UART_LSR_FE | UART_LSR_PE); + port->icount.brk++; + /* + * We do the SysRQ and SAK checking + * here because otherwise the break + * may get masked by ignore_status_mask + * or read_status_mask. + */ + if (uart_handle_break(port)) + return; + } else if (lsr & UART_LSR_PE) + port->icount.parity++; + else if (lsr & UART_LSR_FE) + port->icount.frame++; + if (lsr & UART_LSR_OE) + port->icount.overrun++; + + /* + * Mask off conditions which should be ignored. + */ + lsr &= port->read_status_mask; + + if (lsr & UART_LSR_BI) { + DEBUG_INTR("handling break...."); + flag = TTY_BREAK; + } else if (lsr & UART_LSR_PE) + flag = TTY_PARITY; + else if (lsr & UART_LSR_FE) + flag = TTY_FRAME; + } + if (uart_handle_sysrq_char(port, ch)) + return; + + uart_insert_char(port, lsr, UART_LSR_OE, ch, flag); +} + /* * serial8250_rx_chars: processes according to the passed in LSR * value, and returns the remaining LSR bits not handled * by this Rx routine. */ -unsigned char -serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) +unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) { struct uart_port *port = &up->port; - unsigned char ch; int max_count = 256; - char flag; do { - if (likely(lsr & UART_LSR_DR)) - ch = serial_in(up, UART_RX); - else - /* - * Intel 82571 has a Serial Over Lan device that will - * set UART_LSR_BI without setting UART_LSR_DR when - * it receives a break. To avoid reading from the - * receive buffer without UART_LSR_DR bit set, we - * just force the read character to be 0 - */ - ch = 0; - - flag = TTY_NORMAL; - port->icount.rx++; - - lsr |= up->lsr_saved_flags; - up->lsr_saved_flags = 0; - - if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) { - if (lsr & UART_LSR_BI) { - lsr &= ~(UART_LSR_FE | UART_LSR_PE); - port->icount.brk++; - /* - * We do the SysRQ and SAK checking - * here because otherwise the break - * may get masked by ignore_status_mask - * or read_status_mask. - */ - if (uart_handle_break(port)) - goto ignore_char; - } else if (lsr & UART_LSR_PE) - port->icount.parity++; - else if (lsr & UART_LSR_FE) - port->icount.frame++; - if (lsr & UART_LSR_OE) - port->icount.overrun++; - - /* - * Mask off conditions which should be ignored. - */ - lsr &= port->read_status_mask; - - if (lsr & UART_LSR_BI) { - DEBUG_INTR("handling break...."); - flag = TTY_BREAK; - } else if (lsr & UART_LSR_PE) - flag = TTY_PARITY; - else if (lsr & UART_LSR_FE) - flag = TTY_FRAME; - } - if (uart_handle_sysrq_char(port, ch)) - goto ignore_char; - - uart_insert_char(port, lsr, UART_LSR_OE, ch, flag); - -ignore_char: + serial8250_read_char(up, lsr); + if (--max_count == 0) + break; lsr = serial_in(up, UART_LSR); - } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (--max_count > 0)); - spin_unlock(&port->lock); + } while (lsr & (UART_LSR_DR | UART_LSR_BI)); + tty_flip_buffer_push(&port->state->port); - spin_lock(&port->lock); return lsr; } EXPORT_SYMBOL_GPL(serial8250_rx_chars); @@ -1519,11 +1733,9 @@ void serial8250_tx_chars(struct uart_8250_port *up) port->icount.tx++; if (uart_circ_empty(xmit)) break; - if (up->capabilities & UART_CAP_HFIFO) { - if ((serial_port_in(port, UART_LSR) & BOTH_EMPTY) != - BOTH_EMPTY) - break; - } + if ((up->capabilities & UART_CAP_HFIFO) && + (serial_in(up, UART_LSR) & BOTH_EMPTY) != BOTH_EMPTY) + break; } while (--count > 0); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) @@ -1752,6 +1964,7 @@ 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; @@ -1985,23 +2198,23 @@ int serial8250_do_startup(struct uart_port *port) serial8250_set_mctrl(port, port->mctrl); - /* Serial over Lan (SoL) hack: - Intel 8257x Gigabit ethernet chips have a - 16550 emulation, to be used for Serial Over Lan. - Those chips take a longer time than a normal - serial device to signalize that a transmission - data was queued. Due to that, the above test generally - fails. One solution would be to delay the reading of - iir. However, this is not reliable, since the timeout - is variable. So, let's just don't test if we receive - TX irq. This way, we'll never enable UART_BUG_TXEN. + /* + * Serial over Lan (SoL) hack: + * Intel 8257x Gigabit ethernet chips have a 16550 emulation, to be + * used for Serial Over Lan. Those chips take a longer time than a + * normal serial device to signalize that a transmission data was + * queued. Due to that, the above test generally fails. One solution + * would be to delay the reading of iir. However, this is not + * reliable, since the timeout is variable. So, let's just don't + * test if we receive TX irq. This way, we'll never enable + * UART_BUG_TXEN. */ if (up->port.flags & UPF_NO_TXEN_TEST) goto dont_test_tx_en; /* - * Do a quick test to see if we receive an - * interrupt when we enable the TX irq. + * Do a quick test to see if we receive an interrupt when we enable + * the TX irq. */ serial_port_out(port, UART_IER, UART_IER_THRI); lsr = serial_port_in(port, UART_LSR); @@ -2084,8 +2297,12 @@ void serial8250_do_shutdown(struct uart_port *port) /* * Disable interrupts from this port */ + spin_lock_irqsave(&port->lock, flags); up->ier = 0; serial_port_out(port, UART_IER, 0); + spin_unlock_irqrestore(&port->lock, flags); + + synchronize_irq(port->irq); if (up->dma) serial8250_release_dma(up); @@ -2251,9 +2468,9 @@ static void serial8250_set_divisor(struct uart_port *port, unsigned int baud, serial_port_out(port, 0x2, quot_frac); } -static unsigned int -serial8250_get_baud_rate(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) +static unsigned int serial8250_get_baud_rate(struct uart_port *port, + struct ktermios *termios, + struct ktermios *old) { unsigned int tolerance = port->uartclk / 100; @@ -2270,7 +2487,7 @@ serial8250_get_baud_rate(struct uart_port *port, struct ktermios *termios, void serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + struct ktermios *old) { struct uart_8250_port *up = up_to_u8250p(port); unsigned char cval; @@ -2583,8 +2800,7 @@ static int do_get_rxtrig(struct tty_port *port) { struct uart_state *state = container_of(port, struct uart_state, port); struct uart_port *uport = state->uart_port; - struct uart_8250_port *up = - container_of(uport, struct uart_8250_port, port); + struct uart_8250_port *up = up_to_u8250p(uport); if (!(up->capabilities & UART_CAP_FIFO) || uport->fifosize <= 1) return -EINVAL; @@ -2620,8 +2836,7 @@ static int do_set_rxtrig(struct tty_port *port, unsigned char bytes) { struct uart_state *state = container_of(port, struct uart_state, port); struct uart_port *uport = state->uart_port; - struct uart_8250_port *up = - container_of(uport, struct uart_8250_port, port); + struct uart_8250_port *up = up_to_u8250p(uport); int rxtrig; if (!(up->capabilities & UART_CAP_FIFO) || uport->fifosize <= 1 || @@ -2745,8 +2960,7 @@ serial8250_verify_port(struct uart_port *port, struct serial_struct *ser) return 0; } -static const char * -serial8250_type(struct uart_port *port) +static const char *serial8250_type(struct uart_port *port) { int type = port->type; diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c index bab6b3ae2540..1b7bd26555b7 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; }; -#ifdef CONFIG_SERIAL_8250_CONSOLE +#if defined(CONFIG_SERIAL_8250_CONSOLE) && !defined(MODULE) static int __init uniphier_early_console_setup(struct earlycon_device *device, const char *options) { diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index b03cb5175113..64742a086ae3 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -262,7 +262,12 @@ config SERIAL_8250_RSA bool "Support RSA serial ports" depends on SERIAL_8250_EXTENDED help - ::: To be written ::: + Say Y here if you have a IODATA RSA-DV II/S ISA card and + would like to use its >115kbps speeds. + You will need to provide module parameter "probe_rsa", or boot-time + parameter 8250.probe_rsa with I/O addresses of this card then. + + If you don't have such card, or if unsure, say N. config SERIAL_8250_ACORN tristate "Acorn expansion card serial port support" @@ -272,6 +277,30 @@ config SERIAL_8250_ACORN system, say Y to this option. The driver can handle 1, 2, or 3 port cards. If unsure, say N. +config SERIAL_8250_BCM2835AUX + tristate "BCM2835 auxiliar mini UART support" + depends on ARCH_BCM2835 || COMPILE_TEST + depends on SERIAL_8250 && SERIAL_8250_SHARE_IRQ + help + Support for the BCM2835 auxiliar mini UART. + + Features and limitations of the UART are + Registers are similar to 16650 registers, + set bits in the control registers that are unsupported + are ignored and read back as 0 + 7/8 bit operation with 1 start and 1 stop bit + 8 symbols deep fifo for rx and tx + SW controlled RTS and SW readable CTS + Clock rate derived from system clock + Uses 8 times oversampling (compared to 16 times for 16650) + Missing break detection (but break generation) + Missing framing error detection + Missing parity bit + Missing receive time-out interrupt + Missing DCD, DSR, DTR and RI signals + + If unsure, say N. + config SERIAL_8250_FSL bool depends on SERIAL_8250_CONSOLE @@ -295,6 +324,7 @@ config SERIAL_8250_EM config SERIAL_8250_RT288X bool "Ralink RT288x/RT305x/RT3662/RT3883 serial port support" depends on SERIAL_8250 + depends on MIPS || COMPILE_TEST default y if MIPS_ALCHEMY || SOC_RT288X || SOC_RT305X || SOC_RT3883 || SOC_MT7620 help Selecting this option will add support for the alternate register @@ -346,7 +376,7 @@ config SERIAL_8250_LPC18XX serial port, say Y to this option. If unsure, say Y. config SERIAL_8250_MT6577 - bool "Mediatek serial port support" + tristate "Mediatek serial port support" depends on SERIAL_8250 && ARCH_MEDIATEK help If you have a Mediatek based board and want to use the @@ -360,9 +390,10 @@ config SERIAL_8250_UNIPHIER serial ports, say Y to this option. If unsure, say N. config SERIAL_8250_INGENIC - bool "Support for Ingenic SoC serial ports" - depends on OF_FLATTREE - select LIBFDT + tristate "Support for Ingenic SoC serial ports" + depends on SERIAL_8250 + depends on (OF_FLATTREE && SERIAL_8250_CONSOLE) || !SERIAL_EARLYCON + depends on MIPS || COMPILE_TEST help If you have a system using an Ingenic SoC and wish to make use of its UARTs, say Y to this option. If unsure, say N. @@ -378,6 +409,16 @@ config SERIAL_8250_MID present on the UART found on Intel Medfield SOC and various other Intel platforms. +config SERIAL_8250_MOXA + tristate "MOXA SmartIO MUE support" + depends on SERIAL_8250 && PCI + help + Say Y here if you have a Moxa SmartIO MUE multiport serial card. + If unsure, say N. + + This driver can also be built as a module. The module will be called + 8250_moxa. If you want to do that, say M here. + config SERIAL_OF_PLATFORM tristate "Devicetree based probing for 8250 ports" depends on SERIAL_8250 && OF diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile index b9b9bca5b6c3..c9a2d6ed87e9 100644 --- a/drivers/tty/serial/8250/Makefile +++ b/drivers/tty/serial/8250/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o +obj-$(CONFIG_SERIAL_8250_BCM2835AUX) += 8250_bcm2835aux.o obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o obj-$(CONFIG_SERIAL_8250_FOURPORT) += 8250_fourport.o obj-$(CONFIG_SERIAL_8250_ACCENT) += 8250_accent.o @@ -28,6 +29,7 @@ obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o obj-$(CONFIG_SERIAL_8250_UNIPHIER) += 8250_uniphier.o obj-$(CONFIG_SERIAL_8250_INGENIC) += 8250_ingenic.o obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o +obj-$(CONFIG_SERIAL_8250_MOXA) += 8250_moxa.o obj-$(CONFIG_SERIAL_OF_PLATFORM) += 8250_of.o CFLAGS_8250_ingenic.o += -I$(srctree)/scripts/dtc/libfdt diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c index 4d180c9423ef..933c2688dd7e 100644 --- a/drivers/tty/serial/8250/serial_cs.c +++ b/drivers/tty/serial/8250/serial_cs.c @@ -28,7 +28,7 @@ and other provisions required by the GPL. If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the GPL. - + ======================================================================*/ #include <linux/module.h> @@ -257,7 +257,7 @@ static const struct serial_quirk quirks[] = { }; -static int serial_config(struct pcmcia_device * link); +static int serial_config(struct pcmcia_device *link); static void serial_remove(struct pcmcia_device *link) @@ -309,7 +309,7 @@ static int serial_probe(struct pcmcia_device *link) dev_dbg(&link->dev, "serial_attach()\n"); /* Create new serial device */ - info = kzalloc(sizeof (*info), GFP_KERNEL); + info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; info->p_dev = link; @@ -339,7 +339,7 @@ static void serial_detach(struct pcmcia_device *link) /*====================================================================*/ -static int setup_serial(struct pcmcia_device *handle, struct serial_info * info, +static int setup_serial(struct pcmcia_device *handle, struct serial_info *info, unsigned int iobase, int irq) { struct uart_8250_port uart; @@ -441,16 +441,20 @@ static int simple_config(struct pcmcia_device *link) struct serial_info *info = link->priv; int i = -ENODEV, try; - /* First pass: look for a config entry that looks normal. - * Two tries: without IO aliases, then with aliases */ + /* + * First pass: look for a config entry that looks normal. + * Two tries: without IO aliases, then with aliases. + */ link->config_flags |= CONF_AUTO_SET_VPP; for (try = 0; try < 4; try++) if (!pcmcia_loop_config(link, simple_config_check, &try)) goto found_port; - /* Second pass: try to find an entry that isn't picky about - its base address, then try to grab any standard serial port - address, and finally try to get any free port. */ + /* + * Second pass: try to find an entry that isn't picky about + * its base address, then try to grab any standard serial port + * address, and finally try to get any free port. + */ if (!pcmcia_loop_config(link, simple_config_check_notpicky, NULL)) goto found_port; @@ -480,8 +484,10 @@ static int multi_config_check(struct pcmcia_device *p_dev, void *priv_data) if (p_dev->resource[1]->end) return -EINVAL; - /* The quad port cards have bad CIS's, so just look for a - window larger than 8 ports and assume it will be right */ + /* + * The quad port cards have bad CIS's, so just look for a + * window larger than 8 ports and assume it will be right. + */ if (p_dev->resource[0]->end <= 8) return -EINVAL; @@ -527,8 +533,8 @@ static int multi_config(struct pcmcia_device *link) info->multi = 2; if (pcmcia_loop_config(link, multi_config_check_notpicky, &base2)) { - dev_warn(&link->dev, "no usable port range " - "found, giving up\n"); + dev_warn(&link->dev, + "no usable port range found, giving up\n"); return -ENODEV; } } @@ -600,7 +606,7 @@ static int serial_check_for_multi(struct pcmcia_device *p_dev, void *priv_data) } -static int serial_config(struct pcmcia_device * link) +static int serial_config(struct pcmcia_device *link) { struct serial_info *info = link->priv; int i; @@ -623,8 +629,10 @@ static int serial_config(struct pcmcia_device * link) break; } - /* Another check for dual-serial cards: look for either serial or - multifunction cards that ask for appropriate IO port ranges */ + /* + * Another check for dual-serial cards: look for either serial or + * multifunction cards that ask for appropriate IO port ranges. + */ if ((info->multi == 0) && (link->has_func_id) && (link->socket->pcmcia_pfc == 0) && @@ -701,7 +709,7 @@ static const struct pcmcia_device_id serial_ids[] = { PCMCIA_PFC_DEVICE_PROD_ID12(1, "LINKSYS", "PCMLM336", 0xf7cb0b07, 0x7a821b58), PCMCIA_PFC_DEVICE_PROD_ID12(1, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e), PCMCIA_PFC_DEVICE_PROD_ID12(1, "MICRO RESEARCH", "COMBO-L/M-336", 0xb2ced065, 0x3ced0555), - PCMCIA_PFC_DEVICE_PROD_ID12(1, "NEC", "PK-UG-J001" ,0x18df0ba0 ,0x831b1064), + PCMCIA_PFC_DEVICE_PROD_ID12(1, "NEC", "PK-UG-J001", 0x18df0ba0, 0x831b1064), PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Diamonds Modem+Ethernet", 0xc2f80cd, 0x656947b9), PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Hearts Modem+Ethernet", 0xc2f80cd, 0xdc9ba5ed), PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc), @@ -797,30 +805,30 @@ static const struct pcmcia_device_id serial_ids[] = { PCMCIA_DEVICE_CIS_PROD_ID123("ADVANTECH", "COMpad-32/85", "1.0", 0x96913a85, 0x8fbe92ae, 0x0877b627, "cis/COMpad2.cis"), PCMCIA_DEVICE_CIS_PROD_ID2("RS-COM 2P", 0xad20b156, "cis/RS-COM-2P.cis"), PCMCIA_DEVICE_CIS_MANF_CARD(0x0013, 0x0000, "cis/GLOBETROTTER.cis"), - PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL100 1.00.",0x19ca78af,0xf964f42b), - PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL100",0x19ca78af,0x71d98e83), - PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL232 1.00.",0x19ca78af,0x69fb7490), - PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL232",0x19ca78af,0xb6bc0235), - PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.","SERIAL CARD: CF232",0x63f2e0bd,0xb9e175d3), - PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.","SERIAL CARD: CF232-5",0x63f2e0bd,0xfce33442), - PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF232",0x3beb8cf2,0x171e7190), - PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF232-5",0x3beb8cf2,0x20da4262), - PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF428",0x3beb8cf2,0xea5dd57d), - PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF500",0x3beb8cf2,0xd77255fa), - PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: IC232",0x3beb8cf2,0x6a709903), - PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: SL232",0x3beb8cf2,0x18430676), - PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: XL232",0x3beb8cf2,0x6f933767), - PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: CF332",0x3beb8cf2,0x16dc1ba7), - PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL332",0x3beb8cf2,0x19816c41), - PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL385",0x3beb8cf2,0x64112029), - PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4), - PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial+Parallel Port: SP230",0x3beb8cf2,0xdb9e58bc), - PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: CF332",0x3beb8cf2,0x16dc1ba7), - PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL332",0x3beb8cf2,0x19816c41), - PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL385",0x3beb8cf2,0x64112029), - PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4), - PCMCIA_MFC_DEVICE_PROD_ID12(2,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4), - PCMCIA_MFC_DEVICE_PROD_ID12(3,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4), + PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL100 1.00.", 0x19ca78af, 0xf964f42b), + PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL100", 0x19ca78af, 0x71d98e83), + PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL232 1.00.", 0x19ca78af, 0x69fb7490), + PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL232", 0x19ca78af, 0xb6bc0235), + PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.", "SERIAL CARD: CF232", 0x63f2e0bd, 0xb9e175d3), + PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.", "SERIAL CARD: CF232-5", 0x63f2e0bd, 0xfce33442), + PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: CF232", 0x3beb8cf2, 0x171e7190), + PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: CF232-5", 0x3beb8cf2, 0x20da4262), + PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: CF428", 0x3beb8cf2, 0xea5dd57d), + PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: CF500", 0x3beb8cf2, 0xd77255fa), + PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: IC232", 0x3beb8cf2, 0x6a709903), + PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: SL232", 0x3beb8cf2, 0x18430676), + PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: XL232", 0x3beb8cf2, 0x6f933767), + PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial Port: CF332", 0x3beb8cf2, 0x16dc1ba7), + PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial Port: SL332", 0x3beb8cf2, 0x19816c41), + PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial Port: SL385", 0x3beb8cf2, 0x64112029), + PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial Port: SL432", 0x3beb8cf2, 0x1cce7ac4), + PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial+Parallel Port: SP230", 0x3beb8cf2, 0xdb9e58bc), + PCMCIA_MFC_DEVICE_PROD_ID12(1, "Elan", "Serial Port: CF332", 0x3beb8cf2, 0x16dc1ba7), + PCMCIA_MFC_DEVICE_PROD_ID12(1, "Elan", "Serial Port: SL332", 0x3beb8cf2, 0x19816c41), + PCMCIA_MFC_DEVICE_PROD_ID12(1, "Elan", "Serial Port: SL385", 0x3beb8cf2, 0x64112029), + PCMCIA_MFC_DEVICE_PROD_ID12(1, "Elan", "Serial Port: SL432", 0x3beb8cf2, 0x1cce7ac4), + PCMCIA_MFC_DEVICE_PROD_ID12(2, "Elan", "Serial Port: SL432", 0x3beb8cf2, 0x1cce7ac4), + PCMCIA_MFC_DEVICE_PROD_ID12(3, "Elan", "Serial Port: SL432", 0x3beb8cf2, 0x1cce7ac4), PCMCIA_DEVICE_MANF_CARD(0x0279, 0x950b), /* too generic */ /* PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0160, 0x0002), */ diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 39721ec4f415..13d4ed6caac4 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -610,6 +610,7 @@ config SERIAL_UARTLITE_CONSOLE bool "Support for console on Xilinx uartlite serial port" depends on SERIAL_UARTLITE=y select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON help Say Y here if you wish to use a Xilinx uartlite as the system console (the system console is the device which receives all kernel @@ -732,7 +733,7 @@ config SERIAL_IP22_ZILOG_CONSOLE config SERIAL_SH_SCI tristate "SuperH SCI(F) serial port support" - depends on SUPERH || ARCH_SHMOBILE || H8300 || COMPILE_TEST + depends on SUPERH || ARCH_RENESAS || H8300 || COMPILE_TEST select SERIAL_CORE config SERIAL_SH_SCI_NR_UARTS @@ -745,6 +746,12 @@ config SERIAL_SH_SCI_CONSOLE depends on SERIAL_SH_SCI=y select SERIAL_CORE_CONSOLE +config SERIAL_SH_SCI_EARLYCON + bool "Support for early console on SuperH SCI(F)" + depends on SERIAL_SH_SCI=y + select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON + config SERIAL_SH_SCI_DMA bool "DMA support" depends on SERIAL_SH_SCI && DMA_ENGINE @@ -793,17 +800,6 @@ config SERIAL_CORE_CONSOLE config CONSOLE_POLL bool -config SERIAL_68328 - bool "68328 serial support" - depends on M68328 || M68EZ328 || M68VZ328 - help - This driver supports the built-in serial port of the Motorola 68328 - (standard, EZ and VZ varieties). - -config SERIAL_68328_RTS_CTS - bool "Support RTS/CTS on 68328 serial port" - depends on SERIAL_68328 - config SERIAL_MCF bool "Coldfire serial support" depends on COLDFIRE @@ -1606,6 +1602,28 @@ config SERIAL_STM32_CONSOLE depends on SERIAL_STM32=y select SERIAL_CORE_CONSOLE +config SERIAL_MVEBU_UART + bool "Marvell EBU serial port support" + select SERIAL_CORE + help + This driver is for Marvell EBU SoC's UART. If you have a machine + based on the Armada-3700 SoC and wish to use the on-board serial + port, + say 'Y' here. + Otherwise, say 'N'. + +config SERIAL_MVEBU_CONSOLE + bool "Console on Marvell EBU serial port" + depends on SERIAL_MVEBU_UART + select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON + default y + help + Say 'Y' here if you wish to use Armada-3700 UART as the system console. + (the system console is the device which receives all kernel messages + and warnings and which allows logins in single user mode) + Otherwise, say 'N'. + endmenu config SERIAL_MCTRL_GPIO diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index b391c9b31960..8c261adac04e 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -34,7 +34,6 @@ obj-$(CONFIG_SERIAL_MAX3100) += max3100.o obj-$(CONFIG_SERIAL_MAX310X) += max310x.o obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o obj-$(CONFIG_SERIAL_MUX) += mux.o -obj-$(CONFIG_SERIAL_68328) += 68328serial.o obj-$(CONFIG_SERIAL_MCF) += mcf.o obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o obj-$(CONFIG_SERIAL_HS_LPC32XX) += lpc32xx_hs.o @@ -91,6 +90,7 @@ obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR) += digicolor-usart.o obj-$(CONFIG_SERIAL_MEN_Z135) += men_z135_uart.o obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o obj-$(CONFIG_SERIAL_STM32) += stm32-usart.o +obj-$(CONFIG_SERIAL_MVEBU_UART) += mvebu-uart.o # GPIOLIB helpers for modem control lines obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index c0da0ccbbcf5..7c198e0a3178 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -187,7 +187,7 @@ static const u16 pl011_zte_offsets[REG_ARRAY_SIZE] = { [REG_DMACR] = ZX_UART011_DMACR, }; -static struct vendor_data vendor_zte = { +static struct vendor_data vendor_zte __maybe_unused = { .reg_offset = pl011_zte_offsets, .access_32b = true, .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, @@ -420,7 +420,7 @@ static void pl011_dma_probe(struct uart_amba_port *uap) /* Optionally make use of an RX channel as well */ chan = dma_request_slave_channel(dev, "rx"); - if (!chan && plat->dma_rx_param) { + if (!chan && plat && plat->dma_rx_param) { chan = dma_request_channel(mask, plat->dma_filter, plat->dma_rx_param); if (!chan) { @@ -1167,7 +1167,7 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap) /* Disable RX and TX DMA */ while (pl011_read(uap, REG_FR) & UART01x_FR_BUSY) - barrier(); + cpu_relax(); spin_lock_irq(&uap->port.lock); uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE); @@ -1611,7 +1611,7 @@ static void pl011_put_poll_char(struct uart_port *port, container_of(port, struct uart_amba_port, port); while (pl011_read(uap, REG_FR) & UART01x_FR_TXFF) - barrier(); + cpu_relax(); pl011_write(ch, uap, REG_DR); } @@ -1947,6 +1947,8 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, lcr_h |= UART01x_LCRH_PEN; if (!(termios->c_cflag & PARODD)) lcr_h |= UART01x_LCRH_EPS; + if (termios->c_cflag & CMSPAR) + lcr_h |= UART011_LCRH_SPS; } if (uap->fifosize > 1) lcr_h |= UART01x_LCRH_FEN; @@ -2150,7 +2152,7 @@ static void pl011_console_putchar(struct uart_port *port, int ch) container_of(port, struct uart_amba_port, port); while (pl011_read(uap, REG_FR) & UART01x_FR_TXFF) - barrier(); + cpu_relax(); pl011_write(ch, uap, REG_DR); } @@ -2158,7 +2160,7 @@ static void pl011_console_write(struct console *co, const char *s, unsigned int count) { struct uart_amba_port *uap = amba_ports[co->index]; - unsigned int status, old_cr = 0, new_cr; + unsigned int old_cr = 0, new_cr; unsigned long flags; int locked = 1; @@ -2188,9 +2190,8 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) * Finally, wait for transmitter to become empty * and restore the TCR */ - do { - status = pl011_read(uap, REG_FR); - } while (status & UART01x_FR_BUSY); + while (pl011_read(uap, REG_FR) & UART01x_FR_BUSY) + cpu_relax(); if (!uap->vendor->always_enabled) pl011_write(old_cr, uap, REG_CR); @@ -2302,13 +2303,13 @@ static struct console amba_console = { static void pl011_putc(struct uart_port *port, int c) { while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF) - ; + cpu_relax(); if (port->iotype == UPIO_MEM32) writel(c, port->membase + UART01x_DR); else writeb(c, port->membase + UART01x_DR); while (readl(port->membase + UART01x_FR) & UART01x_FR_BUSY) - ; + cpu_relax(); } static void pl011_early_write(struct console *con, const char *s, unsigned n) @@ -2327,7 +2328,6 @@ static int __init pl011_early_console_setup(struct earlycon_device *device, device->con->write = pl011_early_write; return 0; } -EARLYCON_DECLARE(pl011, pl011_early_console_setup); OF_EARLYCON_DECLARE(pl011, "arm,pl011", pl011_early_console_setup); #else diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index 03ebe401fff7..3a1de5c87cb4 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -576,7 +576,6 @@ static int __init arc_early_console_setup(struct earlycon_device *dev, dev->con->write = arc_early_serial_write; return 0; } -EARLYCON_DECLARE(arc_uart, arc_early_console_setup); OF_EARLYCON_DECLARE(arc_uart, "snps,arc-uart", arc_early_console_setup); #endif /* CONFIG_SERIAL_ARC_CONSOLE */ diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 1c0884d8ef32..d9439e6ab719 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -159,8 +159,9 @@ struct atmel_uart_port { u32 rts_high; u32 rts_low; bool ms_irq_enabled; - bool is_usart; /* usart or uart */ - struct timer_list uart_timer; /* uart timer */ + u32 rtor; /* address of receiver timeout register if it exists */ + bool has_hw_timer; + struct timer_list uart_timer; bool suspended; unsigned int pending; @@ -1710,19 +1711,24 @@ static void atmel_get_ip_name(struct uart_port *port) struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); int name = atmel_uart_readl(port, ATMEL_US_NAME); u32 version; - int usart, uart; - /* usart and uart ascii */ - usart = 0x55534152; - uart = 0x44424755; - - atmel_port->is_usart = false; - - if (name == usart) { - dev_dbg(port->dev, "This is usart\n"); - atmel_port->is_usart = true; - } else if (name == uart) { - dev_dbg(port->dev, "This is uart\n"); - atmel_port->is_usart = false; + u32 usart, dbgu_uart, new_uart; + /* ASCII decoding for IP version */ + usart = 0x55534152; /* USAR(T) */ + dbgu_uart = 0x44424755; /* DBGU */ + new_uart = 0x55415254; /* UART */ + + atmel_port->has_hw_timer = false; + + if (name == new_uart) { + dev_dbg(port->dev, "Uart with hw timer"); + atmel_port->has_hw_timer = true; + atmel_port->rtor = ATMEL_UA_RTOR; + } else if (name == usart) { + dev_dbg(port->dev, "Usart\n"); + atmel_port->has_hw_timer = true; + atmel_port->rtor = ATMEL_US_RTOR; + } else if (name == dbgu_uart) { + dev_dbg(port->dev, "Dbgu or uart without hw timer\n"); } else { /* fallback for older SoCs: use version field */ version = atmel_uart_readl(port, ATMEL_US_VERSION); @@ -1730,12 +1736,12 @@ static void atmel_get_ip_name(struct uart_port *port) case 0x302: case 0x10213: dev_dbg(port->dev, "This version is usart\n"); - atmel_port->is_usart = true; + atmel_port->has_hw_timer = true; + atmel_port->rtor = ATMEL_US_RTOR; break; case 0x203: case 0x10202: dev_dbg(port->dev, "This version is uart\n"); - atmel_port->is_usart = false; break; default: dev_err(port->dev, "Not supported ip name nor version, set to uart\n"); @@ -1835,12 +1841,13 @@ static int atmel_startup(struct uart_port *port) if (atmel_use_pdc_rx(port)) { /* set UART timeout */ - if (!atmel_port->is_usart) { + if (!atmel_port->has_hw_timer) { mod_timer(&atmel_port->uart_timer, jiffies + uart_poll_timeout(port)); /* set USART timeout */ } else { - atmel_uart_writel(port, ATMEL_US_RTOR, PDC_RX_TIMEOUT); + atmel_uart_writel(port, atmel_port->rtor, + PDC_RX_TIMEOUT); atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STTTO); atmel_uart_writel(port, ATMEL_US_IER, @@ -1850,12 +1857,13 @@ static int atmel_startup(struct uart_port *port) atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN); } else if (atmel_use_dma_rx(port)) { /* set UART timeout */ - if (!atmel_port->is_usart) { + if (!atmel_port->has_hw_timer) { mod_timer(&atmel_port->uart_timer, jiffies + uart_poll_timeout(port)); /* set USART timeout */ } else { - atmel_uart_writel(port, ATMEL_US_RTOR, PDC_RX_TIMEOUT); + atmel_uart_writel(port, atmel_port->rtor, + PDC_RX_TIMEOUT); atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STTTO); atmel_uart_writel(port, ATMEL_US_IER, @@ -2478,13 +2486,13 @@ static int __init atmel_console_init(void) struct atmel_uart_data *pdata = dev_get_platdata(&atmel_default_console_device->dev); int id = pdata->num; - struct atmel_uart_port *port = &atmel_ports[id]; + struct atmel_uart_port *atmel_port = &atmel_ports[id]; - port->backup_imr = 0; - port->uart.line = id; + atmel_port->backup_imr = 0; + atmel_port->uart.line = id; add_preferred_console(ATMEL_DEVICENAME, id, NULL); - ret = atmel_init_port(port, atmel_default_console_device); + ret = atmel_init_port(atmel_port, atmel_default_console_device); if (ret) return ret; register_console(&atmel_console); @@ -2599,23 +2607,23 @@ static int atmel_serial_resume(struct platform_device *pdev) #define atmel_serial_resume NULL #endif -static void atmel_serial_probe_fifos(struct atmel_uart_port *port, +static void atmel_serial_probe_fifos(struct atmel_uart_port *atmel_port, struct platform_device *pdev) { - port->fifo_size = 0; - port->rts_low = 0; - port->rts_high = 0; + atmel_port->fifo_size = 0; + atmel_port->rts_low = 0; + atmel_port->rts_high = 0; if (of_property_read_u32(pdev->dev.of_node, "atmel,fifo-size", - &port->fifo_size)) + &atmel_port->fifo_size)) return; - if (!port->fifo_size) + if (!atmel_port->fifo_size) return; - if (port->fifo_size < ATMEL_MIN_FIFO_SIZE) { - port->fifo_size = 0; + if (atmel_port->fifo_size < ATMEL_MIN_FIFO_SIZE) { + atmel_port->fifo_size = 0; dev_err(&pdev->dev, "Invalid FIFO size\n"); return; } @@ -2628,22 +2636,22 @@ static void atmel_serial_probe_fifos(struct atmel_uart_port *port, * Threshold to a reasonably high value respecting this 16 data * empirical rule when possible. */ - port->rts_high = max_t(int, port->fifo_size >> 1, - port->fifo_size - ATMEL_RTS_HIGH_OFFSET); - port->rts_low = max_t(int, port->fifo_size >> 2, - port->fifo_size - ATMEL_RTS_LOW_OFFSET); + atmel_port->rts_high = max_t(int, atmel_port->fifo_size >> 1, + atmel_port->fifo_size - ATMEL_RTS_HIGH_OFFSET); + atmel_port->rts_low = max_t(int, atmel_port->fifo_size >> 2, + atmel_port->fifo_size - ATMEL_RTS_LOW_OFFSET); dev_info(&pdev->dev, "Using FIFO (%u data)\n", - port->fifo_size); + atmel_port->fifo_size); dev_dbg(&pdev->dev, "RTS High Threshold : %2u data\n", - port->rts_high); + atmel_port->rts_high); dev_dbg(&pdev->dev, "RTS Low Threshold : %2u data\n", - port->rts_low); + atmel_port->rts_low); } static int atmel_serial_probe(struct platform_device *pdev) { - struct atmel_uart_port *port; + struct atmel_uart_port *atmel_port; struct device_node *np = pdev->dev.of_node; struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev); void *data; @@ -2674,99 +2682,133 @@ static int atmel_serial_probe(struct platform_device *pdev) goto err; } - port = &atmel_ports[ret]; - port->backup_imr = 0; - port->uart.line = ret; - atmel_serial_probe_fifos(port, pdev); + atmel_port = &atmel_ports[ret]; + atmel_port->backup_imr = 0; + atmel_port->uart.line = ret; + atmel_serial_probe_fifos(atmel_port, pdev); - spin_lock_init(&port->lock_suspended); + spin_lock_init(&atmel_port->lock_suspended); - ret = atmel_init_port(port, pdev); + ret = atmel_init_port(atmel_port, pdev); if (ret) goto err_clear_bit; - port->gpios = mctrl_gpio_init(&port->uart, 0); - if (IS_ERR(port->gpios)) { - ret = PTR_ERR(port->gpios); + atmel_port->gpios = mctrl_gpio_init(&atmel_port->uart, 0); + if (IS_ERR(atmel_port->gpios)) { + ret = PTR_ERR(atmel_port->gpios); goto err_clear_bit; } - if (!atmel_use_pdc_rx(&port->uart)) { + if (!atmel_use_pdc_rx(&atmel_port->uart)) { ret = -ENOMEM; data = kmalloc(sizeof(struct atmel_uart_char) * ATMEL_SERIAL_RINGSIZE, GFP_KERNEL); if (!data) goto err_alloc_ring; - port->rx_ring.buf = data; + atmel_port->rx_ring.buf = data; } - rs485_enabled = port->uart.rs485.flags & SER_RS485_ENABLED; + rs485_enabled = atmel_port->uart.rs485.flags & SER_RS485_ENABLED; - ret = uart_add_one_port(&atmel_uart, &port->uart); + ret = uart_add_one_port(&atmel_uart, &atmel_port->uart); if (ret) goto err_add_port; #ifdef CONFIG_SERIAL_ATMEL_CONSOLE - if (atmel_is_console_port(&port->uart) + if (atmel_is_console_port(&atmel_port->uart) && ATMEL_CONSOLE_DEVICE->flags & CON_ENABLED) { /* * The serial core enabled the clock for us, so undo * the clk_prepare_enable() in atmel_console_setup() */ - clk_disable_unprepare(port->clk); + clk_disable_unprepare(atmel_port->clk); } #endif device_init_wakeup(&pdev->dev, 1); - platform_set_drvdata(pdev, port); + platform_set_drvdata(pdev, atmel_port); /* * The peripheral clock has been disabled by atmel_init_port(): * enable it before accessing I/O registers */ - clk_prepare_enable(port->clk); + clk_prepare_enable(atmel_port->clk); if (rs485_enabled) { - atmel_uart_writel(&port->uart, ATMEL_US_MR, + atmel_uart_writel(&atmel_port->uart, ATMEL_US_MR, ATMEL_US_USMODE_NORMAL); - atmel_uart_writel(&port->uart, ATMEL_US_CR, ATMEL_US_RTSEN); + atmel_uart_writel(&atmel_port->uart, ATMEL_US_CR, + ATMEL_US_RTSEN); } /* * Get port name of usart or uart */ - atmel_get_ip_name(&port->uart); + atmel_get_ip_name(&atmel_port->uart); /* * The peripheral clock can now safely be disabled till the port * is used */ - clk_disable_unprepare(port->clk); + clk_disable_unprepare(atmel_port->clk); return 0; err_add_port: - kfree(port->rx_ring.buf); - port->rx_ring.buf = NULL; + kfree(atmel_port->rx_ring.buf); + atmel_port->rx_ring.buf = NULL; err_alloc_ring: - if (!atmel_is_console_port(&port->uart)) { - clk_put(port->clk); - port->clk = NULL; + if (!atmel_is_console_port(&atmel_port->uart)) { + clk_put(atmel_port->clk); + atmel_port->clk = NULL; } err_clear_bit: - clear_bit(port->uart.line, atmel_ports_in_use); + clear_bit(atmel_port->uart.line, atmel_ports_in_use); err: return ret; } +/* + * Even if the driver is not modular, it makes sense to be able to + * unbind a device: there can be many bound devices, and there are + * situations where dynamic binding and unbinding can be useful. + * + * For example, a connected device can require a specific firmware update + * protocol that needs bitbanging on IO lines, but use the regular serial + * port in the normal case. + */ +static int atmel_serial_remove(struct platform_device *pdev) +{ + struct uart_port *port = platform_get_drvdata(pdev); + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + int ret = 0; + + tasklet_kill(&atmel_port->tasklet); + + device_init_wakeup(&pdev->dev, 0); + + ret = uart_remove_one_port(&atmel_uart, port); + + kfree(atmel_port->rx_ring.buf); + + /* "port" is allocated statically, so we shouldn't free it */ + + clear_bit(port->line, atmel_ports_in_use); + + clk_put(atmel_port->clk); + atmel_port->clk = NULL; + + return ret; +} + static struct platform_driver atmel_serial_driver = { .probe = atmel_serial_probe, + .remove = atmel_serial_remove, .suspend = atmel_serial_suspend, .resume = atmel_serial_resume, .driver = { .name = "atmel_usart", .of_match_table = of_match_ptr(atmel_serial_dt_ids), - .suppress_bind_attrs = true, }, }; diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c index b3a4e0cdddaa..5beafd2d2218 100644 --- a/drivers/tty/serial/clps711x.c +++ b/drivers/tty/serial/clps711x.c @@ -450,6 +450,7 @@ static int uart_clps711x_probe(struct platform_device *pdev) struct clps711x_port *s; struct resource *res; struct clk *uart_clk; + int irq; if (index < 0 || index >= UART_CLPS711X_NR) return -EINVAL; @@ -467,12 +468,13 @@ static int uart_clps711x_probe(struct platform_device *pdev) if (IS_ERR(s->port.membase)) return PTR_ERR(s->port.membase); - s->port.irq = platform_get_irq(pdev, 0); - if (IS_ERR_VALUE(s->port.irq)) - return s->port.irq; + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + s->port.irq = irq; s->rx_irq = platform_get_irq(pdev, 1); - if (IS_ERR_VALUE(s->rx_irq)) + if (s->rx_irq < 0) return s->rx_irq; if (!np) { diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index f13f2ebd215b..c0172bf54a9b 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c @@ -1413,9 +1413,8 @@ rs_stop(struct tty_struct *tty) xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->port.tty)); xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, stop); - if (tty->termios.c_iflag & IXON ) { + if (I_IXON(tty)) xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); - } *((unsigned long *)&info->ioport[REG_XOFF]) = xoff; local_irq_restore(flags); @@ -1436,9 +1435,8 @@ rs_start(struct tty_struct *tty) info->xmit.tail,SERIAL_XMIT_SIZE))); xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(tty)); xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable); - if (tty->termios.c_iflag & IXON ) { + if (I_IXON(tty)) xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); - } *((unsigned long *)&info->ioport[REG_XOFF]) = xoff; if (!info->uses_dma_out && @@ -2968,7 +2966,7 @@ static int rs_raw_write(struct tty_struct *tty, local_save_flags(flags); DFLOW(DEBUG_LOG(info->line, "write count %i ", count)); - DFLOW(DEBUG_LOG(info->line, "ldisc %i\n", tty->ldisc.chars_in_buffer(tty))); + DFLOW(DEBUG_LOG(info->line, "ldisc\n")); /* The local_irq_disable/restore_flags pairs below are needed @@ -3161,13 +3159,12 @@ rs_throttle(struct tty_struct * tty) { struct e100_serial *info = (struct e100_serial *)tty->driver_data; #ifdef SERIAL_DEBUG_THROTTLE - printk("throttle %s: %lu....\n", tty_name(tty), - (unsigned long)tty->ldisc.chars_in_buffer(tty)); + printk("throttle %s ....\n", tty_name(tty)); #endif - DFLOW(DEBUG_LOG(info->line,"rs_throttle %lu\n", tty->ldisc.chars_in_buffer(tty))); + DFLOW(DEBUG_LOG(info->line,"rs_throttle\n")); /* Do RTS before XOFF since XOFF might take some time */ - if (tty->termios.c_cflag & CRTSCTS) { + if (C_CRTSCTS(tty)) { /* Turn off RTS line */ e100_rts(info, 0); } @@ -3181,13 +3178,12 @@ rs_unthrottle(struct tty_struct * tty) { struct e100_serial *info = (struct e100_serial *)tty->driver_data; #ifdef SERIAL_DEBUG_THROTTLE - printk("unthrottle %s: %lu....\n", tty_name(tty), - (unsigned long)tty->ldisc.chars_in_buffer(tty)); + printk("unthrottle %s ....\n", tty_name(tty)); #endif - DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc %d\n", tty->ldisc.chars_in_buffer(tty))); + DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc\n")); DFLOW(DEBUG_LOG(info->line,"rs_unthrottle flip.count: %i\n", tty->flip.count)); /* Do RTS before XOFF since XOFF might take some time */ - if (tty->termios.c_cflag & CRTSCTS) { + if (C_CRTSCTS(tty)) { /* Assert RTS line */ e100_rts(info, 1); } @@ -3555,8 +3551,7 @@ rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) change_speed(info); /* Handle turning off CRTSCTS */ - if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios.c_cflag & CRTSCTS)) + if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) rs_start(tty); } @@ -3615,7 +3610,6 @@ rs_close(struct tty_struct *tty, struct file * filp) local_irq_restore(flags); return; } - info->port.flags |= ASYNC_CLOSING; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. @@ -3654,7 +3648,7 @@ rs_close(struct tty_struct *tty, struct file * filp) schedule_timeout_interruptible(info->port.close_delay); wake_up_interruptible(&info->port.open_wait); } - info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + info->port.flags &= ~ASYNC_NORMAL_ACTIVE; local_irq_restore(flags); /* port closed */ @@ -3767,9 +3761,8 @@ block_til_ready(struct tty_struct *tty, struct file * filp, return 0; } - if (tty->termios.c_cflag & CLOCAL) { - do_clocal = 1; - } + if (C_CLOCAL(tty)) + do_clocal = 1; /* * Block waiting for the carrier detect and the line to become diff --git a/drivers/tty/serial/digicolor-usart.c b/drivers/tty/serial/digicolor-usart.c index a80cdad114f3..02ad6953b167 100644 --- a/drivers/tty/serial/digicolor-usart.c +++ b/drivers/tty/serial/digicolor-usart.c @@ -453,7 +453,7 @@ static struct uart_driver digicolor_uart = { static int digicolor_uart_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - int ret, index; + int irq, ret, index; struct digicolor_port *dp; struct resource *res; struct clk *uart_clk; @@ -481,9 +481,10 @@ static int digicolor_uart_probe(struct platform_device *pdev) if (IS_ERR(dp->port.membase)) return PTR_ERR(dp->port.membase); - dp->port.irq = platform_get_irq(pdev, 0); - if (IS_ERR_VALUE(dp->port.irq)) - return dp->port.irq; + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + dp->port.irq = irq; dp->port.iotype = UPIO_MEM; dp->port.uartclk = clk_get_rate(uart_clk); diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c index 3f2423690d01..067783f0523c 100644 --- a/drivers/tty/serial/earlycon.c +++ b/drivers/tty/serial/earlycon.c @@ -19,7 +19,8 @@ #include <linux/io.h> #include <linux/serial_core.h> #include <linux/sizes.h> -#include <linux/mod_devicetable.h> +#include <linux/of.h> +#include <linux/of_fdt.h> #ifdef CONFIG_FIX_EARLYCON_MEM #include <asm/fixmap.h> @@ -28,22 +29,15 @@ #include <asm/serial.h> static struct console early_con = { - .name = "uart", /* 8250 console switch requires this name */ + .name = "uart", /* fixed up at earlycon registration */ .flags = CON_PRINTBUFFER | CON_BOOT, - .index = -1, + .index = 0, }; static struct earlycon_device early_console_dev = { .con = &early_con, }; -extern struct earlycon_id __earlycon_table[]; -static const struct earlycon_id __earlycon_table_sentinel - __used __section(__earlycon_table_end); - -static const struct of_device_id __earlycon_of_table_sentinel - __used __section(__earlycon_of_table_end); - static void __iomem * __init earlycon_map(unsigned long paddr, size_t size) { void __iomem *base; @@ -61,6 +55,39 @@ static void __iomem * __init earlycon_map(unsigned long paddr, size_t size) return base; } +static void __init earlycon_init(struct earlycon_device *device, + const char *name) +{ + struct console *earlycon = device->con; + struct uart_port *port = &device->port; + const char *s; + size_t len; + + /* scan backwards from end of string for first non-numeral */ + for (s = name + strlen(name); + s > name && s[-1] >= '0' && s[-1] <= '9'; + s--) + ; + if (*s) + earlycon->index = simple_strtoul(s, NULL, 10); + len = s - name; + strlcpy(earlycon->name, name, min(len + 1, sizeof(earlycon->name))); + earlycon->data = &early_console_dev; + + if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM16 || + port->iotype == UPIO_MEM32 || port->iotype == UPIO_MEM32BE) + pr_info("%s%d at MMIO%s %pa (options '%s')\n", + earlycon->name, earlycon->index, + (port->iotype == UPIO_MEM) ? "" : + (port->iotype == UPIO_MEM16) ? "16" : + (port->iotype == UPIO_MEM32) ? "32" : "32be", + &port->mapbase, device->options); + else + pr_info("%s%d at I/O port 0x%lx (options '%s')\n", + earlycon->name, earlycon->index, + port->iobase, device->options); +} + static int __init parse_options(struct earlycon_device *device, char *options) { struct uart_port *port = &device->port; @@ -97,19 +124,6 @@ static int __init parse_options(struct earlycon_device *device, char *options) strlcpy(device->options, options, length); } - if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM16 || - port->iotype == UPIO_MEM32 || port->iotype == UPIO_MEM32BE) - pr_info("Early serial console at MMIO%s 0x%llx (options '%s')\n", - (port->iotype == UPIO_MEM) ? "" : - (port->iotype == UPIO_MEM16) ? "16" : - (port->iotype == UPIO_MEM32) ? "32" : "32be", - (unsigned long long)port->mapbase, - device->options); - else - pr_info("Early serial console at I/O port 0x%lx (options '%s')\n", - port->iobase, - device->options); - return 0; } @@ -127,7 +141,7 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match) if (port->mapbase) port->membase = earlycon_map(port->mapbase, 64); - early_console_dev.con->data = &early_console_dev; + earlycon_init(&early_console_dev, match->name); err = match->setup(&early_console_dev, buf); if (err < 0) return err; @@ -166,7 +180,7 @@ int __init setup_earlycon(char *buf) if (early_con.flags & CON_ENABLED) return -EALREADY; - for (match = __earlycon_table; match->name[0]; match++) { + for (match = __earlycon_table; match < __earlycon_table_end; match++) { size_t len = strlen(match->name); if (strncmp(buf, match->name, len)) @@ -204,20 +218,62 @@ static int __init param_setup_earlycon(char *buf) } early_param("earlycon", param_setup_earlycon); -int __init of_setup_earlycon(unsigned long addr, - int (*setup)(struct earlycon_device *, const char *)) +#ifdef CONFIG_OF_EARLY_FLATTREE + +int __init of_setup_earlycon(const struct earlycon_id *match, + unsigned long node, + const char *options) { int err; struct uart_port *port = &early_console_dev.port; + const __be32 *val; + bool big_endian; + u64 addr; spin_lock_init(&port->lock); port->iotype = UPIO_MEM; + addr = of_flat_dt_translate_address(node); + if (addr == OF_BAD_ADDR) { + pr_warn("[%s] bad address\n", match->name); + return -ENXIO; + } port->mapbase = addr; port->uartclk = BASE_BAUD * 16; - port->membase = earlycon_map(addr, SZ_4K); + port->membase = earlycon_map(port->mapbase, SZ_4K); + + val = of_get_flat_dt_prop(node, "reg-offset", NULL); + if (val) + port->mapbase += be32_to_cpu(*val); + val = of_get_flat_dt_prop(node, "reg-shift", NULL); + if (val) + port->regshift = be32_to_cpu(*val); + big_endian = of_get_flat_dt_prop(node, "big-endian", NULL) != NULL || + (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) && + of_get_flat_dt_prop(node, "native-endian", NULL) != NULL); + val = of_get_flat_dt_prop(node, "reg-io-width", NULL); + if (val) { + switch (be32_to_cpu(*val)) { + case 1: + port->iotype = UPIO_MEM; + break; + case 2: + port->iotype = UPIO_MEM16; + break; + case 4: + port->iotype = (big_endian) ? UPIO_MEM32BE : UPIO_MEM32; + break; + default: + pr_warn("[%s] unsupported reg-io-width\n", match->name); + return -EINVAL; + } + } - early_console_dev.con->data = &early_console_dev; - err = setup(&early_console_dev, NULL); + if (options) { + strlcpy(early_console_dev.options, options, + sizeof(early_console_dev.options)); + } + earlycon_init(&early_console_dev, match->name); + err = match->setup(&early_console_dev, options); if (err < 0) return err; if (!early_console_dev.con->write) @@ -227,3 +283,5 @@ int __init of_setup_earlycon(unsigned long addr, register_console(early_console_dev.con); return 0; } + +#endif /* CONFIG_OF_EARLY_FLATTREE */ diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c index 88246f7e435a..2085a6cfa44b 100644 --- a/drivers/tty/serial/ifx6x60.c +++ b/drivers/tty/serial/ifx6x60.c @@ -395,8 +395,10 @@ static int ifx_spi_decode_spi_header(unsigned char *buffer, int *length, if (h1 == 0 && h2 == 0) { *received_cts = 0; + *more = 0; return IFX_SPI_HEADER_0; } else if (h1 == 0xffff && h2 == 0xffff) { + *more = 0; /* spi_slave_cts remains as it was */ return IFX_SPI_HEADER_F; } @@ -688,6 +690,7 @@ static void ifx_spi_complete(void *ctx) ifx_dev->rx_buffer + IFX_SPI_HEADER_OVERHEAD, (size_t)actual_length); } else { + more = 0; dev_dbg(&ifx_dev->spi_dev->dev, "SPI transfer error %d", ifx_dev->spi_msg.status); } diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 9362f54c816c..231e7d5caf6c 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -2166,7 +2166,8 @@ static int imx_serial_port_suspend(struct device *dev) uart_suspend_port(&imx_reg, &sport->port); - return 0; + /* Needed to enable clock in suspend_noirq */ + return clk_prepare(sport->clk_ipg); } static int imx_serial_port_resume(struct device *dev) @@ -2179,6 +2180,8 @@ static int imx_serial_port_resume(struct device *dev) uart_resume_port(&imx_reg, &sport->port); + clk_unprepare(sport->clk_ipg); + return 0; } diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c index 524e86ab3cae..c5ddfe542451 100644 --- a/drivers/tty/serial/jsm/jsm_tty.c +++ b/drivers/tty/serial/jsm/jsm_tty.c @@ -529,7 +529,6 @@ void jsm_input(struct jsm_channel *ch) int data_len; unsigned long lock_flags; int len = 0; - int n = 0; int s = 0; int i = 0; @@ -569,8 +568,7 @@ void jsm_input(struct jsm_channel *ch) *If the device is not open, or CREAD is off, flush *input data and return immediately. */ - if (!tp || - !(tp->termios.c_cflag & CREAD) ) { + if (!tp || !C_CREAD(tp)) { jsm_dbg(READ, &ch->ch_bd->pci_dev, "input. dropping %d bytes on port %d...\n", @@ -598,16 +596,15 @@ void jsm_input(struct jsm_channel *ch) jsm_dbg(READ, &ch->ch_bd->pci_dev, "start 2\n"); len = tty_buffer_request_room(port, data_len); - n = len; /* - * n now contains the most amount of data we can copy, + * len now contains the most amount of data we can copy, * bounded either by the flip buffer size or the amount * of data the card actually has pending... */ - while (n) { + while (len) { s = ((head >= tail) ? head : RQUEUESIZE) - tail; - s = min(s, n); + s = min(s, len); if (s <= 0) break; @@ -638,7 +635,7 @@ void jsm_input(struct jsm_channel *ch) tty_insert_flip_string(port, ch->ch_rqueue + tail, s); } tail += s; - n -= s; + len -= s; /* Flip queue if needed */ tail &= rmask; } diff --git a/drivers/tty/serial/m32r_sio.c b/drivers/tty/serial/m32r_sio.c index 0eeb64f2499c..68765f7c2645 100644 --- a/drivers/tty/serial/m32r_sio.c +++ b/drivers/tty/serial/m32r_sio.c @@ -47,59 +47,26 @@ #define BAUD_RATE 115200 #include <linux/serial_core.h> -#include "m32r_sio.h" #include "m32r_sio_reg.h" -/* - * Debugging. - */ -#if 0 -#define DEBUG_AUTOCONF(fmt...) printk(fmt) -#else -#define DEBUG_AUTOCONF(fmt...) do { } while (0) -#endif - -#if 0 -#define DEBUG_INTR(fmt...) printk(fmt) -#else -#define DEBUG_INTR(fmt...) do { } while (0) -#endif - #define PASS_LIMIT 256 -#define BASE_BAUD 115200 - /* Standard COM flags */ #define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST) -/* - * SERIAL_PORT_DFNS tells us about built-in ports that have no - * standard enumeration mechanism. Platforms that can find all - * serial ports via mechanisms like ACPI or PCI need not supply it. - */ +static const struct { + unsigned int port; + unsigned int irq; +} old_serial_port[] = { #if defined(CONFIG_PLAT_USRV) - -#define SERIAL_PORT_DFNS \ - /* UART CLK PORT IRQ FLAGS */ \ - { 0, BASE_BAUD, 0x3F8, PLD_IRQ_UART0, STD_COM_FLAGS }, /* ttyS0 */ \ - { 0, BASE_BAUD, 0x2F8, PLD_IRQ_UART1, STD_COM_FLAGS }, /* ttyS1 */ - -#else /* !CONFIG_PLAT_USRV */ - -#if defined(CONFIG_SERIAL_M32R_PLDSIO) -#define SERIAL_PORT_DFNS \ - { 0, BASE_BAUD, ((unsigned long)PLD_ESIO0CR), PLD_IRQ_SIO0_RCV, \ - STD_COM_FLAGS }, /* ttyS0 */ + /* PORT IRQ FLAGS */ + { 0x3F8, PLD_IRQ_UART0 }, /* ttyS0 */ + { 0x2F8, PLD_IRQ_UART1 }, /* ttyS1 */ +#elif defined(CONFIG_SERIAL_M32R_PLDSIO) + { ((unsigned long)PLD_ESIO0CR), PLD_IRQ_SIO0_RCV }, /* ttyS0 */ #else -#define SERIAL_PORT_DFNS \ - { 0, BASE_BAUD, M32R_SIO_OFFSET, M32R_IRQ_SIO0_R, \ - STD_COM_FLAGS }, /* ttyS0 */ + { M32R_SIO_OFFSET, M32R_IRQ_SIO0_R }, /* ttyS0 */ #endif - -#endif /* !CONFIG_PLAT_USRV */ - -static struct old_serial_port old_serial_port[] = { - SERIAL_PORT_DFNS }; #define UART_NR ARRAY_SIZE(old_serial_port) @@ -108,19 +75,7 @@ struct uart_sio_port { struct uart_port port; struct timer_list timer; /* "no irq" timer */ struct list_head list; /* ports on this IRQ */ - unsigned short rev; - unsigned char acr; unsigned char ier; - unsigned char lcr; - unsigned char mcr_mask; /* mask of user bits */ - unsigned char mcr_force; /* mask of forced bits */ - unsigned char lsr_break_flag; - - /* - * We provide a per-port pm hook. - */ - void (*pm)(struct uart_port *port, - unsigned int state, unsigned int old); }; struct irq_info { @@ -345,14 +300,8 @@ static void receive_chars(struct uart_sio_port *up, int *status) */ *status &= up->port.read_status_mask; - if (up->port.line == up->port.cons->index) { - /* Recover the break flag from console xmit */ - *status |= up->lsr_break_flag; - up->lsr_break_flag = 0; - } - if (*status & UART_LSR_BI) { - DEBUG_INTR("handling break...."); + pr_debug("handling break....\n"); flag = TTY_BREAK; } else if (*status & UART_LSR_PE) flag = TTY_PARITY; @@ -413,7 +362,7 @@ static void transmit_chars(struct uart_sio_port *up) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&up->port); - DEBUG_INTR("THRE..."); + pr_debug("THRE...\n"); if (uart_circ_empty(xmit)) m32r_sio_stop_tx(&up->port); @@ -425,7 +374,7 @@ static void transmit_chars(struct uart_sio_port *up) static inline void m32r_sio_handle_port(struct uart_sio_port *up, unsigned int status) { - DEBUG_INTR("status = %x...", status); + pr_debug("status = %x...\n", status); if (status & 0x04) receive_chars(up, &status); @@ -453,7 +402,7 @@ static irqreturn_t m32r_sio_interrupt(int irq, void *dev_id) struct list_head *l, *end = NULL; int pass_counter = 0; - DEBUG_INTR("m32r_sio_interrupt(%d)...", irq); + pr_debug("m32r_sio_interrupt(%d)...\n", irq); #ifdef CONFIG_SERIAL_M32R_PLDSIO // if (irq == PLD_IRQ_SIO0_SND) @@ -493,7 +442,7 @@ static irqreturn_t m32r_sio_interrupt(int irq, void *dev_id) spin_unlock(&i->lock); - DEBUG_INTR("end.\n"); + pr_debug("end.\n"); return IRQ_HANDLED; } @@ -782,20 +731,9 @@ static void m32r_sio_set_termios(struct uart_port *port, serial_out(up, UART_IER, up->ier); - up->lcr = cval; /* Save LCR */ spin_unlock_irqrestore(&up->port.lock, flags); } -static void m32r_sio_pm(struct uart_port *port, unsigned int state, - unsigned int oldstate) -{ - struct uart_sio_port *up = - container_of(port, struct uart_sio_port, port); - - if (up->pm) - up->pm(port, state, oldstate); -} - /* * Resource handling. This is complicated by the fact that resources * depend on the port type. Maybe we should be claiming the standard @@ -932,7 +870,6 @@ static struct uart_ops m32r_sio_pops = { .startup = m32r_sio_startup, .shutdown = m32r_sio_shutdown, .set_termios = m32r_sio_set_termios, - .pm = m32r_sio_pm, .release_port = m32r_sio_release_port, .request_port = m32r_sio_request_port, .config_port = m32r_sio_config_port, @@ -951,15 +888,14 @@ static void __init m32r_sio_init_ports(void) return; first = 0; - for (i = 0, up = m32r_sio_ports; i < ARRAY_SIZE(old_serial_port); - i++, up++) { + for (i = 0, up = m32r_sio_ports; i < UART_NR; i++, up++) { up->port.iobase = old_serial_port[i].port; up->port.irq = irq_canonicalize(old_serial_port[i].irq); - up->port.uartclk = old_serial_port[i].baud_base * 16; - up->port.flags = old_serial_port[i].flags; - up->port.membase = old_serial_port[i].iomem_base; - up->port.iotype = old_serial_port[i].io_type; - up->port.regshift = old_serial_port[i].iomem_reg_shift; + up->port.uartclk = BAUD_RATE * 16; + up->port.flags = STD_COM_FLAGS; + up->port.membase = 0; + up->port.iotype = 0; + up->port.regshift = 0; up->port.ops = &m32r_sio_pops; } } @@ -978,9 +914,6 @@ static void __init m32r_sio_register_ports(struct uart_driver *drv) init_timer(&up->timer); up->timer.function = m32r_sio_timeout; - up->mcr_mask = ~0; - up->mcr_force = 0; - uart_add_one_port(drv, &up->port); } } @@ -1112,28 +1045,6 @@ static struct uart_driver m32r_sio_reg = { .cons = M32R_SIO_CONSOLE, }; -/** - * m32r_sio_suspend_port - suspend one serial port - * @line: serial line number - * - * Suspend one serial port. - */ -void m32r_sio_suspend_port(int line) -{ - uart_suspend_port(&m32r_sio_reg, &m32r_sio_ports[line].port); -} - -/** - * m32r_sio_resume_port - resume one serial port - * @line: serial line number - * - * Resume one serial port. - */ -void m32r_sio_resume_port(int line) -{ - uart_resume_port(&m32r_sio_reg, &m32r_sio_ports[line].port); -} - static int __init m32r_sio_init(void) { int ret, i; @@ -1163,8 +1074,5 @@ static void __exit m32r_sio_exit(void) module_init(m32r_sio_init); module_exit(m32r_sio_exit); -EXPORT_SYMBOL(m32r_sio_suspend_port); -EXPORT_SYMBOL(m32r_sio_resume_port); - MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Generic M32R SIO serial driver"); diff --git a/drivers/tty/serial/m32r_sio.h b/drivers/tty/serial/m32r_sio.h deleted file mode 100644 index 8129824496c6..000000000000 --- a/drivers/tty/serial/m32r_sio.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * m32r_sio.h - * - * Driver for M32R serial ports - * - * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. - * Based on drivers/serial/8250.h. - * - * Copyright (C) 2001 Russell King. - * Copyright (C) 2004 Hirokazu Takata <takata at linux-m32r.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include <linux/pci.h> - -struct m32r_sio_probe { - struct module *owner; - int (*pci_init_one)(struct pci_dev *dev); - void (*pci_remove_one)(struct pci_dev *dev); - void (*pnp_init)(void); -}; - -int m32r_sio_register_probe(struct m32r_sio_probe *probe); -void m32r_sio_unregister_probe(struct m32r_sio_probe *probe); -void m32r_sio_get_irq_map(unsigned int *map); -void m32r_sio_suspend_port(int line); -void m32r_sio_resume_port(int line); - -struct old_serial_port { - unsigned int uart; - unsigned int baud_base; - unsigned int port; - unsigned int irq; - unsigned int flags; - unsigned char io_type; - unsigned char __iomem *iomem_base; - unsigned short iomem_reg_shift; -}; - -#define _INLINE_ inline - -#define PROBE_RSA (1 << 0) -#define PROBE_ANY (~0) - -#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index b12a37bd37b6..024445aa0521 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -78,6 +78,7 @@ /* AML_UART_REG5 bits */ #define AML_UART_BAUD_MASK 0x7fffff #define AML_UART_BAUD_USE BIT(23) +#define AML_UART_BAUD_XTAL BIT(24) #define AML_UART_PORT_NUM 6 #define AML_UART_DEV_NAME "ttyAML" @@ -299,7 +300,12 @@ static void meson_uart_change_speed(struct uart_port *port, unsigned long baud) val = readl(port->membase + AML_UART_REG5); val &= ~AML_UART_BAUD_MASK; - val = ((port->uartclk * 10 / (baud * 4) + 5) / 10) - 1; + if (port->uartclk == 24000000) { + val = ((port->uartclk / 3) / baud) - 1; + val |= AML_UART_BAUD_XTAL; + } else { + val = ((port->uartclk * 10 / (baud * 4) + 5) / 10) - 1; + } val |= AML_UART_BAUD_USE; writel(val, port->membase + AML_UART_REG5); } diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c index 8c3e51314470..3970d6a9aaca 100644 --- a/drivers/tty/serial/mpc52xx_uart.c +++ b/drivers/tty/serial/mpc52xx_uart.c @@ -346,7 +346,7 @@ static irqreturn_t mpc52xx_psc_handle_irq(struct uart_port *port) return mpc5xxx_uart_process_int(port); } -static struct psc_ops mpc52xx_psc_ops = { +static const struct psc_ops mpc52xx_psc_ops = { .fifo_init = mpc52xx_psc_fifo_init, .raw_rx_rdy = mpc52xx_psc_raw_rx_rdy, .raw_tx_rdy = mpc52xx_psc_raw_tx_rdy, @@ -376,7 +376,7 @@ static struct psc_ops mpc52xx_psc_ops = { .get_mr1 = mpc52xx_psc_get_mr1, }; -static struct psc_ops mpc5200b_psc_ops = { +static const struct psc_ops mpc5200b_psc_ops = { .fifo_init = mpc52xx_psc_fifo_init, .raw_rx_rdy = mpc52xx_psc_raw_rx_rdy, .raw_tx_rdy = mpc52xx_psc_raw_tx_rdy, @@ -969,7 +969,7 @@ static u8 mpc5125_psc_get_mr1(struct uart_port *port) return in_8(&PSC_5125(port)->mr1); } -static struct psc_ops mpc5125_psc_ops = { +static const struct psc_ops mpc5125_psc_ops = { .fifo_init = mpc5125_psc_fifo_init, .raw_rx_rdy = mpc5125_psc_raw_rx_rdy, .raw_tx_rdy = mpc5125_psc_raw_tx_rdy, @@ -1004,7 +1004,7 @@ static struct psc_ops mpc5125_psc_ops = { .get_mr1 = mpc5125_psc_get_mr1, }; -static struct psc_ops mpc512x_psc_ops = { +static const struct psc_ops mpc512x_psc_ops = { .fifo_init = mpc512x_psc_fifo_init, .raw_rx_rdy = mpc512x_psc_raw_rx_rdy, .raw_tx_rdy = mpc512x_psc_raw_tx_rdy, diff --git a/drivers/tty/serial/mpsc.c b/drivers/tty/serial/mpsc.c index cadfd1cfae2b..4a3021bcc859 100644 --- a/drivers/tty/serial/mpsc.c +++ b/drivers/tty/serial/mpsc.c @@ -137,8 +137,6 @@ struct mpsc_port_info { /* Internal driver state for this ctlr */ u8 ready; u8 rcv_data; - tcflag_t c_iflag; /* save termios->c_iflag */ - tcflag_t c_cflag; /* save termios->c_cflag */ /* Info passed in from platform */ u8 mirror_regs; /* Need to mirror regs? */ @@ -1407,9 +1405,6 @@ static void mpsc_set_termios(struct uart_port *port, struct ktermios *termios, ulong flags; u32 chr_bits, stop_bits, par; - pi->c_iflag = termios->c_iflag; - pi->c_cflag = termios->c_cflag; - switch (termios->c_cflag & CSIZE) { case CS5: chr_bits = MPSC_MPCR_CL_5; @@ -1870,12 +1865,12 @@ static int mpsc_shared_map_regs(struct platform_device *pd) static void mpsc_shared_unmap_regs(void) { - if (!mpsc_shared_regs.mpsc_routing_base) { + if (mpsc_shared_regs.mpsc_routing_base) { iounmap(mpsc_shared_regs.mpsc_routing_base); release_mem_region(mpsc_shared_regs.mpsc_routing_base_p, MPSC_ROUTING_REG_BLOCK_SIZE); } - if (!mpsc_shared_regs.sdma_intr_base) { + if (mpsc_shared_regs.sdma_intr_base) { iounmap(mpsc_shared_regs.sdma_intr_base); release_mem_region(mpsc_shared_regs.sdma_intr_base_p, MPSC_SDMA_INTR_REG_BLOCK_SIZE); @@ -1891,44 +1886,39 @@ static void mpsc_shared_unmap_regs(void) static int mpsc_shared_drv_probe(struct platform_device *dev) { struct mpsc_shared_pdata *pdata; - int rc = -ENODEV; - - if (dev->id == 0) { - rc = mpsc_shared_map_regs(dev); - if (!rc) { - pdata = (struct mpsc_shared_pdata *) - dev_get_platdata(&dev->dev); - - mpsc_shared_regs.MPSC_MRR_m = pdata->mrr_val; - mpsc_shared_regs.MPSC_RCRR_m= pdata->rcrr_val; - mpsc_shared_regs.MPSC_TCRR_m= pdata->tcrr_val; - mpsc_shared_regs.SDMA_INTR_CAUSE_m = - pdata->intr_cause_val; - mpsc_shared_regs.SDMA_INTR_MASK_m = - pdata->intr_mask_val; - - rc = 0; - } - } + int rc; - return rc; + if (dev->id != 0) + return -ENODEV; + + rc = mpsc_shared_map_regs(dev); + if (rc) + return rc; + + pdata = dev_get_platdata(&dev->dev); + + mpsc_shared_regs.MPSC_MRR_m = pdata->mrr_val; + mpsc_shared_regs.MPSC_RCRR_m= pdata->rcrr_val; + mpsc_shared_regs.MPSC_TCRR_m= pdata->tcrr_val; + mpsc_shared_regs.SDMA_INTR_CAUSE_m = pdata->intr_cause_val; + mpsc_shared_regs.SDMA_INTR_MASK_m = pdata->intr_mask_val; + + return 0; } static int mpsc_shared_drv_remove(struct platform_device *dev) { - int rc = -ENODEV; + if (dev->id != 0) + return -ENODEV; - if (dev->id == 0) { - mpsc_shared_unmap_regs(); - mpsc_shared_regs.MPSC_MRR_m = 0; - mpsc_shared_regs.MPSC_RCRR_m = 0; - mpsc_shared_regs.MPSC_TCRR_m = 0; - mpsc_shared_regs.SDMA_INTR_CAUSE_m = 0; - mpsc_shared_regs.SDMA_INTR_MASK_m = 0; - rc = 0; - } + mpsc_shared_unmap_regs(); + mpsc_shared_regs.MPSC_MRR_m = 0; + mpsc_shared_regs.MPSC_RCRR_m = 0; + mpsc_shared_regs.MPSC_TCRR_m = 0; + mpsc_shared_regs.SDMA_INTR_CAUSE_m = 0; + mpsc_shared_regs.SDMA_INTR_MASK_m = 0; - return rc; + return 0; } static struct platform_driver mpsc_shared_driver = { @@ -1979,10 +1969,6 @@ static int mpsc_drv_map_regs(struct mpsc_port_info *pi, pi->sdma_base_p = r->start; } else { mpsc_resource_err("SDMA base"); - if (pi->mpsc_base) { - iounmap(pi->mpsc_base); - pi->mpsc_base = NULL; - } goto err; } @@ -1993,33 +1979,33 @@ static int mpsc_drv_map_regs(struct mpsc_port_info *pi, pi->brg_base_p = r->start; } else { mpsc_resource_err("BRG base"); - if (pi->mpsc_base) { - iounmap(pi->mpsc_base); - pi->mpsc_base = NULL; - } - if (pi->sdma_base) { - iounmap(pi->sdma_base); - pi->sdma_base = NULL; - } goto err; } return 0; err: + if (pi->sdma_base) { + iounmap(pi->sdma_base); + pi->sdma_base = NULL; + } + if (pi->mpsc_base) { + iounmap(pi->mpsc_base); + pi->mpsc_base = NULL; + } return -ENOMEM; } static void mpsc_drv_unmap_regs(struct mpsc_port_info *pi) { - if (!pi->mpsc_base) { + if (pi->mpsc_base) { iounmap(pi->mpsc_base); release_mem_region(pi->mpsc_base_p, MPSC_REG_BLOCK_SIZE); } - if (!pi->sdma_base) { + if (pi->sdma_base) { iounmap(pi->sdma_base); release_mem_region(pi->sdma_base_p, MPSC_SDMA_REG_BLOCK_SIZE); } - if (!pi->brg_base) { + if (pi->brg_base) { iounmap(pi->brg_base); release_mem_region(pi->brg_base_p, MPSC_BRG_REG_BLOCK_SIZE); } @@ -2073,36 +2059,37 @@ static void mpsc_drv_get_platform_data(struct mpsc_port_info *pi, static int mpsc_drv_probe(struct platform_device *dev) { - struct mpsc_port_info *pi; - int rc = -ENODEV; - - pr_debug("mpsc_drv_probe: Adding MPSC %d\n", dev->id); - - if (dev->id < MPSC_NUM_CTLRS) { - pi = &mpsc_ports[dev->id]; - - rc = mpsc_drv_map_regs(pi, dev); - if (!rc) { - mpsc_drv_get_platform_data(pi, dev, dev->id); - pi->port.dev = &dev->dev; - - rc = mpsc_make_ready(pi); - if (!rc) { - spin_lock_init(&pi->tx_lock); - rc = uart_add_one_port(&mpsc_reg, &pi->port); - if (!rc) { - rc = 0; - } else { - mpsc_release_port((struct uart_port *) - pi); - mpsc_drv_unmap_regs(pi); - } - } else { - mpsc_drv_unmap_regs(pi); - } - } - } + struct mpsc_port_info *pi; + int rc; + + dev_dbg(&dev->dev, "mpsc_drv_probe: Adding MPSC %d\n", dev->id); + + if (dev->id >= MPSC_NUM_CTLRS) + return -ENODEV; + + pi = &mpsc_ports[dev->id]; + + rc = mpsc_drv_map_regs(pi, dev); + if (rc) + return rc; + mpsc_drv_get_platform_data(pi, dev, dev->id); + pi->port.dev = &dev->dev; + + rc = mpsc_make_ready(pi); + if (rc) + goto err_unmap; + + spin_lock_init(&pi->tx_lock); + rc = uart_add_one_port(&mpsc_reg, &pi->port); + if (rc) + goto err_relport; + + return 0; +err_relport: + mpsc_release_port(&pi->port); +err_unmap: + mpsc_drv_unmap_regs(pi); return rc; } @@ -2124,19 +2111,22 @@ static int __init mpsc_drv_init(void) memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs)); rc = uart_register_driver(&mpsc_reg); - if (!rc) { - rc = platform_driver_register(&mpsc_shared_driver); - if (!rc) { - rc = platform_driver_register(&mpsc_driver); - if (rc) { - platform_driver_unregister(&mpsc_shared_driver); - uart_unregister_driver(&mpsc_reg); - } - } else { - uart_unregister_driver(&mpsc_reg); - } - } + if (rc) + return rc; + + rc = platform_driver_register(&mpsc_shared_driver); + if (rc) + goto err_unreg_uart; + rc = platform_driver_register(&mpsc_driver); + if (rc) + goto err_unreg_plat; + + return 0; +err_unreg_plat: + platform_driver_unregister(&mpsc_shared_driver); +err_unreg_uart: + uart_unregister_driver(&mpsc_reg); return rc; } device_initcall(mpsc_drv_init); diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index dcde955475dc..96d3ce8dc2dc 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -1478,7 +1478,6 @@ msm_serial_early_console_setup(struct earlycon_device *device, const char *opt) device->con->write = msm_serial_early_write; return 0; } -EARLYCON_DECLARE(msm_serial, msm_serial_early_console_setup); OF_EARLYCON_DECLARE(msm_serial, "qcom,msm-uart", msm_serial_early_console_setup); @@ -1500,7 +1499,6 @@ msm_serial_early_console_setup_dm(struct earlycon_device *device, device->con->write = msm_serial_early_write_dm; return 0; } -EARLYCON_DECLARE(msm_serial_dm, msm_serial_early_console_setup_dm); OF_EARLYCON_DECLARE(msm_serial_dm, "qcom,msm-uartdm", msm_serial_early_console_setup_dm); diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c new file mode 100644 index 000000000000..0ff27818bb87 --- /dev/null +++ b/drivers/tty/serial/mvebu-uart.c @@ -0,0 +1,650 @@ +/* +* *************************************************************************** +* Copyright (C) 2015 Marvell International Ltd. +* *************************************************************************** +* This program is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the Free +* Software Foundation, either version 2 of the License, or any later version. +* +* 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. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* *************************************************************************** +*/ + +#include <linux/clk.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/of_irq.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/serial.h> +#include <linux/serial_core.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> + +/* Register Map */ +#define UART_RBR 0x00 +#define RBR_BRK_DET BIT(15) +#define RBR_FRM_ERR_DET BIT(14) +#define RBR_PAR_ERR_DET BIT(13) +#define RBR_OVR_ERR_DET BIT(12) + +#define UART_TSH 0x04 + +#define UART_CTRL 0x08 +#define CTRL_SOFT_RST BIT(31) +#define CTRL_TXFIFO_RST BIT(15) +#define CTRL_RXFIFO_RST BIT(14) +#define CTRL_ST_MIRR_EN BIT(13) +#define CTRL_LPBK_EN BIT(12) +#define CTRL_SND_BRK_SEQ BIT(11) +#define CTRL_PAR_EN BIT(10) +#define CTRL_TWO_STOP BIT(9) +#define CTRL_TX_HFL_INT BIT(8) +#define CTRL_RX_HFL_INT BIT(7) +#define CTRL_TX_EMP_INT BIT(6) +#define CTRL_TX_RDY_INT BIT(5) +#define CTRL_RX_RDY_INT BIT(4) +#define CTRL_BRK_DET_INT BIT(3) +#define CTRL_FRM_ERR_INT BIT(2) +#define CTRL_PAR_ERR_INT BIT(1) +#define CTRL_OVR_ERR_INT BIT(0) +#define CTRL_RX_INT (CTRL_RX_RDY_INT | CTRL_BRK_DET_INT |\ + CTRL_FRM_ERR_INT | CTRL_PAR_ERR_INT | CTRL_OVR_ERR_INT) + +#define UART_STAT 0x0c +#define STAT_TX_FIFO_EMP BIT(13) +#define STAT_RX_FIFO_EMP BIT(12) +#define STAT_TX_FIFO_FUL BIT(11) +#define STAT_TX_FIFO_HFL BIT(10) +#define STAT_RX_TOGL BIT(9) +#define STAT_RX_FIFO_FUL BIT(8) +#define STAT_RX_FIFO_HFL BIT(7) +#define STAT_TX_EMP BIT(6) +#define STAT_TX_RDY BIT(5) +#define STAT_RX_RDY BIT(4) +#define STAT_BRK_DET BIT(3) +#define STAT_FRM_ERR BIT(2) +#define STAT_PAR_ERR BIT(1) +#define STAT_OVR_ERR BIT(0) +#define STAT_BRK_ERR (STAT_BRK_DET | STAT_FRM_ERR | STAT_FRM_ERR\ + | STAT_PAR_ERR | STAT_OVR_ERR) + +#define UART_BRDV 0x10 + +#define MVEBU_NR_UARTS 1 + +#define MVEBU_UART_TYPE "mvebu-uart" + +static struct uart_port mvebu_uart_ports[MVEBU_NR_UARTS]; + +struct mvebu_uart_data { + struct uart_port *port; + struct clk *clk; +}; + +/* Core UART Driver Operations */ +static unsigned int mvebu_uart_tx_empty(struct uart_port *port) +{ + unsigned long flags; + unsigned int st; + + spin_lock_irqsave(&port->lock, flags); + st = readl(port->membase + UART_STAT); + spin_unlock_irqrestore(&port->lock, flags); + + return (st & STAT_TX_FIFO_EMP) ? TIOCSER_TEMT : 0; +} + +static unsigned int mvebu_uart_get_mctrl(struct uart_port *port) +{ + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; +} + +static void mvebu_uart_set_mctrl(struct uart_port *port, + unsigned int mctrl) +{ +/* + * Even if we do not support configuring the modem control lines, this + * function must be proided to the serial core + */ +} + +static void mvebu_uart_stop_tx(struct uart_port *port) +{ + unsigned int ctl = readl(port->membase + UART_CTRL); + + ctl &= ~CTRL_TX_RDY_INT; + writel(ctl, port->membase + UART_CTRL); +} + +static void mvebu_uart_start_tx(struct uart_port *port) +{ + unsigned int ctl = readl(port->membase + UART_CTRL); + + ctl |= CTRL_TX_RDY_INT; + writel(ctl, port->membase + UART_CTRL); +} + +static void mvebu_uart_stop_rx(struct uart_port *port) +{ + unsigned int ctl = readl(port->membase + UART_CTRL); + + ctl &= ~CTRL_RX_INT; + writel(ctl, port->membase + UART_CTRL); +} + +static void mvebu_uart_break_ctl(struct uart_port *port, int brk) +{ + unsigned int ctl; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + ctl = readl(port->membase + UART_CTRL); + if (brk == -1) + ctl |= CTRL_SND_BRK_SEQ; + else + ctl &= ~CTRL_SND_BRK_SEQ; + writel(ctl, port->membase + UART_CTRL); + spin_unlock_irqrestore(&port->lock, flags); +} + +static void mvebu_uart_rx_chars(struct uart_port *port, unsigned int status) +{ + struct tty_port *tport = &port->state->port; + unsigned char ch = 0; + char flag = 0; + + do { + if (status & STAT_RX_RDY) { + ch = readl(port->membase + UART_RBR); + ch &= 0xff; + flag = TTY_NORMAL; + port->icount.rx++; + + if (status & STAT_PAR_ERR) + port->icount.parity++; + } + + if (status & STAT_BRK_DET) { + port->icount.brk++; + status &= ~(STAT_FRM_ERR | STAT_PAR_ERR); + if (uart_handle_break(port)) + goto ignore_char; + } + + if (status & STAT_OVR_ERR) + port->icount.overrun++; + + if (status & STAT_FRM_ERR) + port->icount.frame++; + + if (uart_handle_sysrq_char(port, ch)) + goto ignore_char; + + if (status & port->ignore_status_mask & STAT_PAR_ERR) + status &= ~STAT_RX_RDY; + + status &= port->read_status_mask; + + if (status & STAT_PAR_ERR) + flag = TTY_PARITY; + + status &= ~port->ignore_status_mask; + + if (status & STAT_RX_RDY) + tty_insert_flip_char(tport, ch, flag); + + if (status & STAT_BRK_DET) + tty_insert_flip_char(tport, 0, TTY_BREAK); + + if (status & STAT_FRM_ERR) + tty_insert_flip_char(tport, 0, TTY_FRAME); + + if (status & STAT_OVR_ERR) + tty_insert_flip_char(tport, 0, TTY_OVERRUN); + +ignore_char: + status = readl(port->membase + UART_STAT); + } while (status & (STAT_RX_RDY | STAT_BRK_DET)); + + tty_flip_buffer_push(tport); +} + +static void mvebu_uart_tx_chars(struct uart_port *port, unsigned int status) +{ + struct circ_buf *xmit = &port->state->xmit; + unsigned int count; + unsigned int st; + + if (port->x_char) { + writel(port->x_char, port->membase + UART_TSH); + port->icount.tx++; + port->x_char = 0; + return; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + mvebu_uart_stop_tx(port); + return; + } + + for (count = 0; count < port->fifosize; count++) { + writel(xmit->buf[xmit->tail], port->membase + UART_TSH); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + + if (uart_circ_empty(xmit)) + break; + + st = readl(port->membase + UART_STAT); + if (st & STAT_TX_FIFO_FUL) + break; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (uart_circ_empty(xmit)) + mvebu_uart_stop_tx(port); +} + +static irqreturn_t mvebu_uart_isr(int irq, void *dev_id) +{ + struct uart_port *port = (struct uart_port *)dev_id; + unsigned int st = readl(port->membase + UART_STAT); + + if (st & (STAT_RX_RDY | STAT_OVR_ERR | STAT_FRM_ERR | STAT_BRK_DET)) + mvebu_uart_rx_chars(port, st); + + if (st & STAT_TX_RDY) + mvebu_uart_tx_chars(port, st); + + return IRQ_HANDLED; +} + +static int mvebu_uart_startup(struct uart_port *port) +{ + int ret; + + writel(CTRL_TXFIFO_RST | CTRL_RXFIFO_RST, + port->membase + UART_CTRL); + udelay(1); + writel(CTRL_RX_INT, port->membase + UART_CTRL); + + ret = request_irq(port->irq, mvebu_uart_isr, port->irqflags, "serial", + port); + if (ret) { + dev_err(port->dev, "failed to request irq\n"); + return ret; + } + + return 0; +} + +static void mvebu_uart_shutdown(struct uart_port *port) +{ + writel(0, port->membase + UART_CTRL); +} + +static void mvebu_uart_set_termios(struct uart_port *port, + struct ktermios *termios, + struct ktermios *old) +{ + unsigned long flags; + unsigned int baud; + + spin_lock_irqsave(&port->lock, flags); + + port->read_status_mask = STAT_RX_RDY | STAT_OVR_ERR | + STAT_TX_RDY | STAT_TX_FIFO_FUL; + + if (termios->c_iflag & INPCK) + port->read_status_mask |= STAT_FRM_ERR | STAT_PAR_ERR; + + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= + STAT_FRM_ERR | STAT_PAR_ERR | STAT_OVR_ERR; + + if ((termios->c_cflag & CREAD) == 0) + port->ignore_status_mask |= STAT_RX_RDY | STAT_BRK_ERR; + + if (old) + tty_termios_copy_hw(termios, old); + + baud = uart_get_baud_rate(port, termios, old, 0, 460800); + uart_update_timeout(port, termios->c_cflag, baud); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *mvebu_uart_type(struct uart_port *port) +{ + return MVEBU_UART_TYPE; +} + +static void mvebu_uart_release_port(struct uart_port *port) +{ + /* Nothing to do here */ +} + +static int mvebu_uart_request_port(struct uart_port *port) +{ + return 0; +} + +#ifdef CONFIG_CONSOLE_POLL +static int mvebu_uart_get_poll_char(struct uart_port *port) +{ + unsigned int st = readl(port->membase + UART_STAT); + + if (!(st & STAT_RX_RDY)) + return NO_POLL_CHAR; + + return readl(port->membase + UART_RBR); +} + +static void mvebu_uart_put_poll_char(struct uart_port *port, unsigned char c) +{ + unsigned int st; + + for (;;) { + st = readl(port->membase + UART_STAT); + + if (!(st & STAT_TX_FIFO_FUL)) + break; + + udelay(1); + } + + writel(c, port->membase + UART_TSH); +} +#endif + +static const struct uart_ops mvebu_uart_ops = { + .tx_empty = mvebu_uart_tx_empty, + .set_mctrl = mvebu_uart_set_mctrl, + .get_mctrl = mvebu_uart_get_mctrl, + .stop_tx = mvebu_uart_stop_tx, + .start_tx = mvebu_uart_start_tx, + .stop_rx = mvebu_uart_stop_rx, + .break_ctl = mvebu_uart_break_ctl, + .startup = mvebu_uart_startup, + .shutdown = mvebu_uart_shutdown, + .set_termios = mvebu_uart_set_termios, + .type = mvebu_uart_type, + .release_port = mvebu_uart_release_port, + .request_port = mvebu_uart_request_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = mvebu_uart_get_poll_char, + .poll_put_char = mvebu_uart_put_poll_char, +#endif +}; + +/* Console Driver Operations */ + +#ifdef CONFIG_SERIAL_MVEBU_CONSOLE +/* Early Console */ +static void mvebu_uart_putc(struct uart_port *port, int c) +{ + unsigned int st; + + for (;;) { + st = readl(port->membase + UART_STAT); + if (!(st & STAT_TX_FIFO_FUL)) + break; + } + + writel(c, port->membase + UART_TSH); + + for (;;) { + st = readl(port->membase + UART_STAT); + if (st & STAT_TX_FIFO_EMP) + break; + } +} + +static void mvebu_uart_putc_early_write(struct console *con, + const char *s, + unsigned n) +{ + struct earlycon_device *dev = con->data; + + uart_console_write(&dev->port, s, n, mvebu_uart_putc); +} + +static int __init +mvebu_uart_early_console_setup(struct earlycon_device *device, + const char *opt) +{ + if (!device->port.membase) + return -ENODEV; + + device->con->write = mvebu_uart_putc_early_write; + + return 0; +} + +EARLYCON_DECLARE(ar3700_uart, mvebu_uart_early_console_setup); +OF_EARLYCON_DECLARE(ar3700_uart, "marvell,armada-3700-uart", + mvebu_uart_early_console_setup); + +static void wait_for_xmitr(struct uart_port *port) +{ + u32 val; + + readl_poll_timeout_atomic(port->membase + UART_STAT, val, + (val & STAT_TX_EMP), 1, 10000); +} + +static void mvebu_uart_console_putchar(struct uart_port *port, int ch) +{ + wait_for_xmitr(port); + writel(ch, port->membase + UART_TSH); +} + +static void mvebu_uart_console_write(struct console *co, const char *s, + unsigned int count) +{ + struct uart_port *port = &mvebu_uart_ports[co->index]; + unsigned long flags; + unsigned int ier; + int locked = 1; + + if (oops_in_progress) + locked = spin_trylock_irqsave(&port->lock, flags); + else + spin_lock_irqsave(&port->lock, flags); + + ier = readl(port->membase + UART_CTRL) & + (CTRL_RX_INT | CTRL_TX_RDY_INT); + writel(0, port->membase + UART_CTRL); + + uart_console_write(port, s, count, mvebu_uart_console_putchar); + + wait_for_xmitr(port); + + if (ier) + writel(ier, port->membase + UART_CTRL); + + if (locked) + spin_unlock_irqrestore(&port->lock, flags); +} + +static int mvebu_uart_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (co->index < 0 || co->index >= MVEBU_NR_UARTS) + return -EINVAL; + + port = &mvebu_uart_ports[co->index]; + + if (!port->mapbase || !port->membase) { + pr_debug("console on ttyMV%i not present\n", co->index); + return -ENODEV; + } + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct uart_driver mvebu_uart_driver; + +static struct console mvebu_uart_console = { + .name = "ttyMV", + .write = mvebu_uart_console_write, + .device = uart_console_device, + .setup = mvebu_uart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &mvebu_uart_driver, +}; + +static int __init mvebu_uart_console_init(void) +{ + register_console(&mvebu_uart_console); + return 0; +} + +console_initcall(mvebu_uart_console_init); + + +#endif /* CONFIG_SERIAL_MVEBU_CONSOLE */ + +static struct uart_driver mvebu_uart_driver = { + .owner = THIS_MODULE, + .driver_name = "mvebu_serial", + .dev_name = "ttyMV", + .nr = MVEBU_NR_UARTS, +#ifdef CONFIG_SERIAL_MVEBU_CONSOLE + .cons = &mvebu_uart_console, +#endif +}; + +static int mvebu_uart_probe(struct platform_device *pdev) +{ + struct resource *reg = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + struct uart_port *port; + struct mvebu_uart_data *data; + int ret; + + if (!reg || !irq) { + dev_err(&pdev->dev, "no registers/irq defined\n"); + return -EINVAL; + } + + port = &mvebu_uart_ports[0]; + + spin_lock_init(&port->lock); + + port->dev = &pdev->dev; + port->type = PORT_MVEBU; + port->ops = &mvebu_uart_ops; + port->regshift = 0; + + port->fifosize = 32; + port->iotype = UPIO_MEM32; + port->flags = UPF_FIXED_PORT; + port->line = 0; /* single port: force line number to 0 */ + + port->irq = irq->start; + port->irqflags = 0; + port->mapbase = reg->start; + + port->membase = devm_ioremap_resource(&pdev->dev, reg); + if (IS_ERR(port->membase)) + return -PTR_ERR(port->membase); + + data = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_uart_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->port = port; + + port->private_data = data; + platform_set_drvdata(pdev, data); + + ret = uart_add_one_port(&mvebu_uart_driver, port); + if (ret) + return ret; + return 0; +} + +static int mvebu_uart_remove(struct platform_device *pdev) +{ + struct mvebu_uart_data *data = platform_get_drvdata(pdev); + + uart_remove_one_port(&mvebu_uart_driver, data->port); + data->port->private_data = NULL; + data->port->mapbase = 0; + return 0; +} + +/* Match table for of_platform binding */ +static const struct of_device_id mvebu_uart_of_match[] = { + { .compatible = "marvell,armada-3700-uart", }, + {} +}; +MODULE_DEVICE_TABLE(of, mvebu_uart_of_match); + +static struct platform_driver mvebu_uart_platform_driver = { + .probe = mvebu_uart_probe, + .remove = mvebu_uart_remove, + .driver = { + .owner = THIS_MODULE, + .name = "mvebu-uart", + .of_match_table = of_match_ptr(mvebu_uart_of_match), + }, +}; + +static int __init mvebu_uart_init(void) +{ + int ret; + + ret = uart_register_driver(&mvebu_uart_driver); + if (ret) + return ret; + + ret = platform_driver_register(&mvebu_uart_platform_driver); + if (ret) + uart_unregister_driver(&mvebu_uart_driver); + + return ret; +} + +static void __exit mvebu_uart_exit(void) +{ + platform_driver_unregister(&mvebu_uart_platform_driver); + uart_unregister_driver(&mvebu_uart_driver); +} + +arch_initcall(mvebu_uart_init); +module_exit(mvebu_uart_exit); + +MODULE_AUTHOR("Wilson Ding <dingwei@marvell.com>"); +MODULE_DESCRIPTION("Marvell Armada-3700 Serial Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index fa49eb1e2fa2..a2a529994ba5 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -1870,7 +1870,7 @@ static struct platform_driver serial_omap_driver = { .probe = serial_omap_probe, .remove = serial_omap_remove, .driver = { - .name = DRIVER_NAME, + .name = OMAP_SERIAL_DRIVER_NAME, .pm = &serial_omap_dev_pm_ops, .of_match_table = of_match_ptr(omap_serial_of_match), }, diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index d72cd736bdc6..ac7f8df54406 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -601,14 +601,21 @@ static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport) { struct uart_port *port = &ourport->port; unsigned int ufcon, ch, flag, ufstat, uerstat; + unsigned int fifocnt = 0; int max_count = port->fifosize; while (max_count-- > 0) { - ufcon = rd_regl(port, S3C2410_UFCON); - ufstat = rd_regl(port, S3C2410_UFSTAT); - - if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0) - break; + /* + * Receive all characters known to be in FIFO + * before reading FIFO level again + */ + if (fifocnt == 0) { + ufstat = rd_regl(port, S3C2410_UFSTAT); + fifocnt = s3c24xx_serial_rx_fifocnt(ourport, ufstat); + if (fifocnt == 0) + break; + } + fifocnt--; uerstat = rd_regl(port, S3C2410_UERSTAT); ch = rd_regb(port, S3C2410_URXH); @@ -623,6 +630,7 @@ static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport) } } else { if (txe) { + ufcon = rd_regl(port, S3C2410_UFCON); ufcon |= S3C2410_UFCON_RESETRX; wr_regl(port, S3C2410_UFCON, ufcon); rx_enabled(port) = 1; @@ -2451,7 +2459,6 @@ static int __init s3c2410_early_console_setup(struct earlycon_device *device, } OF_EARLYCON_DECLARE(s3c2410, "samsung,s3c2410-uart", s3c2410_early_console_setup); -EARLYCON_DECLARE(s3c2410, s3c2410_early_console_setup); /* S3C2412, S3C2440, S3C64xx */ static struct samsung_early_console_data s3c2440_early_console_data = { @@ -2470,9 +2477,6 @@ OF_EARLYCON_DECLARE(s3c2440, "samsung,s3c2440-uart", s3c2440_early_console_setup); OF_EARLYCON_DECLARE(s3c6400, "samsung,s3c6400-uart", s3c2440_early_console_setup); -EARLYCON_DECLARE(s3c2412, s3c2440_early_console_setup); -EARLYCON_DECLARE(s3c2440, s3c2440_early_console_setup); -EARLYCON_DECLARE(s3c6400, s3c2440_early_console_setup); /* S5PV210, EXYNOS */ static struct samsung_early_console_data s5pv210_early_console_data = { @@ -2489,8 +2493,6 @@ OF_EARLYCON_DECLARE(s5pv210, "samsung,s5pv210-uart", s5pv210_early_console_setup); OF_EARLYCON_DECLARE(exynos4210, "samsung,exynos4210-uart", s5pv210_early_console_setup); -EARLYCON_DECLARE(s5pv210, s5pv210_early_console_setup); -EARLYCON_DECLARE(exynos4210, s5pv210_early_console_setup); #endif MODULE_ALIAS("platform:samsung-uart"); diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 13f8d5f70272..025a4264430e 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -196,14 +196,14 @@ * or (IO6) * - only on 75x/76x */ -#define SC16IS7XX_MSR_CTS_BIT (1 << 0) /* CTS */ -#define SC16IS7XX_MSR_DSR_BIT (1 << 1) /* DSR (IO4) +#define SC16IS7XX_MSR_CTS_BIT (1 << 4) /* CTS */ +#define SC16IS7XX_MSR_DSR_BIT (1 << 5) /* DSR (IO4) * - only on 75x/76x */ -#define SC16IS7XX_MSR_RI_BIT (1 << 2) /* RI (IO7) +#define SC16IS7XX_MSR_RI_BIT (1 << 6) /* RI (IO7) * - only on 75x/76x */ -#define SC16IS7XX_MSR_CD_BIT (1 << 3) /* CD (IO6) +#define SC16IS7XX_MSR_CD_BIT (1 << 7) /* CD (IO6) * - only on 75x/76x */ #define SC16IS7XX_MSR_DELTA_MASK 0x0F /* Any of the delta bits! */ @@ -240,7 +240,7 @@ /* IOControl register bits (Only 750/760) */ #define SC16IS7XX_IOCONTROL_LATCH_BIT (1 << 0) /* Enable input latching */ -#define SC16IS7XX_IOCONTROL_GPIO_BIT (1 << 1) /* Enable GPIO[7:4] */ +#define SC16IS7XX_IOCONTROL_MODEM_BIT (1 << 1) /* Enable GPIO[7:4] as modem pins */ #define SC16IS7XX_IOCONTROL_SRESET_BIT (1 << 3) /* Software Reset */ /* EFCR register bits */ @@ -687,7 +687,7 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) case SC16IS7XX_IIR_CTSRTS_SRC: msr = sc16is7xx_port_read(port, SC16IS7XX_MSR_REG); uart_handle_cts_change(port, - !!(msr & SC16IS7XX_MSR_CTS_BIT)); + !!(msr & SC16IS7XX_MSR_DCTS_BIT)); break; case SC16IS7XX_IIR_THRI_SRC: sc16is7xx_handle_tx(port); @@ -761,12 +761,20 @@ static void sc16is7xx_reg_proc(struct kthread_work *ws) memset(&one->config, 0, sizeof(one->config)); spin_unlock_irqrestore(&one->port.lock, irqflags); - if (config.flags & SC16IS7XX_RECONF_MD) + if (config.flags & SC16IS7XX_RECONF_MD) { sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG, SC16IS7XX_MCR_LOOP_BIT, (one->port.mctrl & TIOCM_LOOP) ? SC16IS7XX_MCR_LOOP_BIT : 0); - + sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG, + SC16IS7XX_MCR_RTS_BIT, + (one->port.mctrl & TIOCM_RTS) ? + SC16IS7XX_MCR_RTS_BIT : 0); + sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG, + SC16IS7XX_MCR_DTR_BIT, + (one->port.mctrl & TIOCM_DTR) ? + SC16IS7XX_MCR_DTR_BIT : 0); + } if (config.flags & SC16IS7XX_RECONF_IER) sc16is7xx_port_update(&one->port, SC16IS7XX_IER_REG, config.ier_clear, 0); diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index b1f54ab1818c..a126a603b083 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -171,14 +171,12 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, */ uart_change_speed(tty, state, NULL); - if (init_hw) { - /* - * Setup the RTS and DTR signals once the - * port is open and ready to respond. - */ - if (tty->termios.c_cflag & CBAUD) - uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR); - } + /* + * Setup the RTS and DTR signals once the + * port is open and ready to respond. + */ + if (init_hw && C_BAUD(tty)) + uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR); } /* @@ -240,7 +238,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) if (uart_console(uport) && tty) uport->cons->cflag = tty->termios.c_cflag; - if (!tty || (tty->termios.c_cflag & HUPCL)) + if (!tty || C_HUPCL(tty)) uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS); uart_port_shutdown(port); @@ -485,12 +483,15 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, spin_unlock_irq(&uport->lock); } -static inline int __uart_put_char(struct uart_port *port, - struct circ_buf *circ, unsigned char c) +static int uart_put_char(struct tty_struct *tty, unsigned char c) { + struct uart_state *state = tty->driver_data; + struct uart_port *port = state->uart_port; + struct circ_buf *circ; unsigned long flags; int ret = 0; + circ = &state->xmit; if (!circ->buf) return 0; @@ -504,13 +505,6 @@ static inline int __uart_put_char(struct uart_port *port, return ret; } -static int uart_put_char(struct tty_struct *tty, unsigned char ch) -{ - struct uart_state *state = tty->driver_data; - - return __uart_put_char(state->uart_port, &state->xmit, ch); -} - static void uart_flush_chars(struct tty_struct *tty) { uart_start(tty); @@ -639,7 +633,7 @@ static void uart_throttle(struct tty_struct *tty) if (I_IXOFF(tty)) mask |= UPSTAT_AUTOXOFF; - if (tty->termios.c_cflag & CRTSCTS) + if (C_CRTSCTS(tty)) mask |= UPSTAT_AUTORTS; if (port->status & mask) { @@ -647,11 +641,11 @@ static void uart_throttle(struct tty_struct *tty) mask &= ~port->status; } - if (mask & UPSTAT_AUTOXOFF) - uart_send_xchar(tty, STOP_CHAR(tty)); - if (mask & UPSTAT_AUTORTS) uart_clear_mctrl(port, TIOCM_RTS); + + if (mask & UPSTAT_AUTOXOFF) + uart_send_xchar(tty, STOP_CHAR(tty)); } static void uart_unthrottle(struct tty_struct *tty) @@ -662,7 +656,7 @@ static void uart_unthrottle(struct tty_struct *tty) if (I_IXOFF(tty)) mask |= UPSTAT_AUTOXOFF; - if (tty->termios.c_cflag & CRTSCTS) + if (C_CRTSCTS(tty)) mask |= UPSTAT_AUTORTS; if (port->status & mask) { @@ -670,21 +664,25 @@ static void uart_unthrottle(struct tty_struct *tty) mask &= ~port->status; } - if (mask & UPSTAT_AUTOXOFF) - uart_send_xchar(tty, START_CHAR(tty)); - if (mask & UPSTAT_AUTORTS) uart_set_mctrl(port, TIOCM_RTS); + + if (mask & UPSTAT_AUTOXOFF) + uart_send_xchar(tty, START_CHAR(tty)); } -static void do_uart_get_info(struct tty_port *port, - struct serial_struct *retinfo) +static void uart_get_info(struct tty_port *port, struct serial_struct *retinfo) { struct uart_state *state = container_of(port, struct uart_state, port); struct uart_port *uport = state->uart_port; memset(retinfo, 0, sizeof(*retinfo)); + /* + * Ensure the state we copy is consistent and no hardware changes + * occur as we go + */ + mutex_lock(&port->mutex); retinfo->type = uport->type; retinfo->line = uport->line; retinfo->port = uport->iobase; @@ -703,15 +701,6 @@ static void do_uart_get_info(struct tty_port *port, retinfo->io_type = uport->iotype; retinfo->iomem_reg_shift = uport->regshift; retinfo->iomem_base = (void *)(unsigned long)uport->mapbase; -} - -static void uart_get_info(struct tty_port *port, - struct serial_struct *retinfo) -{ - /* Ensure the state we copy is consistent and no hardware changes - occur as we go */ - mutex_lock(&port->mutex); - do_uart_get_info(port, retinfo); mutex_unlock(&port->mutex); } @@ -719,6 +708,7 @@ static int uart_get_info_user(struct tty_port *port, struct serial_struct __user *retinfo) { struct serial_struct tmp; + uart_get_info(port, &tmp); if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) @@ -1391,8 +1381,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp) uport = state->uart_port; port = &state->port; - - pr_debug("uart_close(%d) called\n", uport ? uport->line : -1); + pr_debug("uart_close(%d) called\n", tty->index); if (!port->count || tty_port_close_start(port, tty, filp) == 0) return; @@ -1434,7 +1423,6 @@ static void uart_close(struct tty_struct *tty, struct file *filp) * Wake up anyone trying to open this port. */ clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); - clear_bit(ASYNCB_CLOSING, &port->flags); spin_unlock_irq(&port->lock); wake_up_interruptible(&port->open_wait); @@ -1510,7 +1498,7 @@ static void uart_hangup(struct tty_struct *tty) struct tty_port *port = &state->port; unsigned long flags; - pr_debug("uart_hangup(%d)\n", state->uart_port->line); + pr_debug("uart_hangup(%d)\n", tty->index); mutex_lock(&port->mutex); if (port->flags & ASYNC_NORMAL_ACTIVE) { @@ -1591,7 +1579,7 @@ static void uart_dtr_rts(struct tty_port *port, int onoff) */ static int uart_open(struct tty_struct *tty, struct file *filp) { - struct uart_driver *drv = (struct uart_driver *)tty->driver->driver_state; + struct uart_driver *drv = tty->driver->driver_state; int retval, line = tty->index; struct uart_state *state = drv->state + line; struct tty_port *port = &state->port; @@ -1633,15 +1621,12 @@ static int uart_open(struct tty_struct *tty, struct file *filp) /* * If we succeeded, wait until the port is ready. */ +err_unlock: mutex_unlock(&port->mutex); if (retval == 0) retval = tty_port_block_til_ready(port, tty, filp); - end: return retval; -err_unlock: - mutex_unlock(&port->mutex); - goto end; } static const char *uart_type(struct uart_port *port) @@ -1700,17 +1685,13 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i) seq_printf(m, " tx:%d rx:%d", uport->icount.tx, uport->icount.rx); if (uport->icount.frame) - seq_printf(m, " fe:%d", - uport->icount.frame); + seq_printf(m, " fe:%d", uport->icount.frame); if (uport->icount.parity) - seq_printf(m, " pe:%d", - uport->icount.parity); + seq_printf(m, " pe:%d", uport->icount.parity); if (uport->icount.brk) - seq_printf(m, " brk:%d", - uport->icount.brk); + seq_printf(m, " brk:%d", uport->icount.brk); if (uport->icount.overrun) - seq_printf(m, " oe:%d", - uport->icount.overrun); + seq_printf(m, " oe:%d", uport->icount.overrun); #define INFOBIT(bit, str) \ if (uport->mctrl & (bit)) \ @@ -1745,8 +1726,7 @@ static int uart_proc_show(struct seq_file *m, void *v) struct uart_driver *drv = ttydrv->driver_state; int i; - seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n", - "", "", ""); + seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n", "", "", ""); for (i = 0; i < drv->nr; i++) uart_line_info(m, drv, i); return 0; @@ -1895,26 +1875,6 @@ uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow) } EXPORT_SYMBOL_GPL(uart_parse_options); -struct baud_rates { - unsigned int rate; - unsigned int cflag; -}; - -static const struct baud_rates baud_rates[] = { - { 921600, B921600 }, - { 460800, B460800 }, - { 230400, B230400 }, - { 115200, B115200 }, - { 57600, B57600 }, - { 38400, B38400 }, - { 19200, B19200 }, - { 9600, B9600 }, - { 4800, B4800 }, - { 2400, B2400 }, - { 1200, B1200 }, - { 0, B38400 } -}; - /** * uart_set_options - setup the serial console parameters * @port: pointer to the serial ports uart_port structure @@ -1930,7 +1890,6 @@ uart_set_options(struct uart_port *port, struct console *co, { struct ktermios termios; static struct ktermios dummy; - int i; /* * Ensure that the serial console lock is initialised @@ -1945,16 +1904,8 @@ uart_set_options(struct uart_port *port, struct console *co, memset(&termios, 0, sizeof(struct ktermios)); - termios.c_cflag = CREAD | HUPCL | CLOCAL; - - /* - * Construct a cflag setting. - */ - for (i = 0; baud_rates[i].rate; i++) - if (baud_rates[i].rate <= baud) - break; - - termios.c_cflag |= baud_rates[i].cflag; + termios.c_cflag |= CREAD | HUPCL | CLOCAL; + tty_termios_encode_baud_rate(&termios, baud, baud); if (bits == 7) termios.c_cflag |= CS7; diff --git a/drivers/tty/serial/serial_ks8695.c b/drivers/tty/serial/serial_ks8695.c index b4decf8787de..57f152394af5 100644 --- a/drivers/tty/serial/serial_ks8695.c +++ b/drivers/tty/serial/serial_ks8695.c @@ -554,7 +554,7 @@ static struct uart_port ks8695uart_ports[SERIAL_KS8695_NR] = { .uartclk = KS8695_CLOCK_RATE * 16, .fifosize = 16, .ops = &ks8695uart_pops, - .flags = ASYNC_BOOT_AUTOCONF, + .flags = UPF_BOOT_AUTOCONF, .line = 0, } }; diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c index 226ad23b136c..02147361eaa9 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.c +++ b/drivers/tty/serial/serial_mctrl_gpio.c @@ -20,6 +20,7 @@ #include <linux/gpio/consumer.h> #include <linux/termios.h> #include <linux/serial_core.h> +#include <linux/module.h> #include "serial_mctrl_gpio.h" @@ -249,3 +250,5 @@ void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios) } } EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms); + +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 4646a9f531ad..0130feb069ae 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -84,6 +84,22 @@ enum SCI_CLKS { SCI_NUM_CLKS }; +/* Bit x set means sampling rate x + 1 is supported */ +#define SCI_SR(x) BIT((x) - 1) +#define SCI_SR_RANGE(x, y) GENMASK((y) - 1, (x) - 1) + +#define SCI_SR_SCIFAB SCI_SR(5) | SCI_SR(7) | SCI_SR(11) | \ + SCI_SR(13) | SCI_SR(16) | SCI_SR(17) | \ + SCI_SR(19) | SCI_SR(27) + +#define min_sr(_port) ffs((_port)->sampling_rate_mask) +#define max_sr(_port) fls((_port)->sampling_rate_mask) + +/* Iterate over all supported sampling rates, from high to low */ +#define for_each_sr(_sr, _port) \ + for ((_sr) = max_sr(_port); (_sr) >= min_sr(_port); (_sr)--) \ + if ((_port)->sampling_rate_mask & SCI_SR((_sr))) + struct sci_port { struct uart_port port; @@ -93,7 +109,7 @@ struct sci_port { unsigned int overrun_mask; unsigned int error_mask; unsigned int error_clear; - unsigned int sampling_rate; + unsigned int sampling_rate_mask; resource_size_t reg_size; /* Break timer */ @@ -637,7 +653,8 @@ static void sci_clear_SCxSR(struct uart_port *port, unsigned int mask) } } -#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE) +#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE) || \ + defined(CONFIG_SERIAL_SH_SCI_EARLYCON) #ifdef CONFIG_CONSOLE_POLL static int sci_poll_get_char(struct uart_port *port) @@ -678,7 +695,8 @@ static void sci_poll_put_char(struct uart_port *port, unsigned char c) serial_port_out(port, SCxTDR, c); sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port)); } -#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */ +#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE || + CONFIG_SERIAL_SH_SCI_EARLYCON */ static void sci_init_pins(struct uart_port *port, unsigned int cflag) { @@ -1902,19 +1920,13 @@ static int sci_sck_calc(struct sci_port *s, unsigned int bps, unsigned int *srr) { unsigned long freq = s->clk_rates[SCI_SCK]; - unsigned int min_sr, max_sr, sr; int err, min_err = INT_MAX; + unsigned int sr; - if (s->sampling_rate) { - /* SCI(F) has a fixed sampling rate */ - min_sr = max_sr = s->sampling_rate / 2; - } else { - /* HSCIF has a variable 1/(8..32) sampling rate */ - min_sr = 8; - max_sr = 32; - } + if (s->port.type != PORT_HSCIF) + freq *= 2; - for (sr = max_sr; sr >= min_sr; sr--) { + for_each_sr(sr, s) { err = DIV_ROUND_CLOSEST(freq, sr) - bps; if (abs(err) >= abs(min_err)) continue; @@ -1935,19 +1947,13 @@ static int sci_brg_calc(struct sci_port *s, unsigned int bps, unsigned long freq, unsigned int *dlr, unsigned int *srr) { - unsigned int min_sr, max_sr, sr, dl; int err, min_err = INT_MAX; + unsigned int sr, dl; - if (s->sampling_rate) { - /* SCIF has a fixed sampling rate */ - min_sr = max_sr = s->sampling_rate / 2; - } else { - /* HSCIF has a variable 1/(8..32) sampling rate */ - min_sr = 8; - max_sr = 32; - } + if (s->port.type != PORT_HSCIF) + freq *= 2; - for (sr = max_sr; sr >= min_sr; sr--) { + for_each_sr(sr, s) { dl = DIV_ROUND_CLOSEST(freq, sr * bps); dl = clamp(dl, 1U, 65535U); @@ -1973,19 +1979,12 @@ static int sci_scbrr_calc(struct sci_port *s, unsigned int bps, unsigned int *brr, unsigned int *srr, unsigned int *cks) { - unsigned int min_sr, max_sr, shift, sr, br, prediv, scrate, c; unsigned long freq = s->clk_rates[SCI_FCK]; + unsigned int sr, br, prediv, scrate, c; int err, min_err = INT_MAX; - if (s->sampling_rate) { - min_sr = max_sr = s->sampling_rate; - shift = 0; - } else { - /* HSCIF has a variable sample rate */ - min_sr = 8; - max_sr = 32; - shift = 1; - } + if (s->port.type != PORT_HSCIF) + freq *= 2; /* * Find the combination of sample rate and clock select with the @@ -2002,10 +2001,10 @@ static int sci_scbrr_calc(struct sci_port *s, unsigned int bps, * (|D - 0.5| / N * (1 + F))| * NOTE: Usually, treat D for 0.5, F is 0 by this calculation. */ - for (sr = max_sr; sr >= min_sr; sr--) { + for_each_sr(sr, s) { for (c = 0; c <= 3; c++) { /* integerized formulas from HSCIF documentation */ - prediv = sr * (1 << (2 * c + shift)); + prediv = sr * (1 << (2 * c + 1)); /* * We need to calculate: @@ -2062,7 +2061,7 @@ static void sci_reset(struct uart_port *port) static void sci_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { - unsigned int baud, smr_val = 0, scr_val = 0, i; + unsigned int baud, smr_val = SCSMR_ASYNC, scr_val = 0, i; unsigned int brr = 255, cks = 0, srr = 15, dl = 0, sccks = 0; unsigned int brr1 = 255, cks1 = 0, srr1 = 15, dl1 = 0; struct sci_port *s = to_sci_port(port); @@ -2096,8 +2095,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, for (i = 0; i < SCI_NUM_CLKS; i++) max_freq = max(max_freq, s->clk_rates[i]); - baud = uart_get_baud_rate(port, termios, old, 0, - max_freq / max(s->sampling_rate, 8U)); + baud = uart_get_baud_rate(port, termios, old, 0, max_freq / min_sr(s)); if (!baud) goto done; @@ -2185,6 +2183,17 @@ done: uart_update_timeout(port, termios->c_cflag, baud); if (best_clk >= 0) { + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) + switch (srr + 1) { + case 5: smr_val |= SCSMR_SRC_5; break; + case 7: smr_val |= SCSMR_SRC_7; break; + case 11: smr_val |= SCSMR_SRC_11; break; + case 13: smr_val |= SCSMR_SRC_13; break; + case 16: smr_val |= SCSMR_SRC_16; break; + case 17: smr_val |= SCSMR_SRC_17; break; + case 19: smr_val |= SCSMR_SRC_19; break; + case 27: smr_val |= SCSMR_SRC_27; break; + } smr_val |= cks; dev_dbg(port->dev, "SCR 0x%x SMR 0x%x BRR %u CKS 0x%x DL %u SRR %u\n", @@ -2200,7 +2209,8 @@ done: } else { /* Don't touch the bit rate configuration */ scr_val = s->cfg->scscr & (SCSCR_CKE1 | SCSCR_CKE0); - smr_val |= serial_port_in(port, SCSMR) & SCSMR_CKS; + smr_val |= serial_port_in(port, SCSMR) & + (SCSMR_CKEDG | SCSMR_SRC_MASK | SCSMR_CKS); dev_dbg(port->dev, "SCR 0x%x SMR 0x%x\n", scr_val, smr_val); serial_port_out(port, SCSCR, scr_val); serial_port_out(port, SCSMR, smr_val); @@ -2232,6 +2242,16 @@ done: scr_val |= s->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0); dev_dbg(port->dev, "SCSCR 0x%x\n", scr_val); serial_port_out(port, SCSCR, scr_val); + if ((srr + 1 == 5) && + (port->type == PORT_SCIFA || port->type == PORT_SCIFB)) { + /* + * In asynchronous mode, when the sampling rate is 1/5, first + * received data may become invalid on some SCIFA and SCIFB. + * To avoid this problem wait more than 1 serial data time (1 + * bit time x serial data number) after setting SCSCR.RE = 1. + */ + udelay(DIV_ROUND_UP(10 * 1000000, baud)); + } #ifdef CONFIG_SERIAL_SH_SCI_DMA /* @@ -2528,37 +2548,37 @@ static int sci_init_single(struct platform_device *dev, port->fifosize = 256; sci_port->overrun_reg = SCxSR; sci_port->overrun_mask = SCIFA_ORER; - sci_port->sampling_rate = 16; + sci_port->sampling_rate_mask = SCI_SR_SCIFAB; break; case PORT_HSCIF: port->fifosize = 128; sci_port->overrun_reg = SCLSR; sci_port->overrun_mask = SCLSR_ORER; - sci_port->sampling_rate = 0; + sci_port->sampling_rate_mask = SCI_SR_RANGE(8, 32); break; case PORT_SCIFA: port->fifosize = 64; sci_port->overrun_reg = SCxSR; sci_port->overrun_mask = SCIFA_ORER; - sci_port->sampling_rate = 16; + sci_port->sampling_rate_mask = SCI_SR_SCIFAB; break; case PORT_SCIF: port->fifosize = 16; if (p->regtype == SCIx_SH7705_SCIF_REGTYPE) { sci_port->overrun_reg = SCxSR; sci_port->overrun_mask = SCIFA_ORER; - sci_port->sampling_rate = 16; + sci_port->sampling_rate_mask = SCI_SR(16); } else { sci_port->overrun_reg = SCLSR; sci_port->overrun_mask = SCLSR_ORER; - sci_port->sampling_rate = 32; + sci_port->sampling_rate_mask = SCI_SR(32); } break; default: port->fifosize = 1; sci_port->overrun_reg = SCxSR; sci_port->overrun_mask = SCI_ORER; - sci_port->sampling_rate = 32; + sci_port->sampling_rate_mask = SCI_SR(32); break; } @@ -2567,7 +2587,7 @@ static int sci_init_single(struct platform_device *dev, * data override the sampling rate for now. */ if (p->sampling_rate) - sci_port->sampling_rate = p->sampling_rate; + sci_port->sampling_rate_mask = SCI_SR(p->sampling_rate); if (!early) { ret = sci_init_clocks(sci_port, &dev->dev); @@ -2632,7 +2652,8 @@ static void sci_cleanup_single(struct sci_port *port) pm_runtime_disable(port->port.dev); } -#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE +#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) || \ + defined(CONFIG_SERIAL_SH_SCI_EARLYCON) static void serial_console_putchar(struct uart_port *port, int ch) { sci_poll_put_char(port, ch); @@ -2652,9 +2673,12 @@ static void serial_console_write(struct console *co, const char *s, int locked = 1; local_irq_save(flags); +#if defined(SUPPORT_SYSRQ) if (port->sysrq) locked = 0; - else if (oops_in_progress) + else +#endif + if (oops_in_progress) locked = spin_trylock(&port->lock); else spin_lock(&port->lock); @@ -2764,7 +2788,7 @@ static inline int sci_probe_earlyprintk(struct platform_device *pdev) #define SCI_CONSOLE NULL -#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */ +#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE || CONFIG_SERIAL_SH_SCI_EARLYCON */ static const char banner[] __initconst = "SuperH (H)SCI(F) driver initialized"; @@ -2998,6 +3022,62 @@ static void __exit sci_exit(void) early_platform_init_buffer("earlyprintk", &sci_driver, early_serial_buf, ARRAY_SIZE(early_serial_buf)); #endif +#ifdef CONFIG_SERIAL_SH_SCI_EARLYCON +static struct __init plat_sci_port port_cfg; + +static int __init early_console_setup(struct earlycon_device *device, + int type) +{ + if (!device->port.membase) + return -ENODEV; + + device->port.serial_in = sci_serial_in; + device->port.serial_out = sci_serial_out; + device->port.type = type; + memcpy(&sci_ports[0].port, &device->port, sizeof(struct uart_port)); + sci_ports[0].cfg = &port_cfg; + sci_ports[0].cfg->type = type; + sci_probe_regmap(sci_ports[0].cfg); + port_cfg.scscr = sci_serial_in(&sci_ports[0].port, SCSCR) | + SCSCR_RE | SCSCR_TE; + sci_serial_out(&sci_ports[0].port, SCSCR, port_cfg.scscr); + + device->con->write = serial_console_write; + return 0; +} +static int __init sci_early_console_setup(struct earlycon_device *device, + const char *opt) +{ + return early_console_setup(device, PORT_SCI); +} +static int __init scif_early_console_setup(struct earlycon_device *device, + const char *opt) +{ + return early_console_setup(device, PORT_SCIF); +} +static int __init scifa_early_console_setup(struct earlycon_device *device, + const char *opt) +{ + return early_console_setup(device, PORT_SCIFA); +} +static int __init scifb_early_console_setup(struct earlycon_device *device, + const char *opt) +{ + return early_console_setup(device, PORT_SCIFB); +} +static int __init hscif_early_console_setup(struct earlycon_device *device, + const char *opt) +{ + return early_console_setup(device, PORT_HSCIF); +} + +OF_EARLYCON_DECLARE(sci, "renesas,sci", sci_early_console_setup); +OF_EARLYCON_DECLARE(scif, "renesas,scif", scif_early_console_setup); +OF_EARLYCON_DECLARE(scifa, "renesas,scifa", scifa_early_console_setup); +OF_EARLYCON_DECLARE(scifb, "renesas,scifb", scifb_early_console_setup); +OF_EARLYCON_DECLARE(hscif, "renesas,hscif", hscif_early_console_setup); +#endif /* CONFIG_SERIAL_SH_SCI_EARLYCON */ + module_init(sci_init); module_exit(sci_exit); diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h index fb1760250421..7a4fa185b93e 100644 --- a/drivers/tty/serial/sh-sci.h +++ b/drivers/tty/serial/sh-sci.h @@ -35,12 +35,27 @@ enum { /* SCSMR (Serial Mode Register) */ +#define SCSMR_C_A BIT(7) /* Communication Mode */ +#define SCSMR_CSYNC BIT(7) /* - Clocked synchronous mode */ +#define SCSMR_ASYNC 0 /* - Asynchronous mode */ #define SCSMR_CHR BIT(6) /* 7-bit Character Length */ #define SCSMR_PE BIT(5) /* Parity Enable */ #define SCSMR_ODD BIT(4) /* Odd Parity */ #define SCSMR_STOP BIT(3) /* Stop Bit Length */ #define SCSMR_CKS 0x0003 /* Clock Select */ +/* Serial Mode Register, SCIFA/SCIFB only bits */ +#define SCSMR_CKEDG BIT(12) /* Transmit/Receive Clock Edge Select */ +#define SCSMR_SRC_MASK 0x0700 /* Sampling Control */ +#define SCSMR_SRC_16 0x0000 /* Sampling rate 1/16 */ +#define SCSMR_SRC_5 0x0100 /* Sampling rate 1/5 */ +#define SCSMR_SRC_7 0x0200 /* Sampling rate 1/7 */ +#define SCSMR_SRC_11 0x0300 /* Sampling rate 1/11 */ +#define SCSMR_SRC_13 0x0400 /* Sampling rate 1/13 */ +#define SCSMR_SRC_17 0x0500 /* Sampling rate 1/17 */ +#define SCSMR_SRC_19 0x0600 /* Sampling rate 1/19 */ +#define SCSMR_SRC_27 0x0700 /* Sampling rate 1/27 */ + /* Serial Control Register, SCIFA/SCIFB only bits */ #define SCSCR_TDRQE BIT(15) /* Tx Data Transfer Request Enable */ #define SCSCR_RDRQE BIT(14) /* Rx Data Transfer Request Enable */ diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c index ef26c4a60be4..18971063f95f 100644 --- a/drivers/tty/serial/sprd_serial.c +++ b/drivers/tty/serial/sprd_serial.c @@ -624,8 +624,6 @@ static int __init sprd_early_console_setup( device->con->write = sprd_early_write; return 0; } - -EARLYCON_DECLARE(sprd_serial, sprd_early_console_setup); OF_EARLYCON_DECLARE(sprd_serial, "sprd,sc9836-uart", sprd_early_console_setup); diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c index b1c6bd3d483f..c9fdfc8bf47f 100644 --- a/drivers/tty/serial/uartlite.c +++ b/drivers/tty/serial/uartlite.c @@ -28,7 +28,7 @@ #define ULITE_NAME "ttyUL" #define ULITE_MAJOR 204 #define ULITE_MINOR 187 -#define ULITE_NR_UARTS 4 +#define ULITE_NR_UARTS 16 /* --------------------------------------------------------------------- * Register definitions @@ -72,7 +72,7 @@ static void uartlite_outbe32(u32 val, void __iomem *addr) iowrite32be(val, addr); } -static struct uartlite_reg_ops uartlite_be = { +static const struct uartlite_reg_ops uartlite_be = { .in = uartlite_inbe32, .out = uartlite_outbe32, }; @@ -87,21 +87,21 @@ static void uartlite_outle32(u32 val, void __iomem *addr) iowrite32(val, addr); } -static struct uartlite_reg_ops uartlite_le = { +static const struct uartlite_reg_ops uartlite_le = { .in = uartlite_inle32, .out = uartlite_outle32, }; static inline u32 uart_in32(u32 offset, struct uart_port *port) { - struct uartlite_reg_ops *reg_ops = port->private_data; + const struct uartlite_reg_ops *reg_ops = port->private_data; return reg_ops->in(port->membase + offset); } static inline void uart_out32(u32 val, u32 offset, struct uart_port *port) { - struct uartlite_reg_ops *reg_ops = port->private_data; + const struct uartlite_reg_ops *reg_ops = port->private_data; reg_ops->out(val, port->membase + offset); } @@ -193,12 +193,15 @@ static int ulite_transmit(struct uart_port *port, int stat) static irqreturn_t ulite_isr(int irq, void *dev_id) { struct uart_port *port = dev_id; - int busy, n = 0; + int stat, busy, n = 0; + unsigned long flags; do { - int stat = uart_in32(ULITE_STATUS, port); + spin_lock_irqsave(&port->lock, flags); + stat = uart_in32(ULITE_STATUS, port); busy = ulite_receive(port, stat); busy |= ulite_transmit(port, stat); + spin_unlock_irqrestore(&port->lock, flags); n++; } while (busy); @@ -259,7 +262,8 @@ static int ulite_startup(struct uart_port *port) { int ret; - ret = request_irq(port->irq, ulite_isr, IRQF_SHARED, "uartlite", port); + ret = request_irq(port->irq, ulite_isr, IRQF_SHARED | IRQF_TRIGGER_RISING, + "uartlite", port); if (ret) return ret; @@ -519,6 +523,47 @@ static int __init ulite_console_init(void) console_initcall(ulite_console_init); +static void early_uartlite_putc(struct uart_port *port, int c) +{ + /* + * Limit how many times we'll spin waiting for TX FIFO status. + * This will prevent lockups if the base address is incorrectly + * set, or any other issue on the UARTLITE. + * This limit is pretty arbitrary, unless we are at about 10 baud + * we'll never timeout on a working UART. + */ + + unsigned retries = 1000000; + /* read status bit - 0x8 offset */ + while (--retries && (readl(port->membase + 8) & (1 << 3))) + ; + + /* Only attempt the iowrite if we didn't timeout */ + /* write to TX_FIFO - 0x4 offset */ + if (retries) + writel(c & 0xff, port->membase + 4); +} + +static void early_uartlite_write(struct console *console, + const char *s, unsigned n) +{ + struct earlycon_device *device = console->data; + uart_console_write(&device->port, s, n, early_uartlite_putc); +} + +static int __init early_uartlite_setup(struct earlycon_device *device, + const char *options) +{ + if (!device->port.membase) + return -ENODEV; + + device->con->write = early_uartlite_write; + return 0; +} +EARLYCON_DECLARE(uartlite, early_uartlite_setup); +OF_EARLYCON_DECLARE(uartlite_b, "xlnx,opb-uartlite-1.00.b", early_uartlite_setup); +OF_EARLYCON_DECLARE(uartlite_a, "xlnx,xps-uartlite-1.00.a", early_uartlite_setup); + #endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */ static struct uart_driver ulite_uart_driver = { diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 009e0dbc12d2..cd46e64c4255 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -50,24 +50,24 @@ module_param(rx_timeout, uint, S_IRUGO); MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255"); /* Register offsets for the UART. */ -#define CDNS_UART_CR_OFFSET 0x00 /* Control Register */ -#define CDNS_UART_MR_OFFSET 0x04 /* Mode Register */ -#define CDNS_UART_IER_OFFSET 0x08 /* Interrupt Enable */ -#define CDNS_UART_IDR_OFFSET 0x0C /* Interrupt Disable */ -#define CDNS_UART_IMR_OFFSET 0x10 /* Interrupt Mask */ -#define CDNS_UART_ISR_OFFSET 0x14 /* Interrupt Status */ -#define CDNS_UART_BAUDGEN_OFFSET 0x18 /* Baud Rate Generator */ -#define CDNS_UART_RXTOUT_OFFSET 0x1C /* RX Timeout */ -#define CDNS_UART_RXWM_OFFSET 0x20 /* RX FIFO Trigger Level */ -#define CDNS_UART_MODEMCR_OFFSET 0x24 /* Modem Control */ -#define CDNS_UART_MODEMSR_OFFSET 0x28 /* Modem Status */ -#define CDNS_UART_SR_OFFSET 0x2C /* Channel Status */ -#define CDNS_UART_FIFO_OFFSET 0x30 /* FIFO */ -#define CDNS_UART_BAUDDIV_OFFSET 0x34 /* Baud Rate Divider */ -#define CDNS_UART_FLOWDEL_OFFSET 0x38 /* Flow Delay */ -#define CDNS_UART_IRRX_PWIDTH_OFFSET 0x3C /* IR Min Received Pulse Width */ -#define CDNS_UART_IRTX_PWIDTH_OFFSET 0x40 /* IR Transmitted pulse Width */ -#define CDNS_UART_TXWM_OFFSET 0x44 /* TX FIFO Trigger Level */ +#define CDNS_UART_CR 0x00 /* Control Register */ +#define CDNS_UART_MR 0x04 /* Mode Register */ +#define CDNS_UART_IER 0x08 /* Interrupt Enable */ +#define CDNS_UART_IDR 0x0C /* Interrupt Disable */ +#define CDNS_UART_IMR 0x10 /* Interrupt Mask */ +#define CDNS_UART_ISR 0x14 /* Interrupt Status */ +#define CDNS_UART_BAUDGEN 0x18 /* Baud Rate Generator */ +#define CDNS_UART_RXTOUT 0x1C /* RX Timeout */ +#define CDNS_UART_RXWM 0x20 /* RX FIFO Trigger Level */ +#define CDNS_UART_MODEMCR 0x24 /* Modem Control */ +#define CDNS_UART_MODEMSR 0x28 /* Modem Status */ +#define CDNS_UART_SR 0x2C /* Channel Status */ +#define CDNS_UART_FIFO 0x30 /* FIFO */ +#define CDNS_UART_BAUDDIV 0x34 /* Baud Rate Divider */ +#define CDNS_UART_FLOWDEL 0x38 /* Flow Delay */ +#define CDNS_UART_IRRX_PWIDTH 0x3C /* IR Min Received Pulse Width */ +#define CDNS_UART_IRTX_PWIDTH 0x40 /* IR Transmitted pulse Width */ +#define CDNS_UART_TXWM 0x44 /* TX FIFO Trigger Level */ /* Control Register Bit Definitions */ #define CDNS_UART_CR_STOPBRK 0x00000100 /* Stop TX break */ @@ -126,6 +126,10 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255"); #define CDNS_UART_IXR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt. */ #define CDNS_UART_IXR_MASK 0x00001FFF /* Valid bit mask */ +#define CDNS_UART_RX_IRQS (CDNS_UART_IXR_PARITY | CDNS_UART_IXR_FRAMING | \ + CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_RXTRIG | \ + CDNS_UART_IXR_TOUT) + /* Goes in read_status_mask for break detection as the HW doesn't do it*/ #define CDNS_UART_IXR_BRK 0x80000000 @@ -172,43 +176,22 @@ struct cdns_uart { #define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \ clk_rate_change_nb); -/** - * cdns_uart_isr - Interrupt handler - * @irq: Irq number - * @dev_id: Id of the port - * - * Return: IRQHANDLED - */ -static irqreturn_t cdns_uart_isr(int irq, void *dev_id) +static void cdns_uart_handle_rx(struct uart_port *port, unsigned int isrstatus) { - struct uart_port *port = (struct uart_port *)dev_id; - unsigned long flags; - unsigned int isrstatus, numbytes; - unsigned int data; - char status = TTY_NORMAL; - - spin_lock_irqsave(&port->lock, flags); - - /* Read the interrupt status register to determine which - * interrupt(s) is/are active. - */ - isrstatus = readl(port->membase + CDNS_UART_ISR_OFFSET); - /* * There is no hardware break detection, so we interpret framing * error with all-zeros data as a break sequence. Most of the time, * there's another non-zero byte at the end of the sequence. */ if (isrstatus & CDNS_UART_IXR_FRAMING) { - while (!(readl(port->membase + CDNS_UART_SR_OFFSET) & + while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_RXEMPTY)) { - if (!readl(port->membase + CDNS_UART_FIFO_OFFSET)) { + if (!readl(port->membase + CDNS_UART_FIFO)) { port->read_status_mask |= CDNS_UART_IXR_BRK; isrstatus &= ~CDNS_UART_IXR_FRAMING; } } - writel(CDNS_UART_IXR_FRAMING, - port->membase + CDNS_UART_ISR_OFFSET); + writel(CDNS_UART_IXR_FRAMING, port->membase + CDNS_UART_ISR); } /* drop byte with parity error if IGNPAR specified */ @@ -218,94 +201,106 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id) isrstatus &= port->read_status_mask; isrstatus &= ~port->ignore_status_mask; - if ((isrstatus & CDNS_UART_IXR_TOUT) || - (isrstatus & CDNS_UART_IXR_RXTRIG)) { - /* Receive Timeout Interrupt */ - while (!(readl(port->membase + CDNS_UART_SR_OFFSET) & - CDNS_UART_SR_RXEMPTY)) { - data = readl(port->membase + CDNS_UART_FIFO_OFFSET); - - /* Non-NULL byte after BREAK is garbage (99%) */ - if (data && (port->read_status_mask & - CDNS_UART_IXR_BRK)) { - port->read_status_mask &= ~CDNS_UART_IXR_BRK; - port->icount.brk++; - if (uart_handle_break(port)) - continue; - } + if (!(isrstatus & (CDNS_UART_IXR_TOUT | CDNS_UART_IXR_RXTRIG))) + return; -#ifdef SUPPORT_SYSRQ - /* - * uart_handle_sysrq_char() doesn't work if - * spinlocked, for some reason - */ - if (port->sysrq) { - spin_unlock(&port->lock); - if (uart_handle_sysrq_char(port, - (unsigned char)data)) { - spin_lock(&port->lock); - continue; - } - spin_lock(&port->lock); - } -#endif + while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_RXEMPTY)) { + u32 data; + char status = TTY_NORMAL; - port->icount.rx++; + data = readl(port->membase + CDNS_UART_FIFO); - if (isrstatus & CDNS_UART_IXR_PARITY) { - port->icount.parity++; - status = TTY_PARITY; - } else if (isrstatus & CDNS_UART_IXR_FRAMING) { - port->icount.frame++; - status = TTY_FRAME; - } else if (isrstatus & CDNS_UART_IXR_OVERRUN) { - port->icount.overrun++; - } + /* Non-NULL byte after BREAK is garbage (99%) */ + if (data && (port->read_status_mask & CDNS_UART_IXR_BRK)) { + port->read_status_mask &= ~CDNS_UART_IXR_BRK; + port->icount.brk++; + if (uart_handle_break(port)) + continue; + } + + if (uart_handle_sysrq_char(port, data)) + continue; + + port->icount.rx++; - uart_insert_char(port, isrstatus, CDNS_UART_IXR_OVERRUN, - data, status); + if (isrstatus & CDNS_UART_IXR_PARITY) { + port->icount.parity++; + status = TTY_PARITY; + } else if (isrstatus & CDNS_UART_IXR_FRAMING) { + port->icount.frame++; + status = TTY_FRAME; + } else if (isrstatus & CDNS_UART_IXR_OVERRUN) { + port->icount.overrun++; } - spin_unlock(&port->lock); - tty_flip_buffer_push(&port->state->port); - spin_lock(&port->lock); + + uart_insert_char(port, isrstatus, CDNS_UART_IXR_OVERRUN, + data, status); } + tty_flip_buffer_push(&port->state->port); +} - /* Dispatch an appropriate handler */ - if ((isrstatus & CDNS_UART_IXR_TXEMPTY) == CDNS_UART_IXR_TXEMPTY) { - if (uart_circ_empty(&port->state->xmit)) { - writel(CDNS_UART_IXR_TXEMPTY, - port->membase + CDNS_UART_IDR_OFFSET); - } else { - numbytes = port->fifosize; - /* Break if no more data available in the UART buffer */ - while (numbytes--) { - if (uart_circ_empty(&port->state->xmit)) - break; - /* Get the data from the UART circular buffer - * and write it to the cdns_uart's TX_FIFO - * register. - */ - writel(port->state->xmit.buf[ - port->state->xmit.tail], - port->membase + CDNS_UART_FIFO_OFFSET); - - port->icount.tx++; - - /* Adjust the tail of the UART buffer and wrap - * the buffer if it reaches limit. - */ - port->state->xmit.tail = - (port->state->xmit.tail + 1) & - (UART_XMIT_SIZE - 1); - } +static void cdns_uart_handle_tx(struct uart_port *port) +{ + unsigned int numbytes; - if (uart_circ_chars_pending( - &port->state->xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - } + if (uart_circ_empty(&port->state->xmit)) { + writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR); + return; + } + + numbytes = port->fifosize; + while (numbytes && !uart_circ_empty(&port->state->xmit) && + !(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL)) { + /* + * Get the data from the UART circular buffer + * and write it to the cdns_uart's TX_FIFO + * register. + */ + writel(port->state->xmit.buf[port->state->xmit.tail], + port->membase + CDNS_UART_FIFO); + port->icount.tx++; + + /* + * Adjust the tail of the UART buffer and wrap + * the buffer if it reaches limit. + */ + port->state->xmit.tail = + (port->state->xmit.tail + 1) & (UART_XMIT_SIZE - 1); + + numbytes--; } - writel(isrstatus, port->membase + CDNS_UART_ISR_OFFSET); + if (uart_circ_chars_pending(&port->state->xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); +} + +/** + * cdns_uart_isr - Interrupt handler + * @irq: Irq number + * @dev_id: Id of the port + * + * Return: IRQHANDLED + */ +static irqreturn_t cdns_uart_isr(int irq, void *dev_id) +{ + struct uart_port *port = (struct uart_port *)dev_id; + unsigned long flags; + unsigned int isrstatus; + + spin_lock_irqsave(&port->lock, flags); + + /* Read the interrupt status register to determine which + * interrupt(s) is/are active. + */ + isrstatus = readl(port->membase + CDNS_UART_ISR); + + if (isrstatus & CDNS_UART_RX_IRQS) + cdns_uart_handle_rx(port, isrstatus); + + if ((isrstatus & CDNS_UART_IXR_TXEMPTY) == CDNS_UART_IXR_TXEMPTY) + cdns_uart_handle_tx(port); + + writel(isrstatus, port->membase + CDNS_UART_ISR); /* be sure to release the lock and tty before leaving */ spin_unlock_irqrestore(&port->lock, flags); @@ -395,14 +390,14 @@ static unsigned int cdns_uart_set_baud_rate(struct uart_port *port, &div8); /* Write new divisors to hardware */ - mreg = readl(port->membase + CDNS_UART_MR_OFFSET); + mreg = readl(port->membase + CDNS_UART_MR); if (div8) mreg |= CDNS_UART_MR_CLKSEL; else mreg &= ~CDNS_UART_MR_CLKSEL; - writel(mreg, port->membase + CDNS_UART_MR_OFFSET); - writel(cd, port->membase + CDNS_UART_BAUDGEN_OFFSET); - writel(bdiv, port->membase + CDNS_UART_BAUDDIV_OFFSET); + writel(mreg, port->membase + CDNS_UART_MR); + writel(cd, port->membase + CDNS_UART_BAUDGEN); + writel(bdiv, port->membase + CDNS_UART_BAUDDIV); cdns_uart->baud = baud; return calc_baud; @@ -449,9 +444,9 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb, spin_lock_irqsave(&cdns_uart->port->lock, flags); /* Disable the TX and RX to set baud rate */ - ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET); + ctrl_reg = readl(port->membase + CDNS_UART_CR); ctrl_reg |= CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS; - writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET); + writel(ctrl_reg, port->membase + CDNS_UART_CR); spin_unlock_irqrestore(&cdns_uart->port->lock, flags); @@ -476,11 +471,11 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb, spin_lock_irqsave(&cdns_uart->port->lock, flags); /* Set TX/RX Reset */ - ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET); + ctrl_reg = readl(port->membase + CDNS_UART_CR); ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST; - writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET); + writel(ctrl_reg, port->membase + CDNS_UART_CR); - while (readl(port->membase + CDNS_UART_CR_OFFSET) & + while (readl(port->membase + CDNS_UART_CR) & (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST)) cpu_relax(); @@ -489,11 +484,11 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb, * enable bit and RX enable bit to enable the transmitter and * receiver. */ - writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET); - ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET); + writel(rx_timeout, port->membase + CDNS_UART_RXTOUT); + ctrl_reg = readl(port->membase + CDNS_UART_CR); ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS); ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN; - writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET); + writel(ctrl_reg, port->membase + CDNS_UART_CR); spin_unlock_irqrestore(&cdns_uart->port->lock, flags); @@ -510,43 +505,28 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb, */ static void cdns_uart_start_tx(struct uart_port *port) { - unsigned int status, numbytes = port->fifosize; + unsigned int status; - if (uart_circ_empty(&port->state->xmit) || uart_tx_stopped(port)) + if (uart_tx_stopped(port)) return; - status = readl(port->membase + CDNS_UART_CR_OFFSET); - /* Set the TX enable bit and clear the TX disable bit to enable the + /* + * Set the TX enable bit and clear the TX disable bit to enable the * transmitter. */ - writel((status & ~CDNS_UART_CR_TX_DIS) | CDNS_UART_CR_TX_EN, - port->membase + CDNS_UART_CR_OFFSET); + status = readl(port->membase + CDNS_UART_CR); + status &= ~CDNS_UART_CR_TX_DIS; + status |= CDNS_UART_CR_TX_EN; + writel(status, port->membase + CDNS_UART_CR); - while (numbytes-- && ((readl(port->membase + CDNS_UART_SR_OFFSET) & - CDNS_UART_SR_TXFULL)) != CDNS_UART_SR_TXFULL) { - /* Break if no more data available in the UART buffer */ - if (uart_circ_empty(&port->state->xmit)) - break; + if (uart_circ_empty(&port->state->xmit)) + return; - /* Get the data from the UART circular buffer and - * write it to the cdns_uart's TX_FIFO register. - */ - writel(port->state->xmit.buf[port->state->xmit.tail], - port->membase + CDNS_UART_FIFO_OFFSET); - port->icount.tx++; + cdns_uart_handle_tx(port); - /* Adjust the tail of the UART buffer and wrap - * the buffer if it reaches limit. - */ - port->state->xmit.tail = (port->state->xmit.tail + 1) & - (UART_XMIT_SIZE - 1); - } - writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR_OFFSET); + writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR); /* Enable the TX Empty interrupt */ - writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IER_OFFSET); - - if (uart_circ_chars_pending(&port->state->xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); + writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IER); } /** @@ -557,10 +537,10 @@ static void cdns_uart_stop_tx(struct uart_port *port) { unsigned int regval; - regval = readl(port->membase + CDNS_UART_CR_OFFSET); + regval = readl(port->membase + CDNS_UART_CR); regval |= CDNS_UART_CR_TX_DIS; /* Disable the transmitter */ - writel(regval, port->membase + CDNS_UART_CR_OFFSET); + writel(regval, port->membase + CDNS_UART_CR); } /** @@ -571,10 +551,13 @@ static void cdns_uart_stop_rx(struct uart_port *port) { unsigned int regval; - regval = readl(port->membase + CDNS_UART_CR_OFFSET); - regval |= CDNS_UART_CR_RX_DIS; + /* Disable RX IRQs */ + writel(CDNS_UART_RX_IRQS, port->membase + CDNS_UART_IDR); + /* Disable the receiver */ - writel(regval, port->membase + CDNS_UART_CR_OFFSET); + regval = readl(port->membase + CDNS_UART_CR); + regval |= CDNS_UART_CR_RX_DIS; + writel(regval, port->membase + CDNS_UART_CR); } /** @@ -587,7 +570,7 @@ static unsigned int cdns_uart_tx_empty(struct uart_port *port) { unsigned int status; - status = readl(port->membase + CDNS_UART_SR_OFFSET) & + status = readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXEMPTY; return status ? TIOCSER_TEMT : 0; } @@ -605,15 +588,15 @@ static void cdns_uart_break_ctl(struct uart_port *port, int ctl) spin_lock_irqsave(&port->lock, flags); - status = readl(port->membase + CDNS_UART_CR_OFFSET); + status = readl(port->membase + CDNS_UART_CR); if (ctl == -1) writel(CDNS_UART_CR_STARTBRK | status, - port->membase + CDNS_UART_CR_OFFSET); + port->membase + CDNS_UART_CR); else { if ((status & CDNS_UART_CR_STOPBRK) == 0) writel(CDNS_UART_CR_STOPBRK | status, - port->membase + CDNS_UART_CR_OFFSET); + port->membase + CDNS_UART_CR); } spin_unlock_irqrestore(&port->lock, flags); } @@ -636,18 +619,18 @@ static void cdns_uart_set_termios(struct uart_port *port, spin_lock_irqsave(&port->lock, flags); /* Wait for the transmit FIFO to empty before making changes */ - if (!(readl(port->membase + CDNS_UART_CR_OFFSET) & + if (!(readl(port->membase + CDNS_UART_CR) & CDNS_UART_CR_TX_DIS)) { - while (!(readl(port->membase + CDNS_UART_SR_OFFSET) & + while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXEMPTY)) { cpu_relax(); } } /* Disable the TX and RX to set baud rate */ - ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET); + ctrl_reg = readl(port->membase + CDNS_UART_CR); ctrl_reg |= CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS; - writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET); + writel(ctrl_reg, port->membase + CDNS_UART_CR); /* * Min baud rate = 6bps and Max Baud Rate is 10Mbps for 100Mhz clk @@ -666,20 +649,20 @@ static void cdns_uart_set_termios(struct uart_port *port, uart_update_timeout(port, termios->c_cflag, baud); /* Set TX/RX Reset */ - ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET); + ctrl_reg = readl(port->membase + CDNS_UART_CR); ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST; - writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET); + writel(ctrl_reg, port->membase + CDNS_UART_CR); /* * Clear the RX disable and TX disable bits and then set the TX enable * bit and RX enable bit to enable the transmitter and receiver. */ - ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET); + ctrl_reg = readl(port->membase + CDNS_UART_CR); ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS); ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN; - writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET); + writel(ctrl_reg, port->membase + CDNS_UART_CR); - writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET); + writel(rx_timeout, port->membase + CDNS_UART_RXTOUT); port->read_status_mask = CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_RXTRIG | CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_TOUT; @@ -699,7 +682,7 @@ static void cdns_uart_set_termios(struct uart_port *port, CDNS_UART_IXR_TOUT | CDNS_UART_IXR_PARITY | CDNS_UART_IXR_FRAMING | CDNS_UART_IXR_OVERRUN; - mode_reg = readl(port->membase + CDNS_UART_MR_OFFSET); + mode_reg = readl(port->membase + CDNS_UART_MR); /* Handling Data Size */ switch (termios->c_cflag & CSIZE) { @@ -740,7 +723,7 @@ static void cdns_uart_set_termios(struct uart_port *port, cval |= CDNS_UART_MR_PARITY_NONE; } cval |= mode_reg & 1; - writel(cval, port->membase + CDNS_UART_MR_OFFSET); + writel(cval, port->membase + CDNS_UART_MR); spin_unlock_irqrestore(&port->lock, flags); } @@ -753,63 +736,67 @@ static void cdns_uart_set_termios(struct uart_port *port, */ static int cdns_uart_startup(struct uart_port *port) { - unsigned int retval = 0, status = 0; + int ret; + unsigned long flags; + unsigned int status = 0; - retval = request_irq(port->irq, cdns_uart_isr, 0, CDNS_UART_NAME, - (void *)port); - if (retval) - return retval; + spin_lock_irqsave(&port->lock, flags); /* Disable the TX and RX */ writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS, - port->membase + CDNS_UART_CR_OFFSET); + port->membase + CDNS_UART_CR); /* Set the Control Register with TX/RX Enable, TX/RX Reset, * no break chars. */ writel(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST, - port->membase + CDNS_UART_CR_OFFSET); - - status = readl(port->membase + CDNS_UART_CR_OFFSET); + port->membase + CDNS_UART_CR); - /* Clear the RX disable and TX disable bits and then set the TX enable - * bit and RX enable bit to enable the transmitter and receiver. + /* + * Clear the RX disable bit and then set the RX enable bit to enable + * the receiver. */ - writel((status & ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS)) - | (CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN | - CDNS_UART_CR_STOPBRK), - port->membase + CDNS_UART_CR_OFFSET); + status = readl(port->membase + CDNS_UART_CR); + status &= CDNS_UART_CR_RX_DIS; + status |= CDNS_UART_CR_RX_EN; + writel(status, port->membase + CDNS_UART_CR); /* Set the Mode Register with normal mode,8 data bits,1 stop bit, * no parity. */ writel(CDNS_UART_MR_CHMODE_NORM | CDNS_UART_MR_STOPMODE_1_BIT | CDNS_UART_MR_PARITY_NONE | CDNS_UART_MR_CHARLEN_8_BIT, - port->membase + CDNS_UART_MR_OFFSET); + port->membase + CDNS_UART_MR); /* * Set the RX FIFO Trigger level to use most of the FIFO, but it * can be tuned with a module parameter */ - writel(rx_trigger_level, port->membase + CDNS_UART_RXWM_OFFSET); + writel(rx_trigger_level, port->membase + CDNS_UART_RXWM); /* * Receive Timeout register is enabled but it * can be tuned with a module parameter */ - writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET); + writel(rx_timeout, port->membase + CDNS_UART_RXTOUT); /* Clear out any pending interrupts before enabling them */ - writel(readl(port->membase + CDNS_UART_ISR_OFFSET), - port->membase + CDNS_UART_ISR_OFFSET); + writel(readl(port->membase + CDNS_UART_ISR), + port->membase + CDNS_UART_ISR); + + spin_unlock_irqrestore(&port->lock, flags); + + ret = request_irq(port->irq, cdns_uart_isr, 0, CDNS_UART_NAME, port); + if (ret) { + dev_err(port->dev, "request_irq '%d' failed with %d\n", + port->irq, ret); + return ret; + } /* Set the Interrupt Registers with desired interrupts */ - writel(CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_PARITY | - CDNS_UART_IXR_FRAMING | CDNS_UART_IXR_OVERRUN | - CDNS_UART_IXR_RXTRIG | CDNS_UART_IXR_TOUT, - port->membase + CDNS_UART_IER_OFFSET); + writel(CDNS_UART_RX_IRQS, port->membase + CDNS_UART_IER); - return retval; + return 0; } /** @@ -819,14 +806,21 @@ static int cdns_uart_startup(struct uart_port *port) static void cdns_uart_shutdown(struct uart_port *port) { int status; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); /* Disable interrupts */ - status = readl(port->membase + CDNS_UART_IMR_OFFSET); - writel(status, port->membase + CDNS_UART_IDR_OFFSET); + status = readl(port->membase + CDNS_UART_IMR); + writel(status, port->membase + CDNS_UART_IDR); + writel(0xffffffff, port->membase + CDNS_UART_ISR); /* Disable the TX and RX */ writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS, - port->membase + CDNS_UART_CR_OFFSET); + port->membase + CDNS_UART_CR); + + spin_unlock_irqrestore(&port->lock, flags); + free_irq(port->irq, port); } @@ -928,7 +922,7 @@ static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) { u32 val; - val = readl(port->membase + CDNS_UART_MODEMCR_OFFSET); + val = readl(port->membase + CDNS_UART_MODEMCR); val &= ~(CDNS_UART_MODEMCR_RTS | CDNS_UART_MODEMCR_DTR); @@ -937,55 +931,46 @@ static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) if (mctrl & TIOCM_DTR) val |= CDNS_UART_MODEMCR_DTR; - writel(val, port->membase + CDNS_UART_MODEMCR_OFFSET); + writel(val, port->membase + CDNS_UART_MODEMCR); } #ifdef CONFIG_CONSOLE_POLL static int cdns_uart_poll_get_char(struct uart_port *port) { - u32 imr; int c; + unsigned long flags; - /* Disable all interrupts */ - imr = readl(port->membase + CDNS_UART_IMR_OFFSET); - writel(imr, port->membase + CDNS_UART_IDR_OFFSET); + spin_lock_irqsave(&port->lock, flags); /* Check if FIFO is empty */ - if (readl(port->membase + CDNS_UART_SR_OFFSET) & CDNS_UART_SR_RXEMPTY) + if (readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_RXEMPTY) c = NO_POLL_CHAR; else /* Read a character */ - c = (unsigned char) readl( - port->membase + CDNS_UART_FIFO_OFFSET); + c = (unsigned char) readl(port->membase + CDNS_UART_FIFO); - /* Enable interrupts */ - writel(imr, port->membase + CDNS_UART_IER_OFFSET); + spin_unlock_irqrestore(&port->lock, flags); return c; } static void cdns_uart_poll_put_char(struct uart_port *port, unsigned char c) { - u32 imr; + unsigned long flags; - /* Disable all interrupts */ - imr = readl(port->membase + CDNS_UART_IMR_OFFSET); - writel(imr, port->membase + CDNS_UART_IDR_OFFSET); + spin_lock_irqsave(&port->lock, flags); /* Wait until FIFO is empty */ - while (!(readl(port->membase + CDNS_UART_SR_OFFSET) & - CDNS_UART_SR_TXEMPTY)) + while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXEMPTY)) cpu_relax(); /* Write a character */ - writel(c, port->membase + CDNS_UART_FIFO_OFFSET); + writel(c, port->membase + CDNS_UART_FIFO); /* Wait until FIFO is empty */ - while (!(readl(port->membase + CDNS_UART_SR_OFFSET) & - CDNS_UART_SR_TXEMPTY)) + while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXEMPTY)) cpu_relax(); - /* Enable interrupts */ - writel(imr, port->membase + CDNS_UART_IER_OFFSET); + spin_unlock_irqrestore(&port->lock, flags); return; } @@ -1059,8 +1044,7 @@ static struct uart_port *cdns_uart_get_port(int id) */ static void cdns_uart_console_wait_tx(struct uart_port *port) { - while (!(readl(port->membase + CDNS_UART_SR_OFFSET) & - CDNS_UART_SR_TXEMPTY)) + while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXEMPTY)) barrier(); } @@ -1072,7 +1056,7 @@ static void cdns_uart_console_wait_tx(struct uart_port *port) static void cdns_uart_console_putchar(struct uart_port *port, int ch) { cdns_uart_console_wait_tx(port); - writel(ch, port->membase + CDNS_UART_FIFO_OFFSET); + writel(ch, port->membase + CDNS_UART_FIFO); } static void __init cdns_early_write(struct console *con, const char *s, @@ -1093,7 +1077,9 @@ static int __init cdns_early_console_setup(struct earlycon_device *device, return 0; } -EARLYCON_DECLARE(cdns, cdns_early_console_setup); +OF_EARLYCON_DECLARE(cdns, "xlnx,xuartps", cdns_early_console_setup); +OF_EARLYCON_DECLARE(cdns, "cdns,uart-r1p8", cdns_early_console_setup); +OF_EARLYCON_DECLARE(cdns, "cdns,uart-r1p12", cdns_early_console_setup); /** * cdns_uart_console_write - perform write operation @@ -1109,30 +1095,33 @@ static void cdns_uart_console_write(struct console *co, const char *s, unsigned int imr, ctrl; int locked = 1; - if (oops_in_progress) + if (port->sysrq) + locked = 0; + else if (oops_in_progress) locked = spin_trylock_irqsave(&port->lock, flags); else spin_lock_irqsave(&port->lock, flags); /* save and disable interrupt */ - imr = readl(port->membase + CDNS_UART_IMR_OFFSET); - writel(imr, port->membase + CDNS_UART_IDR_OFFSET); + imr = readl(port->membase + CDNS_UART_IMR); + writel(imr, port->membase + CDNS_UART_IDR); /* * Make sure that the tx part is enabled. Set the TX enable bit and * clear the TX disable bit to enable the transmitter. */ - ctrl = readl(port->membase + CDNS_UART_CR_OFFSET); - writel((ctrl & ~CDNS_UART_CR_TX_DIS) | CDNS_UART_CR_TX_EN, - port->membase + CDNS_UART_CR_OFFSET); + ctrl = readl(port->membase + CDNS_UART_CR); + ctrl &= ~CDNS_UART_CR_TX_DIS; + ctrl |= CDNS_UART_CR_TX_EN; + writel(ctrl, port->membase + CDNS_UART_CR); uart_console_write(port, s, count, cdns_uart_console_putchar); cdns_uart_console_wait_tx(port); - writel(ctrl, port->membase + CDNS_UART_CR_OFFSET); + writel(ctrl, port->membase + CDNS_UART_CR); /* restore interrupt state */ - writel(imr, port->membase + CDNS_UART_IER_OFFSET); + writel(imr, port->membase + CDNS_UART_IER); if (locked) spin_unlock_irqrestore(&port->lock, flags); @@ -1244,14 +1233,13 @@ static int cdns_uart_suspend(struct device *device) spin_lock_irqsave(&port->lock, flags); /* Empty the receive FIFO 1st before making changes */ - while (!(readl(port->membase + CDNS_UART_SR_OFFSET) & + while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_RXEMPTY)) - readl(port->membase + CDNS_UART_FIFO_OFFSET); + readl(port->membase + CDNS_UART_FIFO); /* set RX trigger level to 1 */ - writel(1, port->membase + CDNS_UART_RXWM_OFFSET); + writel(1, port->membase + CDNS_UART_RXWM); /* disable RX timeout interrups */ - writel(CDNS_UART_IXR_TOUT, - port->membase + CDNS_UART_IDR_OFFSET); + writel(CDNS_UART_IXR_TOUT, port->membase + CDNS_UART_IDR); spin_unlock_irqrestore(&port->lock, flags); } @@ -1290,30 +1278,28 @@ static int cdns_uart_resume(struct device *device) spin_lock_irqsave(&port->lock, flags); /* Set TX/RX Reset */ - ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET); + ctrl_reg = readl(port->membase + CDNS_UART_CR); ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST; - writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET); - while (readl(port->membase + CDNS_UART_CR_OFFSET) & + writel(ctrl_reg, port->membase + CDNS_UART_CR); + while (readl(port->membase + CDNS_UART_CR) & (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST)) cpu_relax(); /* restore rx timeout value */ - writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET); + writel(rx_timeout, port->membase + CDNS_UART_RXTOUT); /* Enable Tx/Rx */ - ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET); + ctrl_reg = readl(port->membase + CDNS_UART_CR); ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS); ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN; - writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET); + writel(ctrl_reg, port->membase + CDNS_UART_CR); spin_unlock_irqrestore(&port->lock, flags); } else { spin_lock_irqsave(&port->lock, flags); /* restore original rx trigger level */ - writel(rx_trigger_level, - port->membase + CDNS_UART_RXWM_OFFSET); + writel(rx_trigger_level, port->membase + CDNS_UART_RXWM); /* enable RX timeout interrupt */ - writel(CDNS_UART_IXR_TOUT, - port->membase + CDNS_UART_IER_OFFSET); + writel(CDNS_UART_IXR_TOUT, port->membase + CDNS_UART_IER); spin_unlock_irqrestore(&port->lock, flags); } @@ -1406,27 +1392,30 @@ static int cdns_uart_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Cannot get uart_port structure\n"); rc = -ENODEV; goto err_out_notif_unreg; - } else { - /* Register the port. - * This function also registers this device with the tty layer - * and triggers invocation of the config_port() entry point. - */ - port->mapbase = res->start; - port->irq = irq; - port->dev = &pdev->dev; - port->uartclk = clk_get_rate(cdns_uart_data->uartclk); - port->private_data = cdns_uart_data; - cdns_uart_data->port = port; - platform_set_drvdata(pdev, port); - rc = uart_add_one_port(&cdns_uart_uart_driver, port); - if (rc) { - dev_err(&pdev->dev, - "uart_add_one_port() failed; err=%i\n", rc); - goto err_out_notif_unreg; - } - return 0; } + /* + * Register the port. + * This function also registers this device with the tty layer + * and triggers invocation of the config_port() entry point. + */ + port->mapbase = res->start; + port->irq = irq; + port->dev = &pdev->dev; + port->uartclk = clk_get_rate(cdns_uart_data->uartclk); + port->private_data = cdns_uart_data; + cdns_uart_data->port = port; + platform_set_drvdata(pdev, port); + + rc = uart_add_one_port(&cdns_uart_uart_driver, port); + if (rc) { + dev_err(&pdev->dev, + "uart_add_one_port() failed; err=%i\n", rc); + goto err_out_notif_unreg; + } + + return 0; + err_out_notif_unreg: #ifdef CONFIG_COMMON_CLK clk_notifier_unregister(cdns_uart_data->uartclk, diff --git a/drivers/tty/serial/zs.c b/drivers/tty/serial/zs.c index 2b65bb7ffb8a..eeefd76a30da 100644 --- a/drivers/tty/serial/zs.c +++ b/drivers/tty/serial/zs.c @@ -1181,6 +1181,10 @@ static void zs_console_write(struct console *co, const char *s, if (txint & TxINT_ENAB) { zport->regs[1] |= TxINT_ENAB; write_zsreg(zport, R1, zport->regs[1]); + + /* Resume any transmission as the TxIP bit won't be set. */ + if (!zport->tx_stopped) + zs_raw_transmit_chars(zport); } spin_unlock_irqrestore(&scc->zlock, flags); } diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index 6188059fd523..f5476e270734 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -2363,7 +2363,7 @@ static void mgsl_throttle(struct tty_struct * tty) if (I_IXOFF(tty)) mgsl_send_xchar(tty, STOP_CHAR(tty)); - if (tty->termios.c_cflag & CRTSCTS) { + if (C_CRTSCTS(tty)) { spin_lock_irqsave(&info->irq_spinlock,flags); info->serial_signals &= ~SerialSignal_RTS; usc_set_serial_signals(info); @@ -2397,7 +2397,7 @@ static void mgsl_unthrottle(struct tty_struct * tty) mgsl_send_xchar(tty, START_CHAR(tty)); } - if (tty->termios.c_cflag & CRTSCTS) { + if (C_CRTSCTS(tty)) { spin_lock_irqsave(&info->irq_spinlock,flags); info->serial_signals |= SerialSignal_RTS; usc_set_serial_signals(info); @@ -3039,30 +3039,25 @@ static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termio mgsl_change_params(info); /* Handle transition to B0 status */ - if (old_termios->c_cflag & CBAUD && - !(tty->termios.c_cflag & CBAUD)) { + if ((old_termios->c_cflag & CBAUD) && !C_BAUD(tty)) { info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR); spin_lock_irqsave(&info->irq_spinlock,flags); usc_set_serial_signals(info); spin_unlock_irqrestore(&info->irq_spinlock,flags); } - + /* Handle transition away from B0 status */ - if (!(old_termios->c_cflag & CBAUD) && - tty->termios.c_cflag & CBAUD) { + if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) { info->serial_signals |= SerialSignal_DTR; - if (!(tty->termios.c_cflag & CRTSCTS) || - !test_bit(TTY_THROTTLED, &tty->flags)) { + if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags)) info->serial_signals |= SerialSignal_RTS; - } spin_lock_irqsave(&info->irq_spinlock,flags); usc_set_serial_signals(info); spin_unlock_irqrestore(&info->irq_spinlock,flags); } - + /* Handle turning off CRTSCTS */ - if (old_termios->c_cflag & CRTSCTS && - !(tty->termios.c_cflag & CRTSCTS)) { + if (old_termios->c_cflag & CRTSCTS && !C_CRTSCTS(tty)) { tty->hw_stopped = 0; mgsl_start(tty); } @@ -3281,7 +3276,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, return 0; } - if (tty->termios.c_cflag & CLOCAL) + if (C_CLOCAL(tty)) do_clocal = true; /* Wait for carrier detect and the line to become diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index 5505ea842179..c0a2f5a1b1c2 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -774,8 +774,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios) change_params(info); /* Handle transition to B0 status */ - if (old_termios->c_cflag & CBAUD && - !(tty->termios.c_cflag & CBAUD)) { + if ((old_termios->c_cflag & CBAUD) && !C_BAUD(tty)) { info->signals &= ~(SerialSignal_RTS | SerialSignal_DTR); spin_lock_irqsave(&info->lock,flags); set_signals(info); @@ -783,21 +782,17 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios) } /* Handle transition away from B0 status */ - if (!(old_termios->c_cflag & CBAUD) && - tty->termios.c_cflag & CBAUD) { + if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) { info->signals |= SerialSignal_DTR; - if (!(tty->termios.c_cflag & CRTSCTS) || - !test_bit(TTY_THROTTLED, &tty->flags)) { + if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags)) info->signals |= SerialSignal_RTS; - } spin_lock_irqsave(&info->lock,flags); set_signals(info); spin_unlock_irqrestore(&info->lock,flags); } /* Handle turning off CRTSCTS */ - if (old_termios->c_cflag & CRTSCTS && - !(tty->termios.c_cflag & CRTSCTS)) { + if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) { tty->hw_stopped = 0; tx_release(tty); } @@ -1362,7 +1357,7 @@ static void throttle(struct tty_struct * tty) DBGINFO(("%s throttle\n", info->device_name)); if (I_IXOFF(tty)) send_xchar(tty, STOP_CHAR(tty)); - if (tty->termios.c_cflag & CRTSCTS) { + if (C_CRTSCTS(tty)) { spin_lock_irqsave(&info->lock,flags); info->signals &= ~SerialSignal_RTS; set_signals(info); @@ -1387,7 +1382,7 @@ static void unthrottle(struct tty_struct * tty) else send_xchar(tty, START_CHAR(tty)); } - if (tty->termios.c_cflag & CRTSCTS) { + if (C_CRTSCTS(tty)) { spin_lock_irqsave(&info->lock,flags); info->signals |= SerialSignal_RTS; set_signals(info); @@ -3280,7 +3275,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, return 0; } - if (tty->termios.c_cflag & CLOCAL) + if (C_CLOCAL(tty)) do_clocal = true; /* Wait for carrier detect and the line to become diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index fb00a06dfa4b..90da0c712262 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -549,8 +549,8 @@ static int tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); static int set_break(struct tty_struct *tty, int break_state); -static void add_device(SLMP_INFO *info); -static void device_init(int adapter_num, struct pci_dev *pdev); +static int add_device(SLMP_INFO *info); +static int device_init(int adapter_num, struct pci_dev *pdev); static int claim_resources(SLMP_INFO *info); static void release_resources(SLMP_INFO *info); @@ -871,8 +871,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios) change_params(info); /* Handle transition to B0 status */ - if (old_termios->c_cflag & CBAUD && - !(tty->termios.c_cflag & CBAUD)) { + if ((old_termios->c_cflag & CBAUD) && !C_BAUD(tty)) { info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR); spin_lock_irqsave(&info->lock,flags); set_signals(info); @@ -880,21 +879,17 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios) } /* Handle transition away from B0 status */ - if (!(old_termios->c_cflag & CBAUD) && - tty->termios.c_cflag & CBAUD) { + if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) { info->serial_signals |= SerialSignal_DTR; - if (!(tty->termios.c_cflag & CRTSCTS) || - !test_bit(TTY_THROTTLED, &tty->flags)) { + if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags)) info->serial_signals |= SerialSignal_RTS; - } spin_lock_irqsave(&info->lock,flags); set_signals(info); spin_unlock_irqrestore(&info->lock,flags); } /* Handle turning off CRTSCTS */ - if (old_termios->c_cflag & CRTSCTS && - !(tty->termios.c_cflag & CRTSCTS)) { + if (old_termios->c_cflag & CRTSCTS && !C_CRTSCTS(tty)) { tty->hw_stopped = 0; tx_release(tty); } @@ -1472,7 +1467,7 @@ static void throttle(struct tty_struct * tty) if (I_IXOFF(tty)) send_xchar(tty, STOP_CHAR(tty)); - if (tty->termios.c_cflag & CRTSCTS) { + if (C_CRTSCTS(tty)) { spin_lock_irqsave(&info->lock,flags); info->serial_signals &= ~SerialSignal_RTS; set_signals(info); @@ -1501,7 +1496,7 @@ static void unthrottle(struct tty_struct * tty) send_xchar(tty, START_CHAR(tty)); } - if (tty->termios.c_cflag & CRTSCTS) { + if (C_CRTSCTS(tty)) { spin_lock_irqsave(&info->lock,flags); info->serial_signals |= SerialSignal_RTS; set_signals(info); @@ -3297,7 +3292,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, return 0; } - if (tty->termios.c_cflag & CLOCAL) + if (C_CLOCAL(tty)) do_clocal = true; /* Wait for carrier detect and the line to become @@ -3693,7 +3688,7 @@ static void release_resources(SLMP_INFO *info) /* Add the specified device instance data structure to the * global linked list of devices and increment the device count. */ -static void add_device(SLMP_INFO *info) +static int add_device(SLMP_INFO *info) { info->next_device = NULL; info->line = synclinkmp_device_count; @@ -3731,7 +3726,9 @@ static void add_device(SLMP_INFO *info) info->max_frame_size ); #if SYNCLINK_GENERIC_HDLC - hdlcdev_init(info); + return hdlcdev_init(info); +#else + return 0; #endif } @@ -3820,10 +3817,10 @@ static SLMP_INFO *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev) return info; } -static void device_init(int adapter_num, struct pci_dev *pdev) +static int device_init(int adapter_num, struct pci_dev *pdev) { SLMP_INFO *port_array[SCA_MAX_PORTS]; - int port; + int port, rc; /* allocate device instances for up to SCA_MAX_PORTS devices */ for ( port = 0; port < SCA_MAX_PORTS; ++port ) { @@ -3833,14 +3830,16 @@ static void device_init(int adapter_num, struct pci_dev *pdev) tty_port_destroy(&port_array[port]->port); kfree(port_array[port]); } - return; + return -ENOMEM; } } /* give copy of port_array to all ports and add to device list */ for ( port = 0; port < SCA_MAX_PORTS; ++port ) { memcpy(port_array[port]->port_array,port_array,sizeof(port_array)); - add_device( port_array[port] ); + rc = add_device( port_array[port] ); + if (rc) + goto err_add; spin_lock_init(&port_array[port]->lock); } @@ -3860,21 +3859,30 @@ static void device_init(int adapter_num, struct pci_dev *pdev) alloc_dma_bufs(port_array[port]); } - if ( request_irq(port_array[0]->irq_level, + rc = request_irq(port_array[0]->irq_level, synclinkmp_interrupt, port_array[0]->irq_flags, port_array[0]->device_name, - port_array[0]) < 0 ) { + port_array[0]); + if ( rc ) { printk( "%s(%d):%s Can't request interrupt, IRQ=%d\n", __FILE__,__LINE__, port_array[0]->device_name, port_array[0]->irq_level ); + goto err_irq; } - else { - port_array[0]->irq_requested = true; - adapter_test(port_array[0]); - } + port_array[0]->irq_requested = true; + adapter_test(port_array[0]); } + return 0; +err_irq: + release_resources( port_array[0] ); +err_add: + for ( port = 0; port < SCA_MAX_PORTS; ++port ) { + tty_port_destroy(&port_array[port]->port); + kfree(port_array[port]); + } + return rc; } static const struct tty_operations ops = { @@ -5589,8 +5597,7 @@ static int synclinkmp_init_one (struct pci_dev *dev, printk("error enabling pci device %p\n", dev); return -EIO; } - device_init( ++synclinkmp_adapter_count, dev ); - return 0; + return device_init( ++synclinkmp_adapter_count, dev ); } static void synclinkmp_remove_one (struct pci_dev *dev) diff --git a/drivers/tty/tty_audit.c b/drivers/tty/tty_audit.c index 3d245cd3d8e6..df2d735338e2 100644 --- a/drivers/tty/tty_audit.c +++ b/drivers/tty/tty_audit.c @@ -14,16 +14,23 @@ #include <linux/tty.h> struct tty_audit_buf { - atomic_t count; struct mutex mutex; /* Protects all data below */ - int major, minor; /* The TTY which the data is from */ + dev_t dev; /* The TTY which the data is from */ unsigned icanon:1; size_t valid; unsigned char *data; /* Allocated size N_TTY_BUF_SIZE */ }; -static struct tty_audit_buf *tty_audit_buf_alloc(int major, int minor, - unsigned icanon) +static struct tty_audit_buf *tty_audit_buf_ref(void) +{ + struct tty_audit_buf *buf; + + buf = current->signal->tty_audit_buf; + WARN_ON(buf == ERR_PTR(-ESRCH)); + return buf; +} + +static struct tty_audit_buf *tty_audit_buf_alloc(void) { struct tty_audit_buf *buf; @@ -33,11 +40,9 @@ static struct tty_audit_buf *tty_audit_buf_alloc(int major, int minor, buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL); if (!buf->data) goto err_buf; - atomic_set(&buf->count, 1); mutex_init(&buf->mutex); - buf->major = major; - buf->minor = minor; - buf->icanon = icanon; + buf->dev = MKDEV(0, 0); + buf->icanon = 0; buf->valid = 0; return buf; @@ -54,13 +59,7 @@ static void tty_audit_buf_free(struct tty_audit_buf *buf) kfree(buf); } -static void tty_audit_buf_put(struct tty_audit_buf *buf) -{ - if (atomic_dec_and_test(&buf->count)) - tty_audit_buf_free(buf); -} - -static void tty_audit_log(const char *description, int major, int minor, +static void tty_audit_log(const char *description, dev_t dev, unsigned char *data, size_t size) { struct audit_buffer *ab; @@ -76,7 +75,7 @@ static void tty_audit_log(const char *description, int major, int minor, audit_log_format(ab, "%s pid=%u uid=%u auid=%u ses=%u major=%d" " minor=%d comm=", description, pid, uid, - loginuid, sessionid, major, minor); + loginuid, sessionid, MAJOR(dev), MINOR(dev)); get_task_comm(name, tsk); audit_log_untrustedstring(ab, name); audit_log_format(ab, " data="); @@ -99,7 +98,7 @@ static void tty_audit_buf_push(struct tty_audit_buf *buf) buf->valid = 0; return; } - tty_audit_log("tty", buf->major, buf->minor, buf->data, buf->valid); + tty_audit_log("tty", buf->dev, buf->data, buf->valid); buf->valid = 0; } @@ -108,21 +107,20 @@ static void tty_audit_buf_push(struct tty_audit_buf *buf) * * Make sure all buffered data is written out and deallocate the buffer. * Only needs to be called if current->signal->tty_audit_buf != %NULL. + * + * The process is single-threaded at this point; no other threads share + * current->signal. */ void tty_audit_exit(void) { struct tty_audit_buf *buf; - buf = current->signal->tty_audit_buf; - current->signal->tty_audit_buf = NULL; + buf = xchg(¤t->signal->tty_audit_buf, ERR_PTR(-ESRCH)); if (!buf) return; - mutex_lock(&buf->mutex); tty_audit_buf_push(buf); - mutex_unlock(&buf->mutex); - - tty_audit_buf_put(buf); + tty_audit_buf_free(buf); } /** @@ -133,7 +131,6 @@ void tty_audit_exit(void) void tty_audit_fork(struct signal_struct *sig) { sig->audit_tty = current->signal->audit_tty; - sig->audit_tty_log_passwd = current->signal->audit_tty_log_passwd; } /** @@ -141,123 +138,62 @@ void tty_audit_fork(struct signal_struct *sig) */ void tty_audit_tiocsti(struct tty_struct *tty, char ch) { - struct tty_audit_buf *buf; - int major, minor, should_audit; - unsigned long flags; + dev_t dev; - spin_lock_irqsave(¤t->sighand->siglock, flags); - should_audit = current->signal->audit_tty; - buf = current->signal->tty_audit_buf; - if (buf) - atomic_inc(&buf->count); - spin_unlock_irqrestore(¤t->sighand->siglock, flags); - - major = tty->driver->major; - minor = tty->driver->minor_start + tty->index; - if (buf) { - mutex_lock(&buf->mutex); - if (buf->major == major && buf->minor == minor) - tty_audit_buf_push(buf); - mutex_unlock(&buf->mutex); - tty_audit_buf_put(buf); - } - - if (should_audit && audit_enabled) { - kuid_t auid; - unsigned int sessionid; + dev = MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index; + if (tty_audit_push()) + return; - auid = audit_get_loginuid(current); - sessionid = audit_get_sessionid(current); - tty_audit_log("ioctl=TIOCSTI", major, minor, &ch, 1); - } + if (audit_enabled) + tty_audit_log("ioctl=TIOCSTI", dev, &ch, 1); } /** - * tty_audit_push_current - Flush current's pending audit data + * tty_audit_push - Flush current's pending audit data * - * Try to lock sighand and get a reference to the tty audit buffer if available. - * Flush the buffer or return an appropriate error code. + * Returns 0 if success, -EPERM if tty audit is disabled */ -int tty_audit_push_current(void) +int tty_audit_push(void) { - struct tty_audit_buf *buf = ERR_PTR(-EPERM); - struct task_struct *tsk = current; - unsigned long flags; + struct tty_audit_buf *buf; - if (!lock_task_sighand(tsk, &flags)) - return -ESRCH; + if (~current->signal->audit_tty & AUDIT_TTY_ENABLE) + return -EPERM; - if (tsk->signal->audit_tty) { - buf = tsk->signal->tty_audit_buf; - if (buf) - atomic_inc(&buf->count); + buf = tty_audit_buf_ref(); + if (!IS_ERR_OR_NULL(buf)) { + mutex_lock(&buf->mutex); + tty_audit_buf_push(buf); + mutex_unlock(&buf->mutex); } - unlock_task_sighand(tsk, &flags); - - /* - * Return 0 when signal->audit_tty set - * but tsk->signal->tty_audit_buf == NULL. - */ - if (!buf || IS_ERR(buf)) - return PTR_ERR(buf); - - mutex_lock(&buf->mutex); - tty_audit_buf_push(buf); - mutex_unlock(&buf->mutex); - - tty_audit_buf_put(buf); return 0; } /** * tty_audit_buf_get - Get an audit buffer. * - * Get an audit buffer for @tty, allocate it if necessary. Return %NULL - * if TTY auditing is disabled or out of memory. Otherwise, return a new - * reference to the buffer. + * Get an audit buffer, allocate it if necessary. Return %NULL + * if out of memory or ERR_PTR(-ESRCH) if tty_audit_exit() has already + * occurred. Otherwise, return a new reference to the buffer. */ -static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty, - unsigned icanon) +static struct tty_audit_buf *tty_audit_buf_get(void) { - struct tty_audit_buf *buf, *buf2; - unsigned long flags; - - buf = NULL; - buf2 = NULL; - spin_lock_irqsave(¤t->sighand->siglock, flags); - if (likely(!current->signal->audit_tty)) - goto out; - buf = current->signal->tty_audit_buf; - if (buf) { - atomic_inc(&buf->count); - goto out; - } - spin_unlock_irqrestore(¤t->sighand->siglock, flags); + struct tty_audit_buf *buf; + + buf = tty_audit_buf_ref(); + if (buf) + return buf; - buf2 = tty_audit_buf_alloc(tty->driver->major, - tty->driver->minor_start + tty->index, - icanon); - if (buf2 == NULL) { + buf = tty_audit_buf_alloc(); + if (buf == NULL) { audit_log_lost("out of memory in TTY auditing"); return NULL; } - spin_lock_irqsave(¤t->sighand->siglock, flags); - if (!current->signal->audit_tty) - goto out; - buf = current->signal->tty_audit_buf; - if (!buf) { - current->signal->tty_audit_buf = buf2; - buf = buf2; - buf2 = NULL; - } - atomic_inc(&buf->count); - /* Fall through */ - out: - spin_unlock_irqrestore(¤t->sighand->siglock, flags); - if (buf2) - tty_audit_buf_free(buf2); - return buf; + /* Race to use this buffer, free it if another wins */ + if (cmpxchg(¤t->signal->tty_audit_buf, NULL, buf) != NULL) + tty_audit_buf_free(buf); + return tty_audit_buf_ref(); } /** @@ -265,39 +201,36 @@ static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty, * * Audit @data of @size from @tty, if necessary. */ -void tty_audit_add_data(struct tty_struct *tty, const void *data, - size_t size, unsigned icanon) +void tty_audit_add_data(struct tty_struct *tty, const void *data, size_t size) { struct tty_audit_buf *buf; - int major, minor; - int audit_log_tty_passwd; - unsigned long flags; + unsigned int icanon = !!L_ICANON(tty); + unsigned int audit_tty; + dev_t dev; - if (unlikely(size == 0)) + audit_tty = READ_ONCE(current->signal->audit_tty); + if (~audit_tty & AUDIT_TTY_ENABLE) return; - spin_lock_irqsave(¤t->sighand->siglock, flags); - audit_log_tty_passwd = current->signal->audit_tty_log_passwd; - spin_unlock_irqrestore(¤t->sighand->siglock, flags); - if (!audit_log_tty_passwd && icanon && !L_ECHO(tty)) + if (unlikely(size == 0)) return; if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER) return; - buf = tty_audit_buf_get(tty, icanon); - if (!buf) + if ((~audit_tty & AUDIT_TTY_LOG_PASSWD) && icanon && !L_ECHO(tty)) + return; + + buf = tty_audit_buf_get(); + if (IS_ERR_OR_NULL(buf)) return; mutex_lock(&buf->mutex); - major = tty->driver->major; - minor = tty->driver->minor_start + tty->index; - if (buf->major != major || buf->minor != minor - || buf->icanon != icanon) { + dev = MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index; + if (buf->dev != dev || buf->icanon != icanon) { tty_audit_buf_push(buf); - buf->major = major; - buf->minor = minor; + buf->dev = dev; buf->icanon = icanon; } do { @@ -314,38 +247,4 @@ void tty_audit_add_data(struct tty_struct *tty, const void *data, tty_audit_buf_push(buf); } while (size != 0); mutex_unlock(&buf->mutex); - tty_audit_buf_put(buf); -} - -/** - * tty_audit_push - Push buffered data out - * - * Make sure no audit data is pending for @tty on the current process. - */ -void tty_audit_push(struct tty_struct *tty) -{ - struct tty_audit_buf *buf; - unsigned long flags; - - spin_lock_irqsave(¤t->sighand->siglock, flags); - if (likely(!current->signal->audit_tty)) { - spin_unlock_irqrestore(¤t->sighand->siglock, flags); - return; - } - buf = current->signal->tty_audit_buf; - if (buf) - atomic_inc(&buf->count); - spin_unlock_irqrestore(¤t->sighand->siglock, flags); - - if (buf) { - int major, minor; - - major = tty->driver->major; - minor = tty->driver->minor_start + tty->index; - mutex_lock(&buf->mutex); - if (buf->major == major && buf->minor == minor) - tty_audit_buf_push(buf); - mutex_unlock(&buf->mutex); - tty_audit_buf_put(buf); - } } diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 3cd31e0d4bd9..a946e49a2626 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -435,25 +435,42 @@ int tty_prepare_flip_string(struct tty_port *port, unsigned char **chars, } EXPORT_SYMBOL_GPL(tty_prepare_flip_string); +/** + * tty_ldisc_receive_buf - forward data to line discipline + * @ld: line discipline to process input + * @p: char buffer + * @f: TTY_* flags buffer + * @count: number of bytes to process + * + * Callers other than flush_to_ldisc() need to exclude the kworker + * from concurrent use of the line discipline, see paste_selection(). + * + * Returns the number of bytes not processed + */ +int tty_ldisc_receive_buf(struct tty_ldisc *ld, unsigned char *p, + char *f, int count) +{ + if (ld->ops->receive_buf2) + count = ld->ops->receive_buf2(ld->tty, p, f, count); + else { + count = min_t(int, count, ld->tty->receive_room); + if (count && ld->ops->receive_buf) + ld->ops->receive_buf(ld->tty, p, f, count); + } + return count; +} +EXPORT_SYMBOL_GPL(tty_ldisc_receive_buf); static int -receive_buf(struct tty_struct *tty, struct tty_buffer *head, int count) +receive_buf(struct tty_ldisc *ld, struct tty_buffer *head, int count) { - struct tty_ldisc *disc = tty->ldisc; unsigned char *p = char_buf_ptr(head, head->read); char *f = NULL; if (~head->flags & TTYB_NORMAL) f = flag_buf_ptr(head, head->read); - if (disc->ops->receive_buf2) - count = disc->ops->receive_buf2(tty, p, f, count); - else { - count = min_t(int, count, tty->receive_room); - if (count && disc->ops->receive_buf) - disc->ops->receive_buf(tty, p, f, count); - } - return count; + return tty_ldisc_receive_buf(ld, p, f, count); } /** @@ -514,7 +531,7 @@ static void flush_to_ldisc(struct work_struct *work) continue; } - count = receive_buf(tty, head, count); + count = receive_buf(disc, head, count); if (!count) break; head->read += count; diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index a7eacef1bd22..8d26ed79bb4c 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -123,7 +123,8 @@ struct ktermios tty_std_termios = { /* for the benefit of tty drivers */ ECHOCTL | ECHOKE | IEXTEN, .c_cc = INIT_C_CC, .c_ispeed = 38400, - .c_ospeed = 38400 + .c_ospeed = 38400, + /* .c_line = N_TTY, */ }; EXPORT_SYMBOL(tty_std_termios); @@ -134,13 +135,8 @@ EXPORT_SYMBOL(tty_std_termios); LIST_HEAD(tty_drivers); /* linked list of tty drivers */ -/* Mutex to protect creating and releasing a tty. This is shared with - vt.c for deeply disgusting hack reasons */ +/* Mutex to protect creating and releasing a tty */ DEFINE_MUTEX(tty_mutex); -EXPORT_SYMBOL(tty_mutex); - -/* Spinlock to protect the tty->tty_files list */ -DEFINE_SPINLOCK(tty_files_lock); static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *); static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *); @@ -168,10 +164,9 @@ static void release_tty(struct tty_struct *tty, int idx); * Locking: none. Must be called after tty is definitely unused */ -void free_tty_struct(struct tty_struct *tty) +static void free_tty_struct(struct tty_struct *tty) { - if (!tty) - return; + tty_ldisc_deinit(tty); put_device(tty->dev); kfree(tty->write_buf); tty->magic = 0xDEADDEAD; @@ -204,9 +199,9 @@ void tty_add_file(struct tty_struct *tty, struct file *file) priv->tty = tty; priv->file = file; - spin_lock(&tty_files_lock); + spin_lock(&tty->files_lock); list_add(&priv->list, &tty->tty_files); - spin_unlock(&tty_files_lock); + spin_unlock(&tty->files_lock); } /** @@ -227,10 +222,11 @@ void tty_free_file(struct file *file) static void tty_del_file(struct file *file) { struct tty_file_private *priv = file->private_data; + struct tty_struct *tty = priv->tty; - spin_lock(&tty_files_lock); + spin_lock(&tty->files_lock); list_del(&priv->list); - spin_unlock(&tty_files_lock); + spin_unlock(&tty->files_lock); tty_free_file(file); } @@ -288,11 +284,11 @@ static int check_tty_count(struct tty_struct *tty, const char *routine) struct list_head *p; int count = 0; - spin_lock(&tty_files_lock); + spin_lock(&tty->files_lock); list_for_each(p, &tty->tty_files) { count++; } - spin_unlock(&tty_files_lock); + spin_unlock(&tty->files_lock); if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_SLAVE && tty->link && tty->link->count) @@ -383,6 +379,12 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line) EXPORT_SYMBOL_GPL(tty_find_polling_driver); #endif +static int is_ignored(int sig) +{ + return (sigismember(¤t->blocked, sig) || + current->sighand->action[sig-1].sa.sa_handler == SIG_IGN); +} + /** * tty_check_change - check for POSIX terminal changes * @tty: tty to check @@ -466,6 +468,11 @@ static long hung_up_tty_compat_ioctl(struct file *file, return cmd == TIOCSPGRP ? -ENOTTY : -EIO; } +static int hung_up_tty_fasync(int fd, struct file *file, int on) +{ + return -ENOTTY; +} + static const struct file_operations tty_fops = { .llseek = no_llseek, .read = tty_read, @@ -498,6 +505,7 @@ static const struct file_operations hung_up_tty_fops = { .unlocked_ioctl = hung_up_tty_ioctl, .compat_ioctl = hung_up_tty_compat_ioctl, .release = tty_release, + .fasync = hung_up_tty_fasync, }; static DEFINE_SPINLOCK(redirect_lock); @@ -709,7 +717,7 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session) workqueue with the lock held */ check_tty_count(tty, "tty_hangup"); - spin_lock(&tty_files_lock); + spin_lock(&tty->files_lock); /* This breaks for file handles being sent over AF_UNIX sockets ? */ list_for_each_entry(priv, &tty->tty_files, list) { filp = priv->file; @@ -721,14 +729,14 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session) __tty_fasync(-1, filp, 0); /* can't block */ filp->f_op = &hung_up_tty_fops; } - spin_unlock(&tty_files_lock); + spin_unlock(&tty->files_lock); refs = tty_signal_session_leader(tty, exit_session); /* Account for the p->signal references we killed */ while (refs--) tty_kref_put(tty); - tty_ldisc_hangup(tty); + tty_ldisc_hangup(tty, cons_filp != NULL); spin_lock_irq(&tty->ctrl_lock); clear_bit(TTY_THROTTLED, &tty->flags); @@ -753,10 +761,9 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session) } else if (tty->ops->hangup) tty->ops->hangup(tty); /* - * We don't want to have driver/ldisc interactions beyond - * the ones we did here. The driver layer expects no - * calls after ->hangup() from the ldisc side. However we - * can't yet guarantee all that. + * We don't want to have driver/ldisc interactions beyond the ones + * we did here. The driver layer expects no calls after ->hangup() + * from the ldisc side, which is now guaranteed. */ set_bit(TTY_HUPPED, &tty->flags); tty_unlock(tty); @@ -1069,6 +1076,8 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count, /* We want to wait for the line discipline to sort out in this situation */ ld = tty_ldisc_ref_wait(tty); + if (!ld) + return hung_up_tty_read(file, buf, count, ppos); if (ld->ops->read) i = ld->ops->read(tty, file, buf, count); else @@ -1243,6 +1252,8 @@ static ssize_t tty_write(struct file *file, const char __user *buf, if (tty->ops->write_room == NULL) tty_err(tty, "missing write_room method\n"); ld = tty_ldisc_ref_wait(tty); + if (!ld) + return hung_up_tty_write(file, buf, count, ppos); if (!ld->ops->write) ret = -EIO; else @@ -1378,7 +1389,7 @@ static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver, * the tty_mutex currently so we can be relaxed about ordering. */ -int tty_init_termios(struct tty_struct *tty) +void tty_init_termios(struct tty_struct *tty) { struct ktermios *tp; int idx = tty->index; @@ -1388,24 +1399,21 @@ int tty_init_termios(struct tty_struct *tty) else { /* Check for lazy saved data */ tp = tty->driver->termios[idx]; - if (tp != NULL) + if (tp != NULL) { tty->termios = *tp; - else + tty->termios.c_line = tty->driver->init_termios.c_line; + } else tty->termios = tty->driver->init_termios; } /* Compatibility until drivers always set this */ tty->termios.c_ispeed = tty_termios_input_baud_rate(&tty->termios); tty->termios.c_ospeed = tty_termios_baud_rate(&tty->termios); - return 0; } EXPORT_SYMBOL_GPL(tty_init_termios); int tty_standard_install(struct tty_driver *driver, struct tty_struct *tty) { - int ret = tty_init_termios(tty); - if (ret) - return ret; - + tty_init_termios(tty); tty_driver_kref_get(driver); tty->count++; driver->ttys[tty->index] = tty; @@ -1442,7 +1450,7 @@ static int tty_driver_install_tty(struct tty_driver *driver, * * Locking: tty_mutex for now */ -void tty_driver_remove_tty(struct tty_driver *driver, struct tty_struct *tty) +static void tty_driver_remove_tty(struct tty_driver *driver, struct tty_struct *tty) { if (driver->ops->remove) driver->ops->remove(driver, tty); @@ -1475,7 +1483,8 @@ static int tty_reopen(struct tty_struct *tty) tty->count++; - WARN_ON(!tty->ldisc); + if (!tty->ldisc) + return tty_ldisc_reinit(tty, tty->termios.c_line); return 0; } @@ -1529,7 +1538,7 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx) tty_lock(tty); retval = tty_driver_install_tty(driver, tty); if (retval < 0) - goto err_deinit_tty; + goto err_free_tty; if (!tty->port) tty->port = driver->ports[idx]; @@ -1551,9 +1560,8 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx) /* Return the tty locked so that it cannot vanish under the caller */ return tty; -err_deinit_tty: +err_free_tty: tty_unlock(tty); - deinitialize_tty_struct(tty); free_tty_struct(tty); err_module_put: module_put(driver->owner); @@ -1568,7 +1576,7 @@ err_release_tty: return ERR_PTR(retval); } -void tty_free_termios(struct tty_struct *tty) +static void tty_free_termios(struct tty_struct *tty) { struct ktermios *tp; int idx = tty->index; @@ -1587,7 +1595,6 @@ void tty_free_termios(struct tty_struct *tty) } *tp = tty->termios; } -EXPORT_SYMBOL(tty_free_termios); /** * tty_flush_works - flush all works of a tty/pty pair @@ -1634,9 +1641,9 @@ static void release_one_tty(struct work_struct *work) tty_driver_kref_put(driver); module_put(owner); - spin_lock(&tty_files_lock); + spin_lock(&tty->files_lock); list_del_init(&tty->tty_files); - spin_unlock(&tty_files_lock); + spin_unlock(&tty->files_lock); put_pid(tty->pgrp); put_pid(tty->session); @@ -1967,7 +1974,7 @@ static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp) * Locking: tty_mutex protects get_tty_driver */ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp, - int *noctty, int *index) + int *index) { struct tty_driver *driver; @@ -1977,7 +1984,6 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp, extern struct tty_driver *console_driver; driver = tty_driver_kref_get(console_driver); *index = fg_console; - *noctty = 1; break; } #endif @@ -1988,7 +1994,6 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp, if (driver) { /* Don't let /dev/console block */ filp->f_flags |= O_NONBLOCK; - *noctty = 1; break; } } @@ -2004,6 +2009,69 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp, } /** + * tty_open_by_driver - open a tty device + * @device: dev_t of device to open + * @inode: inode of device file + * @filp: file pointer to tty + * + * Performs the driver lookup, checks for a reopen, or otherwise + * performs the first-time tty initialization. + * + * Returns the locked initialized or re-opened &tty_struct + * + * Claims the global tty_mutex to serialize: + * - concurrent first-time tty initialization + * - concurrent tty driver removal w/ lookup + * - concurrent tty removal from driver table + */ +static struct tty_struct *tty_open_by_driver(dev_t device, struct inode *inode, + struct file *filp) +{ + struct tty_struct *tty; + struct tty_driver *driver = NULL; + int index = -1; + int retval; + + mutex_lock(&tty_mutex); + driver = tty_lookup_driver(device, filp, &index); + if (IS_ERR(driver)) { + mutex_unlock(&tty_mutex); + return ERR_CAST(driver); + } + + /* check whether we're reopening an existing tty */ + tty = tty_driver_lookup_tty(driver, inode, index); + if (IS_ERR(tty)) { + mutex_unlock(&tty_mutex); + goto out; + } + + if (tty) { + mutex_unlock(&tty_mutex); + retval = tty_lock_interruptible(tty); + if (retval) { + if (retval == -EINTR) + retval = -ERESTARTSYS; + tty = ERR_PTR(retval); + goto out; + } + /* safe to drop the kref from tty_driver_lookup_tty() */ + tty_kref_put(tty); + retval = tty_reopen(tty); + if (retval < 0) { + tty_unlock(tty); + tty = ERR_PTR(retval); + } + } else { /* Returns with the tty_lock held for now */ + tty = tty_init_dev(driver, index); + mutex_unlock(&tty_mutex); + } +out: + tty_driver_kref_put(driver); + return tty; +} + +/** * tty_open - open a tty device * @inode: inode of device file * @filp: file pointer to tty @@ -2031,8 +2099,6 @@ static int tty_open(struct inode *inode, struct file *filp) { struct tty_struct *tty; int noctty, retval; - struct tty_driver *driver = NULL; - int index; dev_t device = inode->i_rdev; unsigned saved_flags = filp->f_flags; @@ -2043,53 +2109,15 @@ retry_open: if (retval) return -ENOMEM; - noctty = filp->f_flags & O_NOCTTY; - index = -1; - retval = 0; - tty = tty_open_current_tty(device, filp); - if (!tty) { - mutex_lock(&tty_mutex); - driver = tty_lookup_driver(device, filp, &noctty, &index); - if (IS_ERR(driver)) { - retval = PTR_ERR(driver); - goto err_unlock; - } - - /* check whether we're reopening an existing tty */ - tty = tty_driver_lookup_tty(driver, inode, index); - if (IS_ERR(tty)) { - retval = PTR_ERR(tty); - goto err_unlock; - } - - if (tty) { - mutex_unlock(&tty_mutex); - retval = tty_lock_interruptible(tty); - tty_kref_put(tty); /* drop kref from tty_driver_lookup_tty() */ - if (retval) { - if (retval == -EINTR) - retval = -ERESTARTSYS; - goto err_unref; - } - retval = tty_reopen(tty); - if (retval < 0) { - tty_unlock(tty); - tty = ERR_PTR(retval); - } - } else { /* Returns with the tty_lock held for now */ - tty = tty_init_dev(driver, index); - mutex_unlock(&tty_mutex); - } - - tty_driver_kref_put(driver); - } + if (!tty) + tty = tty_open_by_driver(device, inode, filp); if (IS_ERR(tty)) { + tty_free_file(filp); retval = PTR_ERR(tty); if (retval != -EAGAIN || signal_pending(current)) - goto err_file; - tty_free_file(filp); + return retval; schedule(); goto retry_open; } @@ -2097,10 +2125,6 @@ retry_open: tty_add_file(tty, filp); check_tty_count(tty, __func__); - if (tty->driver->type == TTY_DRIVER_TYPE_PTY && - tty->driver->subtype == PTY_TYPE_MASTER) - noctty = 1; - tty_debug_hangup(tty, "opening (count=%d)\n", tty->count); if (tty->ops->open) @@ -2133,6 +2157,12 @@ retry_open: read_lock(&tasklist_lock); spin_lock_irq(¤t->sighand->siglock); + noctty = (filp->f_flags & O_NOCTTY) || + device == MKDEV(TTY_MAJOR, 0) || + device == MKDEV(TTYAUX_MAJOR, 1) || + (tty->driver->type == TTY_DRIVER_TYPE_PTY && + tty->driver->subtype == PTY_TYPE_MASTER); + if (!noctty && current->signal->leader && !current->signal->tty && @@ -2158,15 +2188,6 @@ retry_open: read_unlock(&tasklist_lock); tty_unlock(tty); return 0; -err_unlock: - mutex_unlock(&tty_mutex); -err_unref: - /* after locks to avoid deadlock */ - if (!IS_ERR_OR_NULL(driver)) - tty_driver_kref_put(driver); -err_file: - tty_free_file(filp); - return retval; } @@ -2193,6 +2214,8 @@ static unsigned int tty_poll(struct file *filp, poll_table *wait) return 0; ld = tty_ldisc_ref_wait(tty); + if (!ld) + return hung_up_tty_poll(filp, wait); if (ld->ops->poll) ret = ld->ops->poll(tty, filp, wait); tty_ldisc_deref(ld); @@ -2202,7 +2225,6 @@ static unsigned int tty_poll(struct file *filp, poll_table *wait) static int __tty_fasync(int fd, struct file *filp, int on) { struct tty_struct *tty = file_tty(filp); - struct tty_ldisc *ldisc; unsigned long flags; int retval = 0; @@ -2213,13 +2235,6 @@ static int __tty_fasync(int fd, struct file *filp, int on) if (retval <= 0) goto out; - ldisc = tty_ldisc_ref(tty); - if (ldisc) { - if (ldisc->ops->fasync) - ldisc->ops->fasync(tty, on); - tty_ldisc_deref(ldisc); - } - if (on) { enum pid_type type; struct pid *pid; @@ -2245,10 +2260,11 @@ out: static int tty_fasync(int fd, struct file *filp, int on) { struct tty_struct *tty = file_tty(filp); - int retval; + int retval = -ENOTTY; tty_lock(tty); - retval = __tty_fasync(fd, filp, on); + if (!tty_hung_up_p(filp)) + retval = __tty_fasync(fd, filp, on); tty_unlock(tty); return retval; @@ -2282,6 +2298,8 @@ static int tiocsti(struct tty_struct *tty, char __user *p) return -EFAULT; tty_audit_tiocsti(tty, ch); ld = tty_ldisc_ref_wait(tty); + if (!ld) + return -EIO; ld->ops->receive_buf(tty, &ch, &mbz, 1); tty_ldisc_deref(ld); return 0; @@ -2646,13 +2664,13 @@ static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t _ static int tiocsetd(struct tty_struct *tty, int __user *p) { - int ldisc; + int disc; int ret; - if (get_user(ldisc, p)) + if (get_user(disc, p)) return -EFAULT; - ret = tty_set_ldisc(tty, ldisc); + ret = tty_set_ldisc(tty, disc); return ret; } @@ -2674,6 +2692,8 @@ static int tiocgetd(struct tty_struct *tty, int __user *p) int ret; ld = tty_ldisc_ref_wait(tty); + if (!ld) + return -EIO; ret = put_user(ld->ops->num, p); tty_ldisc_deref(ld); return ret; @@ -2971,6 +2991,8 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return retval; } ld = tty_ldisc_ref_wait(tty); + if (!ld) + return hung_up_tty_ioctl(file, cmd, arg); retval = -EINVAL; if (ld->ops->ioctl) { retval = ld->ops->ioctl(tty, file, cmd, arg); @@ -2999,6 +3021,8 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd, } ld = tty_ldisc_ref_wait(tty); + if (!ld) + return hung_up_tty_compat_ioctl(file, cmd, arg); if (ld->ops->compat_ioctl) retval = ld->ops->compat_ioctl(tty, file, cmd, arg); else @@ -3149,6 +3173,7 @@ struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx) mutex_init(&tty->atomic_write_lock); spin_lock_init(&tty->ctrl_lock); spin_lock_init(&tty->flow_lock); + spin_lock_init(&tty->files_lock); INIT_LIST_HEAD(&tty->tty_files); INIT_WORK(&tty->SAK_work, do_SAK_work); @@ -3162,20 +3187,6 @@ struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx) } /** - * deinitialize_tty_struct - * @tty: tty to deinitialize - * - * This subroutine deinitializes a tty structure that has been newly - * allocated but tty_release cannot be called on that yet. - * - * Locking: none - tty in question must not be exposed at this point - */ -void deinitialize_tty_struct(struct tty_struct *tty) -{ - tty_ldisc_deinit(tty); -} - -/** * tty_put_char - write one character to a tty * @tty: tty * @ch: character @@ -3569,7 +3580,7 @@ void __init console_init(void) initcall_t *call; /* Setup the default TTY line discipline. */ - tty_ldisc_begin(); + n_tty_init(); /* * set up the console device so that later boot sequences can diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index 0ea351388724..23bf5bb1d8bf 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -719,16 +719,16 @@ static int get_sgflags(struct tty_struct *tty) { int flags = 0; - if (!(tty->termios.c_lflag & ICANON)) { - if (tty->termios.c_lflag & ISIG) + if (!L_ICANON(tty)) { + if (L_ISIG(tty)) flags |= 0x02; /* cbreak */ else flags |= 0x20; /* raw */ } - if (tty->termios.c_lflag & ECHO) + if (L_ECHO(tty)) flags |= 0x08; /* echo */ - if (tty->termios.c_oflag & OPOST) - if (tty->termios.c_oflag & ONLCR) + if (O_OPOST(tty)) + if (O_ONLCR(tty)) flags |= 0x10; /* crmod */ return flags; } @@ -908,7 +908,7 @@ static int tty_change_softcar(struct tty_struct *tty, int arg) tty->termios.c_cflag |= bit; if (tty->ops->set_termios) tty->ops->set_termios(tty, &old); - if ((tty->termios.c_cflag & CLOCAL) != bit) + if (C_CLOCAL(tty) != bit) ret = -EINVAL; up_write(&tty->termios_rwsem); return ret; diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index a054d03c22e7..68947f6de5ad 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -140,9 +140,16 @@ static void put_ldops(struct tty_ldisc_ops *ldops) * @disc: ldisc number * * Takes a reference to a line discipline. Deals with refcounts and - * module locking counts. Returns NULL if the discipline is not available. - * Returns a pointer to the discipline and bumps the ref count if it is - * available + * module locking counts. + * + * Returns: -EINVAL if the discipline index is not [N_TTY..NR_LDISCS] or + * if the discipline is not registered + * -EAGAIN if request_module() failed to load or register the + * the discipline + * -ENOMEM if allocation failure + * + * Otherwise, returns a pointer to the discipline and bumps the + * ref count * * Locking: * takes tty_ldiscs_lock to guard against ldisc races @@ -250,19 +257,23 @@ const struct file_operations tty_ldiscs_proc_fops = { * reference to it. If the line discipline is in flux then * wait patiently until it changes. * + * Returns: NULL if the tty has been hungup and not re-opened with + * a new file descriptor, otherwise valid ldisc reference + * * Note: Must not be called from an IRQ/timer context. The caller * must also be careful not to hold other locks that will deadlock * against a discipline change, such as an existing ldisc reference * (which we check for) * - * Note: only callable from a file_operations routine (which - * guarantees tty->ldisc != NULL when the lock is acquired). + * Note: a file_operations routine (read/poll/write) should use this + * function to wait for any ldisc lifetime events to finish. */ struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty) { ldsem_down_read(&tty->ldisc_sem, MAX_SCHEDULE_TIMEOUT); - WARN_ON(!tty->ldisc); + if (!tty->ldisc) + ldsem_up_read(&tty->ldisc_sem); return tty->ldisc; } EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); @@ -304,13 +315,13 @@ void tty_ldisc_deref(struct tty_ldisc *ld) EXPORT_SYMBOL_GPL(tty_ldisc_deref); -static inline int __lockfunc +static inline int __tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout) { return ldsem_down_write(&tty->ldisc_sem, timeout); } -static inline int __lockfunc +static inline int __tty_ldisc_lock_nested(struct tty_struct *tty, unsigned long timeout) { return ldsem_down_write_nested(&tty->ldisc_sem, @@ -322,8 +333,7 @@ static inline void __tty_ldisc_unlock(struct tty_struct *tty) ldsem_up_write(&tty->ldisc_sem); } -static int __lockfunc -tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout) +static int tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout) { int ret; @@ -340,7 +350,7 @@ static void tty_ldisc_unlock(struct tty_struct *tty) __tty_ldisc_unlock(tty); } -static int __lockfunc +static int tty_ldisc_lock_pair_timeout(struct tty_struct *tty, struct tty_struct *tty2, unsigned long timeout) { @@ -376,14 +386,13 @@ tty_ldisc_lock_pair_timeout(struct tty_struct *tty, struct tty_struct *tty2, return 0; } -static void __lockfunc -tty_ldisc_lock_pair(struct tty_struct *tty, struct tty_struct *tty2) +static void tty_ldisc_lock_pair(struct tty_struct *tty, struct tty_struct *tty2) { tty_ldisc_lock_pair_timeout(tty, tty2, MAX_SCHEDULE_TIMEOUT); } -static void __lockfunc tty_ldisc_unlock_pair(struct tty_struct *tty, - struct tty_struct *tty2) +static void tty_ldisc_unlock_pair(struct tty_struct *tty, + struct tty_struct *tty2) { __tty_ldisc_unlock(tty); if (tty2) @@ -411,7 +420,7 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush); /** * tty_set_termios_ldisc - set ldisc field * @tty: tty structure - * @num: line discipline number + * @disc: line discipline number * * This is probably overkill for real world processors but * they are not on hot paths so a little discipline won't do @@ -424,10 +433,10 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush); * Locking: takes termios_rwsem */ -static void tty_set_termios_ldisc(struct tty_struct *tty, int num) +static void tty_set_termios_ldisc(struct tty_struct *tty, int disc) { down_write(&tty->termios_rwsem); - tty->termios.c_line = num; + tty->termios.c_line = disc; up_write(&tty->termios_rwsem); tty->disc_data = NULL; @@ -455,7 +464,7 @@ static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld) if (ret) clear_bit(TTY_LDISC_OPEN, &tty->flags); - tty_ldisc_debug(tty, "%p: opened\n", tty->ldisc); + tty_ldisc_debug(tty, "%p: opened\n", ld); return ret; } return 0; @@ -476,7 +485,7 @@ static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld) clear_bit(TTY_LDISC_OPEN, &tty->flags); if (ld->ops->close) ld->ops->close(tty); - tty_ldisc_debug(tty, "%p: closed\n", tty->ldisc); + tty_ldisc_debug(tty, "%p: closed\n", ld); } /** @@ -525,12 +534,12 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old) * the close of one side of a tty/pty pair, and eventually hangup. */ -int tty_set_ldisc(struct tty_struct *tty, int ldisc) +int tty_set_ldisc(struct tty_struct *tty, int disc) { int retval; struct tty_ldisc *old_ldisc, *new_ldisc; - new_ldisc = tty_ldisc_get(tty, ldisc); + new_ldisc = tty_ldisc_get(tty, disc); if (IS_ERR(new_ldisc)) return PTR_ERR(new_ldisc); @@ -539,8 +548,13 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) if (retval) goto err; + if (!tty->ldisc) { + retval = -EIO; + goto out; + } + /* Check the no-op case */ - if (tty->ldisc->ops->num == ldisc) + if (tty->ldisc->ops->num == disc) goto out; if (test_bit(TTY_HUPPED, &tty->flags)) { @@ -556,7 +570,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) /* Now set up the new line discipline. */ tty->ldisc = new_ldisc; - tty_set_termios_ldisc(tty, ldisc); + tty_set_termios_ldisc(tty, disc); retval = tty_ldisc_open(tty, new_ldisc); if (retval < 0) { @@ -590,6 +604,25 @@ err: } /** + * tty_ldisc_kill - teardown ldisc + * @tty: tty being released + * + * Perform final close of the ldisc and reset tty->ldisc + */ +static void tty_ldisc_kill(struct tty_struct *tty) +{ + if (!tty->ldisc) + return; + /* + * Now kill off the ldisc + */ + tty_ldisc_close(tty, tty->ldisc); + tty_ldisc_put(tty->ldisc); + /* Force an oops if we mess this up */ + tty->ldisc = NULL; +} + +/** * tty_reset_termios - reset terminal state * @tty: tty to reset * @@ -609,28 +642,44 @@ static void tty_reset_termios(struct tty_struct *tty) /** * tty_ldisc_reinit - reinitialise the tty ldisc * @tty: tty to reinit - * @ldisc: line discipline to reinitialize + * @disc: line discipline to reinitialize + * + * Completely reinitialize the line discipline state, by closing the + * current instance, if there is one, and opening a new instance. If + * an error occurs opening the new non-N_TTY instance, the instance + * is dropped and tty->ldisc reset to NULL. The caller can then retry + * with N_TTY instead. * - * Switch the tty to a line discipline and leave the ldisc - * state closed + * Returns 0 if successful, otherwise error code < 0 */ -static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc) +int tty_ldisc_reinit(struct tty_struct *tty, int disc) { - struct tty_ldisc *ld = tty_ldisc_get(tty, ldisc); + struct tty_ldisc *ld; + int retval; - if (IS_ERR(ld)) - return -1; + ld = tty_ldisc_get(tty, disc); + if (IS_ERR(ld)) { + BUG_ON(disc == N_TTY); + return PTR_ERR(ld); + } - tty_ldisc_close(tty, tty->ldisc); - tty_ldisc_put(tty->ldisc); - /* - * Switch the line discipline back - */ - tty->ldisc = ld; - tty_set_termios_ldisc(tty, ldisc); + if (tty->ldisc) { + tty_ldisc_close(tty, tty->ldisc); + tty_ldisc_put(tty->ldisc); + } - return 0; + /* switch the line discipline */ + tty->ldisc = ld; + tty_set_termios_ldisc(tty, disc); + retval = tty_ldisc_open(tty, tty->ldisc); + if (retval) { + if (!WARN_ON(disc == N_TTY)) { + tty_ldisc_put(tty->ldisc); + tty->ldisc = NULL; + } + } + return retval; } /** @@ -648,13 +697,11 @@ static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc) * tty itself so we must be careful about locking rules. */ -void tty_ldisc_hangup(struct tty_struct *tty) +void tty_ldisc_hangup(struct tty_struct *tty, bool reinit) { struct tty_ldisc *ld; - int reset = tty->driver->flags & TTY_DRIVER_RESET_TERMIOS; - int err = 0; - tty_ldisc_debug(tty, "%p: closing\n", tty->ldisc); + tty_ldisc_debug(tty, "%p: hangup\n", tty->ldisc); ld = tty_ldisc_ref(tty); if (ld != NULL) { @@ -680,31 +727,17 @@ void tty_ldisc_hangup(struct tty_struct *tty) */ tty_ldisc_lock(tty, MAX_SCHEDULE_TIMEOUT); - if (tty->ldisc) { - - /* At this point we have a halted ldisc; we want to close it and - reopen a new ldisc. We could defer the reopen to the next - open but it means auditing a lot of other paths so this is - a FIXME */ - if (reset == 0) { + if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) + tty_reset_termios(tty); - if (!tty_ldisc_reinit(tty, tty->termios.c_line)) - err = tty_ldisc_open(tty, tty->ldisc); - else - err = 1; - } - /* If the re-open fails or we reset then go to N_TTY. The - N_TTY open cannot fail */ - if (reset || err) { - BUG_ON(tty_ldisc_reinit(tty, N_TTY)); - WARN_ON(tty_ldisc_open(tty, tty->ldisc)); - } + if (tty->ldisc) { + if (reinit) { + if (tty_ldisc_reinit(tty, tty->termios.c_line) < 0) + tty_ldisc_reinit(tty, N_TTY); + } else + tty_ldisc_kill(tty); } tty_ldisc_unlock(tty); - if (reset) - tty_reset_termios(tty); - - tty_ldisc_debug(tty, "%p: re-opened\n", tty->ldisc); } /** @@ -719,44 +752,26 @@ void tty_ldisc_hangup(struct tty_struct *tty) int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty) { - struct tty_ldisc *ld = tty->ldisc; - int retval; - - retval = tty_ldisc_open(tty, ld); + int retval = tty_ldisc_open(tty, tty->ldisc); if (retval) return retval; if (o_tty) { retval = tty_ldisc_open(o_tty, o_tty->ldisc); if (retval) { - tty_ldisc_close(tty, ld); + tty_ldisc_close(tty, tty->ldisc); return retval; } } return 0; } -static void tty_ldisc_kill(struct tty_struct *tty) -{ - /* - * Now kill off the ldisc - */ - tty_ldisc_close(tty, tty->ldisc); - tty_ldisc_put(tty->ldisc); - /* Force an oops if we mess this up */ - tty->ldisc = NULL; - - /* Ensure the next open requests the N_TTY ldisc */ - tty_set_termios_ldisc(tty, N_TTY); -} - /** * tty_ldisc_release - release line discipline * @tty: tty being shut down (or one end of pty pair) * * Called during the final close of a tty or a pty pair in order to shut - * down the line discpline layer. On exit, each ldisc assigned is N_TTY and - * each ldisc has not been opened. + * down the line discpline layer. On exit, each tty's ldisc is NULL. */ void tty_ldisc_release(struct tty_struct *tty) @@ -797,7 +812,7 @@ void tty_ldisc_init(struct tty_struct *tty) } /** - * tty_ldisc_init - ldisc cleanup for new tty + * tty_ldisc_deinit - ldisc cleanup for new tty * @tty: tty that was allocated recently * * The tty structure must not becompletely set up (tty_ldisc_setup) when @@ -805,12 +820,7 @@ void tty_ldisc_init(struct tty_struct *tty) */ void tty_ldisc_deinit(struct tty_struct *tty) { - tty_ldisc_put(tty->ldisc); + if (tty->ldisc) + tty_ldisc_put(tty->ldisc); tty->ldisc = NULL; } - -void tty_ldisc_begin(void) -{ - /* Setup the default TTY line discipline. */ - (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY); -} diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c index dfa9ec03fa8e..d8bae67a6174 100644 --- a/drivers/tty/tty_mutex.c +++ b/drivers/tty/tty_mutex.c @@ -10,7 +10,7 @@ * Getting the big tty mutex. */ -void __lockfunc tty_lock(struct tty_struct *tty) +void tty_lock(struct tty_struct *tty) { if (WARN(tty->magic != TTY_MAGIC, "L Bad %p\n", tty)) return; @@ -32,7 +32,7 @@ int tty_lock_interruptible(struct tty_struct *tty) return ret; } -void __lockfunc tty_unlock(struct tty_struct *tty) +void tty_unlock(struct tty_struct *tty) { if (WARN(tty->magic != TTY_MAGIC, "U Bad %p\n", tty)) return; @@ -41,13 +41,13 @@ void __lockfunc tty_unlock(struct tty_struct *tty) } EXPORT_SYMBOL(tty_unlock); -void __lockfunc tty_lock_slave(struct tty_struct *tty) +void tty_lock_slave(struct tty_struct *tty) { if (tty && tty != tty->link) tty_lock(tty); } -void __lockfunc tty_unlock_slave(struct tty_struct *tty) +void tty_unlock_slave(struct tty_struct *tty) { if (tty && tty != tty->link) tty_unlock(tty); diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 846ed481c24f..dbcca30a54b1 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -370,7 +370,7 @@ int tty_port_block_til_ready(struct tty_port *port, } if (filp->f_flags & O_NONBLOCK) { /* Indicate we are open */ - if (tty->termios.c_cflag & CBAUD) + if (C_BAUD(tty)) tty_port_raise_dtr_rts(port); port->flags |= ASYNC_NORMAL_ACTIVE; return 0; @@ -476,7 +476,6 @@ int tty_port_close_start(struct tty_port *port, spin_unlock_irqrestore(&port->lock, flags); return 0; } - set_bit(ASYNCB_CLOSING, &port->flags); spin_unlock_irqrestore(&port->lock, flags); tty->closing = 1; @@ -510,14 +509,12 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty) if (port->blocked_open) { spin_unlock_irqrestore(&port->lock, flags); - if (port->close_delay) { - msleep_interruptible( - jiffies_to_msecs(port->close_delay)); - } + if (port->close_delay) + msleep_interruptible(jiffies_to_msecs(port->close_delay)); spin_lock_irqsave(&port->lock, flags); wake_up_interruptible(&port->open_wait); } - port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING); + port->flags &= ~ASYNC_NORMAL_ACTIVE; spin_unlock_irqrestore(&port->lock, flags); } EXPORT_SYMBOL(tty_port_close_end); diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 6f0336fff501..f973bfce5d08 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -1706,16 +1706,12 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm) return -EINVAL; if (ct) { - dia = kmalloc(sizeof(struct kbdiacr) * ct, - GFP_KERNEL); - if (!dia) - return -ENOMEM; - if (copy_from_user(dia, a->kbdiacr, - sizeof(struct kbdiacr) * ct)) { - kfree(dia); - return -EFAULT; - } + dia = memdup_user(a->kbdiacr, + sizeof(struct kbdiacr) * ct); + if (IS_ERR(dia)) + return PTR_ERR(dia); + } spin_lock_irqsave(&kbd_event_lock, flags); diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 381a2b13682c..4dd9dd2270a0 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -347,6 +347,8 @@ int paste_selection(struct tty_struct *tty) console_unlock(); ld = tty_ldisc_ref_wait(tty); + if (!ld) + return -EIO; /* ldisc was hung up */ tty_buffer_lock_exclusive(&vc->port); add_wait_queue(&vc->paste_wait, &wait); diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index bd51bdd0a7bf..3e3c7575e92d 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -568,7 +568,7 @@ static void delete_char(struct vc_data *vc, unsigned int nr) vc->vc_cols - vc->vc_x); } -static int softcursor_original; +static int softcursor_original = -1; static void add_softcursor(struct vc_data *vc) { diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index 3806e7014199..a66b01bb1fa1 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c @@ -147,10 +147,7 @@ static int usb_console_setup(struct console *co, char *options) kref_get(&tty->driver->kref); __module_get(tty->driver->owner); tty->ops = &usb_console_fake_tty_ops; - if (tty_init_termios(tty)) { - retval = -ENOMEM; - goto put_tty; - } + tty_init_termios(tty); tty_port_tty_set(&port->port, tty); } @@ -185,7 +182,6 @@ static int usb_console_setup(struct console *co, char *options) fail: tty_port_tty_set(&port->port, NULL); - put_tty: tty_kref_put(tty); reset_open_count: port->port.count = 0; diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 01bf53392819..b283eb8b86d6 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -1165,8 +1165,7 @@ static void cypress_read_int_callback(struct urb *urb) /* hangup, as defined in acm.c... this might be a bad place for it * though */ - if (tty && !(tty->termios.c_cflag & CLOCAL) && - !(priv->current_status & UART_CD)) { + if (tty && !C_CLOCAL(tty) && !(priv->current_status & UART_CD)) { dev_dbg(dev, "%s - calling hangup\n", __func__); tty_hangup(tty); goto continue_read; diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 12b0e67473ba..010a42a92688 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -695,11 +695,11 @@ static void digi_set_termios(struct tty_struct *tty, arg = -1; /* reassert DTR and (maybe) RTS on transition from B0 */ - if ((old_cflag&CBAUD) == B0) { + if ((old_cflag & CBAUD) == B0) { /* don't set RTS if using hardware flow control */ /* and throttling input */ modem_signals = TIOCM_DTR; - if (!(tty->termios.c_cflag & CRTSCTS) || + if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags)) modem_signals |= TIOCM_RTS; digi_set_modem_signals(port, modem_signals, 1); @@ -1491,8 +1491,8 @@ static int digi_read_oob_callback(struct urb *urb) rts = 0; if (tty) - rts = tty->termios.c_cflag & CRTSCTS; - + rts = C_CRTSCTS(tty); + if (tty && opcode == DIGI_CMD_READ_INPUT_SIGNALS) { spin_lock(&priv->dp_port_lock); /* convert from digi flags to termiox flags */ diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index f49327d20ee8..f3007ecdd1b4 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -1398,7 +1398,7 @@ static void edge_throttle(struct tty_struct *tty) } /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios.c_cflag & CRTSCTS) { + if (C_CRTSCTS(tty)) { edge_port->shadowMCR &= ~MCR_RTS; status = send_cmd_write_uart_register(edge_port, MCR, edge_port->shadowMCR); @@ -1435,7 +1435,7 @@ static void edge_unthrottle(struct tty_struct *tty) return; } /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios.c_cflag & CRTSCTS) { + if (C_CRTSCTS(tty)) { edge_port->shadowMCR |= MCR_RTS; send_cmd_write_uart_register(edge_port, MCR, edge_port->shadowMCR); diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index fd707d6a10e2..4446b8d70ac2 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -428,7 +428,7 @@ static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port) * either. */ spin_lock_irqsave(&priv->lock, flags); - if (tty && (tty->termios.c_cflag & CBAUD)) + if (tty && C_BAUD(tty)) priv->control_state = TIOCM_DTR | TIOCM_RTS; else priv->control_state = 0; diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 78b4f64c6b00..2eddbe538cda 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -1308,7 +1308,7 @@ static void mos7720_throttle(struct tty_struct *tty) } /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios.c_cflag & CRTSCTS) { + if (C_CRTSCTS(tty)) { mos7720_port->shadowMCR &= ~UART_MCR_RTS; write_mos_reg(port->serial, port->port_number, MOS7720_MCR, mos7720_port->shadowMCR); @@ -1338,7 +1338,7 @@ static void mos7720_unthrottle(struct tty_struct *tty) } /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios.c_cflag & CRTSCTS) { + if (C_CRTSCTS(tty)) { mos7720_port->shadowMCR |= UART_MCR_RTS; write_mos_reg(port->serial, port->port_number, MOS7720_MCR, mos7720_port->shadowMCR); diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 2c69bfcdacc6..02ea975754f5 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -1425,7 +1425,7 @@ static void mos7840_throttle(struct tty_struct *tty) return; } /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios.c_cflag & CRTSCTS) { + if (C_CRTSCTS(tty)) { mos7840_port->shadowMCR &= ~MCR_RTS; status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, mos7840_port->shadowMCR); @@ -1466,7 +1466,7 @@ static void mos7840_unthrottle(struct tty_struct *tty) } /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios.c_cflag & CRTSCTS) { + if (C_CRTSCTS(tty)) { mos7840_port->shadowMCR |= MCR_RTS; status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, mos7840_port->shadowMCR); diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 772c784ba763..8f5a12ab2f2b 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -157,7 +157,7 @@ #define EARLYCON_TABLE() STRUCT_ALIGN(); \ VMLINUX_SYMBOL(__earlycon_table) = .; \ *(__earlycon_table) \ - *(__earlycon_table_end) + VMLINUX_SYMBOL(__earlycon_table_end) = .; #else #define EARLYCON_TABLE() #endif @@ -179,7 +179,6 @@ #define RESERVEDMEM_OF_TABLES() OF_TABLE(CONFIG_OF_RESERVED_MEM, reservedmem) #define CPU_METHOD_OF_TABLES() OF_TABLE(CONFIG_SMP, cpu_method) #define CPUIDLE_METHOD_OF_TABLES() OF_TABLE(CONFIG_CPU_IDLE, cpuidle_method) -#define EARLYCON_OF_TABLES() OF_TABLE(CONFIG_SERIAL_EARLYCON, earlycon) #ifdef CONFIG_ACPI #define ACPI_PROBE_TABLE(name) \ @@ -527,8 +526,7 @@ IRQCHIP_OF_MATCH_TABLE() \ ACPI_PROBE_TABLE(irqchip) \ ACPI_PROBE_TABLE(clksrc) \ - EARLYCON_TABLE() \ - EARLYCON_OF_TABLES() + EARLYCON_TABLE() #define INIT_TEXT \ *(.init.text) \ diff --git a/include/linux/atmel_serial.h b/include/linux/atmel_serial.h index ee696d7e8a43..5a4d664af87a 100644 --- a/include/linux/atmel_serial.h +++ b/include/linux/atmel_serial.h @@ -119,7 +119,8 @@ #define ATMEL_US_BRGR 0x20 /* Baud Rate Generator Register */ #define ATMEL_US_CD GENMASK(15, 0) /* Clock Divider */ -#define ATMEL_US_RTOR 0x24 /* Receiver Time-out Register */ +#define ATMEL_US_RTOR 0x24 /* Receiver Time-out Register for USART */ +#define ATMEL_UA_RTOR 0x28 /* Receiver Time-out Register for UART */ #define ATMEL_US_TO GENMASK(15, 0) /* Time-out Value */ #define ATMEL_US_TTGR 0x28 /* Transmitter Timeguard Register */ diff --git a/include/linux/audit.h b/include/linux/audit.h index b40ed5df5542..e38e3fc13ea8 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -109,6 +109,10 @@ extern int audit_classify_compat_syscall(int abi, unsigned syscall); /* maximized args number that audit_socketcall can process */ #define AUDITSC_ARGS 6 +/* bit values for ->signal->audit_tty */ +#define AUDIT_TTY_ENABLE BIT(0) +#define AUDIT_TTY_LOG_PASSWD BIT(1) + struct filename; extern void audit_log_session_info(struct audit_buffer *ab); diff --git a/include/linux/isdn.h b/include/linux/isdn.h index 1e9a0f2a8626..df97c8444f5d 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -319,6 +319,7 @@ typedef struct modem_info { int online; /* 1 = B-Channel is up, drop data */ /* 2 = B-Channel is up, deliver d.*/ int dialing; /* Dial in progress or ATA */ + int closing; int rcvsched; /* Receive needs schedule */ int isdn_driver; /* Index to isdn-driver */ int isdn_channel; /* Index to isdn-channel */ diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h index df9ef3801812..2fbe8682a66f 100644 --- a/include/linux/of_fdt.h +++ b/include/linux/of_fdt.h @@ -88,7 +88,7 @@ extern void unflatten_device_tree(void); extern void unflatten_and_copy_device_tree(void); extern void early_init_devtree(void *); extern void early_get_first_memblock_info(void *, phys_addr_t *); -extern u64 fdt_translate_address(const void *blob, int node_offset); +extern u64 of_flat_dt_translate_address(unsigned long node); extern void of_fdt_limit_memory(int limit); #else /* CONFIG_OF_FLATTREE */ static inline void early_init_fdt_scan_reserved_mem(void) {} diff --git a/include/linux/platform_data/sa11x0-serial.h b/include/linux/platform_data/sa11x0-serial.h index 4504d5d592f0..009e1d83fe39 100644 --- a/include/linux/platform_data/sa11x0-serial.h +++ b/include/linux/platform_data/sa11x0-serial.h @@ -26,8 +26,12 @@ struct sa1100_port_fns { void sa1100_register_uart_fns(struct sa1100_port_fns *fns); void sa1100_register_uart(int idx, int port); #else -#define sa1100_register_uart_fns(fns) do { } while (0) -#define sa1100_register_uart(idx,port) do { } while (0) +static inline void sa1100_register_uart_fns(struct sa1100_port_fns *fns) +{ +} +static inline void sa1100_register_uart(int idx, int port) +{ +} #endif #endif diff --git a/include/linux/platform_data/serial-omap.h b/include/linux/platform_data/serial-omap.h index d09275f3cde3..2ba2c34ca3d3 100644 --- a/include/linux/platform_data/serial-omap.h +++ b/include/linux/platform_data/serial-omap.h @@ -21,7 +21,7 @@ #include <linux/device.h> #include <linux/pm_qos.h> -#define DRIVER_NAME "omap_uart" +#define OMAP_SERIAL_DRIVER_NAME "omap_uart" /* * Use tty device name as ttyO, [O -> OMAP] diff --git a/include/linux/sched.h b/include/linux/sched.h index eb7f2f84009b..bd242bed4abb 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -777,7 +777,6 @@ struct signal_struct { #endif #ifdef CONFIG_AUDIT unsigned audit_tty; - unsigned audit_tty_log_passwd; struct tty_audit_buf *tty_audit_buf; #endif diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index faa0e0370ce7..434879759725 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -76,6 +76,12 @@ struct uart_8250_ops { void (*release_irq)(struct uart_8250_port *); }; +struct uart_8250_em485 { + struct timer_list start_tx_timer; /* "rs485 start tx" timer */ + struct timer_list stop_tx_timer; /* "rs485 stop tx" timer */ + struct timer_list *active_timer; /* pointer to active timer */ +}; + /* * This should be used by drivers which want to register * their own 8250 ports without registering their own @@ -122,6 +128,8 @@ struct uart_8250_port { /* 8250 specific callbacks */ int (*dl_read)(struct uart_8250_port *); void (*dl_write)(struct uart_8250_port *, int); + + struct uart_8250_em485 *em485; }; static inline struct uart_8250_port *up_to_u8250p(struct uart_port *up) diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index e03d6ba5e5b4..cbfcf38e220d 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -342,21 +342,26 @@ struct earlycon_device { struct earlycon_id { char name[16]; + char compatible[128]; int (*setup)(struct earlycon_device *, const char *options); } __aligned(32); -extern int setup_earlycon(char *buf); -extern int of_setup_earlycon(unsigned long addr, - int (*setup)(struct earlycon_device *, const char *)); +extern const struct earlycon_id __earlycon_table[]; +extern const struct earlycon_id __earlycon_table_end[]; + +#define OF_EARLYCON_DECLARE(_name, compat, fn) \ + static const struct earlycon_id __UNIQUE_ID(__earlycon_##_name) \ + __used __section(__earlycon_table) \ + = { .name = __stringify(_name), \ + .compatible = compat, \ + .setup = fn } -#define EARLYCON_DECLARE(_name, func) \ - static const struct earlycon_id __earlycon_##_name \ - __used __section(__earlycon_table) \ - = { .name = __stringify(_name), \ - .setup = func } +#define EARLYCON_DECLARE(_name, fn) OF_EARLYCON_DECLARE(_name, "", fn) -#define OF_EARLYCON_DECLARE(name, compat, fn) \ - _OF_DECLARE(earlycon, name, compat, fn, void *) +extern int setup_earlycon(char *buf); +extern int of_setup_earlycon(const struct earlycon_id *match, + unsigned long node, + const char *options); struct uart_port *uart_get_console(struct uart_port *ports, int nr, struct console *c); diff --git a/include/linux/tty.h b/include/linux/tty.h index d9fb4b043f56..3b09f235db66 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -302,6 +302,7 @@ struct tty_struct { struct work_struct hangup_work; void *disc_data; void *driver_data; + spinlock_t files_lock; /* protects tty_files list */ struct list_head tty_files; #define N_TTY_BUF_SIZE 4096 @@ -336,7 +337,6 @@ struct tty_file_private { #define TTY_IO_ERROR 1 /* Cause an I/O error (may be no ldisc too) */ #define TTY_OTHER_CLOSED 2 /* Other side (if any) has closed */ #define TTY_EXCLUSIVE 3 /* Exclusive open mode */ -#define TTY_DEBUG 4 /* Debugging */ #define TTY_DO_WRITE_WAKEUP 5 /* Call write_wakeup after queuing new */ #define TTY_OTHER_DONE 6 /* Closed pty has completed input processing */ #define TTY_LDISC_OPEN 11 /* Line discipline is open */ @@ -433,8 +433,6 @@ extern struct device *tty_register_device_attr(struct tty_driver *driver, void *drvdata, const struct attribute_group **attr_grp); extern void tty_unregister_device(struct tty_driver *driver, unsigned index); -extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp, - int buflen); extern void tty_write_message(struct tty_struct *tty, char *msg); extern int tty_send_xchar(struct tty_struct *tty, char ch); extern int tty_put_char(struct tty_struct *tty, unsigned char c); @@ -446,12 +444,7 @@ extern void tty_unthrottle(struct tty_struct *tty); extern int tty_throttle_safe(struct tty_struct *tty); extern int tty_unthrottle_safe(struct tty_struct *tty); extern int tty_do_resize(struct tty_struct *tty, struct winsize *ws); -extern void tty_driver_remove_tty(struct tty_driver *driver, - struct tty_struct *tty); -extern void tty_free_termios(struct tty_struct *tty); extern int is_current_pgrp_orphaned(void); -extern int is_ignored(int sig); -extern int tty_signal(int sig, struct tty_struct *tty); extern void tty_hangup(struct tty_struct *tty); extern void tty_vhangup(struct tty_struct *tty); extern int tty_hung_up_p(struct file *filp); @@ -493,7 +486,8 @@ extern int tty_set_termios(struct tty_struct *tty, struct ktermios *kt); extern struct tty_ldisc *tty_ldisc_ref(struct tty_struct *); extern void tty_ldisc_deref(struct tty_ldisc *); extern struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *); -extern void tty_ldisc_hangup(struct tty_struct *tty); +extern void tty_ldisc_hangup(struct tty_struct *tty, bool reset); +extern int tty_ldisc_reinit(struct tty_struct *tty, int disc); extern const struct file_operations tty_ldiscs_proc_fops; extern void tty_wakeup(struct tty_struct *tty); @@ -508,16 +502,13 @@ extern struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx); extern int tty_alloc_file(struct file *file); extern void tty_add_file(struct tty_struct *tty, struct file *file); extern void tty_free_file(struct file *file); -extern void free_tty_struct(struct tty_struct *tty); -extern void deinitialize_tty_struct(struct tty_struct *tty); extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx); extern int tty_release(struct inode *inode, struct file *filp); -extern int tty_init_termios(struct tty_struct *tty); +extern void tty_init_termios(struct tty_struct *tty); extern int tty_standard_install(struct tty_driver *driver, struct tty_struct *tty); extern struct mutex tty_mutex; -extern spinlock_t tty_files_lock; #define tty_is_writelocked(tty) (mutex_is_locked(&tty->atomic_write_lock)) @@ -575,43 +566,29 @@ static inline int tty_port_users(struct tty_port *port) extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc); extern int tty_unregister_ldisc(int disc); -extern int tty_set_ldisc(struct tty_struct *tty, int ldisc); +extern int tty_set_ldisc(struct tty_struct *tty, int disc); extern int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty); extern void tty_ldisc_release(struct tty_struct *tty); extern void tty_ldisc_init(struct tty_struct *tty); extern void tty_ldisc_deinit(struct tty_struct *tty); -extern void tty_ldisc_begin(void); - -static inline int tty_ldisc_receive_buf(struct tty_ldisc *ld, unsigned char *p, - char *f, int count) -{ - if (ld->ops->receive_buf2) - count = ld->ops->receive_buf2(ld->tty, p, f, count); - else { - count = min_t(int, count, ld->tty->receive_room); - if (count) - ld->ops->receive_buf(ld->tty, p, f, count); - } - return count; -} - +extern int tty_ldisc_receive_buf(struct tty_ldisc *ld, unsigned char *p, + char *f, int count); /* n_tty.c */ -extern struct tty_ldisc_ops tty_ldisc_N_TTY; extern void n_tty_inherit_ops(struct tty_ldisc_ops *ops); +extern void __init n_tty_init(void); /* tty_audit.c */ #ifdef CONFIG_AUDIT extern void tty_audit_add_data(struct tty_struct *tty, const void *data, - size_t size, unsigned icanon); + size_t size); extern void tty_audit_exit(void); extern void tty_audit_fork(struct signal_struct *sig); extern void tty_audit_tiocsti(struct tty_struct *tty, char ch); -extern void tty_audit_push(struct tty_struct *tty); -extern int tty_audit_push_current(void); +extern int tty_audit_push(void); #else static inline void tty_audit_add_data(struct tty_struct *tty, const void *data, - size_t size, unsigned icanon) + size_t size) { } static inline void tty_audit_tiocsti(struct tty_struct *tty, char ch) @@ -623,10 +600,7 @@ static inline void tty_audit_exit(void) static inline void tty_audit_fork(struct signal_struct *sig) { } -static inline void tty_audit_push(struct tty_struct *tty) -{ -} -static inline int tty_audit_push_current(void) +static inline int tty_audit_push(void) { return 0; } @@ -648,11 +622,11 @@ extern long vt_compat_ioctl(struct tty_struct *tty, /* tty_mutex.c */ /* functions for preparation of BKL removal */ -extern void __lockfunc tty_lock(struct tty_struct *tty); +extern void tty_lock(struct tty_struct *tty); extern int tty_lock_interruptible(struct tty_struct *tty); -extern void __lockfunc tty_unlock(struct tty_struct *tty); -extern void __lockfunc tty_lock_slave(struct tty_struct *tty); -extern void __lockfunc tty_unlock_slave(struct tty_struct *tty); +extern void tty_unlock(struct tty_struct *tty); +extern void tty_lock_slave(struct tty_struct *tty); +extern void tty_unlock_slave(struct tty_struct *tty); extern void tty_set_lock_subclass(struct tty_struct *tty); #ifdef CONFIG_PROC_FS diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h index 00c9d688d7b7..3971cf0eb467 100644 --- a/include/linux/tty_ldisc.h +++ b/include/linux/tty_ldisc.h @@ -25,12 +25,6 @@ * buffers of any input characters it may have queued to be * delivered to the user mode process. * - * ssize_t (*chars_in_buffer)(struct tty_struct *tty); - * - * This function returns the number of input characters the line - * discipline may have queued up to be delivered to the user mode - * process. - * * ssize_t (*read)(struct tty_struct * tty, struct file * file, * unsigned char * buf, size_t nr); * @@ -104,11 +98,6 @@ * seek to perform this action quickly but should wait until * any pending driver I/O is completed. * - * void (*fasync)(struct tty_struct *, int on) - * - * Notify line discipline when signal-driven I/O is enabled or - * disabled. - * * void (*dcd_change)(struct tty_struct *tty, unsigned int status) * * Tells the discipline that the DCD pin has changed its status. @@ -188,7 +177,6 @@ struct tty_ldisc_ops { int (*open)(struct tty_struct *); void (*close)(struct tty_struct *); void (*flush_buffer)(struct tty_struct *tty); - ssize_t (*chars_in_buffer)(struct tty_struct *tty); ssize_t (*read)(struct tty_struct *tty, struct file *file, unsigned char __user *buf, size_t nr); ssize_t (*write)(struct tty_struct *tty, struct file *file, @@ -209,7 +197,6 @@ struct tty_ldisc_ops { char *fp, int count); void (*write_wakeup)(struct tty_struct *); void (*dcd_change)(struct tty_struct *, unsigned int); - void (*fasync)(struct tty_struct *tty, int on); int (*receive_buf2)(struct tty_struct *, const unsigned char *cp, char *fp, int count); diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h index 3e5d757407fb..e513a4ee369b 100644 --- a/include/uapi/linux/serial_core.h +++ b/include/uapi/linux/serial_core.h @@ -261,4 +261,7 @@ /* STM32 USART */ #define PORT_STM32 113 +/* MVEBU UART */ +#define PORT_MVEBU 114 + #endif /* _UAPILINUX_SERIAL_CORE_H */ diff --git a/kernel/audit.c b/kernel/audit.c index 3a3e5deeda8d..2651e423b2dc 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -920,7 +920,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (err == 1) { /* match or error */ err = 0; if (msg_type == AUDIT_USER_TTY) { - err = tty_audit_push_current(); + err = tty_audit_push(); if (err) break; } @@ -1030,20 +1030,19 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) break; case AUDIT_TTY_GET: { struct audit_tty_status s; - struct task_struct *tsk = current; + unsigned int t; - spin_lock(&tsk->sighand->siglock); - s.enabled = tsk->signal->audit_tty; - s.log_passwd = tsk->signal->audit_tty_log_passwd; - spin_unlock(&tsk->sighand->siglock); + t = READ_ONCE(current->signal->audit_tty); + s.enabled = t & AUDIT_TTY_ENABLE; + s.log_passwd = !!(t & AUDIT_TTY_LOG_PASSWD); audit_send_reply(skb, seq, AUDIT_TTY_GET, 0, 0, &s, sizeof(s)); break; } case AUDIT_TTY_SET: { struct audit_tty_status s, old; - struct task_struct *tsk = current; struct audit_buffer *ab; + unsigned int t; memset(&s, 0, sizeof(s)); /* guard against past and future API changes */ @@ -1053,14 +1052,14 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) (s.log_passwd != 0 && s.log_passwd != 1)) err = -EINVAL; - spin_lock(&tsk->sighand->siglock); - old.enabled = tsk->signal->audit_tty; - old.log_passwd = tsk->signal->audit_tty_log_passwd; - if (!err) { - tsk->signal->audit_tty = s.enabled; - tsk->signal->audit_tty_log_passwd = s.log_passwd; + if (err) + t = READ_ONCE(current->signal->audit_tty); + else { + t = s.enabled | (-s.log_passwd & AUDIT_TTY_LOG_PASSWD); + t = xchg(¤t->signal->audit_tty, t); } - spin_unlock(&tsk->sighand->siglock); + old.enabled = t & AUDIT_TTY_ENABLE; + old.log_passwd = !!(t & AUDIT_TTY_LOG_PASSWD); audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE); audit_log_format(ab, " op=tty_set old-enabled=%d new-enabled=%d" diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index a4237707f79d..da126ee6d218 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -287,14 +287,14 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, if (filp->f_flags & O_NONBLOCK) { /* nonblock mode is set */ - if (tty->termios.c_cflag & CBAUD) + if (C_BAUD(tty)) tty_port_raise_dtr_rts(port); port->flags |= ASYNC_NORMAL_ACTIVE; pr_debug("%s(), O_NONBLOCK requested!\n", __func__); return 0; } - if (tty->termios.c_cflag & CLOCAL) { + if (C_CLOCAL(tty)) { pr_debug("%s(), doing CLOCAL!\n", __func__); do_clocal = 1; } @@ -806,7 +806,7 @@ static void ircomm_tty_throttle(struct tty_struct *tty) ircomm_tty_send_xchar(tty, STOP_CHAR(tty)); /* Hardware flow control? */ - if (tty->termios.c_cflag & CRTSCTS) { + if (C_CRTSCTS(tty)) { self->settings.dte &= ~IRCOMM_RTS; self->settings.dte |= IRCOMM_DELTA_RTS; @@ -831,12 +831,11 @@ static void ircomm_tty_unthrottle(struct tty_struct *tty) IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); /* Using software flow control? */ - if (I_IXOFF(tty)) { + if (I_IXOFF(tty)) ircomm_tty_send_xchar(tty, START_CHAR(tty)); - } /* Using hardware flow control? */ - if (tty->termios.c_cflag & CRTSCTS) { + if (C_CRTSCTS(tty)) { self->settings.dte |= (IRCOMM_RTS|IRCOMM_DELTA_RTS); ircomm_param_request(self, IRCOMM_DTE, TRUE); @@ -1268,10 +1267,6 @@ static void ircomm_tty_line_info(struct ircomm_tty_cb *self, struct seq_file *m) seq_printf(m, "%cASYNC_LOW_LATENCY", sep); sep = '|'; } - if (self->port.flags & ASYNC_CLOSING) { - seq_printf(m, "%cASYNC_CLOSING", sep); - sep = '|'; - } if (self->port.flags & ASYNC_NORMAL_ACTIVE) { seq_printf(m, "%cASYNC_NORMAL_ACTIVE", sep); sep = '|'; diff --git a/net/irda/ircomm/ircomm_tty_ioctl.c b/net/irda/ircomm/ircomm_tty_ioctl.c index 75ccdbd0728e..d3687aaa23de 100644 --- a/net/irda/ircomm/ircomm_tty_ioctl.c +++ b/net/irda/ircomm/ircomm_tty_ioctl.c @@ -158,26 +158,21 @@ void ircomm_tty_set_termios(struct tty_struct *tty, ircomm_tty_change_speed(self, tty); /* Handle transition to B0 status */ - if ((old_termios->c_cflag & CBAUD) && - !(cflag & CBAUD)) { + if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) { self->settings.dte &= ~(IRCOMM_DTR|IRCOMM_RTS); ircomm_param_request(self, IRCOMM_DTE, TRUE); } /* Handle transition away from B0 status */ - if (!(old_termios->c_cflag & CBAUD) && - (cflag & CBAUD)) { + if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) { self->settings.dte |= IRCOMM_DTR; - if (!(tty->termios.c_cflag & CRTSCTS) || - !test_bit(TTY_THROTTLED, &tty->flags)) { + if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags)) self->settings.dte |= IRCOMM_RTS; - } ircomm_param_request(self, IRCOMM_DTE, TRUE); } /* Handle turning off CRTSCTS */ - if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios.c_cflag & CRTSCTS)) + if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) { tty->hw_stopped = 0; ircomm_tty_start(tty); diff --git a/net/nfc/nci/uart.c b/net/nfc/nci/uart.c index 21d8875673a4..c468eabd6943 100644 --- a/net/nfc/nci/uart.c +++ b/net/nfc/nci/uart.c @@ -171,14 +171,7 @@ static int nci_uart_tty_open(struct tty_struct *tty) tty->disc_data = NULL; tty->receive_room = 65536; - /* Flush any pending characters in the driver and line discipline. */ - - /* FIXME: why is this needed. Note don't use ldisc_ref here as the - * open path is before the ldisc is referencable. - */ - - if (tty->ldisc->ops->flush_buffer) - tty->ldisc->ops->flush_buffer(tty); + /* Flush any pending characters in the driver */ tty_driver_flush_buffer(tty); return 0; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index f1ab71504e1d..912deee3f01e 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2415,7 +2415,7 @@ static inline void flush_unauthorized_files(const struct cred *cred, tty = get_current_tty(); if (tty) { - spin_lock(&tty_files_lock); + spin_lock(&tty->files_lock); if (!list_empty(&tty->tty_files)) { struct tty_file_private *file_priv; @@ -2430,7 +2430,7 @@ static inline void flush_unauthorized_files(const struct cred *cred, if (file_path_has_perm(cred, file, FILE__READ | FILE__WRITE)) drop_tty = 1; } - spin_unlock(&tty_files_lock); + spin_unlock(&tty->files_lock); tty_kref_put(tty); } /* Reset controlling tty. */ |