Merge tag 'tty-4.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 21 May 2016 03:57:27 +0000 (20:57 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 21 May 2016 03:57:27 +0000 (20:57 -0700)
Pull tty and serial driver updates from Greg KH:
 "Here's the large TTY and Serial driver update for 4.7-rc1.

  A few new serial drivers are added here, and Peter has fixed a bunch
  of long-standing bugs in the tty layer and serial drivers as normal.
  Full details in the shortlog.

  All of these have been in linux-next for a while with no reported
  issues"

* tag 'tty-4.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (88 commits)
  MAINTAINERS: 8250: remove website reference
  serial: core: Fix port mutex assert if lockdep disabled
  serial: 8250_dw: fix wrong logic in dw8250_check_lcr()
  tty: vt, finish looping on duplicate
  tty: vt, return error when con_startup fails
  QE-UART: add "fsl,t1040-ucc-uart" to of_device_id
  serial: mctrl_gpio: Drop support for out1-gpios and out2-gpios
  serial: 8250dw: Add device HID for future AMD UART controller
  Fix OpenSSH pty regression on close
  serial: mctrl_gpio: add IRQ locking
  serial: 8250: Integrate Fintek into 8250_base
  serial: mps2-uart: add support for early console
  serial: mps2-uart: add MPS2 UART driver
  dt-bindings: document the MPS2 UART bindings
  serial: sirf: Use generic uart-has-rtscts DT property
  serial: sirf: Introduce helper variable struct device_node *np
  serial: mxs-auart: Use generic uart-has-rtscts DT property
  serial: imx: Use generic uart-has-rtscts DT property
  doc: DT: Add Generic Serial Device Tree Bindings
  serial: 8250: of: Make tegra_serial_handle_break() static
  ...

104 files changed:
Documentation/devicetree/bindings/serial/arm,mps2-uart.txt [new file with mode: 0644]
Documentation/devicetree/bindings/serial/fsl-imx-uart.txt
Documentation/devicetree/bindings/serial/fsl-mxs-auart.txt
Documentation/devicetree/bindings/serial/serial.txt [new file with mode: 0644]
Documentation/devicetree/bindings/serial/sirf-uart.txt
Documentation/kernel-parameters.txt
Documentation/serial/tty.txt
MAINTAINERS
arch/ia64/hp/sim/simserial.c
arch/mips/ath79/early_printk.c
drivers/char/pcmcia/synclink_cs.c
drivers/ipack/devices/ipoctal.c
drivers/isdn/i4l/isdn_tty.c
drivers/mmc/card/sdio_uart.c
drivers/net/usb/hso.c
drivers/s390/char/con3215.c
drivers/s390/char/tty3270.c
drivers/staging/dgnc/dgnc_tty.c
drivers/staging/fwserial/fwserial.c
drivers/staging/speakup/selection.c
drivers/tty/amiserial.c
drivers/tty/cyclades.c
drivers/tty/hvc/hvc_console.c
drivers/tty/hvc/hvcs.c
drivers/tty/hvc/hvsi.c
drivers/tty/ipwireless/hardware.c
drivers/tty/isicom.c
drivers/tty/moxa.c
drivers/tty/mxser.c
drivers/tty/n_gsm.c
drivers/tty/n_hdlc.c
drivers/tty/n_tty.c
drivers/tty/nozomi.c
drivers/tty/pty.c
drivers/tty/rocket.c
drivers/tty/serial/8250/8250.h
drivers/tty/serial/8250/8250_core.c
drivers/tty/serial/8250/8250_dma.c
drivers/tty/serial/8250/8250_dw.c
drivers/tty/serial/8250/8250_fintek.c
drivers/tty/serial/8250/8250_mid.c
drivers/tty/serial/8250/8250_of.c
drivers/tty/serial/8250/8250_omap.c
drivers/tty/serial/8250/8250_pci.c
drivers/tty/serial/8250/8250_port.c
drivers/tty/serial/8250/8250_uniphier.c
drivers/tty/serial/8250/Kconfig
drivers/tty/serial/8250/Makefile
drivers/tty/serial/Kconfig
drivers/tty/serial/Makefile
drivers/tty/serial/amba-pl011.c
drivers/tty/serial/atmel_serial.c
drivers/tty/serial/crisv10.c
drivers/tty/serial/ifx6x60.c
drivers/tty/serial/imx.c
drivers/tty/serial/meson_uart.c
drivers/tty/serial/mps2-uart.c [new file with mode: 0644]
drivers/tty/serial/msm_serial.c
drivers/tty/serial/mvebu-uart.c
drivers/tty/serial/mxs-auart.c
drivers/tty/serial/samsung.c
drivers/tty/serial/sc16is7xx.c
drivers/tty/serial/serial-tegra.c
drivers/tty/serial/serial_core.c
drivers/tty/serial/serial_mctrl_gpio.c
drivers/tty/serial/serial_mctrl_gpio.h
drivers/tty/serial/sirfsoc_uart.c
drivers/tty/serial/uartlite.c
drivers/tty/serial/ucc_uart.c
drivers/tty/synclink.c
drivers/tty/synclink_gt.c
drivers/tty/synclinkmp.c
drivers/tty/tty_buffer.c
drivers/tty/tty_io.c
drivers/tty/tty_ioctl.c
drivers/tty/tty_port.c
drivers/tty/vt/selection.c
drivers/tty/vt/vt.c
drivers/usb/class/cdc-acm.c
drivers/usb/gadget/function/u_serial.c
drivers/usb/misc/sisusbvga/sisusb_con.c
drivers/usb/serial/console.c
drivers/usb/serial/digi_acceleport.c
drivers/usb/serial/generic.c
drivers/usb/serial/mxuport.c
drivers/usb/serial/sierra.c
drivers/usb/serial/usb-serial.c
drivers/usb/serial/usb_wwan.c
drivers/video/console/fbcon.c
drivers/video/console/mdacon.c
drivers/video/console/newport_con.c
drivers/video/console/sticon.c
drivers/video/console/vgacon.c
include/linux/console.h
include/linux/selection.h
include/linux/serial_8250.h
include/linux/serial_core.h
include/linux/tty.h
include/uapi/linux/serial_core.h
include/uapi/linux/tty_flags.h
include/uapi/linux/vt.h
net/irda/ircomm/ircomm_tty.c
net/irda/ircomm/ircomm_tty_attach.c
net/irda/ircomm/ircomm_tty_ioctl.c

diff --git a/Documentation/devicetree/bindings/serial/arm,mps2-uart.txt b/Documentation/devicetree/bindings/serial/arm,mps2-uart.txt
new file mode 100644 (file)
index 0000000..128cc6a
--- /dev/null
@@ -0,0 +1,19 @@
+ARM MPS2 UART
+
+Required properties:
+- compatible   : Should be "arm,mps2-uart"
+- reg          : Address and length of the register set
+- interrupts   : Reference to the UART RX, TX and overrun interrupts
+
+Required clocking property:
+- clocks         : The input clock of the UART
+
+
+Examples:
+
+uart0: serial@40004000 {
+       compatible = "arm,mps2-uart";
+       reg = <0x40004000 0x1000>;
+       interrupts = <0 1 12>;
+       clocks = <&sysclk>;
+};
index ed94c21..1e82802 100644 (file)
@@ -6,7 +6,7 @@ Required properties:
 - interrupts : Should contain uart interrupt
 
 Optional properties:
-- fsl,uart-has-rtscts : Indicate the uart has rts and cts
+- uart-has-rtscts : Indicate the uart has rts and cts
 - fsl,irda-mode : Indicate the uart supports irda mode
 - fsl,dte-mode : Indicate the uart works in DTE mode. The uart works
                   in DCE mode by default.
@@ -24,6 +24,6 @@ uart1: serial@73fbc000 {
        compatible = "fsl,imx51-uart", "fsl,imx21-uart";
        reg = <0x73fbc000 0x4000>;
        interrupts = <31>;
-       fsl,uart-has-rtscts;
+       uart-has-rtscts;
        fsl,dte-mode;
 };
index 7c408c8..5c96d41 100644 (file)
@@ -1,8 +1,10 @@
 * Freescale MXS Application UART (AUART)
 
-Required properties:
-- compatible : Should be "fsl,<soc>-auart". The supported SoCs include
-  imx23 and imx28.
+Required properties for all SoCs:
+- compatible : Should be one of fallowing variants:
+       "fsl,imx23-auart" - Freescale i.MX23
+       "fsl,imx28-auart" - Freescale i.MX28
+       "alphascale,asm9260-auart" - Alphascale ASM9260
 - reg : Address and length of the register set for the device
 - interrupts : Should contain the auart interrupt numbers
 - dmas: DMA specifier, consisting of a phandle to DMA controller node
@@ -10,8 +12,14 @@ Required properties:
   Refer to dma.txt and fsl-mxs-dma.txt for details.
 - dma-names: "rx" for RX channel, "tx" for TX channel.
 
+Required properties for "alphascale,asm9260-auart":
+- clocks : the clocks feeding the watchdog timer. See clock-bindings.txt
+- clock-names : should be set to
+       "mod" - source for tick counter.
+       "ahb" - ahb gate.
+
 Optional properties:
-- fsl,uart-has-rtscts : Indicate the UART has RTS and CTS lines
+- uart-has-rtscts : Indicate the UART has RTS and CTS lines
   for hardware flow control,
        it also means you enable the DMA support for this UART.
 - {rts,cts,dtr,dsr,rng,dcd}-gpios: specify a GPIO for RTS/CTS/DTR/DSR/RI/DCD
diff --git a/Documentation/devicetree/bindings/serial/serial.txt b/Documentation/devicetree/bindings/serial/serial.txt
new file mode 100644 (file)
index 0000000..fd970f7
--- /dev/null
@@ -0,0 +1,57 @@
+Generic Serial DT Bindings
+
+This document lists a set of generic properties for describing UARTs in a
+device tree.  Whether these properties apply to a particular device depends on
+the DT bindings for the actual device.
+
+Optional properties:
+  - cts-gpios: Must contain a GPIO specifier, referring to the GPIO pin to be
+    used as the UART's CTS line.
+  - dcd-gpios: Must contain a GPIO specifier, referring to the GPIO pin to be
+    used as the UART's DCD line.
+  - dsr-gpios: Must contain a GPIO specifier, referring to the GPIO pin to be
+    used as the UART's DSR line.
+  - dtr-gpios: Must contain a GPIO specifier, referring to the GPIO pin to be
+    used as the UART's DTR line.
+  - rng-gpios: Must contain a GPIO specifier, referring to the GPIO pin to be
+    used as the UART's RNG line.
+  - rts-gpios: Must contain a GPIO specifier, referring to the GPIO pin to be
+    used as the UART's RTS line.
+
+  - uart-has-rtscts: The presence of this property indicates that the
+    UART has dedicated lines for RTS/CTS hardware flow control, and that
+    they are available for use (wired and enabled by pinmux configuration).
+    This depends on both the UART hardware and the board wiring.
+    Note that this property is mutually-exclusive with "cts-gpios" and
+    "rts-gpios" above.
+
+
+Examples:
+
+       uart1: serial@48022000 {
+               compatible = "ti,am3352-uart", "ti,omap3-uart";
+               ti,hwmods = "uart2";
+               clock-frequency = <48000000>;
+               reg = <0x48022000 0x2000>;
+               interrupts = <73>;
+               dmas = <&edma 28 0>, <&edma 29 0>;
+               dma-names = "tx", "rx";
+               dtr-gpios = <&gpio2 22 GPIO_ACTIVE_LOW>;
+               dsr-gpios = <&gpio2 23 GPIO_ACTIVE_LOW>;
+               dcd-gpios = <&gpio2 24 GPIO_ACTIVE_LOW>;
+               rng-gpios = <&gpio2 25 GPIO_ACTIVE_LOW>;
+               cts-gpios = <&gpio0 12 GPIO_ACTIVE_LOW>;
+               rts-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
+               status = "okay";
+       };
+
+       scifa4: serial@e6c80000 {
+               compatible = "renesas,scifa-sh73a0", "renesas,scifa";
+               reg = <0xe6c80000 0x100>;
+               interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp2_clks SH73A0_CLK_SCIFA4>;
+               clock-names = "fck";
+               power-domains = <&pd_a3sp>;
+               uart-has-rtscts;
+               status = "okay";
+       };
index 67e2a0a..1e48bbb 100644 (file)
@@ -9,9 +9,9 @@ Required properties:
 - clocks : Should contain uart clock number
 
 Optional properties:
-- sirf,uart-has-rtscts: we have hardware flow controller pins in hardware
-- rts-gpios: RTS pin for USP-based UART if sirf,uart-has-rtscts is true
-- cts-gpios: CTS pin for USP-based UART if sirf,uart-has-rtscts is true
+- uart-has-rtscts: we have hardware flow controller pins in hardware
+- rts-gpios: RTS pin for USP-based UART if uart-has-rtscts is true
+- cts-gpios: CTS pin for USP-based UART if uart-has-rtscts is true
 
 Example:
 
@@ -28,7 +28,7 @@ On the board-specific dts, we can put rts-gpios and cts-gpios like
 
 usp@b0090000 {
        compatible = "sirf,prima2-usp-uart";
-       sirf,uart-has-rtscts;
+       uart-has-rtscts;
        rts-gpios = <&gpio 15 0>;
        cts-gpios = <&gpio 46 0>;
 };
index 4e76a34..82b42c9 100644 (file)
@@ -1054,6 +1054,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        the driver will use only 32-bit accessors to read/write
                        the device registers.
 
+               meson,<addr>
+                       Start an early, polled-mode console on a meson serial
+                       port at the specified address. The serial port must
+                       already be setup and configured. Options are not yet
+                       supported.
+
                msm_serial,<addr>
                        Start an early, polled-mode console on an msm serial
                        port at the specified address. The serial port
index 798cba8..b487809 100644 (file)
@@ -210,9 +210,6 @@ TTY_IO_ERROR                If set, causes all subsequent userspace read/write
 
 TTY_OTHER_CLOSED       Device is a pty and the other side has closed.
 
-TTY_OTHER_DONE         Device is a pty and the other side has closed and
-                       all pending input processing has been completed.
-
 TTY_NO_WRITE_SPLIT     Prevent driver from splitting up writes into
                        smaller chunks.
 
index e840831..832f070 100644 (file)
@@ -175,7 +175,6 @@ F:  drivers/net/ethernet/realtek/r8169.c
 8250/16?50 (AND CLONE UARTS) SERIAL DRIVER
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 L:     linux-serial@vger.kernel.org
-W:     http://serial.sourceforge.net
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git
 F:     drivers/tty/serial/8250*
index e70cade..21fd50d 100644 (file)
@@ -300,7 +300,7 @@ static int rs_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
        if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
            (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
            (cmd != TIOCMIWAIT)) {
-               if (tty->flags & (1 << TTY_IO_ERROR))
+               if (tty_io_error(tty))
                    return -EIO;
        }
 
index b955faf..d1adc59 100644 (file)
@@ -31,13 +31,15 @@ static inline void prom_putchar_wait(void __iomem *reg, u32 mask, u32 val)
        } while (1);
 }
 
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
 static void prom_putchar_ar71xx(unsigned char ch)
 {
        void __iomem *base = (void __iomem *)(KSEG1ADDR(AR71XX_UART_BASE));
 
-       prom_putchar_wait(base + UART_LSR * 4, UART_LSR_THRE, UART_LSR_THRE);
+       prom_putchar_wait(base + UART_LSR * 4, BOTH_EMPTY, BOTH_EMPTY);
        __raw_writel(ch, base + UART_TX * 4);
-       prom_putchar_wait(base + UART_LSR * 4, UART_LSR_THRE, UART_LSR_THRE);
+       prom_putchar_wait(base + UART_LSR * 4, BOTH_EMPTY, BOTH_EMPTY);
 }
 
 static void prom_putchar_ar933x(unsigned char ch)
index e524e83..d28922d 100644 (file)
@@ -1101,7 +1101,7 @@ static void dcd_change(MGSLPC_INFO *info, struct tty_struct *tty)
        wake_up_interruptible(&info->status_event_wait_q);
        wake_up_interruptible(&info->event_wait_q);
 
-       if (info->port.flags & ASYNC_CHECK_CD) {
+       if (tty_port_check_carrier(&info->port)) {
                if (debug_level >= DEBUG_LEVEL_ISR)
                        printk("%s CD now %s...", info->device_name,
                               (info->serial_signals & SerialSignal_DCD) ? "on" : "off");
@@ -1272,7 +1272,7 @@ static int startup(MGSLPC_INFO * info, struct tty_struct *tty)
        if (debug_level >= DEBUG_LEVEL_INFO)
                printk("%s(%d):startup(%s)\n", __FILE__, __LINE__, info->device_name);
 
-       if (info->port.flags & ASYNC_INITIALIZED)
+       if (tty_port_initialized(&info->port))
                return 0;
 
        if (!info->tx_buf) {
@@ -1311,7 +1311,7 @@ static int startup(MGSLPC_INFO * info, struct tty_struct *tty)
        if (tty)
                clear_bit(TTY_IO_ERROR, &tty->flags);
 
-       info->port.flags |= ASYNC_INITIALIZED;
+       tty_port_set_initialized(&info->port, 1);
 
        return 0;
 }
@@ -1322,7 +1322,7 @@ static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty)
 {
        unsigned long flags;
 
-       if (!(info->port.flags & ASYNC_INITIALIZED))
+       if (!tty_port_initialized(&info->port))
                return;
 
        if (debug_level >= DEBUG_LEVEL_INFO)
@@ -1361,7 +1361,7 @@ static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty)
        if (tty)
                set_bit(TTY_IO_ERROR, &tty->flags);
 
-       info->port.flags &= ~ASYNC_INITIALIZED;
+       tty_port_set_initialized(&info->port, 0);
 }
 
 static void mgslpc_program_hw(MGSLPC_INFO *info, struct tty_struct *tty)
@@ -1466,15 +1466,8 @@ static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty)
        }
        info->timeout += HZ/50;         /* Add .02 seconds of slop */
 
-       if (cflag & CRTSCTS)
-               info->port.flags |= ASYNC_CTS_FLOW;
-       else
-               info->port.flags &= ~ASYNC_CTS_FLOW;
-
-       if (cflag & CLOCAL)
-               info->port.flags &= ~ASYNC_CHECK_CD;
-       else
-               info->port.flags |= ASYNC_CHECK_CD;
+       tty_port_set_cts_flow(&info->port, cflag & CRTSCTS);
+       tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL);
 
        /* process tty input control flags */
 
@@ -2246,7 +2239,7 @@ static int mgslpc_ioctl(struct tty_struct *tty,
 
        if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
            (cmd != TIOCMIWAIT)) {
-               if (tty->flags & (1 << TTY_IO_ERROR))
+               if (tty_io_error(tty))
                    return -EIO;
        }
 
@@ -2316,7 +2309,7 @@ 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) && C_BAUD(tty)) {
                info->serial_signals |= SerialSignal_DTR;
-               if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags))
+               if (!C_CRTSCTS(tty) || !tty_throttled(tty))
                        info->serial_signals |= SerialSignal_RTS;
                spin_lock_irqsave(&info->lock, flags);
                set_signals(info);
@@ -2345,7 +2338,7 @@ static void mgslpc_close(struct tty_struct *tty, struct file * filp)
        if (tty_port_close_start(port, tty, filp) == 0)
                goto cleanup;
 
-       if (port->flags & ASYNC_INITIALIZED)
+       if (tty_port_initialized(port))
                mgslpc_wait_until_sent(tty, info->timeout);
 
        mgslpc_flush_buffer(tty);
@@ -2378,7 +2371,7 @@ static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout)
        if (mgslpc_paranoia_check(info, tty->name, "mgslpc_wait_until_sent"))
                return;
 
-       if (!(info->port.flags & ASYNC_INITIALIZED))
+       if (!tty_port_initialized(&info->port))
                goto exit;
 
        orig_jiffies = jiffies;
index 035d544..75dd15d 100644 (file)
@@ -629,8 +629,7 @@ static void ipoctal_hangup(struct tty_struct *tty)
        tty_port_hangup(&channel->tty_port);
 
        ipoctal_reset_channel(channel);
-
-       clear_bit(ASYNCB_INITIALIZED, &channel->tty_port.flags);
+       tty_port_set_initialized(&channel->tty_port, 0);
        wake_up_interruptible(&channel->tty_port.open_wait);
 }
 
@@ -642,7 +641,7 @@ static void ipoctal_shutdown(struct tty_struct *tty)
                return;
 
        ipoctal_reset_channel(channel);
-       clear_bit(ASYNCB_INITIALIZED, &channel->tty_port.flags);
+       tty_port_set_initialized(&channel->tty_port, 0);
 }
 
 static void ipoctal_cleanup(struct tty_struct *tty)
index 947d5c9..63eaa0a 100644 (file)
@@ -1043,17 +1043,13 @@ isdn_tty_change_speed(modem_info *info)
        if (!(cflag & PARODD))
                cval |= UART_LCR_EPAR;
 
-       if (cflag & CLOCAL)
-               port->flags &= ~ASYNC_CHECK_CD;
-       else {
-               port->flags |= ASYNC_CHECK_CD;
-       }
+       tty_port_set_check_carrier(port, ~cflag & CLOCAL);
 }
 
 static int
 isdn_tty_startup(modem_info *info)
 {
-       if (info->port.flags & ASYNC_INITIALIZED)
+       if (tty_port_initialized(&info->port))
                return 0;
        isdn_lock_drivers();
 #ifdef ISDN_DEBUG_MODEM_OPEN
@@ -1070,7 +1066,7 @@ isdn_tty_startup(modem_info *info)
         */
        isdn_tty_change_speed(info);
 
-       info->port.flags |= ASYNC_INITIALIZED;
+       tty_port_set_initialized(&info->port, 1);
        info->msr |= (UART_MSR_DSR | UART_MSR_CTS);
        info->send_outstanding = 0;
        return 0;
@@ -1083,7 +1079,7 @@ isdn_tty_startup(modem_info *info)
 static void
 isdn_tty_shutdown(modem_info *info)
 {
-       if (!(info->port.flags & ASYNC_INITIALIZED))
+       if (!tty_port_initialized(&info->port))
                return;
 #ifdef ISDN_DEBUG_MODEM_OPEN
        printk(KERN_DEBUG "Shutting down isdnmodem port %d ....\n", info->line);
@@ -1103,7 +1099,7 @@ isdn_tty_shutdown(modem_info *info)
        if (info->port.tty)
                set_bit(TTY_IO_ERROR, &info->port.tty->flags);
 
-       info->port.flags &= ~ASYNC_INITIALIZED;
+       tty_port_set_initialized(&info->port, 0);
 }
 
 /* isdn_tty_write() is the main send-routine. It is called from the upper
@@ -1351,7 +1347,7 @@ isdn_tty_tiocmget(struct tty_struct *tty)
 
        if (isdn_tty_paranoia_check(info, tty->name, __func__))
                return -ENODEV;
-       if (tty->flags & (1 << TTY_IO_ERROR))
+       if (tty_io_error(tty))
                return -EIO;
 
        mutex_lock(&modem_info_mutex);
@@ -1378,7 +1374,7 @@ isdn_tty_tiocmset(struct tty_struct *tty,
 
        if (isdn_tty_paranoia_check(info, tty->name, __func__))
                return -ENODEV;
-       if (tty->flags & (1 << TTY_IO_ERROR))
+       if (tty_io_error(tty))
                return -EIO;
 
 #ifdef ISDN_DEBUG_MODEM_IOCTL
@@ -1419,7 +1415,7 @@ isdn_tty_ioctl(struct tty_struct *tty, uint cmd, ulong arg)
 
        if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_ioctl"))
                return -ENODEV;
-       if (tty->flags & (1 << TTY_IO_ERROR))
+       if (tty_io_error(tty))
                return -EIO;
        switch (cmd) {
        case TCSBRK:   /* SVID version: non-zero arg --> no break */
@@ -1581,7 +1577,7 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
         * interrupt driver to stop checking the data ready bit in the
         * line status register.
         */
-       if (port->flags & ASYNC_INITIALIZED) {
+       if (tty_port_initialized(port)) {
                tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
                /*
                 * Before we drop DTR, make sure the UART transmitter
@@ -1622,7 +1618,7 @@ isdn_tty_hangup(struct tty_struct *tty)
                return;
        isdn_tty_shutdown(info);
        port->count = 0;
-       port->flags &= ~ASYNC_NORMAL_ACTIVE;
+       tty_port_set_active(port, 0);
        port->tty = NULL;
        wake_up_interruptible(&port->open_wait);
 }
@@ -1979,7 +1975,7 @@ isdn_tty_find_icall(int di, int ch, setup_parm *setup)
 #endif
                        if (
 #ifndef FIX_FILE_TRANSFER
-                               (info->port.flags & ASYNC_NORMAL_ACTIVE) &&
+                           tty_port_active(&info->port) &&
 #endif
                                (info->isdn_driver == -1) &&
                                (info->isdn_channel == -1) &&
@@ -2018,8 +2014,6 @@ isdn_tty_find_icall(int di, int ch, setup_parm *setup)
        return (wret == 2) ? 3 : 0;
 }
 
-#define TTY_IS_ACTIVE(info)    (info->port.flags & ASYNC_NORMAL_ACTIVE)
-
 int
 isdn_tty_stat_callback(int i, isdn_ctrl *c)
 {
@@ -2077,7 +2071,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
 #ifdef ISDN_TTY_STAT_DEBUG
                        printk(KERN_DEBUG "tty_STAT_DCONN ttyI%d\n", info->line);
 #endif
-                       if (TTY_IS_ACTIVE(info)) {
+                       if (tty_port_active(&info->port)) {
                                if (info->dialing == 1) {
                                        info->dialing = 2;
                                        return 1;
@@ -2088,7 +2082,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
 #ifdef ISDN_TTY_STAT_DEBUG
                        printk(KERN_DEBUG "tty_STAT_DHUP ttyI%d\n", info->line);
 #endif
-                       if (TTY_IS_ACTIVE(info)) {
+                       if (tty_port_active(&info->port)) {
                                if (info->dialing == 1)
                                        isdn_tty_modem_result(RESULT_BUSY, info);
                                if (info->dialing > 1)
@@ -2118,7 +2112,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
                         * waiting for it and
                         * set DCD-bit of its modem-status.
                         */
-                       if (TTY_IS_ACTIVE(info) ||
+                       if (tty_port_active(&info->port) ||
                            (info->port.blocked_open &&
                             (info->emu.mdmreg[REG_DCD] & BIT_DCD))) {
                                info->msr |= UART_MSR_DCD;
@@ -2145,7 +2139,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
 #ifdef ISDN_TTY_STAT_DEBUG
                        printk(KERN_DEBUG "tty_STAT_BHUP ttyI%d\n", info->line);
 #endif
-                       if (TTY_IS_ACTIVE(info)) {
+                       if (tty_port_active(&info->port)) {
 #ifdef ISDN_DEBUG_MODEM_HUP
                                printk(KERN_DEBUG "Mhup in ISDN_STAT_BHUP\n");
 #endif
@@ -2157,7 +2151,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
 #ifdef ISDN_TTY_STAT_DEBUG
                        printk(KERN_DEBUG "tty_STAT_NODCH ttyI%d\n", info->line);
 #endif
-                       if (TTY_IS_ACTIVE(info)) {
+                       if (tty_port_active(&info->port)) {
                                if (info->dialing) {
                                        info->dialing = 0;
                                        info->last_l2 = -1;
@@ -2183,14 +2177,14 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
                        return 1;
 #ifdef CONFIG_ISDN_TTY_FAX
                case ISDN_STAT_FAXIND:
-                       if (TTY_IS_ACTIVE(info)) {
+                       if (tty_port_active(&info->port)) {
                                isdn_tty_fax_command(info, c);
                        }
                        break;
 #endif
 #ifdef CONFIG_ISDN_AUDIO
                case ISDN_STAT_AUDIO:
-                       if (TTY_IS_ACTIVE(info)) {
+                       if (tty_port_active(&info->port)) {
                                switch (c->parm.num[0]) {
                                case ISDN_AUDIO_DTMF:
                                        if (info->vonline) {
@@ -2528,7 +2522,7 @@ isdn_tty_modem_result(int code, modem_info *info)
                if (info->closing || (!info->port.tty))
                        return;
 
-               if (info->port.flags & ASYNC_CHECK_CD)
+               if (tty_port_check_carrier(&info->port))
                        tty_hangup(info->port.tty);
        }
 }
index 5415056..5af6fb9 100644 (file)
@@ -895,7 +895,7 @@ static void sdio_uart_set_termios(struct tty_struct *tty,
        /* Handle transition away from B0 status */
        if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
                unsigned int mask = TIOCM_DTR;
-               if (!(cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags))
+               if (!(cflag & CRTSCTS) || !tty_throttled(tty))
                        mask |= TIOCM_RTS;
                sdio_uart_set_mctrl(port, mask);
        }
index 111d907..4b44586 100644 (file)
@@ -2029,7 +2029,7 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
 
        tty = tty_port_tty_get(&serial->port);
 
-       if (tty && test_bit(TTY_THROTTLED, &tty->flags)) {
+       if (tty && tty_throttled(tty)) {
                tty_kref_put(tty);
                return -1;
        }
index e7e078b..931d10e 100644 (file)
@@ -289,7 +289,7 @@ static void raw3215_timeout(unsigned long __data)
 
        spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
        raw->flags &= ~RAW3215_TIMER_RUNS;
-       if (!(raw->port.flags & ASYNC_SUSPENDED)) {
+       if (!tty_port_suspended(&raw->port)) {
                raw3215_mk_write_req(raw);
                raw3215_start_io(raw);
                if ((raw->queued_read || raw->queued_write) &&
@@ -311,8 +311,7 @@ static void raw3215_timeout(unsigned long __data)
  */
 static inline void raw3215_try_io(struct raw3215_info *raw)
 {
-       if (!(raw->port.flags & ASYNC_INITIALIZED) ||
-                       (raw->port.flags & ASYNC_SUSPENDED))
+       if (!tty_port_initialized(&raw->port) || tty_port_suspended(&raw->port))
                return;
        if (raw->queued_read != NULL)
                raw3215_start_io(raw);
@@ -494,7 +493,7 @@ static void raw3215_make_room(struct raw3215_info *raw, unsigned int length)
                /* While console is frozen for suspend we have no other
                 * choice but to drop message from the buffer to make
                 * room for even more messages. */
-               if (raw->port.flags & ASYNC_SUSPENDED) {
+               if (tty_port_suspended(&raw->port)) {
                        raw3215_drop_line(raw);
                        continue;
                }
@@ -616,10 +615,10 @@ static int raw3215_startup(struct raw3215_info *raw)
 {
        unsigned long flags;
 
-       if (raw->port.flags & ASYNC_INITIALIZED)
+       if (tty_port_initialized(&raw->port))
                return 0;
        raw->line_pos = 0;
-       raw->port.flags |= ASYNC_INITIALIZED;
+       tty_port_set_initialized(&raw->port, 1);
        spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
        raw3215_try_io(raw);
        spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
@@ -635,8 +634,7 @@ static void raw3215_shutdown(struct raw3215_info *raw)
        DECLARE_WAITQUEUE(wait, current);
        unsigned long flags;
 
-       if (!(raw->port.flags & ASYNC_INITIALIZED) ||
-           (raw->flags & RAW3215_FIXED))
+       if (!tty_port_initialized(&raw->port) || (raw->flags & RAW3215_FIXED))
                return;
        /* Wait for outstanding requests, then free irq */
        spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
@@ -650,7 +648,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;
+               tty_port_set_initialized(&raw->port, 1);
        }
        spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
 }
@@ -773,7 +771,7 @@ static int raw3215_pm_stop(struct ccw_device *cdev)
        raw = dev_get_drvdata(&cdev->dev);
        spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
        raw3215_make_room(raw, RAW3215_BUFFER_SIZE);
-       raw->port.flags |= ASYNC_SUSPENDED;
+       tty_port_set_suspended(&raw->port, 1);
        spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
        return 0;
 }
@@ -786,7 +784,7 @@ static int raw3215_pm_start(struct ccw_device *cdev)
        /* Allow I/O again and flush output buffer. */
        raw = dev_get_drvdata(&cdev->dev);
        spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
-       raw->port.flags &= ~ASYNC_SUSPENDED;
+       tty_port_set_suspended(&raw->port, 0);
        raw->flags |= RAW3215_FLUSHING;
        raw3215_try_io(raw);
        raw->flags &= ~RAW3215_FLUSHING;
@@ -859,7 +857,7 @@ static void con3215_flush(void)
        unsigned long flags;
 
        raw = raw3215[0];  /* console 3215 is the first one */
-       if (raw->port.flags & ASYNC_SUSPENDED)
+       if (tty_port_suspended(&raw->port))
                /* The console is still frozen for suspend. */
                if (ccw_device_force_console(raw->cdev))
                        /* Forcing didn't work, no panic message .. */
index 0a9f219..272cb6c 100644 (file)
@@ -1860,7 +1860,7 @@ static int tty3270_ioctl(struct tty_struct *tty, unsigned int cmd,
        tp = tty->driver_data;
        if (!tp)
                return -ENODEV;
-       if (tty->flags & (1 << TTY_IO_ERROR))
+       if (tty_io_error(tty))
                return -EIO;
        return kbd_ioctl(tp->kbd, cmd, arg);
 }
@@ -1874,7 +1874,7 @@ static long tty3270_compat_ioctl(struct tty_struct *tty,
        tp = tty->driver_data;
        if (!tp)
                return -ENODEV;
-       if (tty->flags & (1 << TTY_IO_ERROR))
+       if (tty_io_error(tty))
                return -EIO;
        return kbd_ioctl(tp->kbd, cmd, (unsigned long)compat_ptr(arg));
 }
index bcd2bdf..5c22159 100644 (file)
@@ -1255,7 +1255,7 @@ static int dgnc_block_til_ready(struct tty_struct *tty,
                        if (file->f_flags & O_NONBLOCK)
                                break;
 
-                       if (tty->flags & (1 << TTY_IO_ERROR)) {
+                       if (tty_io_error(tty)) {
                                retval = -EIO;
                                break;
                        }
index 9b23b5c..1f9389d 100644 (file)
@@ -1305,7 +1305,7 @@ static void fwtty_set_termios(struct tty_struct *tty, struct ktermios *old)
        if ((baud == 0) && (old->c_cflag & CBAUD)) {
                port->mctrl &= ~(TIOCM_DTR | TIOCM_RTS);
        } else if ((baud != 0) && !(old->c_cflag & CBAUD)) {
-               if (C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags))
+               if (C_CRTSCTS(tty) || !tty_throttled(tty))
                        port->mctrl |= TIOCM_DTR | TIOCM_RTS;
                else
                        port->mctrl |= TIOCM_DTR;
index 41ef099..0149edc 100644 (file)
@@ -150,7 +150,7 @@ static void __speakup_paste_selection(struct work_struct *work)
        add_wait_queue(&vc->paste_wait, &wait);
        while (sel_buffer && sel_buffer_lth > pasted) {
                set_current_state(TASK_INTERRUPTIBLE);
-               if (test_bit(TTY_THROTTLED, &tty->flags)) {
+               if (tty_throttled(tty)) {
                        schedule();
                        continue;
                }
index eacf4c9..208f573 100644 (file)
@@ -398,7 +398,7 @@ static void check_modem_status(struct serial_state *info)
                wake_up_interruptible(&port->delta_msr_wait);
        }
 
-       if ((port->flags & ASYNC_CHECK_CD) && (dstatus & SER_DCD)) {
+       if (tty_port_check_carrier(port) && (dstatus & SER_DCD)) {
 #if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
                printk("ttyS%d CD now %s...", info->line,
                       (!(status & SER_DCD)) ? "on" : "off");
@@ -525,7 +525,7 @@ static int startup(struct tty_struct *tty, struct serial_state *info)
 
        local_irq_save(flags);
 
-       if (port->flags & ASYNC_INITIALIZED) {
+       if (tty_port_initialized(port)) {
                free_page(page);
                goto errout;
        }
@@ -586,7 +586,7 @@ static int startup(struct tty_struct *tty, struct serial_state *info)
         */
        change_speed(tty, info, NULL);
 
-       port->flags |= ASYNC_INITIALIZED;
+       tty_port_set_initialized(port, 1);
        local_irq_restore(flags);
        return 0;
 
@@ -604,7 +604,7 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info)
        unsigned long   flags;
        struct serial_state *state;
 
-       if (!(info->tport.flags & ASYNC_INITIALIZED))
+       if (!tty_port_initialized(&info->tport))
                return;
 
        state = info;
@@ -645,7 +645,7 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info)
 
        set_bit(TTY_IO_ERROR, &tty->flags);
 
-       info->tport.flags &= ~ASYNC_INITIALIZED;
+       tty_port_set_initialized(&info->tport, 0);
        local_irq_restore(flags);
 }
 
@@ -727,17 +727,12 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info,
        info->IER &= ~UART_IER_MSI;
        if (port->flags & ASYNC_HARDPPS_CD)
                info->IER |= UART_IER_MSI;
-       if (cflag & CRTSCTS) {
-               port->flags |= ASYNC_CTS_FLOW;
+       tty_port_set_cts_flow(port, cflag & CRTSCTS);
+       if (cflag & CRTSCTS)
                info->IER |= UART_IER_MSI;
-       } else
-               port->flags &= ~ASYNC_CTS_FLOW;
-       if (cflag & CLOCAL)
-               port->flags &= ~ASYNC_CHECK_CD;
-       else {
-               port->flags |= ASYNC_CHECK_CD;
+       tty_port_set_check_carrier(port, ~cflag & CLOCAL);
+       if (~cflag & CLOCAL)
                info->IER |= UART_IER_MSI;
-       }
        /* TBD:
         * Does clearing IER_MSI imply that we should disable the VBL interrupt ?
         */
@@ -1089,7 +1084,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
        port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
 check_and_exit:
-       if (port->flags & ASYNC_INITIALIZED) {
+       if (tty_port_initialized(port)) {
                if (change_spd) {
                        if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
                                tty->alt_speed = 57600;
@@ -1143,7 +1138,7 @@ static int rs_tiocmget(struct tty_struct *tty)
 
        if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
                return -ENODEV;
-       if (tty->flags & (1 << TTY_IO_ERROR))
+       if (tty_io_error(tty))
                return -EIO;
 
        control = info->MCR;
@@ -1165,7 +1160,7 @@ static int rs_tiocmset(struct tty_struct *tty, unsigned int set,
 
        if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
                return -ENODEV;
-       if (tty->flags & (1 << TTY_IO_ERROR))
+       if (tty_io_error(tty))
                return -EIO;
 
        local_irq_save(flags);
@@ -1250,7 +1245,7 @@ static int rs_ioctl(struct tty_struct *tty,
        if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
            (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
            (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
-               if (tty->flags & (1 << TTY_IO_ERROR))
+               if (tty_io_error(tty))
                    return -EIO;
        }
 
@@ -1342,7 +1337,7 @@ 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)) {
                info->MCR |= SER_DTR;
-               if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags))
+               if (!C_CRTSCTS(tty) || !tty_throttled(tty))
                        info->MCR |= SER_RTS;
                local_irq_save(flags);
                rtsdtr_ctrl(info->MCR);
@@ -1395,7 +1390,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
         * line status register.
         */
        state->read_status_mask &= ~UART_LSR_DR;
-       if (port->flags & ASYNC_INITIALIZED) {
+       if (tty_port_initialized(port)) {
                /* disable receive interrupts */
                custom.intena = IF_RBF;
                mb();
@@ -1495,7 +1490,7 @@ static void rs_hangup(struct tty_struct *tty)
        rs_flush_buffer(tty);
        shutdown(tty, info);
        info->tport.count = 0;
-       info->tport.flags &= ~ASYNC_NORMAL_ACTIVE;
+       tty_port_set_active(&info->tport, 0);
        info->tport.tty = NULL;
        wake_up_interruptible(&info->tport.open_wait);
 }
@@ -1543,7 +1538,7 @@ static inline void line_info(struct seq_file *m, int line,
 
        local_irq_save(flags);
        status = ciab.pra;
-       control = (state->tport.flags & ASYNC_INITIALIZED) ? state->MCR : status;
+       control = tty_port_initialized(&state->tport) ? state->MCR : status;
        local_irq_restore(flags);
 
        stat_buf[0] = 0;
index d67e542..3840d6b 100644 (file)
@@ -714,7 +714,7 @@ static void cyy_chip_modem(struct cyclades_card *cinfo, int chip,
                wake_up_interruptible(&info->port.delta_msr_wait);
        }
 
-       if ((mdm_change & CyDCD) && (info->port.flags & ASYNC_CHECK_CD)) {
+       if ((mdm_change & CyDCD) && tty_port_check_carrier(&info->port)) {
                if (mdm_status & CyDCD)
                        wake_up_interruptible(&info->port.open_wait);
                else
@@ -1119,7 +1119,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
                case C_CM_MDCD:
                        info->icount.dcd++;
                        delta_count++;
-                       if (info->port.flags & ASYNC_CHECK_CD) {
+                       if (tty_port_check_carrier(&info->port)) {
                                u32 dcd = fw_ver > 241 ? param :
                                        readl(&info->u.cyz.ch_ctrl->rs_status);
                                if (dcd & C_RS_DCD)
@@ -1279,7 +1279,7 @@ static int cy_startup(struct cyclades_port *info, struct tty_struct *tty)
 
        spin_lock_irqsave(&card->card_lock, flags);
 
-       if (info->port.flags & ASYNC_INITIALIZED)
+       if (tty_port_initialized(&info->port))
                goto errout;
 
        if (!info->type) {
@@ -1364,7 +1364,7 @@ static int cy_startup(struct cyclades_port *info, struct tty_struct *tty)
                /* enable send, recv, modem !!! */
        }
 
-       info->port.flags |= ASYNC_INITIALIZED;
+       tty_port_set_initialized(&info->port, 1);
 
        clear_bit(TTY_IO_ERROR, &tty->flags);
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
@@ -1424,7 +1424,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
        struct cyclades_card *card;
        unsigned long flags;
 
-       if (!(info->port.flags & ASYNC_INITIALIZED))
+       if (!tty_port_initialized(&info->port))
                return;
 
        card = info->card;
@@ -1448,7 +1448,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
                   some later date (after testing)!!! */
 
                set_bit(TTY_IO_ERROR, &tty->flags);
-               info->port.flags &= ~ASYNC_INITIALIZED;
+               tty_port_set_initialized(&info->port, 0);
                spin_unlock_irqrestore(&card->card_lock, flags);
        } else {
 #ifdef CY_DEBUG_OPEN
@@ -1473,7 +1473,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
                        tty_port_lower_dtr_rts(&info->port);
 
                set_bit(TTY_IO_ERROR, &tty->flags);
-               info->port.flags &= ~ASYNC_INITIALIZED;
+               tty_port_set_initialized(&info->port, 0);
 
                spin_unlock_irqrestore(&card->card_lock, flags);
        }
@@ -1711,7 +1711,7 @@ static void cy_do_close(struct tty_port *port)
                /* Stop accepting input */
                cyy_writeb(info, CyCAR, channel & 0x03);
                cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyRxData);
-               if (info->port.flags & ASYNC_INITIALIZED) {
+               if (tty_port_initialized(&info->port)) {
                        /* Waiting for on-board buffers to be empty before
                           closing the port */
                        spin_unlock_irqrestore(&card->card_lock, flags);
@@ -2083,17 +2083,12 @@ static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
                        info->cor1 |= CyPARITY_NONE;
 
                /* CTS flow control flag */
-               if (cflag & CRTSCTS) {
-                       info->port.flags |= ASYNC_CTS_FLOW;
+               tty_port_set_cts_flow(&info->port, cflag & CRTSCTS);
+               if (cflag & CRTSCTS)
                        info->cor2 |= CyCtsAE;
-               } else {
-                       info->port.flags &= ~ASYNC_CTS_FLOW;
-                       info->cor2 &= ~CyCtsAE;
-               }
-               if (cflag & CLOCAL)
-                       info->port.flags &= ~ASYNC_CHECK_CD;
                else
-                       info->port.flags |= ASYNC_CHECK_CD;
+                       info->cor2 &= ~CyCtsAE;
+               tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL);
 
         /***********************************************
            The hardware option, CyRtsAO, presents RTS when
@@ -2234,7 +2229,7 @@ static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
                }
                /* As the HW flow control is done in firmware, the driver
                   doesn't need to care about it */
-               info->port.flags &= ~ASYNC_CTS_FLOW;
+               tty_port_set_cts_flow(&info->port, 0);
 
                /* XON/XOFF/XANY flow control flags */
                sw_flow = 0;
@@ -2252,10 +2247,7 @@ static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
                }
 
                /* CD sensitivity */
-               if (cflag & CLOCAL)
-                       info->port.flags &= ~ASYNC_CHECK_CD;
-               else
-                       info->port.flags |= ASYNC_CHECK_CD;
+               tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL);
 
                if (baud == 0) {        /* baud rate is zero, turn off line */
                        cy_writel(&ch_ctrl->rs_control,
@@ -2342,7 +2334,7 @@ cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
        info->port.closing_wait = new_serial.closing_wait * HZ / 100;
 
 check_and_exit:
-       if (info->port.flags & ASYNC_INITIALIZED) {
+       if (tty_port_initialized(&info->port)) {
                cy_set_line_char(info, tty);
                ret = 0;
        } else {
index e46d628..ce86487 100644 (file)
@@ -632,7 +632,7 @@ int hvc_poll(struct hvc_struct *hp)
                goto bail;
 
        /* Now check if we can get data (are we throttled ?) */
-       if (test_bit(TTY_THROTTLED, &tty->flags))
+       if (tty_throttled(tty))
                goto throttled;
 
        /* If we aren't notifier driven and aren't throttled, we always
@@ -814,7 +814,7 @@ static int hvc_poll_get_char(struct tty_driver *driver, int line)
 
        n = hp->ops->get_chars(hp->vtermno, &ch, 1);
 
-       if (n == 0)
+       if (n <= 0)
                return NO_POLL_CHAR;
 
        return ch;
index 5997b17..3c4d7c2 100644 (file)
@@ -600,7 +600,7 @@ static int hvcs_io(struct hvcs_struct *hvcsd)
 
        hvcs_try_write(hvcsd);
 
-       if (!tty || test_bit(TTY_THROTTLED, &tty->flags)) {
+       if (!tty || tty_throttled(tty)) {
                hvcsd->todo_mask &= ~(HVCS_READ_MASK);
                goto bail;
        } else if (!(hvcsd->todo_mask & (HVCS_READ_MASK)))
index a75146f..96ce6bd 100644 (file)
@@ -509,7 +509,7 @@ static irqreturn_t hvsi_interrupt(int irq, void *arg)
        }
 
        spin_lock_irqsave(&hp->lock, flags);
-       if (tty && hp->n_throttle && !test_bit(TTY_THROTTLED, &tty->flags)) {
+       if (tty && hp->n_throttle && !tty_throttled(tty)) {
                /* we weren't hung up and we weren't throttled, so we can
                 * deliver the rest now */
                hvsi_send_overflow(hp);
index ad7031a..df0204b 100644 (file)
@@ -1572,6 +1572,11 @@ static void handle_received_SETUP_packet(struct ipw_hardware *hw,
                                        sizeof(struct ipw_setup_reboot_msg_ack),
                                        ADDR_SETUP_PROT, TL_PROTOCOLID_SETUP,
                                        TL_SETUP_SIGNO_REBOOT_MSG_ACK);
+                       if (!packet) {
+                               pr_err(IPWIRELESS_PCCARD_NAME
+                                      ": Not enough memory to send reboot packet");
+                               break;
+                       }
                        packet->header.length =
                                sizeof(struct TlSetupRebootMsgAck);
                        send_packet(hw, PRIO_SETUP, &packet->header);
index 8bf6763..b70187b 100644 (file)
@@ -438,8 +438,8 @@ static void isicom_tx(unsigned long _data)
 
        for (; count > 0; count--, port++) {
                /* port not active or tx disabled to force flow control */
-               if (!(port->port.flags & ASYNC_INITIALIZED) ||
-                               !(port->status & ISI_TXOK))
+               if (!tty_port_initialized(&port->port) ||
+                       !(port->status & ISI_TXOK))
                        continue;
 
                txcount = min_t(short, TX_SIZE, port->xmit_cnt);
@@ -553,7 +553,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
                return IRQ_HANDLED;
        }
        port = card->ports + channel;
-       if (!(port->port.flags & ASYNC_INITIALIZED)) {
+       if (!tty_port_initialized(&port->port)) {
                outw(0x0000, base+0x04); /* enable interrupts */
                spin_unlock(&card->card_lock);
                return IRQ_HANDLED;
@@ -577,7 +577,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
                header = inw(base);
                switch (header & 0xff) {
                case 0: /* Change in EIA signals */
-                       if (port->port.flags & ASYNC_CHECK_CD) {
+                       if (tty_port_check_carrier(&port->port)) {
                                if (port->status & ISI_DCD) {
                                        if (!(header & ISI_DCD)) {
                                        /* Carrier has been lost  */
@@ -758,18 +758,13 @@ static void isicom_config_port(struct tty_struct *tty)
                outw(channel_setup, base);
                InterruptTheCard(base);
        }
-       if (C_CLOCAL(tty))
-               port->port.flags &= ~ASYNC_CHECK_CD;
-       else
-               port->port.flags |= ASYNC_CHECK_CD;
+       tty_port_set_check_carrier(&port->port, !C_CLOCAL(tty));
 
        /* flow control settings ...*/
        flow_ctrl = 0;
-       port->port.flags &= ~ASYNC_CTS_FLOW;
-       if (C_CRTSCTS(tty)) {
-               port->port.flags |= ASYNC_CTS_FLOW;
+       tty_port_set_cts_flow(&port->port, C_CRTSCTS(tty));
+       if (C_CRTSCTS(tty))
                flow_ctrl |= ISICOM_CTSRTS;
-       }
        if (I_IXON(tty))
                flow_ctrl |= ISICOM_RESPOND_XONXOFF;
        if (I_IXOFF(tty))
index 92982d7..60d37b2 100644 (file)
@@ -912,7 +912,7 @@ static void moxa_board_deinit(struct moxa_board_conf *brd)
 
        /* pci hot-un-plug support */
        for (a = 0; a < brd->numPorts; a++)
-               if (brd->ports[a].port.flags & ASYNC_INITIALIZED)
+               if (tty_port_initialized(&brd->ports[a].port))
                        tty_port_tty_hangup(&brd->ports[a].port, false);
 
        for (a = 0; a < MAX_PORTS_PER_BOARD; a++)
@@ -921,7 +921,7 @@ static void moxa_board_deinit(struct moxa_board_conf *brd)
        while (1) {
                opened = 0;
                for (a = 0; a < brd->numPorts; a++)
-                       if (brd->ports[a].port.flags & ASYNC_INITIALIZED)
+                       if (tty_port_initialized(&brd->ports[a].port))
                                opened++;
                mutex_unlock(&moxa_openlock);
                if (!opened)
@@ -1192,13 +1192,13 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
        tty->driver_data = ch;
        tty_port_tty_set(&ch->port, tty);
        mutex_lock(&ch->port.mutex);
-       if (!(ch->port.flags & ASYNC_INITIALIZED)) {
+       if (!tty_port_initialized(&ch->port)) {
                ch->statusflags = 0;
                moxa_set_tty_param(tty, &tty->termios);
                MoxaPortLineCtrl(ch, 1, 1);
                MoxaPortEnable(ch);
                MoxaSetFifo(ch, ch->type == PORT_16550A);
-               ch->port.flags |= ASYNC_INITIALIZED;
+               tty_port_set_initialized(&ch->port, 1);
        }
        mutex_unlock(&ch->port.mutex);
        mutex_unlock(&moxa_openlock);
@@ -1379,7 +1379,7 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
 {
        struct tty_struct *tty = tty_port_tty_get(&p->port);
        void __iomem *ofsAddr;
-       unsigned int inited = p->port.flags & ASYNC_INITIALIZED;
+       unsigned int inited = tty_port_initialized(&p->port);
        u16 intr;
 
        if (tty) {
@@ -1394,7 +1394,7 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
                        tty_wakeup(tty);
                }
 
-               if (inited && !test_bit(TTY_THROTTLED, &tty->flags) &&
+               if (inited && !tty_throttled(tty) &&
                                MoxaPortRxQueue(p) > 0) { /* RX */
                        MoxaPortReadData(p);
                        tty_schedule_flip(&p->port);
index 2f12bb9..98d2bd1 100644 (file)
@@ -711,8 +711,8 @@ static int mxser_change_speed(struct tty_struct *tty,
        /* CTS flow control flag and modem status interrupts */
        info->IER &= ~UART_IER_MSI;
        info->MCR &= ~UART_MCR_AFE;
+       tty_port_set_cts_flow(&info->port, cflag & CRTSCTS);
        if (cflag & CRTSCTS) {
-               info->port.flags |= ASYNC_CTS_FLOW;
                info->IER |= UART_IER_MSI;
                if ((info->type == PORT_16550A) || (info->board->chip_flag)) {
                        info->MCR |= UART_MCR_AFE;
@@ -744,16 +744,11 @@ static int mxser_change_speed(struct tty_struct *tty,
                                }
                        }
                }
-       } else {
-               info->port.flags &= ~ASYNC_CTS_FLOW;
        }
        outb(info->MCR, info->ioaddr + UART_MCR);
-       if (cflag & CLOCAL) {
-               info->port.flags &= ~ASYNC_CHECK_CD;
-       } else {
-               info->port.flags |= ASYNC_CHECK_CD;
+       tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL);
+       if (~cflag & CLOCAL)
                info->IER |= UART_IER_MSI;
-       }
        outb(info->IER, info->ioaddr + UART_IER);
 
        /*
@@ -826,7 +821,7 @@ static void mxser_check_modem_status(struct tty_struct *tty,
        port->mon_data.modem_status = status;
        wake_up_interruptible(&port->port.delta_msr_wait);
 
-       if ((port->port.flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
+       if (tty_port_check_carrier(&port->port) && (status & UART_MSR_DDCD)) {
                if (status & UART_MSR_DCD)
                        wake_up_interruptible(&port->port.open_wait);
        }
@@ -1086,12 +1081,10 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
        mutex_lock(&port->mutex);
        mxser_close_port(port);
        mxser_flush_buffer(tty);
-       if (test_bit(ASYNCB_INITIALIZED, &port->flags)) {
-               if (C_HUPCL(tty))
-                       tty_port_lower_dtr_rts(port);
-       }
+       if (tty_port_initialized(port) && C_HUPCL(tty))
+               tty_port_lower_dtr_rts(port);
        mxser_shutdown_port(port);
-       clear_bit(ASYNCB_INITIALIZED, &port->flags);
+       tty_port_set_initialized(port, 0);
        mutex_unlock(&port->mutex);
        info->closing = 0;
        /* Right now the tty_port set is done outside of the close_end helper
@@ -1287,7 +1280,7 @@ static int mxser_set_serial_info(struct tty_struct *tty,
 
        process_txrx_fifo(info);
 
-       if (test_bit(ASYNCB_INITIALIZED, &port->flags)) {
+       if (tty_port_initialized(port)) {
                if (flags != (port->flags & ASYNC_SPD_MASK)) {
                        spin_lock_irqsave(&info->slock, sl_flags);
                        mxser_change_speed(tty, NULL);
@@ -1296,7 +1289,7 @@ static int mxser_set_serial_info(struct tty_struct *tty,
        } else {
                retval = mxser_activate(port, tty);
                if (retval == 0)
-                       set_bit(ASYNCB_INITIALIZED, &port->flags);
+                       tty_port_set_initialized(port, 1);
        }
        return retval;
 }
@@ -1334,7 +1327,7 @@ static int mxser_tiocmget(struct tty_struct *tty)
 
        if (tty->index == MXSER_PORTS)
                return -ENOIOCTLCMD;
-       if (test_bit(TTY_IO_ERROR, &tty->flags))
+       if (tty_io_error(tty))
                return -EIO;
 
        control = info->MCR;
@@ -1361,7 +1354,7 @@ static int mxser_tiocmset(struct tty_struct *tty,
 
        if (tty->index == MXSER_PORTS)
                return -ENOIOCTLCMD;
-       if (test_bit(TTY_IO_ERROR, &tty->flags))
+       if (tty_io_error(tty))
                return -EIO;
 
        spin_lock_irqsave(&info->slock, flags);
@@ -1715,8 +1708,7 @@ static int mxser_ioctl(struct tty_struct *tty,
                return 0;
        }
 
-       if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT &&
-                       test_bit(TTY_IO_ERROR, &tty->flags))
+       if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT && tty_io_error(tty))
                return -EIO;
 
        switch (cmd) {
@@ -2257,7 +2249,7 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
                                iir &= MOXA_MUST_IIR_MASK;
                                tty = tty_port_tty_get(&port->port);
                                if (!tty || port->closing ||
-                                   !(port->port.flags & ASYNC_INITIALIZED)) {
+                                   !tty_port_initialized(&port->port)) {
                                        status = inb(port->ioaddr + UART_LSR);
                                        outb(0x27, port->ioaddr + UART_FCR);
                                        inb(port->ioaddr + UART_MSR);
@@ -2400,7 +2392,6 @@ static int mxser_initbrd(struct mxser_board *brd,
                if (brd->chip_flag != MOXA_OTHER_UART)
                        mxser_enable_must_enchance_mode(info->ioaddr);
 
-               info->port.flags = ASYNC_SHARE_IRQ;
                info->type = brd->uart_type;
 
                process_txrx_fifo(info);
index 0c27a00..54cab59 100644 (file)
@@ -2045,7 +2045,9 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm)
                }
        }
        spin_unlock(&gsm_mux_lock);
-       WARN_ON(i == MAX_MUX);
+       /* open failed before registering => nothing to do */
+       if (i == MAX_MUX)
+               return;
 
        /* In theory disconnecting DLCI 0 is sufficient but for some
           modems this is apparently not the case. */
@@ -2947,7 +2949,7 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp)
        dlci->modem_rx = 0;
        /* We could in theory open and close before we wait - eg if we get
           a DM straight back. This is ok as that will have caused a hangup */
-       set_bit(ASYNCB_INITIALIZED, &port->flags);
+       tty_port_set_initialized(port, 1);
        /* Start sending off SABM messages */
        gsm_dlci_begin_open(dlci);
        /* And wait for virtual carrier */
@@ -2970,10 +2972,8 @@ static void gsmtty_close(struct tty_struct *tty, struct file *filp)
        if (tty_port_close_start(&dlci->port, tty, filp) == 0)
                return;
        gsm_dlci_begin_close(dlci);
-       if (test_bit(ASYNCB_INITIALIZED, &dlci->port.flags)) {
-               if (C_HUPCL(tty))
-                       tty_port_lower_dtr_rts(&dlci->port);
-       }
+       if (tty_port_initialized(&dlci->port) && C_HUPCL(tty))
+               tty_port_lower_dtr_rts(&dlci->port);
        tty_port_close_end(&dlci->port, tty);
        tty_port_tty_set(&dlci->port, NULL);
        return;
index bcaba17..a7fa016 100644 (file)
@@ -599,7 +599,7 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
        add_wait_queue(&tty->read_wait, &wait);
 
        for (;;) {
-               if (test_bit(TTY_OTHER_DONE, &tty->flags)) {
+               if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
                        ret = -EIO;
                        break;
                }
@@ -827,7 +827,7 @@ static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
                /* set bits for operations that won't block */
                if (n_hdlc->rx_buf_list.head)
                        mask |= POLLIN | POLLRDNORM;    /* readable */
-               if (test_bit(TTY_OTHER_DONE, &tty->flags))
+               if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
                        mask |= POLLHUP;
                if (tty_hung_up_p(filp))
                        mask |= POLLHUP;
index fb76a7d..bdf0e6e 100644 (file)
@@ -1917,18 +1917,6 @@ static inline int input_available_p(struct tty_struct *tty, int poll)
                return ldata->commit_head - ldata->read_tail >= amt;
 }
 
-static inline int check_other_done(struct tty_struct *tty)
-{
-       int done = test_bit(TTY_OTHER_DONE, &tty->flags);
-       if (done) {
-               /* paired with cmpxchg() in check_other_closed(); ensures
-                * read buffer head index is not stale
-                */
-               smp_mb__after_atomic();
-       }
-       return done;
-}
-
 /**
  *     copy_from_read_buf      -       copy read data directly
  *     @tty: terminal device
@@ -2124,7 +2112,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
        struct n_tty_data *ldata = tty->disc_data;
        unsigned char __user *b = buf;
        DEFINE_WAIT_FUNC(wait, woken_wake_function);
-       int c, done;
+       int c;
        int minimum, time;
        ssize_t retval = 0;
        long timeout;
@@ -2183,32 +2171,35 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
                        break;
                }
 
-               done = check_other_done(tty);
-
                if (!input_available_p(tty, 0)) {
-                       if (done) {
-                               retval = -EIO;
-                               break;
-                       }
-                       if (tty_hung_up_p(file))
-                               break;
-                       if (!timeout)
-                               break;
-                       if (file->f_flags & O_NONBLOCK) {
-                               retval = -EAGAIN;
-                               break;
-                       }
-                       if (signal_pending(current)) {
-                               retval = -ERESTARTSYS;
-                               break;
-                       }
                        up_read(&tty->termios_rwsem);
+                       tty_buffer_flush_work(tty->port);
+                       down_read(&tty->termios_rwsem);
+                       if (!input_available_p(tty, 0)) {
+                               if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
+                                       retval = -EIO;
+                                       break;
+                               }
+                               if (tty_hung_up_p(file))
+                                       break;
+                               if (!timeout)
+                                       break;
+                               if (file->f_flags & O_NONBLOCK) {
+                                       retval = -EAGAIN;
+                                       break;
+                               }
+                               if (signal_pending(current)) {
+                                       retval = -ERESTARTSYS;
+                                       break;
+                               }
+                               up_read(&tty->termios_rwsem);
 
-                       timeout = wait_woken(&wait, TASK_INTERRUPTIBLE,
-                                            timeout);
+                               timeout = wait_woken(&wait, TASK_INTERRUPTIBLE,
+                                               timeout);
 
-                       down_read(&tty->termios_rwsem);
-                       continue;
+                               down_read(&tty->termios_rwsem);
+                               continue;
+                       }
                }
 
                if (ldata->icanon && !L_EXTPROC(tty)) {
@@ -2386,12 +2377,17 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
 
        poll_wait(file, &tty->read_wait, wait);
        poll_wait(file, &tty->write_wait, wait);
-       if (check_other_done(tty))
-               mask |= POLLHUP;
        if (input_available_p(tty, 1))
                mask |= POLLIN | POLLRDNORM;
+       else {
+               tty_buffer_flush_work(tty->port);
+               if (input_available_p(tty, 1))
+                       mask |= POLLIN | POLLRDNORM;
+       }
        if (tty->packet && tty->link->ctrl_status)
                mask |= POLLPRI | POLLIN | POLLRDNORM;
+       if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
+               mask |= POLLHUP;
        if (tty_hung_up_p(file))
                mask |= POLLHUP;
        if (tty->ops->write && !tty_is_writelocked(tty) &&
index 5cc80b8..d6fd0e8 100644 (file)
@@ -826,7 +826,7 @@ static int receive_data(enum port_type index, struct nozomi *dc)
        size = __le32_to_cpu(readl(addr));
        /*  DBG1( "%d bytes port: %d", size, index); */
 
-       if (tty && test_bit(TTY_THROTTLED, &tty->flags)) {
+       if (tty && tty_throttled(tty)) {
                DBG1("No room in tty, don't read data, don't ack interrupt, "
                        "disable interrupt");
 
index cf0dc51..dd4b841 100644 (file)
@@ -44,7 +44,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
        if (tty->driver->subtype == PTY_TYPE_MASTER)
                WARN_ON(tty->count > 1);
        else {
-               if (test_bit(TTY_IO_ERROR, &tty->flags))
+               if (tty_io_error(tty))
                        return;
                if (tty->count > 2)
                        return;
@@ -59,7 +59,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
        if (!tty->link)
                return;
        set_bit(TTY_OTHER_CLOSED, &tty->link->flags);
-       tty_flip_buffer_push(tty->link->port);
+       wake_up_interruptible(&tty->link->read_wait);
        wake_up_interruptible(&tty->link->write_wait);
        if (tty->driver->subtype == PTY_TYPE_MASTER) {
                set_bit(TTY_OTHER_CLOSED, &tty->flags);
@@ -247,9 +247,7 @@ static int pty_open(struct tty_struct *tty, struct file *filp)
                goto out;
 
        clear_bit(TTY_IO_ERROR, &tty->flags);
-       /* TTY_OTHER_CLOSED must be cleared before TTY_OTHER_DONE */
        clear_bit(TTY_OTHER_CLOSED, &tty->link->flags);
-       clear_bit(TTY_OTHER_DONE, &tty->link->flags);
        set_bit(TTY_THROTTLED, &tty->flags);
        return 0;
 
index 0b802cd..b0cc47c 100644 (file)
@@ -495,7 +495,7 @@ static void rp_handle_port(struct r_port *info)
        if (!info)
                return;
 
-       if ((info->port.flags & ASYNC_INITIALIZED) == 0) {
+       if (!tty_port_initialized(&info->port)) {
                printk(KERN_WARNING "rp: WARNING: rp_handle_port called with "
                                "info->flags & NOT_INIT\n");
                return;
@@ -615,7 +615,8 @@ static void rp_do_poll(unsigned long dummy)
  *  the board.  
  *  Inputs:  board, aiop, chan numbers
  */
-static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
+static void __init
+init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
 {
        unsigned rocketMode;
        struct r_port *info;
@@ -920,7 +921,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
        /*
         * Info->count is now 1; so it's safe to sleep now.
         */
-       if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) {
+       if (!tty_port_initialized(port)) {
                cp = &info->channel;
                sSetRxTrigger(cp, TRIG_1);
                if (sGetChanStatus(cp) & CD_ACT)
@@ -944,7 +945,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
                sEnRxFIFO(cp);
                sEnTransmit(cp);
 
-               set_bit(ASYNCB_INITIALIZED, &info->port.flags);
+               tty_port_set_initialized(&info->port, 1);
 
                /*
                 * Set up the tty->alt_speed kludge
@@ -1042,9 +1043,10 @@ static void rp_close(struct tty_struct *tty, struct file *filp)
                }
        }
        spin_lock_irq(&port->lock);
-       info->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_NORMAL_ACTIVE);
        tty->closing = 0;
        spin_unlock_irq(&port->lock);
+       tty_port_set_initialized(port, 0);
+       tty_port_set_active(port, 0);
        mutex_unlock(&port->mutex);
        tty_port_tty_set(port, NULL);
 
@@ -1512,7 +1514,7 @@ static void rp_hangup(struct tty_struct *tty)
        sDisCTSFlowCtl(cp);
        sDisTxSoftFlowCtl(cp);
        sClrTxXOFF(cp);
-       clear_bit(ASYNCB_INITIALIZED, &info->port.flags);
+       tty_port_set_initialized(&info->port, 0);
 
        wake_up_interruptible(&info->port.open_wait);
 }
@@ -1624,7 +1626,7 @@ static int rp_write(struct tty_struct *tty,
        /*  Write remaining data into the port's xmit_buf */
        while (1) {
                /* Hung up ? */
-               if (!test_bit(ASYNCB_NORMAL_ACTIVE, &info->port.flags))
+               if (!tty_port_active(&info->port))
                        goto end;
                c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1);
                c = min(c, XMIT_BUF_SIZE - info->xmit_head);
index 047a7ba..215a992 100644 (file)
@@ -17,7 +17,7 @@
 
 struct uart_8250_dma {
        int (*tx_dma)(struct uart_8250_port *p);
-       int (*rx_dma)(struct uart_8250_port *p, unsigned int iir);
+       int (*rx_dma)(struct uart_8250_port *p);
 
        /* Filter function */
        dma_filter_fn           fn;
@@ -84,7 +84,6 @@ struct serial8250_config {
 #define UART_BUG_THRE  (1 << 3)        /* UART has buggy THRE reassertion */
 #define UART_BUG_PARITY        (1 << 4)        /* UART mishandles parity if FIFO enabled */
 
-#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
 
 #ifdef CONFIG_SERIAL_8250_SHARE_IRQ
 #define SERIAL8250_SHARE_IRQS 1
@@ -151,6 +150,12 @@ static inline int serial8250_pnp_init(void) { return 0; }
 static inline void serial8250_pnp_exit(void) { }
 #endif
 
+#ifdef CONFIG_SERIAL_8250_FINTEK
+int fintek_8250_probe(struct uart_8250_port *uart);
+#else
+static inline int fintek_8250_probe(struct uart_8250_port *uart) { return 0; }
+#endif
+
 #ifdef CONFIG_ARCH_OMAP1
 static inline int is_omap1_8250(struct uart_8250_port *pt)
 {
@@ -190,7 +195,8 @@ static inline int is_omap1510_8250(struct uart_8250_port *pt)
 
 #ifdef CONFIG_SERIAL_8250_DMA
 extern int serial8250_tx_dma(struct uart_8250_port *);
-extern int serial8250_rx_dma(struct uart_8250_port *, unsigned int iir);
+extern int serial8250_rx_dma(struct uart_8250_port *);
+extern void serial8250_rx_dma_flush(struct uart_8250_port *);
 extern int serial8250_request_dma(struct uart_8250_port *);
 extern void serial8250_release_dma(struct uart_8250_port *);
 #else
@@ -198,10 +204,11 @@ static inline int serial8250_tx_dma(struct uart_8250_port *p)
 {
        return -1;
 }
-static inline int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
+static inline int serial8250_rx_dma(struct uart_8250_port *p)
 {
        return -1;
 }
+static inline void serial8250_rx_dma_flush(struct uart_8250_port *p) { }
 static inline int serial8250_request_dma(struct uart_8250_port *p)
 {
        return -1;
index 2f4f5ee..0fbd7c0 100644 (file)
@@ -830,6 +830,7 @@ static int serial8250_probe(struct platform_device *dev)
                uart.port.handle_irq    = p->handle_irq;
                uart.port.handle_break  = p->handle_break;
                uart.port.set_termios   = p->set_termios;
+               uart.port.get_mctrl     = p->get_mctrl;
                uart.port.pm            = p->pm;
                uart.port.dev           = &dev->dev;
                uart.port.irqflags      |= irqflag;
@@ -1022,6 +1023,8 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
                /*  Possibly override set_termios call */
                if (up->port.set_termios)
                        uart->port.set_termios = up->port.set_termios;
+               if (up->port.get_mctrl)
+                       uart->port.get_mctrl = up->port.get_mctrl;
                if (up->port.set_mctrl)
                        uart->port.set_mctrl = up->port.set_mctrl;
                if (up->port.startup)
index 78259d3..7f33d1c 100644 (file)
@@ -110,30 +110,11 @@ err:
        return ret;
 }
 
-int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
+int serial8250_rx_dma(struct uart_8250_port *p)
 {
        struct uart_8250_dma            *dma = p->dma;
        struct dma_async_tx_descriptor  *desc;
 
-       switch (iir & 0x3f) {
-       case UART_IIR_RLSI:
-               /* 8250_core handles errors and break interrupts */
-               return -EIO;
-       case UART_IIR_RX_TIMEOUT:
-               /*
-                * If RCVR FIFO trigger level was not reached, complete the
-                * transfer and let 8250_core copy the remaining data.
-                */
-               if (dma->rx_running) {
-                       dmaengine_pause(dma->rxchan);
-                       __dma_rx_complete(p);
-                       dmaengine_terminate_all(dma->rxchan);
-               }
-               return -ETIMEDOUT;
-       default:
-               break;
-       }
-
        if (dma->rx_running)
                return 0;
 
@@ -154,10 +135,23 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
        return 0;
 }
 
+void serial8250_rx_dma_flush(struct uart_8250_port *p)
+{
+       struct uart_8250_dma *dma = p->dma;
+
+       if (dma->rx_running) {
+               dmaengine_pause(dma->rxchan);
+               __dma_rx_complete(p);
+               dmaengine_terminate_all(dma->rxchan);
+       }
+}
+
 int serial8250_request_dma(struct uart_8250_port *p)
 {
        struct uart_8250_dma    *dma = p->dma;
        dma_cap_mask_t          mask;
+       struct dma_slave_caps   caps;
+       int                     ret;
 
        /* Default slave configuration parameters */
        dma->rxconf.direction           = DMA_DEV_TO_MEM;
@@ -178,6 +172,16 @@ int serial8250_request_dma(struct uart_8250_port *p)
        if (!dma->rxchan)
                return -ENODEV;
 
+       /* 8250 rx dma requires dmaengine driver to support pause/terminate */
+       ret = dma_get_slave_caps(dma->rxchan, &caps);
+       if (ret)
+               goto release_rx;
+       if (!caps.cmd_pause || !caps.cmd_terminate ||
+           caps.residue_granularity == DMA_RESIDUE_GRANULARITY_DESCRIPTOR) {
+               ret = -EINVAL;
+               goto release_rx;
+       }
+
        dmaengine_slave_config(dma->rxchan, &dma->rxconf);
 
        /* Get a channel for TX */
@@ -185,8 +189,17 @@ int serial8250_request_dma(struct uart_8250_port *p)
                                                       dma->fn, dma->tx_param,
                                                       p->port.dev, "tx");
        if (!dma->txchan) {
-               dma_release_channel(dma->rxchan);
-               return -ENODEV;
+               ret = -ENODEV;
+               goto release_rx;
+       }
+
+       /* 8250 tx dma requires dmaengine driver to support terminate */
+       ret = dma_get_slave_caps(dma->txchan, &caps);
+       if (ret)
+               goto err;
+       if (!caps.cmd_terminate) {
+               ret = -EINVAL;
+               goto err;
        }
 
        dmaengine_slave_config(dma->txchan, &dma->txconf);
@@ -197,8 +210,10 @@ int serial8250_request_dma(struct uart_8250_port *p)
 
        dma->rx_buf = dma_alloc_coherent(dma->rxchan->device->dev, dma->rx_size,
                                        &dma->rx_addr, GFP_KERNEL);
-       if (!dma->rx_buf)
+       if (!dma->rx_buf) {
+               ret = -ENOMEM;
                goto err;
+       }
 
        /* TX buffer */
        dma->tx_addr = dma_map_single(dma->txchan->device->dev,
@@ -208,6 +223,7 @@ int serial8250_request_dma(struct uart_8250_port *p)
        if (dma_mapping_error(dma->txchan->device->dev, dma->tx_addr)) {
                dma_free_coherent(dma->rxchan->device->dev, dma->rx_size,
                                  dma->rx_buf, dma->rx_addr);
+               ret = -ENOMEM;
                goto err;
        }
 
@@ -215,10 +231,10 @@ int serial8250_request_dma(struct uart_8250_port *p)
 
        return 0;
 err:
-       dma_release_channel(dma->rxchan);
        dma_release_channel(dma->txchan);
-
-       return -ENOMEM;
+release_rx:
+       dma_release_channel(dma->rxchan);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(serial8250_request_dma);
 
index a3fb95d..e199696 100644 (file)
@@ -104,15 +104,16 @@ static void dw8250_check_lcr(struct uart_port *p, int value)
                dw8250_force_idle(p);
 
 #ifdef CONFIG_64BIT
-               __raw_writeq(value & 0xff, offset);
-#else
+               if (p->type == PORT_OCTEON)
+                       __raw_writeq(value & 0xff, offset);
+               else
+#endif
                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
@@ -617,6 +618,7 @@ static const struct acpi_device_id dw8250_acpi_match[] = {
        { "8086228A", 0 },
        { "APMC0D08", 0},
        { "AMD0020", 0 },
+       { "AMDI0020", 0 },
        { },
 };
 MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
index 8947439..870981d 100644 (file)
@@ -1,9 +1,7 @@
 /*
  *  Probe for F81216A LPC to 4 UART
  *
- *  Based on drivers/tty/serial/8250_pnp.c, by Russell King, et al
- *
- *  Copyright (C) 2014 Ricardo Ribalda, Qtechnology A/S
+ *  Copyright (C) 2014-2016 Ricardo Ribalda, Qtechnology A/S
  *
  *
  * This program is free software; you can redistribute it and/or modify
 #define RXW4C_IRA BIT(3)
 #define TXW4C_IRA BIT(2)
 
-#define DRIVER_NAME "8250_fintek"
-
 struct fintek_8250 {
        u16 base_port;
        u8 index;
        u8 key;
-       long line;
 };
 
 static int fintek_8250_enter_key(u16 base_port, u8 key)
 {
-
-       if (!request_muxed_region(base_port, 2, DRIVER_NAME))
+       if (!request_muxed_region(base_port, 2, "8250_fintek"))
                return -EBUSY;
 
        outb(key, base_port + ADDR_PORT);
@@ -138,7 +132,7 @@ static int fintek_8250_rs485_config(struct uart_port *port,
        return 0;
 }
 
-static int fintek_8250_base_port(u16 io_address, u8 *key, u8 *index)
+static int find_base_port(struct fintek_8250 *pdata, u16 io_address)
 {
        static const u16 addr[] = {0x4e, 0x2e};
        static const u8 keys[] = {0x77, 0xa0, 0x87, 0x67};
@@ -168,10 +162,13 @@ static int fintek_8250_base_port(u16 io_address, u8 *key, u8 *index)
                                        continue;
 
                                fintek_8250_exit_key(addr[i]);
-                               *key = keys[j];
-                               *index = k;
-                               return addr[i];
+                               pdata->key = keys[j];
+                               pdata->base_port = addr[i];
+                               pdata->index = k;
+
+                               return 0;
                        }
+
                        fintek_8250_exit_key(addr[i]);
                }
        }
@@ -179,104 +176,21 @@ static int fintek_8250_base_port(u16 io_address, u8 *key, u8 *index)
        return -ENODEV;
 }
 
-static int
-fintek_8250_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
+int fintek_8250_probe(struct uart_8250_port *uart)
 {
-       struct uart_8250_port uart;
        struct fintek_8250 *pdata;
-       int base_port;
-       u8 key;
-       u8 index;
-
-       if (!pnp_port_valid(dev, 0))
-               return -ENODEV;
+       struct fintek_8250 probe_data;
 
-       base_port = fintek_8250_base_port(pnp_port_start(dev, 0), &key, &index);
-       if (base_port < 0)
+       if (find_base_port(&probe_data, uart->port.iobase))
                return -ENODEV;
 
-       memset(&uart, 0, sizeof(uart));
-
-       pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL);
+       pdata = devm_kzalloc(uart->port.dev, sizeof(*pdata), GFP_KERNEL);
        if (!pdata)
                return -ENOMEM;
-       uart.port.private_data = pdata;
 
-       if (!pnp_irq_valid(dev, 0))
-               return -ENODEV;
-       uart.port.irq = pnp_irq(dev, 0);
-       uart.port.iobase = pnp_port_start(dev, 0);
-       uart.port.iotype = UPIO_PORT;
-       uart.port.rs485_config = fintek_8250_rs485_config;
-
-       uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
-       if (pnp_irq_flags(dev, 0) & IORESOURCE_IRQ_SHAREABLE)
-               uart.port.flags |= UPF_SHARE_IRQ;
-       uart.port.uartclk = 1843200;
-       uart.port.dev = &dev->dev;
-
-       pdata->key = key;
-       pdata->base_port = base_port;
-       pdata->index = index;
-       pdata->line = serial8250_register_8250_port(&uart);
-       if (pdata->line < 0)
-               return -ENODEV;
+       memcpy(pdata, &probe_data, sizeof(probe_data));
+       uart->port.rs485_config = fintek_8250_rs485_config;
+       uart->port.private_data = pdata;
 
-       pnp_set_drvdata(dev, pdata);
        return 0;
 }
-
-static void fintek_8250_remove(struct pnp_dev *dev)
-{
-       struct fintek_8250 *pdata = pnp_get_drvdata(dev);
-
-       if (pdata)
-               serial8250_unregister_port(pdata->line);
-}
-
-#ifdef CONFIG_PM
-static int fintek_8250_suspend(struct pnp_dev *dev, pm_message_t state)
-{
-       struct fintek_8250 *pdata = pnp_get_drvdata(dev);
-
-       if (!pdata)
-               return -ENODEV;
-       serial8250_suspend_port(pdata->line);
-       return 0;
-}
-
-static int fintek_8250_resume(struct pnp_dev *dev)
-{
-       struct fintek_8250 *pdata = pnp_get_drvdata(dev);
-
-       if (!pdata)
-               return -ENODEV;
-       serial8250_resume_port(pdata->line);
-       return 0;
-}
-#else
-#define fintek_8250_suspend NULL
-#define fintek_8250_resume NULL
-#endif /* CONFIG_PM */
-
-static const struct pnp_device_id fintek_dev_table[] = {
-       /* Qtechnology Panel PC / IO1000 */
-       { "PNP0501"},
-       {}
-};
-
-MODULE_DEVICE_TABLE(pnp, fintek_dev_table);
-
-static struct pnp_driver fintek_8250_driver = {
-       .name           = DRIVER_NAME,
-       .probe          = fintek_8250_probe,
-       .remove         = fintek_8250_remove,
-       .suspend        = fintek_8250_suspend,
-       .resume         = fintek_8250_resume,
-       .id_table       = fintek_dev_table,
-};
-
-module_pnp_driver(fintek_8250_driver);
-MODULE_DESCRIPTION("Fintek F812164 module");
-MODULE_AUTHOR("Ricardo Ribalda <ricardo.ribalda@gmail.com>");
-MODULE_LICENSE("GPL");
index 88531a3..86379a7 100644 (file)
@@ -9,11 +9,13 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/rational.h>
+#include <linux/bitops.h>
 #include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/rational.h>
 
 #include <linux/dma/hsu.h>
+#include <linux/8250_pci.h>
 
 #include "8250.h"
 
@@ -24,6 +26,7 @@
 #define PCI_DEVICE_ID_INTEL_DNV_UART   0x19d8
 
 /* Intel MID Specific registers */
+#define INTEL_MID_UART_DNV_FISR                0x08
 #define INTEL_MID_UART_PS              0x30
 #define INTEL_MID_UART_MUL             0x34
 #define INTEL_MID_UART_DIV             0x38
@@ -31,6 +34,7 @@
 struct mid8250;
 
 struct mid8250_board {
+       unsigned int flags;
        unsigned long freq;
        unsigned int base_baud;
        int (*setup)(struct mid8250 *, struct uart_port *p);
@@ -76,7 +80,11 @@ static int tng_setup(struct mid8250 *mid, struct uart_port *p)
        struct pci_dev *pdev = to_pci_dev(p->dev);
        int index = PCI_FUNC(pdev->devfn);
 
-       /* Currently no support for HSU port0 */
+       /*
+        * Device 0000:00:04.0 is not a real HSU port. It provides a global
+        * register set for all HSU ports, although it has the same PCI ID.
+        * Skip it here.
+        */
        if (index-- == 0)
                return -ENODEV;
 
@@ -88,16 +96,16 @@ static int tng_setup(struct mid8250 *mid, struct uart_port *p)
 static int dnv_handle_irq(struct uart_port *p)
 {
        struct mid8250 *mid = p->private_data;
-       int ret;
-
-       ret = hsu_dma_irq(&mid->dma_chip, 0);
-       ret |= hsu_dma_irq(&mid->dma_chip, 1);
-
-       /* For now, letting the HW generate separate interrupt for the UART */
-       if (ret)
-               return ret;
-
-       return serial8250_handle_irq(p, serial_port_in(p, UART_IIR));
+       unsigned int fisr = serial_port_in(p, INTEL_MID_UART_DNV_FISR);
+       int ret = IRQ_NONE;
+
+       if (fisr & BIT(2))
+               ret |= hsu_dma_irq(&mid->dma_chip, 1);
+       if (fisr & BIT(1))
+               ret |= hsu_dma_irq(&mid->dma_chip, 0);
+       if (fisr & BIT(0))
+               ret |= serial8250_handle_irq(p, serial_port_in(p, UART_IIR));
+       return ret;
 }
 
 #define DNV_DMA_CHAN_OFFSET 0x80
@@ -106,12 +114,13 @@ static int dnv_setup(struct mid8250 *mid, struct uart_port *p)
 {
        struct hsu_dma_chip *chip = &mid->dma_chip;
        struct pci_dev *pdev = to_pci_dev(p->dev);
+       unsigned int bar = FL_GET_BASE(mid->board->flags);
        int ret;
 
        chip->dev = &pdev->dev;
        chip->irq = pdev->irq;
        chip->regs = p->membase;
-       chip->length = pci_resource_len(pdev, 0);
+       chip->length = pci_resource_len(pdev, bar);
        chip->offset = DNV_DMA_CHAN_OFFSET;
 
        /* Falling back to PIO mode if DMA probing fails */
@@ -217,6 +226,7 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct uart_8250_port uart;
        struct mid8250 *mid;
+       unsigned int bar;
        int ret;
 
        ret = pcim_enable_device(pdev);
@@ -230,6 +240,7 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                return -ENOMEM;
 
        mid->board = (struct mid8250_board *)id->driver_data;
+       bar = FL_GET_BASE(mid->board->flags);
 
        memset(&uart, 0, sizeof(struct uart_8250_port));
 
@@ -242,8 +253,8 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        uart.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE;
        uart.port.set_termios = mid8250_set_termios;
 
-       uart.port.mapbase = pci_resource_start(pdev, 0);
-       uart.port.membase = pcim_iomap(pdev, 0, 0);
+       uart.port.mapbase = pci_resource_start(pdev, bar);
+       uart.port.membase = pcim_iomap(pdev, bar, 0);
        if (!uart.port.membase)
                return -ENOMEM;
 
@@ -282,18 +293,21 @@ static void mid8250_remove(struct pci_dev *pdev)
 }
 
 static const struct mid8250_board pnw_board = {
+       .flags = FL_BASE0,
        .freq = 50000000,
        .base_baud = 115200,
        .setup = pnw_setup,
 };
 
 static const struct mid8250_board tng_board = {
+       .flags = FL_BASE0,
        .freq = 38400000,
        .base_baud = 1843200,
        .setup = tng_setup,
 };
 
 static const struct mid8250_board dnv_board = {
+       .flags = FL_BASE1,
        .freq = 133333333,
        .base_baud = 115200,
        .setup = dnv_setup,
index c7ed3d2..38963d7 100644 (file)
@@ -29,7 +29,7 @@ struct of_serial_info {
 };
 
 #ifdef CONFIG_ARCH_TEGRA
-void tegra_serial_handle_break(struct uart_port *p)
+static void tegra_serial_handle_break(struct uart_port *p)
 {
        unsigned int status, tmout = 10000;
 
index 6f76051..2c44c79 100644 (file)
@@ -115,6 +115,12 @@ struct omap8250_priv {
        bool rx_dma_broken;
 };
 
+#ifdef CONFIG_SERIAL_8250_DMA
+static void omap_8250_rx_dma_flush(struct uart_8250_port *p);
+#else
+static inline void omap_8250_rx_dma_flush(struct uart_8250_port *p) { }
+#endif
+
 static u32 uart_read(struct uart_8250_port *up, u32 reg)
 {
        return readl(up->port.membase + (reg << up->port.regshift));
@@ -635,7 +641,7 @@ static int omap_8250_startup(struct uart_port *port)
        serial_out(up, UART_OMAP_WER, priv->wer);
 
        if (up->dma)
-               up->dma->rx_dma(up, 0);
+               up->dma->rx_dma(up);
 
        pm_runtime_mark_last_busy(port->dev);
        pm_runtime_put_autosuspend(port->dev);
@@ -654,7 +660,7 @@ static void omap_8250_shutdown(struct uart_port *port)
 
        flush_work(&priv->qos_work);
        if (up->dma)
-               up->dma->rx_dma(up, UART_IIR_RX_TIMEOUT);
+               omap_8250_rx_dma_flush(up);
 
        pm_runtime_get_sync(port->dev);
 
@@ -742,9 +748,9 @@ static void omap_8250_unthrottle(struct uart_port *port)
 }
 
 #ifdef CONFIG_SERIAL_8250_DMA
-static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir);
+static int omap_8250_rx_dma(struct uart_8250_port *p);
 
-static void __dma_rx_do_complete(struct uart_8250_port *p, bool error)
+static void __dma_rx_do_complete(struct uart_8250_port *p)
 {
        struct omap8250_priv    *priv = p->port.private_data;
        struct uart_8250_dma    *dma = p->dma;
@@ -754,9 +760,6 @@ static void __dma_rx_do_complete(struct uart_8250_port *p, bool error)
        unsigned long           flags;
        int                     ret;
 
-       dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr,
-                               dma->rx_size, DMA_FROM_DEVICE);
-
        spin_lock_irqsave(&priv->rx_dma_lock, flags);
 
        if (!dma->rx_running)
@@ -764,7 +767,6 @@ static void __dma_rx_do_complete(struct uart_8250_port *p, bool error)
 
        dma->rx_running = 0;
        dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
-       dmaengine_terminate_all(dma->rxchan);
 
        count = dma->rx_size - state.residue;
 
@@ -775,15 +777,13 @@ static void __dma_rx_do_complete(struct uart_8250_port *p, bool error)
 unlock:
        spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
 
-       if (!error)
-               omap_8250_rx_dma(p, 0);
-
        tty_flip_buffer_push(tty_port);
 }
 
 static void __dma_rx_complete(void *param)
 {
-       __dma_rx_do_complete(param, false);
+       __dma_rx_do_complete(param);
+       omap_8250_rx_dma(param);
 }
 
 static void omap_8250_rx_dma_flush(struct uart_8250_port *p)
@@ -806,10 +806,11 @@ static void omap_8250_rx_dma_flush(struct uart_8250_port *p)
 
        spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
 
-       __dma_rx_do_complete(p, true);
+       __dma_rx_do_complete(p);
+       dmaengine_terminate_all(dma->rxchan);
 }
 
-static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
+static int omap_8250_rx_dma(struct uart_8250_port *p)
 {
        struct omap8250_priv            *priv = p->port.private_data;
        struct uart_8250_dma            *dma = p->dma;
@@ -817,35 +818,6 @@ static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
        struct dma_async_tx_descriptor  *desc;
        unsigned long                   flags;
 
-       switch (iir & 0x3f) {
-       case UART_IIR_RLSI:
-               /* 8250_core handles errors and break interrupts */
-               omap_8250_rx_dma_flush(p);
-               return -EIO;
-       case UART_IIR_RX_TIMEOUT:
-               /*
-                * If RCVR FIFO trigger level was not reached, complete the
-                * transfer and let 8250_core copy the remaining data.
-                */
-               omap_8250_rx_dma_flush(p);
-               return -ETIMEDOUT;
-       case UART_IIR_RDI:
-               /*
-                * The OMAP UART is a special BEAST. If we receive RDI we _have_
-                * a DMA transfer programmed but it didn't work. One reason is
-                * that we were too slow and there were too many bytes in the
-                * FIFO, the UART counted wrong and never kicked the DMA engine
-                * to do anything. That means once we receive RDI on OMAP then
-                * the DMA won't do anything soon so we have to cancel the DMA
-                * transfer and purge the FIFO manually.
-                */
-               omap_8250_rx_dma_flush(p);
-               return -ETIMEDOUT;
-
-       default:
-               break;
-       }
-
        if (priv->rx_dma_broken)
                return -EINVAL;
 
@@ -868,9 +840,6 @@ static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
 
        dma->rx_cookie = dmaengine_submit(desc);
 
-       dma_sync_single_for_device(dma->rxchan->device->dev, dma->rx_addr,
-                                  dma->rx_size, DMA_FROM_DEVICE);
-
        dma_async_issue_pending(dma->rxchan);
 out:
        spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
@@ -1022,6 +991,18 @@ err:
        return ret;
 }
 
+static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir)
+{
+       switch (iir & 0x3f) {
+       case UART_IIR_RLSI:
+       case UART_IIR_RX_TIMEOUT:
+       case UART_IIR_RDI:
+               omap_8250_rx_dma_flush(up);
+               return true;
+       }
+       return omap_8250_rx_dma(up);
+}
+
 /*
  * This is mostly serial8250_handle_irq(). We have a slightly different DMA
  * hoook for RX/TX and need different logic for them in the ISR. Therefore we
@@ -1033,7 +1014,6 @@ static int omap_8250_dma_handle_irq(struct uart_port *port)
        unsigned char status;
        unsigned long flags;
        u8 iir;
-       int dma_err = 0;
 
        serial8250_rpm_get(up);
 
@@ -1048,11 +1028,9 @@ static int omap_8250_dma_handle_irq(struct uart_port *port)
        status = serial_port_in(port, UART_LSR);
 
        if (status & (UART_LSR_DR | UART_LSR_BI)) {
-
-               dma_err = omap_8250_rx_dma(up, iir);
-               if (dma_err) {
+               if (handle_rx_dma(up, iir)) {
                        status = serial8250_rx_chars(up, status);
-                       omap_8250_rx_dma(up, 0);
+                       omap_8250_rx_dma(up);
                }
        }
        serial8250_modem_status(up);
@@ -1066,8 +1044,7 @@ static int omap_8250_dma_handle_irq(struct uart_port *port)
                         * try again due to an earlier failer which
                         * might have been resolved by now.
                         */
-                       dma_err = omap_8250_tx_dma(up);
-                       if (dma_err)
+                       if (omap_8250_tx_dma(up))
                                serial8250_tx_chars(up);
                }
        }
@@ -1084,7 +1061,7 @@ static bool the_no_dma_filter_fn(struct dma_chan *chan, void *param)
 
 #else
 
-static inline int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
+static inline int omap_8250_rx_dma(struct uart_8250_port *p)
 {
        return -EINVAL;
 }
@@ -1395,7 +1372,7 @@ static int omap8250_runtime_suspend(struct device *dev)
        }
 
        if (up->dma && up->dma->rxchan)
-               omap_8250_rx_dma(up, UART_IIR_RX_TIMEOUT);
+               omap_8250_rx_dma_flush(up);
 
        priv->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;
        schedule_work(&priv->qos_work);
@@ -1407,20 +1384,18 @@ static int omap8250_runtime_resume(struct device *dev)
 {
        struct omap8250_priv *priv = dev_get_drvdata(dev);
        struct uart_8250_port *up;
-       int loss_cntx;
 
        /* In case runtime-pm tries this before we are setup */
        if (!priv)
                return 0;
 
        up = serial8250_get_port(priv->line);
-       loss_cntx = omap8250_lost_context(up);
 
-       if (loss_cntx)
+       if (omap8250_lost_context(up))
                omap8250_restore_regs(up);
 
        if (up->dma && up->dma->rxchan)
-               omap_8250_rx_dma(up, 0);
+               omap_8250_rx_dma(up);
 
        priv->latency = priv->calc_latency;
        schedule_work(&priv->qos_work);
index 5eea74d..8dd250f 100644 (file)
@@ -1377,6 +1377,9 @@ byt_set_termios(struct uart_port *p, struct ktermios *termios,
        unsigned long m, n;
        u32 reg;
 
+       /* Gracefully handle the B0 case: fall back to B9600 */
+       fuart = fuart ? fuart : 9600 * 16;
+
        /* Get Fuart closer to Fref */
        fuart *= rounddown_pow_of_two(fref / fuart);
 
@@ -1413,6 +1416,17 @@ static bool byt_dma_filter(struct dma_chan *chan, void *param)
        return true;
 }
 
+static unsigned int
+byt_get_mctrl(struct uart_port *port)
+{
+       unsigned int ret = serial8250_do_get_mctrl(port);
+
+       /* Force DCD and DSR signals to permanently be reported as active. */
+       ret |= TIOCM_CAR | TIOCM_DSR;
+
+       return ret;
+}
+
 static int
 byt_serial_setup(struct serial_private *priv,
                 const struct pciserial_board *board,
@@ -1477,6 +1491,7 @@ byt_serial_setup(struct serial_private *priv,
        port->port.type = PORT_16550A;
        port->port.flags = (port->port.flags | UPF_FIXED_PORT | UPF_FIXED_TYPE);
        port->port.set_termios = byt_set_termios;
+       port->port.get_mctrl = byt_get_mctrl;
        port->port.fifosize = 64;
        port->tx_loadsz = 64;
        port->dma = dma;
index 00ad263..d403603 100644 (file)
@@ -1315,6 +1315,13 @@ static void autoconfig(struct uart_8250_port *up)
 
 out_lock:
        spin_unlock_irqrestore(&port->lock, flags);
+
+       /*
+        * Check if the device is a Fintek F81216A
+        */
+       if (port->type == PORT_16550A)
+               fintek_8250_probe(up);
+
        if (up->capabilities != old_capabilities) {
                pr_warn("ttyS%d: detected caps %08x should be %08x\n",
                       serial_index(port), old_capabilities,
@@ -1788,6 +1795,18 @@ unsigned int serial8250_modem_status(struct uart_8250_port *up)
 }
 EXPORT_SYMBOL_GPL(serial8250_modem_status);
 
+static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir)
+{
+       switch (iir & 0x3f) {
+       case UART_IIR_RX_TIMEOUT:
+               serial8250_rx_dma_flush(up);
+               /* fall-through */
+       case UART_IIR_RLSI:
+               return true;
+       }
+       return up->dma->rx_dma(up);
+}
+
 /*
  * This handles the interrupt from one port.
  */
@@ -1796,7 +1815,6 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
        unsigned char status;
        unsigned long flags;
        struct uart_8250_port *up = up_to_u8250p(port);
-       int dma_err = 0;
 
        if (iir & UART_IIR_NO_INT)
                return 0;
@@ -1808,15 +1826,11 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
        DEBUG_INTR("status = %x...", status);
 
        if (status & (UART_LSR_DR | UART_LSR_BI)) {
-               if (up->dma)
-                       dma_err = up->dma->rx_dma(up, iir);
-
-               if (!up->dma || dma_err)
+               if (!up->dma || handle_rx_dma(up, iir))
                        status = serial8250_rx_chars(up, status);
        }
        serial8250_modem_status(up);
-       if ((!up->dma || (up->dma && up->dma->tx_err)) &&
-           (status & UART_LSR_THRE))
+       if ((!up->dma || up->dma->tx_err) && (status & UART_LSR_THRE))
                serial8250_tx_chars(up);
 
        spin_unlock_irqrestore(&port->lock, flags);
@@ -1882,7 +1896,7 @@ static unsigned int serial8250_tx_empty(struct uart_port *port)
        return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0;
 }
 
-static unsigned int serial8250_get_mctrl(struct uart_port *port)
+unsigned int serial8250_do_get_mctrl(struct uart_port *port)
 {
        struct uart_8250_port *up = up_to_u8250p(port);
        unsigned int status;
@@ -1903,6 +1917,14 @@ static unsigned int serial8250_get_mctrl(struct uart_port *port)
                ret |= TIOCM_CTS;
        return ret;
 }
+EXPORT_SYMBOL_GPL(serial8250_do_get_mctrl);
+
+static unsigned int serial8250_get_mctrl(struct uart_port *port)
+{
+       if (port->get_mctrl)
+               return port->get_mctrl(port);
+       return serial8250_do_get_mctrl(port);
+}
 
 void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
index 1b7bd26..efd1f9c 100644 (file)
@@ -209,7 +209,7 @@ static int uniphier_uart_probe(struct platform_device *pdev)
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
-               dev_err(dev, "failed to get IRQ number");
+               dev_err(dev, "failed to get IRQ number\n");
                return irq;
        }
 
index 4d7cb9c..e46761d 100644 (file)
@@ -57,6 +57,18 @@ config SERIAL_8250_PNP
          This builds standard PNP serial support. You may be able to
          disable this feature if you only need legacy serial support.
 
+config SERIAL_8250_FINTEK
+       bool "Support for Fintek F81216A LPC to 4 UART RS485 API"
+       depends on SERIAL_8250
+       ---help---
+         Selecting this option will add support for the RS485 capabilities
+         of the Fintek F81216A LPC to 4 UART.
+
+         If this option is not selected the device will be configured as a
+         standard 16550A serial port.
+
+         If unsure, say N.
+
 config SERIAL_8250_CONSOLE
        bool "Console on 8250/16550 and compatible serial port"
        depends on SERIAL_8250=y
@@ -358,14 +370,6 @@ config SERIAL_8250_OMAP_TTYO_FIXUP
          not booting kernel because the serial console remains silent in case
          they forgot to update the command line.
 
-config SERIAL_8250_FINTEK
-       tristate "Support for Fintek F81216A LPC to 4 UART"
-       depends on SERIAL_8250 && PNP
-       help
-         Selecting this option will add support for the Fintek F81216A
-         LPC to 4 UART. This device has some RS485 functionality not available
-         through the PNP driver. If unsure, say N.
-
 config SERIAL_8250_LPC18XX
        tristate "NXP LPC18xx/43xx serial port support"
        depends on SERIAL_8250 && OF && (ARCH_LPC18XX || COMPILE_TEST)
@@ -398,8 +402,10 @@ config SERIAL_8250_INGENIC
          its UARTs, say Y to this option. If unsure, say N.
 
 config SERIAL_8250_MID
-       tristate "Support for serial ports on Intel MID platforms"
+       tristate "Support for serial ports on Intel MID platforms" if EXPERT
+       default SERIAL_8250
        depends on SERIAL_8250 && PCI
+       depends on X86 || COMPILE_TEST
        select HSU_DMA if SERIAL_8250_DMA
        select HSU_DMA_PCI if (HSU_DMA && X86_INTEL_MID)
        select RATIONAL
index c9a2d6e..367d403 100644 (file)
@@ -7,6 +7,7 @@ obj-$(CONFIG_SERIAL_8250)               += 8250.o 8250_base.o
 8250-$(CONFIG_SERIAL_8250_PNP)         += 8250_pnp.o
 8250_base-y                            := 8250_port.o
 8250_base-$(CONFIG_SERIAL_8250_DMA)    += 8250_dma.o
+8250_base-$(CONFIG_SERIAL_8250_FINTEK) += 8250_fintek.o
 obj-$(CONFIG_SERIAL_8250_GSC)          += 8250_gsc.o
 obj-$(CONFIG_SERIAL_8250_PCI)          += 8250_pci.o
 obj-$(CONFIG_SERIAL_8250_HP300)                += 8250_hp300.o
@@ -23,7 +24,6 @@ obj-$(CONFIG_SERIAL_8250_FSL)         += 8250_fsl.o
 obj-$(CONFIG_SERIAL_8250_DW)           += 8250_dw.o
 obj-$(CONFIG_SERIAL_8250_EM)           += 8250_em.o
 obj-$(CONFIG_SERIAL_8250_OMAP)         += 8250_omap.o
-obj-$(CONFIG_SERIAL_8250_FINTEK)       += 8250_fintek.o
 obj-$(CONFIG_SERIAL_8250_LPC18XX)      += 8250_lpc18xx.o
 obj-$(CONFIG_SERIAL_8250_MT6577)       += 8250_mtk.o
 obj-$(CONFIG_SERIAL_8250_UNIPHIER)     += 8250_uniphier.o
index 7711b26..7e3a58c 100644 (file)
@@ -213,6 +213,7 @@ config SERIAL_MESON_CONSOLE
        bool "Support for console on meson"
        depends on SERIAL_MESON=y
        select SERIAL_CORE_CONSOLE
+       select SERIAL_EARLYCON
        help
          Say Y here if you wish to use a Amlogic MesonX UART as the
          system console (the system console is the device which
@@ -1404,11 +1405,12 @@ config SERIAL_PCH_UART_CONSOLE
 config SERIAL_MXS_AUART
        tristate "MXS AUART support"
        depends on HAS_DMA
-       depends on ARCH_MXS || COMPILE_TEST
+       depends on ARCH_MXS || MACH_ASM9260 || COMPILE_TEST
        select SERIAL_CORE
        select SERIAL_MCTRL_GPIO if GPIOLIB
        help
-         This driver supports the MXS Application UART (AUART) port.
+         This driver supports the MXS and Alphascale ASM9260 Application
+         UART (AUART) port.
 
 config SERIAL_MXS_AUART_CONSOLE
        bool "MXS AUART console support"
@@ -1467,6 +1469,19 @@ config SERIAL_EFM32_UART
          This driver support the USART and UART ports on
          Energy Micro's efm32 SoCs.
 
+config SERIAL_MPS2_UART_CONSOLE
+       bool "MPS2 UART console support"
+       depends on SERIAL_MPS2_UART
+       select SERIAL_CORE_CONSOLE
+       select SERIAL_EARLYCON
+
+config SERIAL_MPS2_UART
+       bool "MPS2 UART port"
+       depends on ARM || COMPILE_TEST
+       select SERIAL_CORE
+       help
+         This driver support the UART ports on ARM MPS2.
+
 config SERIAL_EFM32_UART_CONSOLE
        bool "EFM32 UART/USART console support"
        depends on SERIAL_EFM32_UART=y
@@ -1625,6 +1640,7 @@ config SERIAL_STM32_CONSOLE
 
 config SERIAL_MVEBU_UART
        bool "Marvell EBU serial port support"
+       depends on ARCH_MVEBU || COMPILE_TEST
        select SERIAL_CORE
        help
          This driver is for Marvell EBU SoC's UART. If you have a machine
index 74914aa..1278d37 100644 (file)
@@ -92,6 +92,7 @@ obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
 obj-$(CONFIG_SERIAL_STM32)     += stm32-usart.o
 obj-$(CONFIG_SERIAL_MVEBU_UART)        += mvebu-uart.o
 obj-$(CONFIG_SERIAL_PIC32)     += pic32_uart.o
+obj-$(CONFIG_SERIAL_MPS2_UART) += mps2-uart.o
 
 # GPIOLIB helpers for modem control lines
 obj-$(CONFIG_SERIAL_MCTRL_GPIO)        += serial_mctrl_gpio.o
index 7c198e0..a2aa655 100644 (file)
@@ -121,6 +121,7 @@ static struct vendor_data vendor_arm = {
 
 static struct vendor_data vendor_sbsa = {
        .reg_offset             = pl011_std_offsets,
+       .access_32b             = true,
        .oversampling           = false,
        .dma_threshold          = false,
        .cts_event_workaround   = false,
index d9439e6..954941d 100644 (file)
@@ -274,6 +274,13 @@ static bool atmel_use_dma_rx(struct uart_port *port)
        return atmel_port->use_dma_rx;
 }
 
+static bool atmel_use_fifo(struct uart_port *port)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+       return atmel_port->fifo_size;
+}
+
 static unsigned int atmel_get_lines_status(struct uart_port *port)
 {
        struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
@@ -2090,7 +2097,12 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
                mode |= ATMEL_US_USMODE_RS485;
        } else if (termios->c_cflag & CRTSCTS) {
                /* RS232 with hardware handshake (RTS/CTS) */
-               mode |= ATMEL_US_USMODE_HWHS;
+               if (atmel_use_dma_rx(port) && !atmel_use_fifo(port)) {
+                       dev_info(port->dev, "not enabling hardware flow control because DMA is used");
+                       termios->c_cflag &= ~CRTSCTS;
+               } else {
+                       mode |= ATMEL_US_USMODE_HWHS;
+               }
        } else {
                /* RS232 without hadware handshake */
                mode |= ATMEL_US_USMODE_NORMAL;
index c0172bf..315c849 100644 (file)
@@ -2599,7 +2599,7 @@ startup(struct e100_serial * info)
 
        /* if it was already initialized, skip this */
 
-       if (info->port.flags & ASYNC_INITIALIZED) {
+       if (tty_port_initialized(&info->port)) {
                local_irq_restore(flags);
                free_page(xmit_page);
                return 0;
@@ -2703,7 +2703,7 @@ startup(struct e100_serial * info)
        e100_rts(info, 1);
        e100_dtr(info, 1);
 
-       info->port.flags |= ASYNC_INITIALIZED;
+       tty_port_set_initialized(&info->port, 1);
 
        local_irq_restore(flags);
        return 0;
@@ -2745,7 +2745,7 @@ shutdown(struct e100_serial * info)
                info->tr_running = 0;
        }
 
-       if (!(info->port.flags & ASYNC_INITIALIZED))
+       if (!tty_port_initialized(&info->port))
                return;
 
 #ifdef SERIAL_DEBUG_OPEN
@@ -2776,7 +2776,7 @@ shutdown(struct e100_serial * info)
        if (info->port.tty)
                set_bit(TTY_IO_ERROR, &info->port.tty->flags);
 
-       info->port.flags &= ~ASYNC_INITIALIZED;
+       tty_port_set_initialized(&info->port, 0);
        local_irq_restore(flags);
 }
 
@@ -3273,9 +3273,9 @@ set_serial_info(struct e100_serial *info,
        info->port.low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
  check_and_exit:
-       if (info->port.flags & ASYNC_INITIALIZED) {
+       if (tty_port_initialized(&info->port))
                change_speed(info);
-       else
+       else
                retval = startup(info);
        return retval;
 }
@@ -3445,7 +3445,7 @@ rs_ioctl(struct tty_struct *tty,
        if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
            (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
            (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
-               if (tty->flags & (1 << TTY_IO_ERROR))
+               if (tty_io_error(tty))
                        return -EIO;
        }
 
@@ -3628,7 +3628,7 @@ rs_close(struct tty_struct *tty, struct file * filp)
        e100_disable_rx(info);
        e100_disable_rx_irq(info);
 
-       if (info->port.flags & ASYNC_INITIALIZED) {
+       if (tty_port_initialized(&info->port)) {
                /*
                 * Before we drop DTR, make sure the UART transmitter
                 * has completely drained; this is especially
@@ -3648,8 +3648,8 @@ 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;
        local_irq_restore(flags);
+       tty_port_set_active(&info->port, 0);
 
        /* port closed */
 
@@ -3732,7 +3732,7 @@ rs_hangup(struct tty_struct *tty)
        shutdown(info);
        info->event = 0;
        info->port.count = 0;
-       info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
+       tty_port_set_active(&info->port, 0);
        info->port.tty = NULL;
        wake_up_interruptible(&info->port.open_wait);
 }
@@ -3755,9 +3755,8 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
         * If non-blocking mode is set, or the port is not enabled,
         * then make the check up front and then exit.
         */
-       if ((filp->f_flags & O_NONBLOCK) ||
-           (tty->flags & (1 << TTY_IO_ERROR))) {
-               info->port.flags |= ASYNC_NORMAL_ACTIVE;
+       if ((filp->f_flags & O_NONBLOCK) || tty_io_error(tty)) {
+               tty_port_set_active(&info->port, 1);
                return 0;
        }
 
@@ -3788,8 +3787,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
                e100_dtr(info, 1);
                local_irq_restore(flags);
                set_current_state(TASK_INTERRUPTIBLE);
-               if (tty_hung_up_p(filp) ||
-                   !(info->port.flags & ASYNC_INITIALIZED)) {
+               if (tty_hung_up_p(filp) || !tty_port_initialized(&info->port)) {
 #ifdef SERIAL_DO_RESTART
                        if (info->port.flags & ASYNC_HUP_NOTIFY)
                                retval = -EAGAIN;
@@ -3826,7 +3824,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
 #endif
        if (retval)
                return retval;
-       info->port.flags |= ASYNC_NORMAL_ACTIVE;
+       tty_port_set_active(&info->port, 1);
        return 0;
 }
 
index 2085a6c..d386346 100644 (file)
@@ -651,7 +651,7 @@ static void ifx_spi_complete(void *ctx)
        struct ifx_spi_device *ifx_dev = ctx;
        int length;
        int actual_length;
-       unsigned char more;
+       unsigned char more = 0;
        unsigned char cts;
        int local_write_pending = 0;
        int queue_length;
index 231e7d5..0df2b1c 100644 (file)
 #define UCR3_RXDSEN    (1<<6)  /* Receive status interrupt enable */
 #define UCR3_AIRINTEN  (1<<5)  /* Async IR wake interrupt enable */
 #define UCR3_AWAKEN    (1<<4)  /* Async wake interrupt enable */
+#define UCR3_DTRDEN    (1<<3)  /* Data Terminal Ready Delta Enable. */
 #define IMX21_UCR3_RXDMUXSEL   (1<<2)  /* RXD Muxed Input Select */
 #define UCR3_INVT      (1<<1)  /* Inverted Infrared transmission */
 #define UCR3_BPEN      (1<<0)  /* Preset registers enable */
 #define USR1_FRAMERR   (1<<10) /* Frame error interrupt flag */
 #define USR1_RRDY      (1<<9)   /* Receiver ready interrupt/dma flag */
 #define USR1_AGTIM     (1<<8)   /* Ageing timer interrupt flag */
-#define USR1_TIMEOUT   (1<<7)   /* Receive timeout interrupt status */
+#define USR1_DTRD      (1<<7)   /* DTR Delta */
 #define USR1_RXDS       (1<<6)  /* Receiver idle interrupt flag */
 #define USR1_AIRINT     (1<<5)  /* Async IR wake interrupt flag */
 #define USR1_AWAKE      (1<<4)  /* Aysnc wake interrupt flag */
@@ -361,6 +362,7 @@ static void imx_stop_tx(struct uart_port *port)
                        imx_port_rts_inactive(sport, &temp);
                else
                        imx_port_rts_active(sport, &temp);
+               temp |= UCR2_RXEN;
                writel(temp, port->membase + UCR2);
 
                temp = readl(port->membase + UCR4);
@@ -568,6 +570,8 @@ static void imx_start_tx(struct uart_port *port)
                        imx_port_rts_inactive(sport, &temp);
                else
                        imx_port_rts_active(sport, &temp);
+               if (!(port->rs485.flags & SER_RS485_RX_DURING_TX))
+                       temp &= ~UCR2_RXEN;
                writel(temp, port->membase + UCR2);
 
                /* enable transmitter and shifter empty irq */
@@ -729,11 +733,61 @@ static void imx_dma_rxint(struct imx_port *sport)
        spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
+/*
+ * We have a modem side uart, so the meanings of RTS and CTS are inverted.
+ */
+static unsigned int imx_get_hwmctrl(struct imx_port *sport)
+{
+       unsigned int tmp = TIOCM_DSR;
+       unsigned usr1 = readl(sport->port.membase + USR1);
+
+       if (usr1 & USR1_RTSS)
+               tmp |= TIOCM_CTS;
+
+       /* in DCE mode DCDIN is always 0 */
+       if (!(usr1 & USR2_DCDIN))
+               tmp |= TIOCM_CAR;
+
+       if (sport->dte_mode)
+               if (!(readl(sport->port.membase + USR2) & USR2_RIIN))
+                       tmp |= TIOCM_RI;
+
+       return tmp;
+}
+
+/*
+ * Handle any change of modem status signal since we were last called.
+ */
+static void imx_mctrl_check(struct imx_port *sport)
+{
+       unsigned int status, changed;
+
+       status = imx_get_hwmctrl(sport);
+       changed = status ^ sport->old_status;
+
+       if (changed == 0)
+               return;
+
+       sport->old_status = status;
+
+       if (changed & TIOCM_RI && status & TIOCM_RI)
+               sport->port.icount.rng++;
+       if (changed & TIOCM_DSR)
+               sport->port.icount.dsr++;
+       if (changed & TIOCM_CAR)
+               uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
+       if (changed & TIOCM_CTS)
+               uart_handle_cts_change(&sport->port, status & TIOCM_CTS);
+
+       wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
+}
+
 static irqreturn_t imx_int(int irq, void *dev_id)
 {
        struct imx_port *sport = dev_id;
        unsigned int sts;
        unsigned int sts2;
+       irqreturn_t ret = IRQ_NONE;
 
        sts = readl(sport->port.membase + USR1);
        sts2 = readl(sport->port.membase + USR2);
@@ -743,26 +797,47 @@ static irqreturn_t imx_int(int irq, void *dev_id)
                        imx_dma_rxint(sport);
                else
                        imx_rxint(irq, dev_id);
+               ret = IRQ_HANDLED;
        }
 
        if ((sts & USR1_TRDY &&
             readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN) ||
            (sts2 & USR2_TXDC &&
-            readl(sport->port.membase + UCR4) & UCR4_TCEN))
+            readl(sport->port.membase + UCR4) & UCR4_TCEN)) {
                imx_txint(irq, dev_id);
+               ret = IRQ_HANDLED;
+       }
+
+       if (sts & USR1_DTRD) {
+               unsigned long flags;
+
+               if (sts & USR1_DTRD)
+                       writel(USR1_DTRD, sport->port.membase + USR1);
+
+               spin_lock_irqsave(&sport->port.lock, flags);
+               imx_mctrl_check(sport);
+               spin_unlock_irqrestore(&sport->port.lock, flags);
 
-       if (sts & USR1_RTSD)
+               ret = IRQ_HANDLED;
+       }
+
+       if (sts & USR1_RTSD) {
                imx_rtsint(irq, dev_id);
+               ret = IRQ_HANDLED;
+       }
 
-       if (sts & USR1_AWAKE)
+       if (sts & USR1_AWAKE) {
                writel(USR1_AWAKE, sport->port.membase + USR1);
+               ret = IRQ_HANDLED;
+       }
 
        if (sts2 & USR2_ORE) {
                sport->port.icount.overrun++;
                writel(USR2_ORE, sport->port.membase + USR2);
+               ret = IRQ_HANDLED;
        }
 
-       return IRQ_HANDLED;
+       return ret;
 }
 
 /*
@@ -782,28 +857,6 @@ static unsigned int imx_tx_empty(struct uart_port *port)
        return ret;
 }
 
-/*
- * We have a modem side uart, so the meanings of RTS and CTS are inverted.
- */
-static unsigned int imx_get_hwmctrl(struct imx_port *sport)
-{
-       unsigned int tmp = TIOCM_DSR;
-       unsigned usr1 = readl(sport->port.membase + USR1);
-
-       if (usr1 & USR1_RTSS)
-               tmp |= TIOCM_CTS;
-
-       /* in DCE mode DCDIN is always 0 */
-       if (!(usr1 & USR2_DCDIN))
-               tmp |= TIOCM_CAR;
-
-       /* in DCE mode RIIN is always 0 */
-       if (readl(sport->port.membase + USR2) & USR2_RIIN)
-               tmp |= TIOCM_RI;
-
-       return tmp;
-}
-
 static unsigned int imx_get_mctrl(struct uart_port *port)
 {
        struct imx_port *sport = (struct imx_port *)port;
@@ -860,33 +913,6 @@ static void imx_break_ctl(struct uart_port *port, int break_state)
        spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
-/*
- * Handle any change of modem status signal since we were last called.
- */
-static void imx_mctrl_check(struct imx_port *sport)
-{
-       unsigned int status, changed;
-
-       status = imx_get_hwmctrl(sport);
-       changed = status ^ sport->old_status;
-
-       if (changed == 0)
-               return;
-
-       sport->old_status = status;
-
-       if (changed & TIOCM_RI)
-               sport->port.icount.rng++;
-       if (changed & TIOCM_DSR)
-               sport->port.icount.dsr++;
-       if (changed & TIOCM_CAR)
-               uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
-       if (changed & TIOCM_CTS)
-               uart_handle_cts_change(&sport->port, status & TIOCM_CTS);
-
-       wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
-}
-
 /*
  * This is our per-port timeout handler, for checking the
  * modem status signals.
@@ -1193,7 +1219,7 @@ static int imx_startup(struct uart_port *port)
        /*
         * Finally, clear and enable interrupts
         */
-       writel(USR1_RTSD, sport->port.membase + USR1);
+       writel(USR1_RTSD | USR1_DTRD, sport->port.membase + USR1);
        writel(USR2_ORE, sport->port.membase + USR2);
 
        if (sport->dma_is_inited && !sport->dma_is_enabled)
@@ -1212,11 +1238,32 @@ static int imx_startup(struct uart_port *port)
        temp |= (UCR2_RXEN | UCR2_TXEN);
        if (!sport->have_rtscts)
                temp |= UCR2_IRTS;
+       /*
+        * make sure the edge sensitive RTS-irq is disabled,
+        * we're using RTSD instead.
+        */
+       if (!is_imx1_uart(sport))
+               temp &= ~UCR2_RTSEN;
        writel(temp, sport->port.membase + UCR2);
 
        if (!is_imx1_uart(sport)) {
                temp = readl(sport->port.membase + UCR3);
-               temp |= IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP;
+
+               /*
+                * The effect of RI and DCD differs depending on the UFCR_DCEDTE
+                * bit. In DCE mode they control the outputs, in DTE mode they
+                * enable the respective irqs. At least the DCD irq cannot be
+                * cleared on i.MX25 at least, so it's not usable and must be
+                * disabled. I don't have test hardware to check if RI has the
+                * same problem but I consider this likely so it's disabled for
+                * now, too.
+                */
+               temp |= IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP |
+                       UCR3_DTRDEN | UCR3_RI | UCR3_DCD;
+
+               if (sport->dte_mode)
+                       temp &= ~(UCR3_RI | UCR3_DCD);
+
                writel(temp, sport->port.membase + UCR3);
        }
 
@@ -1610,19 +1657,17 @@ static int imx_rs485_config(struct uart_port *port,
                            struct serial_rs485 *rs485conf)
 {
        struct imx_port *sport = (struct imx_port *)port;
+       unsigned long temp;
 
        /* unimplemented */
        rs485conf->delay_rts_before_send = 0;
        rs485conf->delay_rts_after_send = 0;
-       rs485conf->flags |= SER_RS485_RX_DURING_TX;
 
        /* RTS is required to control the transmitter */
        if (!sport->have_rtscts)
                rs485conf->flags &= ~SER_RS485_ENABLED;
 
        if (rs485conf->flags & SER_RS485_ENABLED) {
-               unsigned long temp;
-
                /* disable transmitter */
                temp = readl(sport->port.membase + UCR2);
                if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND)
@@ -1632,6 +1677,14 @@ static int imx_rs485_config(struct uart_port *port,
                writel(temp, sport->port.membase + UCR2);
        }
 
+       /* Make sure Rx is enabled in case Tx is active with Rx disabled */
+       if (!(rs485conf->flags & SER_RS485_ENABLED) ||
+           rs485conf->flags & SER_RS485_RX_DURING_TX) {
+               temp = readl(sport->port.membase + UCR2);
+               temp |= UCR2_RXEN;
+               writel(temp, sport->port.membase + UCR2);
+       }
+
        port->rs485 = *rs485conf;
 
        return 0;
@@ -1927,7 +1980,8 @@ static int serial_imx_probe_dt(struct imx_port *sport,
        }
        sport->port.line = ret;
 
-       if (of_get_property(np, "fsl,uart-has-rtscts", NULL))
+       if (of_get_property(np, "uart-has-rtscts", NULL) ||
+           of_get_property(np, "fsl,uart-has-rtscts", NULL) /* deprecated */)
                sport->have_rtscts = 1;
 
        if (of_get_property(np, "fsl,dte-mode", NULL))
index 024445a..6aea0f4 100644 (file)
@@ -481,18 +481,13 @@ static void meson_console_putchar(struct uart_port *port, int ch)
        writel(ch, port->membase + AML_UART_WFIFO);
 }
 
-static void meson_serial_console_write(struct console *co, const char *s,
-                                      u_int count)
+static void meson_serial_port_write(struct uart_port *port, const char *s,
+                                   u_int count)
 {
-       struct uart_port *port;
        unsigned long flags;
        int locked;
        u32 val, tmp;
 
-       port = meson_ports[co->index];
-       if (!port)
-               return;
-
        local_irq_save(flags);
        if (port->sysrq) {
                locked = 0;
@@ -516,6 +511,18 @@ static void meson_serial_console_write(struct console *co, const char *s,
        local_irq_restore(flags);
 }
 
+static void meson_serial_console_write(struct console *co, const char *s,
+                                      u_int count)
+{
+       struct uart_port *port;
+
+       port = meson_ports[co->index];
+       if (!port)
+               return;
+
+       meson_serial_port_write(port, s, count);
+}
+
 static int meson_serial_console_setup(struct console *co, char *options)
 {
        struct uart_port *port;
@@ -554,6 +561,27 @@ static int __init meson_serial_console_init(void)
 }
 console_initcall(meson_serial_console_init);
 
+static void meson_serial_early_console_write(struct console *co,
+                                            const char *s,
+                                            u_int count)
+{
+       struct earlycon_device *dev = co->data;
+
+       meson_serial_port_write(&dev->port, s, count);
+}
+
+static int __init
+meson_serial_early_console_setup(struct earlycon_device *device, const char *opt)
+{
+       if (!device->port.membase)
+               return -ENODEV;
+
+       device->con->write = meson_serial_early_console_write;
+       return 0;
+}
+OF_EARLYCON_DECLARE(meson, "amlogic,meson-uart",
+                   meson_serial_early_console_setup);
+
 #define MESON_SERIAL_CONSOLE   (&meson_serial_console)
 #else
 #define MESON_SERIAL_CONSOLE   NULL
diff --git a/drivers/tty/serial/mps2-uart.c b/drivers/tty/serial/mps2-uart.c
new file mode 100644 (file)
index 0000000..da9e27d
--- /dev/null
@@ -0,0 +1,625 @@
+/*
+ * Copyright (C) 2015 ARM Limited
+ *
+ * Author: Vladimir Murzin <vladimir.murzin@arm.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.
+ *
+ * TODO: support for SysRq
+ */
+
+#define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/serial_core.h>
+#include <linux/tty_flip.h>
+#include <linux/types.h>
+
+#define SERIAL_NAME    "ttyMPS"
+#define DRIVER_NAME    "mps2-uart"
+#define MAKE_NAME(x)   (DRIVER_NAME # x)
+
+#define UARTn_DATA                             0x00
+
+#define UARTn_STATE                            0x04
+#define UARTn_STATE_TX_FULL                    BIT(0)
+#define UARTn_STATE_RX_FULL                    BIT(1)
+#define UARTn_STATE_TX_OVERRUN                 BIT(2)
+#define UARTn_STATE_RX_OVERRUN                 BIT(3)
+
+#define UARTn_CTRL                             0x08
+#define UARTn_CTRL_TX_ENABLE                   BIT(0)
+#define UARTn_CTRL_RX_ENABLE                   BIT(1)
+#define UARTn_CTRL_TX_INT_ENABLE               BIT(2)
+#define UARTn_CTRL_RX_INT_ENABLE               BIT(3)
+#define UARTn_CTRL_TX_OVERRUN_INT_ENABLE       BIT(4)
+#define UARTn_CTRL_RX_OVERRUN_INT_ENABLE       BIT(5)
+
+#define UARTn_INT                              0x0c
+#define UARTn_INT_TX                           BIT(0)
+#define UARTn_INT_RX                           BIT(1)
+#define UARTn_INT_TX_OVERRUN                   BIT(2)
+#define UARTn_INT_RX_OVERRUN                   BIT(3)
+
+#define UARTn_BAUDDIV                          0x10
+#define UARTn_BAUDDIV_MASK                     GENMASK(20, 0)
+
+/*
+ * Helpers to make typical enable/disable operations more readable.
+ */
+#define UARTn_CTRL_TX_GRP      (UARTn_CTRL_TX_ENABLE            |\
+                                UARTn_CTRL_TX_INT_ENABLE        |\
+                                UARTn_CTRL_TX_OVERRUN_INT_ENABLE)
+
+#define UARTn_CTRL_RX_GRP      (UARTn_CTRL_RX_ENABLE            |\
+                                UARTn_CTRL_RX_INT_ENABLE        |\
+                                UARTn_CTRL_RX_OVERRUN_INT_ENABLE)
+
+#define MPS2_MAX_PORTS         3
+
+struct mps2_uart_port {
+       struct uart_port port;
+       struct clk *clk;
+       unsigned int tx_irq;
+       unsigned int rx_irq;
+};
+
+static inline struct mps2_uart_port *to_mps2_port(struct uart_port *port)
+{
+       return container_of(port, struct mps2_uart_port, port);
+}
+
+static void mps2_uart_write8(struct uart_port *port, u8 val, unsigned int off)
+{
+       struct mps2_uart_port *mps_port = to_mps2_port(port);
+
+       writeb(val, mps_port->port.membase + off);
+}
+
+static u8 mps2_uart_read8(struct uart_port *port, unsigned int off)
+{
+       struct mps2_uart_port *mps_port = to_mps2_port(port);
+
+       return readb(mps_port->port.membase + off);
+}
+
+static void mps2_uart_write32(struct uart_port *port, u32 val, unsigned int off)
+{
+       struct mps2_uart_port *mps_port = to_mps2_port(port);
+
+       writel_relaxed(val, mps_port->port.membase + off);
+}
+
+static unsigned int mps2_uart_tx_empty(struct uart_port *port)
+{
+       u8 status = mps2_uart_read8(port, UARTn_STATE);
+
+       return (status & UARTn_STATE_TX_FULL) ? 0 : TIOCSER_TEMT;
+}
+
+static void mps2_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static unsigned int mps2_uart_get_mctrl(struct uart_port *port)
+{
+       return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR;
+}
+
+static void mps2_uart_stop_tx(struct uart_port *port)
+{
+       u8 control = mps2_uart_read8(port, UARTn_CTRL);
+
+       control &= ~UARTn_CTRL_TX_INT_ENABLE;
+
+       mps2_uart_write8(port, control, UARTn_CTRL);
+}
+
+static void mps2_uart_tx_chars(struct uart_port *port)
+{
+       struct circ_buf *xmit = &port->state->xmit;
+
+       while (!(mps2_uart_read8(port, UARTn_STATE) & UARTn_STATE_TX_FULL)) {
+               if (port->x_char) {
+                       mps2_uart_write8(port, port->x_char, UARTn_DATA);
+                       port->x_char = 0;
+                       port->icount.tx++;
+                       continue;
+               }
+
+               if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+                       break;
+
+               mps2_uart_write8(port, xmit->buf[xmit->tail], UARTn_DATA);
+               xmit->tail = (xmit->tail + 1) % UART_XMIT_SIZE;
+               port->icount.tx++;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (uart_circ_empty(xmit))
+               mps2_uart_stop_tx(port);
+}
+
+static void mps2_uart_start_tx(struct uart_port *port)
+{
+       u8 control = mps2_uart_read8(port, UARTn_CTRL);
+
+       control |= UARTn_CTRL_TX_INT_ENABLE;
+
+       mps2_uart_write8(port, control, UARTn_CTRL);
+
+       /*
+        * We've just unmasked the TX IRQ and now slow-starting via
+        * polling; if there is enough data to fill up the internal
+        * write buffer in one go, the TX IRQ should assert, at which
+        * point we switch to fully interrupt-driven TX.
+        */
+
+       mps2_uart_tx_chars(port);
+}
+
+static void mps2_uart_stop_rx(struct uart_port *port)
+{
+       u8 control = mps2_uart_read8(port, UARTn_CTRL);
+
+       control &= ~UARTn_CTRL_RX_GRP;
+
+       mps2_uart_write8(port, control, UARTn_CTRL);
+}
+
+static void mps2_uart_break_ctl(struct uart_port *port, int ctl)
+{
+}
+
+static void mps2_uart_rx_chars(struct uart_port *port)
+{
+       struct tty_port *tport = &port->state->port;
+
+       while (mps2_uart_read8(port, UARTn_STATE) & UARTn_STATE_RX_FULL) {
+               u8 rxdata = mps2_uart_read8(port, UARTn_DATA);
+
+               port->icount.rx++;
+               tty_insert_flip_char(&port->state->port, rxdata, TTY_NORMAL);
+       }
+
+       tty_flip_buffer_push(tport);
+}
+
+static irqreturn_t mps2_uart_rxirq(int irq, void *data)
+{
+       struct uart_port *port = data;
+       u8 irqflag = mps2_uart_read8(port, UARTn_INT);
+
+       if (unlikely(!(irqflag & UARTn_INT_RX)))
+               return IRQ_NONE;
+
+       spin_lock(&port->lock);
+
+       mps2_uart_write8(port, UARTn_INT_RX, UARTn_INT);
+       mps2_uart_rx_chars(port);
+
+       spin_unlock(&port->lock);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t mps2_uart_txirq(int irq, void *data)
+{
+       struct uart_port *port = data;
+       u8 irqflag = mps2_uart_read8(port, UARTn_INT);
+
+       if (unlikely(!(irqflag & UARTn_INT_TX)))
+               return IRQ_NONE;
+
+       spin_lock(&port->lock);
+
+       mps2_uart_write8(port, UARTn_INT_TX, UARTn_INT);
+       mps2_uart_tx_chars(port);
+
+       spin_unlock(&port->lock);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t mps2_uart_oerrirq(int irq, void *data)
+{
+       irqreturn_t handled = IRQ_NONE;
+       struct uart_port *port = data;
+       u8 irqflag = mps2_uart_read8(port, UARTn_INT);
+
+       spin_lock(&port->lock);
+
+       if (irqflag & UARTn_INT_RX_OVERRUN) {
+               struct tty_port *tport = &port->state->port;
+
+               mps2_uart_write8(port, UARTn_INT_RX_OVERRUN, UARTn_INT);
+               port->icount.overrun++;
+               tty_insert_flip_char(tport, 0, TTY_OVERRUN);
+               tty_flip_buffer_push(tport);
+               handled = IRQ_HANDLED;
+       }
+
+       /*
+        * It's never been seen in practice and it never *should* happen since
+        * we check if there is enough room in TX buffer before sending data.
+        * So we keep this check in case something suspicious has happened.
+        */
+       if (irqflag & UARTn_INT_TX_OVERRUN) {
+               mps2_uart_write8(port, UARTn_INT_TX_OVERRUN, UARTn_INT);
+               handled = IRQ_HANDLED;
+       }
+
+       spin_unlock(&port->lock);
+
+       return handled;
+}
+
+static int mps2_uart_startup(struct uart_port *port)
+{
+       struct mps2_uart_port *mps_port = to_mps2_port(port);
+       u8 control = mps2_uart_read8(port, UARTn_CTRL);
+       int ret;
+
+       control &= ~(UARTn_CTRL_RX_GRP | UARTn_CTRL_TX_GRP);
+
+       mps2_uart_write8(port, control, UARTn_CTRL);
+
+       ret = request_irq(mps_port->rx_irq, mps2_uart_rxirq, 0,
+                         MAKE_NAME(-rx), mps_port);
+       if (ret) {
+               dev_err(port->dev, "failed to register rxirq (%d)\n", ret);
+               return ret;
+       }
+
+       ret = request_irq(mps_port->tx_irq, mps2_uart_txirq, 0,
+                         MAKE_NAME(-tx), mps_port);
+       if (ret) {
+               dev_err(port->dev, "failed to register txirq (%d)\n", ret);
+               goto err_free_rxirq;
+       }
+
+       ret = request_irq(port->irq, mps2_uart_oerrirq, IRQF_SHARED,
+                         MAKE_NAME(-overrun), mps_port);
+
+       if (ret) {
+               dev_err(port->dev, "failed to register oerrirq (%d)\n", ret);
+               goto err_free_txirq;
+       }
+
+       control |= UARTn_CTRL_RX_GRP | UARTn_CTRL_TX_GRP;
+
+       mps2_uart_write8(port, control, UARTn_CTRL);
+
+       return 0;
+
+err_free_txirq:
+       free_irq(mps_port->tx_irq, mps_port);
+err_free_rxirq:
+       free_irq(mps_port->rx_irq, mps_port);
+
+       return ret;
+}
+
+static void mps2_uart_shutdown(struct uart_port *port)
+{
+       struct mps2_uart_port *mps_port = to_mps2_port(port);
+       u8 control = mps2_uart_read8(port, UARTn_CTRL);
+
+       control &= ~(UARTn_CTRL_RX_GRP | UARTn_CTRL_TX_GRP);
+
+       mps2_uart_write8(port, control, UARTn_CTRL);
+
+       free_irq(mps_port->rx_irq, mps_port);
+       free_irq(mps_port->tx_irq, mps_port);
+       free_irq(port->irq, mps_port);
+}
+
+static void
+mps2_uart_set_termios(struct uart_port *port, struct ktermios *termios,
+                     struct ktermios *old)
+{
+       unsigned long flags;
+       unsigned int baud, bauddiv;
+
+       termios->c_cflag &= ~(CRTSCTS | CMSPAR);
+       termios->c_cflag &= ~CSIZE;
+       termios->c_cflag |= CS8;
+       termios->c_cflag &= ~PARENB;
+       termios->c_cflag &= ~CSTOPB;
+
+       baud = uart_get_baud_rate(port, termios, old,
+                       DIV_ROUND_CLOSEST(port->uartclk, UARTn_BAUDDIV_MASK),
+                       DIV_ROUND_CLOSEST(port->uartclk, 16));
+
+       bauddiv = DIV_ROUND_CLOSEST(port->uartclk, baud);
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       uart_update_timeout(port, termios->c_cflag, baud);
+       mps2_uart_write32(port, bauddiv, UARTn_BAUDDIV);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       if (tty_termios_baud_rate(termios))
+               tty_termios_encode_baud_rate(termios, baud, baud);
+}
+
+static const char *mps2_uart_type(struct uart_port *port)
+{
+       return (port->type == PORT_MPS2UART) ? DRIVER_NAME : NULL;
+}
+
+static void mps2_uart_release_port(struct uart_port *port)
+{
+}
+
+static int mps2_uart_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+static void mps2_uart_config_port(struct uart_port *port, int type)
+{
+       if (type & UART_CONFIG_TYPE && !mps2_uart_request_port(port))
+               port->type = PORT_MPS2UART;
+}
+
+static int mps2_uart_verify_port(struct uart_port *port, struct serial_struct *serinfo)
+{
+       return -EINVAL;
+}
+
+static const struct uart_ops mps2_uart_pops = {
+       .tx_empty = mps2_uart_tx_empty,
+       .set_mctrl = mps2_uart_set_mctrl,
+       .get_mctrl = mps2_uart_get_mctrl,
+       .stop_tx = mps2_uart_stop_tx,
+       .start_tx = mps2_uart_start_tx,
+       .stop_rx = mps2_uart_stop_rx,
+       .break_ctl = mps2_uart_break_ctl,
+       .startup = mps2_uart_startup,
+       .shutdown = mps2_uart_shutdown,
+       .set_termios = mps2_uart_set_termios,
+       .type = mps2_uart_type,
+       .release_port = mps2_uart_release_port,
+       .request_port = mps2_uart_request_port,
+       .config_port = mps2_uart_config_port,
+       .verify_port = mps2_uart_verify_port,
+};
+
+static struct mps2_uart_port mps2_uart_ports[MPS2_MAX_PORTS];
+
+#ifdef CONFIG_SERIAL_MPS2_UART_CONSOLE
+static void mps2_uart_console_putchar(struct uart_port *port, int ch)
+{
+       while (mps2_uart_read8(port, UARTn_STATE) & UARTn_STATE_TX_FULL)
+               cpu_relax();
+
+       mps2_uart_write8(port, ch, UARTn_DATA);
+}
+
+static void mps2_uart_console_write(struct console *co, const char *s, unsigned int cnt)
+{
+       struct uart_port *port = &mps2_uart_ports[co->index].port;
+
+       uart_console_write(port, s, cnt, mps2_uart_console_putchar);
+}
+
+static int mps2_uart_console_setup(struct console *co, char *options)
+{
+       struct mps2_uart_port *mps_port;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if (co->index < 0 || co->index >= MPS2_MAX_PORTS)
+               return -ENODEV;
+
+       mps_port = &mps2_uart_ports[co->index];
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(&mps_port->port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver mps2_uart_driver;
+
+static struct console mps2_uart_console = {
+       .name = SERIAL_NAME,
+       .device = uart_console_device,
+       .write = mps2_uart_console_write,
+       .setup = mps2_uart_console_setup,
+       .flags = CON_PRINTBUFFER,
+       .index = -1,
+       .data = &mps2_uart_driver,
+};
+
+#define MPS2_SERIAL_CONSOLE (&mps2_uart_console)
+
+static void mps2_early_putchar(struct uart_port *port, int ch)
+{
+       while (readb(port->membase + UARTn_STATE) & UARTn_STATE_TX_FULL)
+               cpu_relax();
+
+       writeb((unsigned char)ch, port->membase + UARTn_DATA);
+}
+
+static void mps2_early_write(struct console *con, const char *s, unsigned int n)
+{
+       struct earlycon_device *dev = con->data;
+
+       uart_console_write(&dev->port, s, n, mps2_early_putchar);
+}
+
+static int __init mps2_early_console_setup(struct earlycon_device *device,
+                                          const char *opt)
+{
+       if (!device->port.membase)
+               return -ENODEV;
+
+       device->con->write = mps2_early_write;
+
+       return 0;
+}
+
+OF_EARLYCON_DECLARE(mps2, "arm,mps2-uart", mps2_early_console_setup);
+
+#else
+#define MPS2_SERIAL_CONSOLE NULL
+#endif
+
+static struct uart_driver mps2_uart_driver = {
+       .driver_name = DRIVER_NAME,
+       .dev_name = SERIAL_NAME,
+       .nr = MPS2_MAX_PORTS,
+       .cons = MPS2_SERIAL_CONSOLE,
+};
+
+static struct mps2_uart_port *mps2_of_get_port(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       int id;
+
+       if (!np)
+               return NULL;
+
+       id = of_alias_get_id(np, "serial");
+       if (id < 0)
+               id = 0;
+
+       if (WARN_ON(id >= MPS2_MAX_PORTS))
+               return NULL;
+
+       mps2_uart_ports[id].port.line = id;
+       return &mps2_uart_ports[id];
+}
+
+static int mps2_init_port(struct mps2_uart_port *mps_port,
+                         struct platform_device *pdev)
+{
+       struct resource *res;
+       int ret;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       mps_port->port.membase = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(mps_port->port.membase))
+               return PTR_ERR(mps_port->port.membase);
+
+       mps_port->port.mapbase = res->start;
+       mps_port->port.mapsize = resource_size(res);
+
+       mps_port->rx_irq = platform_get_irq(pdev, 0);
+       mps_port->tx_irq = platform_get_irq(pdev, 1);
+       mps_port->port.irq = platform_get_irq(pdev, 2);
+
+       mps_port->port.iotype = UPIO_MEM;
+       mps_port->port.flags = UPF_BOOT_AUTOCONF;
+       mps_port->port.fifosize = 1;
+       mps_port->port.ops = &mps2_uart_pops;
+       mps_port->port.dev = &pdev->dev;
+
+       mps_port->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(mps_port->clk))
+               return PTR_ERR(mps_port->clk);
+
+       ret = clk_prepare_enable(mps_port->clk);
+       if (ret)
+               return ret;
+
+       mps_port->port.uartclk = clk_get_rate(mps_port->clk);
+
+       clk_disable_unprepare(mps_port->clk);
+
+       return ret;
+}
+
+static int mps2_serial_probe(struct platform_device *pdev)
+{
+       struct mps2_uart_port *mps_port;
+       int ret;
+
+       mps_port = mps2_of_get_port(pdev);
+       if (!mps_port)
+               return -ENODEV;
+
+       ret = mps2_init_port(mps_port, pdev);
+       if (ret)
+               return ret;
+
+       ret = uart_add_one_port(&mps2_uart_driver, &mps_port->port);
+       if (ret)
+               return ret;
+
+       platform_set_drvdata(pdev, mps_port);
+
+       return 0;
+}
+
+static int mps2_serial_remove(struct platform_device *pdev)
+{
+       struct mps2_uart_port *mps_port = platform_get_drvdata(pdev);
+
+       uart_remove_one_port(&mps2_uart_driver, &mps_port->port);
+
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id mps2_match[] = {
+       { .compatible = "arm,mps2-uart", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, mps2_match);
+#endif
+
+static struct platform_driver mps2_serial_driver = {
+       .probe = mps2_serial_probe,
+       .remove = mps2_serial_remove,
+
+       .driver = {
+               .name = DRIVER_NAME,
+               .of_match_table = of_match_ptr(mps2_match),
+       },
+};
+
+static int __init mps2_uart_init(void)
+{
+       int ret;
+
+       ret = uart_register_driver(&mps2_uart_driver);
+       if (ret)
+               return ret;
+
+       ret = platform_driver_register(&mps2_serial_driver);
+       if (ret)
+               uart_unregister_driver(&mps2_uart_driver);
+
+       return ret;
+}
+module_init(mps2_uart_init);
+
+static void __exit mps2_uart_exit(void)
+{
+       platform_driver_unregister(&mps2_serial_driver);
+       uart_unregister_driver(&mps2_uart_driver);
+}
+module_exit(mps2_uart_exit);
+
+MODULE_AUTHOR("Vladimir Murzin <vladimir.murzin@arm.com>");
+MODULE_DESCRIPTION("MPS2 UART driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
index 96d3ce8..b7d80bd 100644 (file)
@@ -861,37 +861,72 @@ struct msm_baud_map {
 };
 
 static const struct msm_baud_map *
-msm_find_best_baud(struct uart_port *port, unsigned int baud)
+msm_find_best_baud(struct uart_port *port, unsigned int baud,
+                  unsigned long *rate)
 {
-       unsigned int i, divisor;
-       const struct msm_baud_map *entry;
+       struct msm_port *msm_port = UART_TO_MSM(port);
+       unsigned int divisor, result;
+       unsigned long target, old, best_rate = 0, diff, best_diff = ULONG_MAX;
+       const struct msm_baud_map *entry, *end, *best;
        static const struct msm_baud_map table[] = {
-               { 1536, 0x00,  1 },
-               {  768, 0x11,  1 },
-               {  384, 0x22,  1 },
-               {  192, 0x33,  1 },
-               {   96, 0x44,  1 },
-               {   48, 0x55,  1 },
-               {   32, 0x66,  1 },
-               {   24, 0x77,  1 },
-               {   16, 0x88,  1 },
-               {   12, 0x99,  6 },
-               {    8, 0xaa,  6 },
-               {    6, 0xbb,  6 },
-               {    4, 0xcc,  6 },
-               {    3, 0xdd,  8 },
-               {    2, 0xee, 16 },
                {    1, 0xff, 31 },
-               {    0, 0xff, 31 },
+               {    2, 0xee, 16 },
+               {    3, 0xdd,  8 },
+               {    4, 0xcc,  6 },
+               {    6, 0xbb,  6 },
+               {    8, 0xaa,  6 },
+               {   12, 0x99,  6 },
+               {   16, 0x88,  1 },
+               {   24, 0x77,  1 },
+               {   32, 0x66,  1 },
+               {   48, 0x55,  1 },
+               {   96, 0x44,  1 },
+               {  192, 0x33,  1 },
+               {  384, 0x22,  1 },
+               {  768, 0x11,  1 },
+               { 1536, 0x00,  1 },
        };
 
-       divisor = uart_get_divisor(port, baud);
+       best = table; /* Default to smallest divider */
+       target = clk_round_rate(msm_port->clk, 16 * baud);
+       divisor = DIV_ROUND_CLOSEST(target, 16 * baud);
+
+       end = table + ARRAY_SIZE(table);
+       entry = table;
+       while (entry < end) {
+               if (entry->divisor <= divisor) {
+                       result = target / entry->divisor / 16;
+                       diff = abs(result - baud);
+
+                       /* Keep track of best entry */
+                       if (diff < best_diff) {
+                               best_diff = diff;
+                               best = entry;
+                               best_rate = target;
+                       }
 
-       for (i = 0, entry = table; i < ARRAY_SIZE(table); i++, entry++)
-               if (entry->divisor <= divisor)
-                       break;
+                       if (result == baud)
+                               break;
+               } else if (entry->divisor > divisor) {
+                       old = target;
+                       target = clk_round_rate(msm_port->clk, old + 1);
+                       /*
+                        * The rate didn't get any faster so we can't do
+                        * better at dividing it down
+                        */
+                       if (target == old)
+                               break;
 
-       return entry; /* Default to smallest divider */
+                       /* Start the divisor search over at this new rate */
+                       entry = table;
+                       divisor = DIV_ROUND_CLOSEST(target, 16 * baud);
+                       continue;
+               }
+               entry++;
+       }
+
+       *rate = best_rate;
+       return best;
 }
 
 static int msm_set_baud_rate(struct uart_port *port, unsigned int baud,
@@ -900,22 +935,20 @@ static int msm_set_baud_rate(struct uart_port *port, unsigned int baud,
        unsigned int rxstale, watermark, mask;
        struct msm_port *msm_port = UART_TO_MSM(port);
        const struct msm_baud_map *entry;
-       unsigned long flags;
-
-       entry = msm_find_best_baud(port, baud);
-
-       msm_write(port, entry->code, UART_CSR);
-
-       if (baud > 460800)
-               port->uartclk = baud * 16;
+       unsigned long flags, rate;
 
        flags = *saved_flags;
        spin_unlock_irqrestore(&port->lock, flags);
 
-       clk_set_rate(msm_port->clk, port->uartclk);
+       entry = msm_find_best_baud(port, baud, &rate);
+       clk_set_rate(msm_port->clk, rate);
+       baud = rate / 16 / entry->divisor;
 
        spin_lock_irqsave(&port->lock, flags);
        *saved_flags = flags;
+       port->uartclk = rate;
+
+       msm_write(port, entry->code, UART_CSR);
 
        /* RX stale watermark */
        rxstale = entry->rxstale;
@@ -1577,8 +1610,6 @@ static int msm_serial_probe(struct platform_device *pdev)
                msm_port->pclk = devm_clk_get(&pdev->dev, "iface");
                if (IS_ERR(msm_port->pclk))
                        return PTR_ERR(msm_port->pclk);
-
-               clk_set_rate(msm_port->clk, 1843200);
        }
 
        port->uartclk = clk_get_rate(msm_port->clk);
index 0ff2781..ce362bd 100644 (file)
@@ -1,5 +1,7 @@
 /*
 * ***************************************************************************
+* Marvell Armada-3700 Serial Driver
+* Author: Wilson Ding <dingwei@marvell.com>
 * Copyright (C) 2015 Marvell International Ltd.
 * ***************************************************************************
 * This program is free software: you can redistribute it and/or modify it
@@ -23,7 +25,6 @@
 #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>
@@ -594,30 +595,18 @@ static int mvebu_uart_probe(struct platform_device *pdev)
        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),
+               .suppress_bind_attrs = true,
        },
 };
 
@@ -635,16 +624,4 @@ static int __init mvebu_uart_init(void)
 
        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");
index cd0414b..eb54e5c 100644 (file)
@@ -1,17 +1,18 @@
 /*
- * Freescale STMP37XX/STMP378X Application UART driver
+ * Application UART driver for:
+ *     Freescale STMP37XX/STMP378X
+ *     Alphascale ASM9260
  *
  * Author: dmitry pervushin <dimka@embeddedalley.com>
  *
+ * Copyright 2014 Oleksij Rempel <linux@rempel-privat.de>
+ *     Provide Alphascale ASM9260 support.
  * Copyright 2008-2010 Freescale Semiconductor, Inc.
  * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
  *
  * The code contained herein is licensed under the GNU General Public
  * License. You may obtain a copy of the GNU General Public License
  * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
  */
 
 #if defined(CONFIG_SERIAL_MXS_AUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
 #define MXS_AUART_PORTS 5
 #define MXS_AUART_FIFO_SIZE            16
 
+#define SET_REG                                0x4
+#define CLR_REG                                0x8
+#define TOG_REG                                0xc
+
 #define AUART_CTRL0                    0x00000000
-#define AUART_CTRL0_SET                        0x00000004
-#define AUART_CTRL0_CLR                        0x00000008
-#define AUART_CTRL0_TOG                        0x0000000c
 #define AUART_CTRL1                    0x00000010
-#define AUART_CTRL1_SET                        0x00000014
-#define AUART_CTRL1_CLR                        0x00000018
-#define AUART_CTRL1_TOG                        0x0000001c
 #define AUART_CTRL2                    0x00000020
-#define AUART_CTRL2_SET                        0x00000024
-#define AUART_CTRL2_CLR                        0x00000028
-#define AUART_CTRL2_TOG                        0x0000002c
 #define AUART_LINECTRL                 0x00000030
-#define AUART_LINECTRL_SET             0x00000034
-#define AUART_LINECTRL_CLR             0x00000038
-#define AUART_LINECTRL_TOG             0x0000003c
 #define AUART_LINECTRL2                        0x00000040
-#define AUART_LINECTRL2_SET            0x00000044
-#define AUART_LINECTRL2_CLR            0x00000048
-#define AUART_LINECTRL2_TOG            0x0000004c
 #define AUART_INTR                     0x00000050
-#define AUART_INTR_SET                 0x00000054
-#define AUART_INTR_CLR                 0x00000058
-#define AUART_INTR_TOG                 0x0000005c
 #define AUART_DATA                     0x00000060
 #define AUART_STAT                     0x00000070
 #define AUART_DEBUG                    0x00000080
 #define AUART_STAT_FERR                                (1 << 16)
 #define AUART_STAT_RXCOUNT_MASK                        0xffff
 
+/*
+ * Start of Alphascale asm9260 defines
+ * This list contains only differences of existing bits
+ * between imx2x and asm9260
+ */
+#define ASM9260_HW_CTRL0                       0x0000
+/*
+ * RW. Tell the UART to execute the RX DMA Command. The
+ * UART will clear this bit at the end of receive execution.
+ */
+#define ASM9260_BM_CTRL0_RXDMA_RUN             BIT(28)
+/* RW. 0 use FIFO for status register; 1 use DMA */
+#define ASM9260_BM_CTRL0_RXTO_SOURCE_STATUS    BIT(25)
+/*
+ * RW. RX TIMEOUT Enable. Valid for FIFO and DMA.
+ * Warning: If this bit is set to 0, the RX timeout will not affect receive DMA
+ * operation. If this bit is set to 1, a receive timeout will cause the receive
+ * DMA logic to terminate by filling the remaining DMA bytes with garbage data.
+ */
+#define ASM9260_BM_CTRL0_RXTO_ENABLE           BIT(24)
+/*
+ * RW. Receive Timeout Counter Value: number of 8-bit-time to wait before
+ * asserting timeout on the RX input. If the RXFIFO is not empty and the RX
+ * input is idle, then the watchdog counter will decrement each bit-time. Note
+ * 7-bit-time is added to the programmed value, so a value of zero will set
+ * the counter to 7-bit-time, a value of 0x1 gives 15-bit-time and so on. Also
+ * note that the counter is reloaded at the end of each frame, so if the frame
+ * is 10 bits long and the timeout counter value is zero, then timeout will
+ * occur (when FIFO is not empty) even if the RX input is not idle. The default
+ * value is 0x3 (31 bit-time).
+ */
+#define ASM9260_BM_CTRL0_RXTO_MASK             (0xff << 16)
+/* TIMEOUT = (100*7+1)*(1/BAUD) */
+#define ASM9260_BM_CTRL0_DEFAULT_RXTIMEOUT     (20 << 16)
+
+/* TX ctrl register */
+#define ASM9260_HW_CTRL1                       0x0010
+/*
+ * RW. Tell the UART to execute the TX DMA Command. The
+ * UART will clear this bit at the end of transmit execution.
+ */
+#define ASM9260_BM_CTRL1_TXDMA_RUN             BIT(28)
+
+#define ASM9260_HW_CTRL2                       0x0020
+/*
+ * RW. Receive Interrupt FIFO Level Select.
+ * The trigger points for the receive interrupt are as follows:
+ * ONE_EIGHTHS = 0x0 Trigger on FIFO full to at least 2 of 16 entries.
+ * ONE_QUARTER = 0x1 Trigger on FIFO full to at least 4 of 16 entries.
+ * ONE_HALF = 0x2 Trigger on FIFO full to at least 8 of 16 entries.
+ * THREE_QUARTERS = 0x3 Trigger on FIFO full to at least 12 of 16 entries.
+ * SEVEN_EIGHTHS = 0x4 Trigger on FIFO full to at least 14 of 16 entries.
+ */
+#define ASM9260_BM_CTRL2_RXIFLSEL              (7 << 20)
+#define ASM9260_BM_CTRL2_DEFAULT_RXIFLSEL      (3 << 20)
+/* RW. Same as RXIFLSEL */
+#define ASM9260_BM_CTRL2_TXIFLSEL              (7 << 16)
+#define ASM9260_BM_CTRL2_DEFAULT_TXIFLSEL      (2 << 16)
+/* RW. Set DTR. When this bit is 1, the output is 0. */
+#define ASM9260_BM_CTRL2_DTR                   BIT(10)
+/* RW. Loop Back Enable */
+#define ASM9260_BM_CTRL2_LBE                   BIT(7)
+#define ASM9260_BM_CTRL2_PORT_ENABLE           BIT(0)
+
+#define ASM9260_HW_LINECTRL                    0x0030
+/*
+ * RW. Stick Parity Select. When bits 1, 2, and 7 of this register are set, the
+ * parity bit is transmitted and checked as a 0. When bits 1 and 7 are set,
+ * and bit 2 is 0, the parity bit is transmitted and checked as a 1. When this
+ * bit is cleared stick parity is disabled.
+ */
+#define ASM9260_BM_LCTRL_SPS                   BIT(7)
+/* RW. Word length */
+#define ASM9260_BM_LCTRL_WLEN                  (3 << 5)
+#define ASM9260_BM_LCTRL_CHRL_5                        (0 << 5)
+#define ASM9260_BM_LCTRL_CHRL_6                        (1 << 5)
+#define ASM9260_BM_LCTRL_CHRL_7                        (2 << 5)
+#define ASM9260_BM_LCTRL_CHRL_8                        (3 << 5)
+
+/*
+ * Interrupt register.
+ * contains the interrupt enables and the interrupt status bits
+ */
+#define ASM9260_HW_INTR                                0x0040
+/* Tx FIFO EMPTY Raw Interrupt enable */
+#define ASM9260_BM_INTR_TFEIEN                 BIT(27)
+/* Overrun Error Interrupt Enable. */
+#define ASM9260_BM_INTR_OEIEN                  BIT(26)
+/* Break Error Interrupt Enable. */
+#define ASM9260_BM_INTR_BEIEN                  BIT(25)
+/* Parity Error Interrupt Enable. */
+#define ASM9260_BM_INTR_PEIEN                  BIT(24)
+/* Framing Error Interrupt Enable. */
+#define ASM9260_BM_INTR_FEIEN                  BIT(23)
+
+/* nUARTDSR Modem Interrupt Enable. */
+#define ASM9260_BM_INTR_DSRMIEN                        BIT(19)
+/* nUARTDCD Modem Interrupt Enable. */
+#define ASM9260_BM_INTR_DCDMIEN                        BIT(18)
+/* nUARTRI Modem Interrupt Enable. */
+#define ASM9260_BM_INTR_RIMIEN                 BIT(16)
+/* Auto-Boud Timeout */
+#define ASM9260_BM_INTR_ABTO                   BIT(13)
+#define ASM9260_BM_INTR_ABEO                   BIT(12)
+/* Tx FIFO EMPTY Raw Interrupt state */
+#define ASM9260_BM_INTR_TFEIS                  BIT(11)
+/* Overrun Error */
+#define ASM9260_BM_INTR_OEIS                   BIT(10)
+/* Break Error */
+#define ASM9260_BM_INTR_BEIS                   BIT(9)
+/* Parity Error */
+#define ASM9260_BM_INTR_PEIS                   BIT(8)
+/* Framing Error */
+#define ASM9260_BM_INTR_FEIS                   BIT(7)
+#define ASM9260_BM_INTR_DSRMIS                 BIT(3)
+#define ASM9260_BM_INTR_DCDMIS                 BIT(2)
+#define ASM9260_BM_INTR_RIMIS                  BIT(0)
+
+/*
+ * RW. In DMA mode, up to 4 Received/Transmit characters can be accessed at a
+ * time. In PIO mode, only one character can be accessed at a time. The status
+ * register contains the receive data flags and valid bits.
+ */
+#define ASM9260_HW_DATA                                0x0050
+
+#define ASM9260_HW_STAT                                0x0060
+/* RO. If 1, UARTAPP is present in this product. */
+#define ASM9260_BM_STAT_PRESENT                        BIT(31)
+/* RO. If 1, HISPEED is present in this product. */
+#define ASM9260_BM_STAT_HISPEED                        BIT(30)
+/* RO. Receive FIFO Full. */
+#define ASM9260_BM_STAT_RXFULL                 BIT(26)
+
+/* RO. The UART Debug Register contains the state of the DMA signals. */
+#define ASM9260_HW_DEBUG                       0x0070
+/* DMA Command Run Status */
+#define ASM9260_BM_DEBUG_TXDMARUN              BIT(5)
+#define ASM9260_BM_DEBUG_RXDMARUN              BIT(4)
+/* DMA Command End Status */
+#define ASM9260_BM_DEBUG_TXCMDEND              BIT(3)
+#define ASM9260_BM_DEBUG_RXCMDEND              BIT(2)
+/* DMA Request Status */
+#define ASM9260_BM_DEBUG_TXDMARQ               BIT(1)
+#define ASM9260_BM_DEBUG_RXDMARQ               BIT(0)
+
+#define ASM9260_HW_ILPR                                0x0080
+
+#define ASM9260_HW_RS485CTRL                   0x0090
+/*
+ * RW. This bit reverses the polarity of the direction control signal on the RTS
+ * (or DTR) pin.
+ * If 0, The direction control pin will be driven to logic â€˜0’ when the
+ * transmitter has data to be sent. It will be driven to logic â€˜1’ after the
+ * last bit of data has been transmitted.
+ */
+#define ASM9260_BM_RS485CTRL_ONIV              BIT(5)
+/* RW. Enable Auto Direction Control. */
+#define ASM9260_BM_RS485CTRL_DIR_CTRL          BIT(4)
+/*
+ * RW. If 0 and DIR_CTRL = 1, pin RTS is used for direction control.
+ * If 1 and DIR_CTRL = 1, pin DTR is used for direction control.
+ */
+#define ASM9260_BM_RS485CTRL_PINSEL            BIT(3)
+/* RW. Enable Auto Address Detect (AAD). */
+#define ASM9260_BM_RS485CTRL_AADEN             BIT(2)
+/* RW. Disable receiver. */
+#define ASM9260_BM_RS485CTRL_RXDIS             BIT(1)
+/* RW. Enable RS-485/EIA-485 Normal Multidrop Mode (NMM) */
+#define ASM9260_BM_RS485CTRL_RS485EN           BIT(0)
+
+#define ASM9260_HW_RS485ADRMATCH               0x00a0
+/* Contains the address match value. */
+#define ASM9260_BM_RS485ADRMATCH_MASK          (0xff << 0)
+
+#define ASM9260_HW_RS485DLY                    0x00b0
+/*
+ * RW. Contains the direction control (RTS or DTR) delay value. This delay time
+ * is in periods of the baud clock.
+ */
+#define ASM9260_BM_RS485DLY_MASK               (0xff << 0)
+
+#define ASM9260_HW_AUTOBAUD                    0x00c0
+/* WO. Auto-baud time-out interrupt clear bit. */
+#define ASM9260_BM_AUTOBAUD_TO_INT_CLR         BIT(9)
+/* WO. End of auto-baud interrupt clear bit. */
+#define ASM9260_BM_AUTOBAUD_EO_INT_CLR         BIT(8)
+/* Restart in case of timeout (counter restarts at next UART Rx falling edge) */
+#define ASM9260_BM_AUTOBAUD_AUTORESTART                BIT(2)
+/* Auto-baud mode select bit. 0 - Mode 0, 1 - Mode 1. */
+#define ASM9260_BM_AUTOBAUD_MODE               BIT(1)
+/*
+ * Auto-baud start (auto-baud is running). Auto-baud run bit. This bit is
+ * automatically cleared after auto-baud completion.
+ */
+#define ASM9260_BM_AUTOBAUD_START              BIT(0)
+
+#define ASM9260_HW_CTRL3                       0x00d0
+#define ASM9260_BM_CTRL3_OUTCLK_DIV_MASK       (0xffff << 16)
+/*
+ * RW. Provide clk over OUTCLK pin. In case of asm9260 it can be configured on
+ * pins 137 and 144.
+ */
+#define ASM9260_BM_CTRL3_MASTERMODE            BIT(6)
+/* RW. Baud Rate Mode: 1 - Enable sync mode. 0 - async mode. */
+#define ASM9260_BM_CTRL3_SYNCMODE              BIT(4)
+/* RW. 1 - MSB bit send frist; 0 - LSB bit frist. */
+#define ASM9260_BM_CTRL3_MSBF                  BIT(2)
+/* RW. 1 - sample rate = 8 x Baudrate; 0 - sample rate = 16 x Baudrate. */
+#define ASM9260_BM_CTRL3_BAUD8                 BIT(1)
+/* RW. 1 - Set word length to 9bit. 0 - use ASM9260_BM_LCTRL_WLEN */
+#define ASM9260_BM_CTRL3_9BIT                  BIT(0)
+
+#define ASM9260_HW_ISO7816_CTRL                        0x00e0
+/* RW. Enable High Speed mode. */
+#define ASM9260_BM_ISO7816CTRL_HS              BIT(12)
+/* Disable Successive Receive NACK */
+#define ASM9260_BM_ISO7816CTRL_DS_NACK         BIT(8)
+#define ASM9260_BM_ISO7816CTRL_MAX_ITER_MASK   (0xff << 4)
+/* Receive NACK Inhibit */
+#define ASM9260_BM_ISO7816CTRL_INACK           BIT(3)
+#define ASM9260_BM_ISO7816CTRL_NEG_DATA                BIT(2)
+/* RW. 1 - ISO7816 mode; 0 - USART mode */
+#define ASM9260_BM_ISO7816CTRL_ENABLE          BIT(0)
+
+#define ASM9260_HW_ISO7816_ERRCNT              0x00f0
+/* Parity error counter. Will be cleared after reading */
+#define ASM9260_BM_ISO7816_NB_ERRORS_MASK      (0xff << 0)
+
+#define ASM9260_HW_ISO7816_STATUS              0x0100
+/* Max number of Repetitions Reached */
+#define ASM9260_BM_ISO7816_STAT_ITERATION      BIT(0)
+
+/* End of Alphascale asm9260 defines */
+
 static struct uart_driver auart_driver;
 
 enum mxs_auart_type {
        IMX23_AUART,
        IMX28_AUART,
+       ASM9260_AUART,
+};
+
+struct vendor_data {
+       const u16       *reg_offset;
+};
+
+enum {
+       REG_CTRL0,
+       REG_CTRL1,
+       REG_CTRL2,
+       REG_LINECTRL,
+       REG_LINECTRL2,
+       REG_INTR,
+       REG_DATA,
+       REG_STAT,
+       REG_DEBUG,
+       REG_VERSION,
+       REG_AUTOBAUD,
+
+       /* The size of the array - must be last */
+       REG_ARRAY_SIZE,
+};
+
+static const u16 mxs_asm9260_offsets[REG_ARRAY_SIZE] = {
+       [REG_CTRL0] = ASM9260_HW_CTRL0,
+       [REG_CTRL1] = ASM9260_HW_CTRL1,
+       [REG_CTRL2] = ASM9260_HW_CTRL2,
+       [REG_LINECTRL] = ASM9260_HW_LINECTRL,
+       [REG_INTR] = ASM9260_HW_INTR,
+       [REG_DATA] = ASM9260_HW_DATA,
+       [REG_STAT] = ASM9260_HW_STAT,
+       [REG_DEBUG] = ASM9260_HW_DEBUG,
+       [REG_AUTOBAUD] = ASM9260_HW_AUTOBAUD,
+};
+
+static const u16 mxs_stmp37xx_offsets[REG_ARRAY_SIZE] = {
+       [REG_CTRL0] = AUART_CTRL0,
+       [REG_CTRL1] = AUART_CTRL1,
+       [REG_CTRL2] = AUART_CTRL2,
+       [REG_LINECTRL] = AUART_LINECTRL,
+       [REG_LINECTRL2] = AUART_LINECTRL2,
+       [REG_INTR] = AUART_INTR,
+       [REG_DATA] = AUART_DATA,
+       [REG_STAT] = AUART_STAT,
+       [REG_DEBUG] = AUART_DEBUG,
+       [REG_VERSION] = AUART_VERSION,
+       [REG_AUTOBAUD] = AUART_AUTOBAUD,
+};
+
+static const struct vendor_data vendor_alphascale_asm9260 = {
+       .reg_offset = mxs_asm9260_offsets,
+};
+
+static const struct vendor_data vendor_freescale_stmp37xx = {
+       .reg_offset = mxs_stmp37xx_offsets,
 };
 
 struct mxs_auart_port {
@@ -153,8 +430,10 @@ struct mxs_auart_port {
        unsigned long flags;
        unsigned int mctrl_prev;
        enum mxs_auart_type devtype;
+       const struct vendor_data *vendor;
 
        struct clk *clk;
+       struct clk *clk_ahb;
        struct device *dev;
 
        /* for DMA */
@@ -174,6 +453,7 @@ struct mxs_auart_port {
 static const struct platform_device_id mxs_auart_devtype[] = {
        { .name = "mxs-auart-imx23", .driver_data = IMX23_AUART },
        { .name = "mxs-auart-imx28", .driver_data = IMX28_AUART },
+       { .name = "as-auart-asm9260", .driver_data = ASM9260_AUART },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(platform, mxs_auart_devtype);
@@ -185,6 +465,9 @@ static const struct of_device_id mxs_auart_dt_ids[] = {
        }, {
                .compatible = "fsl,imx23-auart",
                .data = &mxs_auart_devtype[IMX23_AUART]
+       }, {
+               .compatible = "alphascale,asm9260-auart",
+               .data = &mxs_auart_devtype[ASM9260_AUART]
        }, { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, mxs_auart_dt_ids);
@@ -194,11 +477,54 @@ static inline int is_imx28_auart(struct mxs_auart_port *s)
        return s->devtype == IMX28_AUART;
 }
 
+static inline int is_asm9260_auart(struct mxs_auart_port *s)
+{
+       return s->devtype == ASM9260_AUART;
+}
+
 static inline bool auart_dma_enabled(struct mxs_auart_port *s)
 {
        return s->flags & MXS_AUART_DMA_ENABLED;
 }
 
+static unsigned int mxs_reg_to_offset(const struct mxs_auart_port *uap,
+                                     unsigned int reg)
+{
+       return uap->vendor->reg_offset[reg];
+}
+
+static unsigned int mxs_read(const struct mxs_auart_port *uap,
+                            unsigned int reg)
+{
+       void __iomem *addr = uap->port.membase + mxs_reg_to_offset(uap, reg);
+
+       return readl_relaxed(addr);
+}
+
+static void mxs_write(unsigned int val, struct mxs_auart_port *uap,
+                     unsigned int reg)
+{
+       void __iomem *addr = uap->port.membase + mxs_reg_to_offset(uap, reg);
+
+       writel_relaxed(val, addr);
+}
+
+static void mxs_set(unsigned int val, struct mxs_auart_port *uap,
+                   unsigned int reg)
+{
+       void __iomem *addr = uap->port.membase + mxs_reg_to_offset(uap, reg);
+
+       writel_relaxed(val, addr + SET_REG);
+}
+
+static void mxs_clr(unsigned int val, struct mxs_auart_port *uap,
+                   unsigned int reg)
+{
+       void __iomem *addr = uap->port.membase + mxs_reg_to_offset(uap, reg);
+
+       writel_relaxed(val, addr + CLR_REG);
+}
+
 static void mxs_auart_stop_tx(struct uart_port *u);
 
 #define to_auart_port(u) container_of(u, struct mxs_auart_port, port)
@@ -295,19 +621,16 @@ static void mxs_auart_tx_chars(struct mxs_auart_port *s)
        }
 
 
-       while (!(readl(s->port.membase + AUART_STAT) &
-                AUART_STAT_TXFF)) {
+       while (!(mxs_read(s, REG_STAT) & AUART_STAT_TXFF)) {
                if (s->port.x_char) {
                        s->port.icount.tx++;
-                       writel(s->port.x_char,
-                                    s->port.membase + AUART_DATA);
+                       mxs_write(s->port.x_char, s, REG_DATA);
                        s->port.x_char = 0;
                        continue;
                }
                if (!uart_circ_empty(xmit) && !uart_tx_stopped(&s->port)) {
                        s->port.icount.tx++;
-                       writel(xmit->buf[xmit->tail],
-                                    s->port.membase + AUART_DATA);
+                       mxs_write(xmit->buf[xmit->tail], s, REG_DATA);
                        xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
                } else
                        break;
@@ -316,11 +639,9 @@ static void mxs_auart_tx_chars(struct mxs_auart_port *s)
                uart_write_wakeup(&s->port);
 
        if (uart_circ_empty(&(s->port.state->xmit)))
-               writel(AUART_INTR_TXIEN,
-                            s->port.membase + AUART_INTR_CLR);
+               mxs_clr(AUART_INTR_TXIEN, s, REG_INTR);
        else
-               writel(AUART_INTR_TXIEN,
-                            s->port.membase + AUART_INTR_SET);
+               mxs_set(AUART_INTR_TXIEN, s, REG_INTR);
 
        if (uart_tx_stopped(&s->port))
                mxs_auart_stop_tx(&s->port);
@@ -332,8 +653,8 @@ static void mxs_auart_rx_char(struct mxs_auart_port *s)
        u32 stat;
        u8 c;
 
-       c = readl(s->port.membase + AUART_DATA);
-       stat = readl(s->port.membase + AUART_STAT);
+       c = mxs_read(s, REG_DATA);
+       stat = mxs_read(s, REG_STAT);
 
        flag = TTY_NORMAL;
        s->port.icount.rx++;
@@ -368,7 +689,7 @@ static void mxs_auart_rx_char(struct mxs_auart_port *s)
 
        uart_insert_char(&s->port, stat, AUART_STAT_OERR, c, flag);
 out:
-       writel(stat, s->port.membase + AUART_STAT);
+       mxs_write(stat, s, REG_STAT);
 }
 
 static void mxs_auart_rx_chars(struct mxs_auart_port *s)
@@ -376,13 +697,13 @@ static void mxs_auart_rx_chars(struct mxs_auart_port *s)
        u32 stat = 0;
 
        for (;;) {
-               stat = readl(s->port.membase + AUART_STAT);
+               stat = mxs_read(s, REG_STAT);
                if (stat & AUART_STAT_RXFE)
                        break;
                mxs_auart_rx_char(s);
        }
 
-       writel(stat, s->port.membase + AUART_STAT);
+       mxs_write(stat, s, REG_STAT);
        tty_flip_buffer_push(&s->port.state->port);
 }
 
@@ -418,7 +739,7 @@ static void mxs_auart_set_mctrl(struct uart_port *u, unsigned mctrl)
 {
        struct mxs_auart_port *s = to_auart_port(u);
 
-       u32 ctrl = readl(u->membase + AUART_CTRL2);
+       u32 ctrl = mxs_read(s, REG_CTRL2);
 
        ctrl &= ~(AUART_CTRL2_RTSEN | AUART_CTRL2_RTS);
        if (mctrl & TIOCM_RTS) {
@@ -428,7 +749,7 @@ static void mxs_auart_set_mctrl(struct uart_port *u, unsigned mctrl)
                        ctrl |= AUART_CTRL2_RTS;
        }
 
-       writel(ctrl, u->membase + AUART_CTRL2);
+       mxs_write(ctrl, s, REG_CTRL2);
 
        mctrl_gpio_set(s->gpios, mctrl);
 }
@@ -459,7 +780,7 @@ static u32 mxs_auart_modem_status(struct mxs_auart_port *s, u32 mctrl)
 static u32 mxs_auart_get_mctrl(struct uart_port *u)
 {
        struct mxs_auart_port *s = to_auart_port(u);
-       u32 stat = readl(u->membase + AUART_STAT);
+       u32 stat = mxs_read(s, REG_STAT);
        u32 mctrl = 0;
 
        if (stat & AUART_STAT_CTS)
@@ -536,14 +857,14 @@ static void dma_rx_callback(void *arg)
 
        dma_unmap_sg(s->dev, &s->rx_sgl, 1, DMA_FROM_DEVICE);
 
-       stat = readl(s->port.membase + AUART_STAT);
+       stat = mxs_read(s, REG_STAT);
        stat &= ~(AUART_STAT_OERR | AUART_STAT_BERR |
                        AUART_STAT_PERR | AUART_STAT_FERR);
 
        count = stat & AUART_STAT_RXCOUNT_MASK;
        tty_insert_flip_string(port, s->rx_dma_buf, count);
 
-       writel(stat, s->port.membase + AUART_STAT);
+       mxs_write(stat, s, REG_STAT);
        tty_flip_buffer_push(port);
 
        /* start the next DMA for RX. */
@@ -606,8 +927,8 @@ static void mxs_auart_dma_exit_channel(struct mxs_auart_port *s)
 static void mxs_auart_dma_exit(struct mxs_auart_port *s)
 {
 
-       writel(AUART_CTRL2_TXDMAE | AUART_CTRL2_RXDMAE | AUART_CTRL2_DMAONERR,
-               s->port.membase + AUART_CTRL2_CLR);
+       mxs_clr(AUART_CTRL2_TXDMAE | AUART_CTRL2_RXDMAE | AUART_CTRL2_DMAONERR,
+               s, REG_CTRL2);
 
        mxs_auart_dma_exit_channel(s);
        s->flags &= ~MXS_AUART_DMA_ENABLED;
@@ -666,7 +987,7 @@ static void mxs_auart_settermios(struct uart_port *u,
        cflag = termios->c_cflag;
 
        ctrl = AUART_LINECTRL_FEN;
-       ctrl2 = readl(u->membase + AUART_CTRL2);
+       ctrl2 = mxs_read(s, REG_CTRL2);
 
        /* byte size */
        switch (cflag & CSIZE) {
@@ -754,15 +1075,24 @@ static void mxs_auart_settermios(struct uart_port *u,
        }
 
        /* set baud rate */
-       baud_min = DIV_ROUND_UP(u->uartclk * 32, AUART_LINECTRL_BAUD_DIV_MAX);
-       baud_max = u->uartclk * 32 / AUART_LINECTRL_BAUD_DIV_MIN;
-       baud = uart_get_baud_rate(u, termios, old, baud_min, baud_max);
-       div = u->uartclk * 32 / baud;
+       if (is_asm9260_auart(s)) {
+               baud = uart_get_baud_rate(u, termios, old,
+                                         u->uartclk * 4 / 0x3FFFFF,
+                                         u->uartclk / 16);
+               div = u->uartclk * 4 / baud;
+       } else {
+               baud_min = DIV_ROUND_UP(u->uartclk * 32,
+                                       AUART_LINECTRL_BAUD_DIV_MAX);
+               baud_max = u->uartclk * 32 / AUART_LINECTRL_BAUD_DIV_MIN;
+               baud = uart_get_baud_rate(u, termios, old, baud_min, baud_max);
+               div = u->uartclk * 32 / baud;
+       }
+
        ctrl |= AUART_LINECTRL_BAUD_DIVFRAC(div & 0x3F);
        ctrl |= AUART_LINECTRL_BAUD_DIVINT(div >> 6);
+       mxs_write(ctrl, s, REG_LINECTRL);
 
-       writel(ctrl, u->membase + AUART_LINECTRL);
-       writel(ctrl2, u->membase + AUART_CTRL2);
+       mxs_write(ctrl2, s, REG_CTRL2);
 
        uart_update_timeout(u, termios->c_cflag, baud);
 
@@ -771,8 +1101,8 @@ static void mxs_auart_settermios(struct uart_port *u,
                !test_and_set_bit(MXS_AUART_DMA_RX_READY, &s->flags)) {
                if (!mxs_auart_dma_prep_rx(s)) {
                        /* Disable the normal RX interrupt. */
-                       writel(AUART_INTR_RXIEN | AUART_INTR_RTIEN,
-                                       u->membase + AUART_INTR_CLR);
+                       mxs_clr(AUART_INTR_RXIEN | AUART_INTR_RTIEN,
+                               s, REG_INTR);
                } else {
                        mxs_auart_dma_exit(s);
                        dev_err(s->dev, "We can not start up the DMA.\n");
@@ -802,16 +1132,13 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
        u32 istat;
        struct mxs_auart_port *s = context;
        u32 mctrl_temp = s->mctrl_prev;
-       u32 stat = readl(s->port.membase + AUART_STAT);
+       u32 stat = mxs_read(s, REG_STAT);
 
-       istat = readl(s->port.membase + AUART_INTR);
+       istat = mxs_read(s, REG_INTR);
 
        /* ack irq */
-       writel(istat & (AUART_INTR_RTIS
-               | AUART_INTR_TXIS
-               | AUART_INTR_RXIS
-               | AUART_INTR_CTSMIS),
-                       s->port.membase + AUART_INTR_CLR);
+       mxs_clr(istat & (AUART_INTR_RTIS | AUART_INTR_TXIS | AUART_INTR_RXIS
+               | AUART_INTR_CTSMIS), s, REG_INTR);
 
        /*
         * Dealing with GPIO interrupt
@@ -827,8 +1154,7 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
                if (CTS_AT_AUART() && s->ms_irq_enabled)
                        uart_handle_cts_change(&s->port,
                                        stat & AUART_STAT_CTS);
-               writel(AUART_INTR_CTSMIS,
-                               s->port.membase + AUART_INTR_CLR);
+               mxs_clr(AUART_INTR_CTSMIS, s, REG_INTR);
                istat &= ~AUART_INTR_CTSMIS;
        }
 
@@ -846,44 +1172,44 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
        return IRQ_HANDLED;
 }
 
-static void mxs_auart_reset_deassert(struct uart_port *u)
+static void mxs_auart_reset_deassert(struct mxs_auart_port *s)
 {
        int i;
        unsigned int reg;
 
-       writel(AUART_CTRL0_SFTRST, u->membase + AUART_CTRL0_CLR);
+       mxs_clr(AUART_CTRL0_SFTRST, s, REG_CTRL0);
 
        for (i = 0; i < 10000; i++) {
-               reg = readl(u->membase + AUART_CTRL0);
+               reg = mxs_read(s, REG_CTRL0);
                if (!(reg & AUART_CTRL0_SFTRST))
                        break;
                udelay(3);
        }
-       writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_CLR);
+       mxs_clr(AUART_CTRL0_CLKGATE, s, REG_CTRL0);
 }
 
-static void mxs_auart_reset_assert(struct uart_port *u)
+static void mxs_auart_reset_assert(struct mxs_auart_port *s)
 {
        int i;
        u32 reg;
 
-       reg = readl(u->membase + AUART_CTRL0);
+       reg = mxs_read(s, REG_CTRL0);
        /* if already in reset state, keep it untouched */
        if (reg & AUART_CTRL0_SFTRST)
                return;
 
-       writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_CLR);
-       writel(AUART_CTRL0_SFTRST, u->membase + AUART_CTRL0_SET);
+       mxs_clr(AUART_CTRL0_CLKGATE, s, REG_CTRL0);
+       mxs_set(AUART_CTRL0_SFTRST, s, REG_CTRL0);
 
        for (i = 0; i < 1000; i++) {
-               reg = readl(u->membase + AUART_CTRL0);
+               reg = mxs_read(s, REG_CTRL0);
                /* reset is finished when the clock is gated */
                if (reg & AUART_CTRL0_CLKGATE)
                        return;
                udelay(10);
        }
 
-       dev_err(u->dev, "Failed to reset the unit.");
+       dev_err(s->dev, "Failed to reset the unit.");
 }
 
 static int mxs_auart_startup(struct uart_port *u)
@@ -896,17 +1222,17 @@ static int mxs_auart_startup(struct uart_port *u)
                return ret;
 
        if (uart_console(u)) {
-               writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_CLR);
+               mxs_clr(AUART_CTRL0_CLKGATE, s, REG_CTRL0);
        } else {
                /* reset the unit to a well known state */
-               mxs_auart_reset_assert(u);
-               mxs_auart_reset_deassert(u);
+               mxs_auart_reset_assert(s);
+               mxs_auart_reset_deassert(s);
        }
 
-       writel(AUART_CTRL2_UARTEN, u->membase + AUART_CTRL2_SET);
+       mxs_set(AUART_CTRL2_UARTEN, s, REG_CTRL2);
 
-       writel(AUART_INTR_RXIEN | AUART_INTR_RTIEN | AUART_INTR_CTSMIEN,
-                       u->membase + AUART_INTR);
+       mxs_write(AUART_INTR_RXIEN | AUART_INTR_RTIEN | AUART_INTR_CTSMIEN,
+                 s, REG_INTR);
 
        /* Reset FIFO size (it could have changed if DMA was enabled) */
        u->fifosize = MXS_AUART_FIFO_SIZE;
@@ -915,7 +1241,7 @@ static int mxs_auart_startup(struct uart_port *u)
         * Enable fifo so all four bytes of a DMA word are written to
         * output (otherwise, only the LSB is written, ie. 1 in 4 bytes)
         */
-       writel(AUART_LINECTRL_FEN, u->membase + AUART_LINECTRL_SET);
+       mxs_set(AUART_LINECTRL_FEN, s, REG_LINECTRL);
 
        /* get initial status of modem lines */
        mctrl_gpio_get(s->gpios, &s->mctrl_prev);
@@ -934,12 +1260,13 @@ static void mxs_auart_shutdown(struct uart_port *u)
                mxs_auart_dma_exit(s);
 
        if (uart_console(u)) {
-               writel(AUART_CTRL2_UARTEN, u->membase + AUART_CTRL2_CLR);
-               writel(AUART_INTR_RXIEN | AUART_INTR_RTIEN | AUART_INTR_CTSMIEN,
-                               u->membase + AUART_INTR_CLR);
-               writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_SET);
+               mxs_clr(AUART_CTRL2_UARTEN, s, REG_CTRL2);
+
+               mxs_clr(AUART_INTR_RXIEN | AUART_INTR_RTIEN |
+                       AUART_INTR_CTSMIEN, s, REG_INTR);
+               mxs_set(AUART_CTRL0_CLKGATE, s, REG_CTRL0);
        } else {
-               mxs_auart_reset_assert(u);
+               mxs_auart_reset_assert(s);
        }
 
        clk_disable_unprepare(s->clk);
@@ -947,7 +1274,9 @@ static void mxs_auart_shutdown(struct uart_port *u)
 
 static unsigned int mxs_auart_tx_empty(struct uart_port *u)
 {
-       if ((readl(u->membase + AUART_STAT) &
+       struct mxs_auart_port *s = to_auart_port(u);
+
+       if ((mxs_read(s, REG_STAT) &
                 (AUART_STAT_TXFE | AUART_STAT_BUSY)) == AUART_STAT_TXFE)
                return TIOCSER_TEMT;
 
@@ -959,29 +1288,33 @@ static void mxs_auart_start_tx(struct uart_port *u)
        struct mxs_auart_port *s = to_auart_port(u);
 
        /* enable transmitter */
-       writel(AUART_CTRL2_TXE, u->membase + AUART_CTRL2_SET);
+       mxs_set(AUART_CTRL2_TXE, s, REG_CTRL2);
 
        mxs_auart_tx_chars(s);
 }
 
 static void mxs_auart_stop_tx(struct uart_port *u)
 {
-       writel(AUART_CTRL2_TXE, u->membase + AUART_CTRL2_CLR);
+       struct mxs_auart_port *s = to_auart_port(u);
+
+       mxs_clr(AUART_CTRL2_TXE, s, REG_CTRL2);
 }
 
 static void mxs_auart_stop_rx(struct uart_port *u)
 {
-       writel(AUART_CTRL2_RXE, u->membase + AUART_CTRL2_CLR);
+       struct mxs_auart_port *s = to_auart_port(u);
+
+       mxs_clr(AUART_CTRL2_RXE, s, REG_CTRL2);
 }
 
 static void mxs_auart_break_ctl(struct uart_port *u, int ctl)
 {
+       struct mxs_auart_port *s = to_auart_port(u);
+
        if (ctl)
-               writel(AUART_LINECTRL_BRK,
-                            u->membase + AUART_LINECTRL_SET);
+               mxs_set(AUART_LINECTRL_BRK, s, REG_LINECTRL);
        else
-               writel(AUART_LINECTRL_BRK,
-                            u->membase + AUART_LINECTRL_CLR);
+               mxs_clr(AUART_LINECTRL_BRK, s, REG_LINECTRL);
 }
 
 static struct uart_ops mxs_auart_ops = {
@@ -1009,15 +1342,16 @@ static struct mxs_auart_port *auart_port[MXS_AUART_PORTS];
 #ifdef CONFIG_SERIAL_MXS_AUART_CONSOLE
 static void mxs_auart_console_putchar(struct uart_port *port, int ch)
 {
+       struct mxs_auart_port *s = to_auart_port(port);
        unsigned int to = 1000;
 
-       while (readl(port->membase + AUART_STAT) & AUART_STAT_TXFF) {
+       while (mxs_read(s, REG_STAT) & AUART_STAT_TXFF) {
                if (!to--)
                        break;
                udelay(1);
        }
 
-       writel(ch, port->membase + AUART_DATA);
+       mxs_write(ch, s, REG_DATA);
 }
 
 static void
@@ -1037,18 +1371,16 @@ auart_console_write(struct console *co, const char *str, unsigned int count)
        clk_enable(s->clk);
 
        /* First save the CR then disable the interrupts */
-       old_ctrl2 = readl(port->membase + AUART_CTRL2);
-       old_ctrl0 = readl(port->membase + AUART_CTRL0);
+       old_ctrl2 = mxs_read(s, REG_CTRL2);
+       old_ctrl0 = mxs_read(s, REG_CTRL0);
 
-       writel(AUART_CTRL0_CLKGATE,
-                    port->membase + AUART_CTRL0_CLR);
-       writel(AUART_CTRL2_UARTEN | AUART_CTRL2_TXE,
-                    port->membase + AUART_CTRL2_SET);
+       mxs_clr(AUART_CTRL0_CLKGATE, s, REG_CTRL0);
+       mxs_set(AUART_CTRL2_UARTEN | AUART_CTRL2_TXE, s, REG_CTRL2);
 
        uart_console_write(port, str, count, mxs_auart_console_putchar);
 
        /* Finally, wait for transmitter to become empty ... */
-       while (readl(port->membase + AUART_STAT) & AUART_STAT_BUSY) {
+       while (mxs_read(s, REG_STAT) & AUART_STAT_BUSY) {
                udelay(1);
                if (!to--)
                        break;
@@ -1060,24 +1392,25 @@ auart_console_write(struct console *co, const char *str, unsigned int count)
         * unused, but that is better than to disable it while it is still
         * transmitting.
         */
-       if (!(readl(port->membase + AUART_STAT) & AUART_STAT_BUSY)) {
-               writel(old_ctrl0, port->membase + AUART_CTRL0);
-               writel(old_ctrl2, port->membase + AUART_CTRL2);
+       if (!(mxs_read(s, REG_STAT) & AUART_STAT_BUSY)) {
+               mxs_write(old_ctrl0, s, REG_CTRL0);
+               mxs_write(old_ctrl2, s, REG_CTRL2);
        }
 
        clk_disable(s->clk);
 }
 
 static void __init
-auart_console_get_options(struct uart_port *port, int *baud,
+auart_console_get_options(struct mxs_auart_port *s, int *baud,
                          int *parity, int *bits)
 {
+       struct uart_port *port = &s->port;
        unsigned int lcr_h, quot;
 
-       if (!(readl(port->membase + AUART_CTRL2) & AUART_CTRL2_UARTEN))
+       if (!(mxs_read(s, REG_CTRL2) & AUART_CTRL2_UARTEN))
                return;
 
-       lcr_h = readl(port->membase + AUART_LINECTRL);
+       lcr_h = mxs_read(s, REG_LINECTRL);
 
        *parity = 'n';
        if (lcr_h & AUART_LINECTRL_PEN) {
@@ -1092,12 +1425,10 @@ auart_console_get_options(struct uart_port *port, int *baud,
        else
                *bits = 8;
 
-       quot = ((readl(port->membase + AUART_LINECTRL)
-                       & AUART_LINECTRL_BAUD_DIVINT_MASK))
-                           >> (AUART_LINECTRL_BAUD_DIVINT_SHIFT - 6);
-       quot |= ((readl(port->membase + AUART_LINECTRL)
-                       & AUART_LINECTRL_BAUD_DIVFRAC_MASK))
-                               >> AUART_LINECTRL_BAUD_DIVFRAC_SHIFT;
+       quot = ((mxs_read(s, REG_LINECTRL) & AUART_LINECTRL_BAUD_DIVINT_MASK))
+               >> (AUART_LINECTRL_BAUD_DIVINT_SHIFT - 6);
+       quot |= ((mxs_read(s, REG_LINECTRL) & AUART_LINECTRL_BAUD_DIVFRAC_MASK))
+               >> AUART_LINECTRL_BAUD_DIVFRAC_SHIFT;
        if (quot == 0)
                quot = 1;
 
@@ -1132,7 +1463,7 @@ auart_console_setup(struct console *co, char *options)
        if (options)
                uart_parse_options(options, &baud, &parity, &bits, &flow);
        else
-               auart_console_get_options(&s->port, &baud, &parity, &bits);
+               auart_console_get_options(s, &baud, &parity, &bits);
 
        ret = uart_set_options(&s->port, co, baud, parity, bits, flow);
 
@@ -1164,6 +1495,60 @@ static struct uart_driver auart_driver = {
 #endif
 };
 
+static void mxs_init_regs(struct mxs_auart_port *s)
+{
+       if (is_asm9260_auart(s))
+               s->vendor = &vendor_alphascale_asm9260;
+       else
+               s->vendor = &vendor_freescale_stmp37xx;
+}
+
+static int mxs_get_clks(struct mxs_auart_port *s,
+                       struct platform_device *pdev)
+{
+       int err;
+
+       if (!is_asm9260_auart(s)) {
+               s->clk = devm_clk_get(&pdev->dev, NULL);
+               if (IS_ERR(s->clk))
+                       return PTR_ERR(s->clk);
+
+               return 0;
+       }
+
+       s->clk = devm_clk_get(s->dev, "mod");
+       if (IS_ERR(s->clk)) {
+               dev_err(s->dev, "Failed to get \"mod\" clk\n");
+               return PTR_ERR(s->clk);
+       }
+
+       s->clk_ahb = devm_clk_get(s->dev, "ahb");
+       if (IS_ERR(s->clk_ahb)) {
+               dev_err(s->dev, "Failed to get \"ahb\" clk\n");
+               return PTR_ERR(s->clk_ahb);
+       }
+
+       err = clk_prepare_enable(s->clk_ahb);
+       if (err) {
+               dev_err(s->dev, "Failed to enable ahb_clk!\n");
+               return err;
+       }
+
+       err = clk_set_rate(s->clk, clk_get_rate(s->clk_ahb));
+       if (err) {
+               dev_err(s->dev, "Failed to set rate!\n");
+               return err;
+       }
+
+       err = clk_prepare_enable(s->clk);
+       if (err) {
+               dev_err(s->dev, "Failed to enable clk!\n");
+               return err;
+       }
+
+       return 0;
+}
+
 /*
  * This function returns 1 if pdev isn't a device instatiated by dt, 0 if it
  * could successfully get all information from dt or a negative errno.
@@ -1185,7 +1570,8 @@ static int serial_mxs_probe_dt(struct mxs_auart_port *s,
        }
        s->port.line = ret;
 
-       if (of_get_property(np, "fsl,uart-has-rtscts", NULL))
+       if (of_get_property(np, "uart-has-rtscts", NULL) ||
+           of_get_property(np, "fsl,uart-has-rtscts", NULL) /* deprecated */)
                set_bit(MXS_AUART_RTSCTS, &s->flags);
 
        return 0;
@@ -1269,6 +1655,9 @@ static int mxs_auart_probe(struct platform_device *pdev)
        if (!s)
                return -ENOMEM;
 
+       s->port.dev = &pdev->dev;
+       s->dev = &pdev->dev;
+
        ret = serial_mxs_probe_dt(s, pdev);
        if (ret > 0)
                s->port.line = pdev->id < 0 ? 0 : pdev->id;
@@ -1280,15 +1669,14 @@ static int mxs_auart_probe(struct platform_device *pdev)
                s->devtype = pdev->id_entry->driver_data;
        }
 
-       s->clk = devm_clk_get(&pdev->dev, NULL);
-       if (IS_ERR(s->clk))
-               return PTR_ERR(s->clk);
+       ret = mxs_get_clks(s, pdev);
+       if (ret)
+               return ret;
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!r)
                return -ENXIO;
 
-
        s->port.mapbase = r->start;
        s->port.membase = ioremap(r->start, resource_size(r));
        s->port.ops = &mxs_auart_ops;
@@ -1296,7 +1684,8 @@ static int mxs_auart_probe(struct platform_device *pdev)
        s->port.fifosize = MXS_AUART_FIFO_SIZE;
        s->port.uartclk = clk_get_rate(s->clk);
        s->port.type = PORT_IMX;
-       s->port.dev = s->dev = &pdev->dev;
+
+       mxs_init_regs(s);
 
        s->mctrl_prev = 0;
 
@@ -1327,16 +1716,21 @@ static int mxs_auart_probe(struct platform_device *pdev)
 
        auart_port[s->port.line] = s;
 
-       mxs_auart_reset_deassert(&s->port);
+       mxs_auart_reset_deassert(s);
 
        ret = uart_add_one_port(&auart_driver, &s->port);
        if (ret)
                goto out_free_gpio_irq;
 
-       version = readl(s->port.membase + AUART_VERSION);
-       dev_info(&pdev->dev, "Found APPUART %d.%d.%d\n",
-              (version >> 24) & 0xff,
-              (version >> 16) & 0xff, version & 0xffff);
+       /* ASM9260 don't have version reg */
+       if (is_asm9260_auart(s)) {
+               dev_info(&pdev->dev, "Found APPUART ASM9260\n");
+       } else {
+               version = mxs_read(s, REG_VERSION);
+               dev_info(&pdev->dev, "Found APPUART %d.%d.%d\n",
+                        (version >> 24) & 0xff,
+                        (version >> 16) & 0xff, version & 0xffff);
+       }
 
        return 0;
 
index ac7f8df..99bb231 100644 (file)
@@ -1271,6 +1271,8 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
        /* check to see if we need  to change clock source */
 
        if (ourport->baudclk != clk) {
+               clk_prepare_enable(clk);
+
                s3c24xx_serial_setsource(port, clk_sel);
 
                if (!IS_ERR(ourport->baudclk)) {
@@ -1278,8 +1280,6 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
                        ourport->baudclk = ERR_PTR(-EINVAL);
                }
 
-               clk_prepare_enable(clk);
-
                ourport->baudclk = clk;
                ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0;
        }
index e639361..f36e6df 100644 (file)
@@ -666,7 +666,7 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
        struct uart_port *port = &s->p[portno].port;
 
        do {
-               unsigned int iir, msr, rxlen;
+               unsigned int iir, rxlen;
 
                iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG);
                if (iir & SC16IS7XX_IIR_NO_INT_BIT)
@@ -683,12 +683,6 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
                        if (rxlen)
                                sc16is7xx_handle_rx(port, rxlen, iir);
                        break;
-
-               case SC16IS7XX_IIR_CTSRTS_SRC:
-                       msr = sc16is7xx_port_read(port, SC16IS7XX_MSR_REG);
-                       uart_handle_cts_change(port,
-                                              !!(msr & SC16IS7XX_MSR_DCTS_BIT));
-                       break;
                case SC16IS7XX_IIR_THRI_SRC:
                        sc16is7xx_handle_tx(port);
                        break;
@@ -1014,9 +1008,8 @@ static int sc16is7xx_startup(struct uart_port *port)
                              SC16IS7XX_EFCR_TXDISABLE_BIT,
                              0);
 
-       /* Enable RX, TX, CTS change interrupts */
-       val = SC16IS7XX_IER_RDI_BIT | SC16IS7XX_IER_THRI_BIT |
-             SC16IS7XX_IER_CTSI_BIT;
+       /* Enable RX, TX interrupts */
+       val = SC16IS7XX_IER_RDI_BIT | SC16IS7XX_IER_THRI_BIT;
        sc16is7xx_port_write(port, SC16IS7XX_IER_REG, val);
 
        return 0;
index 1d6fc60..1dba671 100644 (file)
@@ -206,10 +206,8 @@ static void set_dtr(struct tegra_uart_port *tup, bool active)
 static void tegra_uart_set_mctrl(struct uart_port *u, unsigned int mctrl)
 {
        struct tegra_uart_port *tup = to_tegra_uport(u);
-       unsigned long mcr;
        int dtr_enable;
 
-       mcr = tup->mcr_shadow;
        tup->rts_active = !!(mctrl & TIOCM_RTS);
        set_rts(tup, tup->rts_active);
 
index a126a60..a333c59 100644 (file)
@@ -64,6 +64,41 @@ static int uart_dcd_enabled(struct uart_port *uport)
        return !!(uport->status & UPSTAT_DCD_ENABLE);
 }
 
+static inline struct uart_port *uart_port_ref(struct uart_state *state)
+{
+       if (atomic_add_unless(&state->refcount, 1, 0))
+               return state->uart_port;
+       return NULL;
+}
+
+static inline void uart_port_deref(struct uart_port *uport)
+{
+       if (uport && atomic_dec_and_test(&uport->state->refcount))
+               wake_up(&uport->state->remove_wait);
+}
+
+#define uart_port_lock(state, flags)                                   \
+       ({                                                              \
+               struct uart_port *__uport = uart_port_ref(state);       \
+               if (__uport)                                            \
+                       spin_lock_irqsave(&__uport->lock, flags);       \
+               __uport;                                                \
+       })
+
+#define uart_port_unlock(uport, flags)                                 \
+       ({                                                              \
+               struct uart_port *__uport = uport;                      \
+               if (__uport)                                            \
+                       spin_unlock_irqrestore(&__uport->lock, flags);  \
+               uart_port_deref(__uport);                               \
+       })
+
+static inline struct uart_port *uart_port_check(struct uart_state *state)
+{
+       lockdep_assert_held(&state->port.mutex);
+       return state->uart_port;
+}
+
 /*
  * This routine is used by the interrupt handler to schedule processing in
  * the software interrupt portion of the driver.
@@ -82,12 +117,13 @@ void uart_write_wakeup(struct uart_port *port)
 static void uart_stop(struct tty_struct *tty)
 {
        struct uart_state *state = tty->driver_data;
-       struct uart_port *port = state->uart_port;
+       struct uart_port *port;
        unsigned long flags;
 
-       spin_lock_irqsave(&port->lock, flags);
-       port->ops->stop_tx(port);
-       spin_unlock_irqrestore(&port->lock, flags);
+       port = uart_port_lock(state, flags);
+       if (port)
+               port->ops->stop_tx(port);
+       uart_port_unlock(port, flags);
 }
 
 static void __uart_start(struct tty_struct *tty)
@@ -95,19 +131,19 @@ static void __uart_start(struct tty_struct *tty)
        struct uart_state *state = tty->driver_data;
        struct uart_port *port = state->uart_port;
 
-       if (!uart_tx_stopped(port))
+       if (port && !uart_tx_stopped(port))
                port->ops->start_tx(port);
 }
 
 static void uart_start(struct tty_struct *tty)
 {
        struct uart_state *state = tty->driver_data;
-       struct uart_port *port = state->uart_port;
+       struct uart_port *port;
        unsigned long flags;
 
-       spin_lock_irqsave(&port->lock, flags);
+       port = uart_port_lock(state, flags);
        __uart_start(tty);
-       spin_unlock_irqrestore(&port->lock, flags);
+       uart_port_unlock(port, flags);
 }
 
 static void
@@ -134,7 +170,7 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
 static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
                int init_hw)
 {
-       struct uart_port *uport = state->uart_port;
+       struct uart_port *uport = uart_port_check(state);
        unsigned long page;
        int retval = 0;
 
@@ -196,7 +232,7 @@ static int uart_startup(struct tty_struct *tty, struct uart_state *state,
        struct tty_port *port = &state->port;
        int retval;
 
-       if (port->flags & ASYNC_INITIALIZED)
+       if (tty_port_initialized(port))
                return 0;
 
        /*
@@ -207,7 +243,7 @@ static int uart_startup(struct tty_struct *tty, struct uart_state *state,
 
        retval = uart_port_startup(tty, state, init_hw);
        if (!retval) {
-               set_bit(ASYNCB_INITIALIZED, &port->flags);
+               tty_port_set_initialized(port, 1);
                clear_bit(TTY_IO_ERROR, &tty->flags);
        } else if (retval > 0)
                retval = 0;
@@ -219,10 +255,12 @@ static int uart_startup(struct tty_struct *tty, struct uart_state *state,
  * This routine will shutdown a serial port; interrupts are disabled, and
  * DTR is dropped if the hangup on close termio flag is on.  Calls to
  * uart_shutdown are serialised by the per-port semaphore.
+ *
+ * uport == NULL if uart_port has already been removed
  */
 static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
 {
-       struct uart_port *uport = state->uart_port;
+       struct uart_port *uport = uart_port_check(state);
        struct tty_port *port = &state->port;
 
        /*
@@ -231,11 +269,13 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
        if (tty)
                set_bit(TTY_IO_ERROR, &tty->flags);
 
-       if (test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags)) {
+       if (tty_port_initialized(port)) {
+               tty_port_set_initialized(port, 0);
+
                /*
                 * Turn off DTR and RTS early.
                 */
-               if (uart_console(uport) && tty)
+               if (uport && uart_console(uport) && tty)
                        uport->cons->cflag = tty->termios.c_cflag;
 
                if (!tty || C_HUPCL(tty))
@@ -249,7 +289,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
         * a DCD drop (hangup) at just the right time.  Clear suspended bit so
         * we don't try to resume a port that has been shutdown.
         */
-       clear_bit(ASYNCB_SUSPENDED, &port->flags);
+       tty_port_set_suspended(port, 0);
 
        /*
         * Free the transmit buffer page.
@@ -441,7 +481,7 @@ EXPORT_SYMBOL(uart_get_divisor);
 static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
                                        struct ktermios *old_termios)
 {
-       struct uart_port *uport = state->uart_port;
+       struct uart_port *uport = uart_port_check(state);
        struct ktermios *termios;
        int hw_stopped;
 
@@ -486,7 +526,7 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
 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 uart_port *port;
        struct circ_buf *circ;
        unsigned long flags;
        int ret = 0;
@@ -495,13 +535,13 @@ static int uart_put_char(struct tty_struct *tty, unsigned char c)
        if (!circ->buf)
                return 0;
 
-       spin_lock_irqsave(&port->lock, flags);
-       if (uart_circ_chars_free(circ) != 0) {
+       port = uart_port_lock(state, flags);
+       if (port && uart_circ_chars_free(circ) != 0) {
                circ->buf[circ->head] = c;
                circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1);
                ret = 1;
        }
-       spin_unlock_irqrestore(&port->lock, flags);
+       uart_port_unlock(port, flags);
        return ret;
 }
 
@@ -528,14 +568,12 @@ static int uart_write(struct tty_struct *tty,
                return -EL3HLT;
        }
 
-       port = state->uart_port;
        circ = &state->xmit;
-
        if (!circ->buf)
                return 0;
 
-       spin_lock_irqsave(&port->lock, flags);
-       while (1) {
+       port = uart_port_lock(state, flags);
+       while (port) {
                c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
                if (count < c)
                        c = count;
@@ -549,32 +587,33 @@ static int uart_write(struct tty_struct *tty,
        }
 
        __uart_start(tty);
-       spin_unlock_irqrestore(&port->lock, flags);
-
+       uart_port_unlock(port, flags);
        return ret;
 }
 
 static int uart_write_room(struct tty_struct *tty)
 {
        struct uart_state *state = tty->driver_data;
+       struct uart_port *port;
        unsigned long flags;
        int ret;
 
-       spin_lock_irqsave(&state->uart_port->lock, flags);
+       port = uart_port_lock(state, flags);
        ret = uart_circ_chars_free(&state->xmit);
-       spin_unlock_irqrestore(&state->uart_port->lock, flags);
+       uart_port_unlock(port, flags);
        return ret;
 }
 
 static int uart_chars_in_buffer(struct tty_struct *tty)
 {
        struct uart_state *state = tty->driver_data;
+       struct uart_port *port;
        unsigned long flags;
        int ret;
 
-       spin_lock_irqsave(&state->uart_port->lock, flags);
+       port = uart_port_lock(state, flags);
        ret = uart_circ_chars_pending(&state->xmit);
-       spin_unlock_irqrestore(&state->uart_port->lock, flags);
+       uart_port_unlock(port, flags);
        return ret;
 }
 
@@ -593,14 +632,15 @@ static void uart_flush_buffer(struct tty_struct *tty)
                return;
        }
 
-       port = state->uart_port;
        pr_debug("uart_flush_buffer(%d) called\n", tty->index);
 
-       spin_lock_irqsave(&port->lock, flags);
+       port = uart_port_lock(state, flags);
+       if (!port)
+               return;
        uart_circ_clear(&state->xmit);
        if (port->ops->flush_buffer)
                port->ops->flush_buffer(port);
-       spin_unlock_irqrestore(&port->lock, flags);
+       uart_port_unlock(port, flags);
        tty_wakeup(tty);
 }
 
@@ -611,9 +651,13 @@ static void uart_flush_buffer(struct tty_struct *tty)
 static void uart_send_xchar(struct tty_struct *tty, char ch)
 {
        struct uart_state *state = tty->driver_data;
-       struct uart_port *port = state->uart_port;
+       struct uart_port *port;
        unsigned long flags;
 
+       port = uart_port_ref(state);
+       if (!port)
+               return;
+
        if (port->ops->send_xchar)
                port->ops->send_xchar(port, ch);
        else {
@@ -623,14 +667,19 @@ static void uart_send_xchar(struct tty_struct *tty, char ch)
                        port->ops->start_tx(port);
                spin_unlock_irqrestore(&port->lock, flags);
        }
+       uart_port_deref(port);
 }
 
 static void uart_throttle(struct tty_struct *tty)
 {
        struct uart_state *state = tty->driver_data;
-       struct uart_port *port = state->uart_port;
+       struct uart_port *port;
        upstat_t mask = 0;
 
+       port = uart_port_ref(state);
+       if (!port)
+               return;
+
        if (I_IXOFF(tty))
                mask |= UPSTAT_AUTOXOFF;
        if (C_CRTSCTS(tty))
@@ -646,14 +695,20 @@ static void uart_throttle(struct tty_struct *tty)
 
        if (mask & UPSTAT_AUTOXOFF)
                uart_send_xchar(tty, STOP_CHAR(tty));
+
+       uart_port_deref(port);
 }
 
 static void uart_unthrottle(struct tty_struct *tty)
 {
        struct uart_state *state = tty->driver_data;
-       struct uart_port *port = state->uart_port;
+       struct uart_port *port;
        upstat_t mask = 0;
 
+       port = uart_port_ref(state);
+       if (!port)
+               return;
+
        if (I_IXOFF(tty))
                mask |= UPSTAT_AUTOXOFF;
        if (C_CRTSCTS(tty))
@@ -669,12 +724,15 @@ static void uart_unthrottle(struct tty_struct *tty)
 
        if (mask & UPSTAT_AUTOXOFF)
                uart_send_xchar(tty, START_CHAR(tty));
+
+       uart_port_deref(port);
 }
 
-static void uart_get_info(struct tty_port *port, struct serial_struct *retinfo)
+static int 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;
+       struct uart_port *uport;
+       int ret = -ENODEV;
 
        memset(retinfo, 0, sizeof(*retinfo));
 
@@ -683,6 +741,10 @@ static void uart_get_info(struct tty_port *port, struct serial_struct *retinfo)
         * occur as we go
         */
        mutex_lock(&port->mutex);
+       uport = uart_port_check(state);
+       if (!uport)
+               goto out;
+
        retinfo->type       = uport->type;
        retinfo->line       = uport->line;
        retinfo->port       = uport->iobase;
@@ -701,7 +763,11 @@ static void uart_get_info(struct tty_port *port, struct serial_struct *retinfo)
        retinfo->io_type         = uport->iotype;
        retinfo->iomem_reg_shift = uport->regshift;
        retinfo->iomem_base      = (void *)(unsigned long)uport->mapbase;
+
+       ret = 0;
+out:
        mutex_unlock(&port->mutex);
+       return ret;
 }
 
 static int uart_get_info_user(struct tty_port *port,
@@ -709,7 +775,8 @@ static int uart_get_info_user(struct tty_port *port,
 {
        struct serial_struct tmp;
 
-       uart_get_info(port, &tmp);
+       if (uart_get_info(port, &tmp) < 0)
+               return -EIO;
 
        if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
                return -EFAULT;
@@ -720,13 +787,16 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
                         struct uart_state *state,
                         struct serial_struct *new_info)
 {
-       struct uart_port *uport = state->uart_port;
+       struct uart_port *uport = uart_port_check(state);
        unsigned long new_port;
        unsigned int change_irq, change_port, closing_wait;
        unsigned int old_custom_divisor, close_delay;
        upf_t old_flags, new_flags;
        int retval = 0;
 
+       if (!uport)
+               return -EIO;
+
        new_port = new_info->port;
        if (HIGH_BITS_OFFSET)
                new_port += (unsigned long) new_info->port_high << HIGH_BITS_OFFSET;
@@ -886,7 +956,7 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
        retval = 0;
        if (uport->type == PORT_UNKNOWN)
                goto exit;
-       if (port->flags & ASYNC_INITIALIZED) {
+       if (tty_port_initialized(port)) {
                if (((old_flags ^ uport->flags) & UPF_SPD_MASK) ||
                    old_custom_divisor != uport->custom_divisor) {
                        /*
@@ -936,13 +1006,11 @@ static int uart_set_info_user(struct tty_struct *tty, struct uart_state *state,
  *     @tty: tty associated with the UART
  *     @state: UART being queried
  *     @value: returned modem value
- *
- *     Note: uart_ioctl protects us against hangups.
  */
 static int uart_get_lsr_info(struct tty_struct *tty,
                        struct uart_state *state, unsigned int __user *value)
 {
-       struct uart_port *uport = state->uart_port;
+       struct uart_port *uport = uart_port_check(state);
        unsigned int result;
 
        result = uport->ops->tx_empty(uport);
@@ -965,18 +1033,22 @@ static int uart_tiocmget(struct tty_struct *tty)
 {
        struct uart_state *state = tty->driver_data;
        struct tty_port *port = &state->port;
-       struct uart_port *uport = state->uart_port;
+       struct uart_port *uport;
        int result = -EIO;
 
        mutex_lock(&port->mutex);
-       if (!(tty->flags & (1 << TTY_IO_ERROR))) {
+       uport = uart_port_check(state);
+       if (!uport)
+               goto out;
+
+       if (!tty_io_error(tty)) {
                result = uport->mctrl;
                spin_lock_irq(&uport->lock);
                result |= uport->ops->get_mctrl(uport);
                spin_unlock_irq(&uport->lock);
        }
+out:
        mutex_unlock(&port->mutex);
-
        return result;
 }
 
@@ -984,15 +1056,20 @@ static int
 uart_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear)
 {
        struct uart_state *state = tty->driver_data;
-       struct uart_port *uport = state->uart_port;
        struct tty_port *port = &state->port;
+       struct uart_port *uport;
        int ret = -EIO;
 
        mutex_lock(&port->mutex);
-       if (!(tty->flags & (1 << TTY_IO_ERROR))) {
+       uport = uart_port_check(state);
+       if (!uport)
+               goto out;
+
+       if (!tty_io_error(tty)) {
                uart_update_mctrl(uport, set, clear);
                ret = 0;
        }
+out:
        mutex_unlock(&port->mutex);
        return ret;
 }
@@ -1001,21 +1078,26 @@ static int uart_break_ctl(struct tty_struct *tty, int break_state)
 {
        struct uart_state *state = tty->driver_data;
        struct tty_port *port = &state->port;
-       struct uart_port *uport = state->uart_port;
+       struct uart_port *uport;
+       int ret = -EIO;
 
        mutex_lock(&port->mutex);
+       uport = uart_port_check(state);
+       if (!uport)
+               goto out;
 
        if (uport->type != PORT_UNKNOWN)
                uport->ops->break_ctl(uport, break_state);
-
+       ret = 0;
+out:
        mutex_unlock(&port->mutex);
-       return 0;
+       return ret;
 }
 
 static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state)
 {
-       struct uart_port *uport = state->uart_port;
        struct tty_port *port = &state->port;
+       struct uart_port *uport;
        int flags, ret;
 
        if (!capable(CAP_SYS_ADMIN))
@@ -1029,6 +1111,12 @@ static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state)
        if (mutex_lock_interruptible(&port->mutex))
                return -ERESTARTSYS;
 
+       uport = uart_port_check(state);
+       if (!uport) {
+               ret = -EIO;
+               goto out;
+       }
+
        ret = -EBUSY;
        if (tty_port_users(port) == 1) {
                uart_shutdown(tty, state);
@@ -1052,6 +1140,7 @@ static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state)
 
                ret = uart_startup(tty, state, 1);
        }
+out:
        mutex_unlock(&port->mutex);
        return ret;
 }
@@ -1074,10 +1163,9 @@ static void uart_enable_ms(struct uart_port *uport)
  * FIXME: This wants extracting into a common all driver implementation
  * of TIOCMWAIT using tty_port.
  */
-static int
-uart_wait_modem_status(struct uart_state *state, unsigned long arg)
+static int uart_wait_modem_status(struct uart_state *state, unsigned long arg)
 {
-       struct uart_port *uport = state->uart_port;
+       struct uart_port *uport;
        struct tty_port *port = &state->port;
        DECLARE_WAITQUEUE(wait, current);
        struct uart_icount cprev, cnow;
@@ -1086,6 +1174,9 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg)
        /*
         * note the counters on entry
         */
+       uport = uart_port_ref(state);
+       if (!uport)
+               return -EIO;
        spin_lock_irq(&uport->lock);
        memcpy(&cprev, &uport->icount, sizeof(struct uart_icount));
        uart_enable_ms(uport);
@@ -1119,6 +1210,7 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg)
        }
        __set_current_state(TASK_RUNNING);
        remove_wait_queue(&port->delta_msr_wait, &wait);
+       uart_port_deref(uport);
 
        return ret;
 }
@@ -1134,11 +1226,15 @@ static int uart_get_icount(struct tty_struct *tty,
 {
        struct uart_state *state = tty->driver_data;
        struct uart_icount cnow;
-       struct uart_port *uport = state->uart_port;
+       struct uart_port *uport;
 
+       uport = uart_port_ref(state);
+       if (!uport)
+               return -EIO;
        spin_lock_irq(&uport->lock);
        memcpy(&cnow, &uport->icount, sizeof(struct uart_icount));
        spin_unlock_irq(&uport->lock);
+       uart_port_deref(uport);
 
        icount->cts         = cnow.cts;
        icount->dsr         = cnow.dsr;
@@ -1200,11 +1296,11 @@ static int uart_set_rs485_config(struct uart_port *port,
  * Called via sys_ioctl.  We can use spin_lock_irq() here.
  */
 static int
-uart_ioctl(struct tty_struct *tty, unsigned int cmd,
-          unsigned long arg)
+uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
 {
        struct uart_state *state = tty->driver_data;
        struct tty_port *port = &state->port;
+       struct uart_port *uport;
        void __user *uarg = (void __user *)arg;
        int ret = -ENOIOCTLCMD;
 
@@ -1238,7 +1334,7 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd,
        if (ret != -ENOIOCTLCMD)
                goto out;
 
-       if (tty->flags & (1 << TTY_IO_ERROR)) {
+       if (tty_io_error(tty)) {
                ret = -EIO;
                goto out;
        }
@@ -1256,8 +1352,9 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd,
                goto out;
 
        mutex_lock(&port->mutex);
+       uport = uart_port_check(state);
 
-       if (tty->flags & (1 << TTY_IO_ERROR)) {
+       if (!uport || tty_io_error(tty)) {
                ret = -EIO;
                goto out_up;
        }
@@ -1273,19 +1370,17 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd,
                break;
 
        case TIOCGRS485:
-               ret = uart_get_rs485_config(state->uart_port, uarg);
+               ret = uart_get_rs485_config(uport, uarg);
                break;
 
        case TIOCSRS485:
-               ret = uart_set_rs485_config(state->uart_port, uarg);
+               ret = uart_set_rs485_config(uport, uarg);
                break;
-       default: {
-               struct uart_port *uport = state->uart_port;
+       default:
                if (uport->ops->ioctl)
                        ret = uport->ops->ioctl(uport, cmd, arg);
                break;
        }
-       }
 out_up:
        mutex_unlock(&port->mutex);
 out:
@@ -1295,24 +1390,29 @@ out:
 static void uart_set_ldisc(struct tty_struct *tty)
 {
        struct uart_state *state = tty->driver_data;
-       struct uart_port *uport = state->uart_port;
+       struct uart_port *uport;
 
-       if (uport->ops->set_ldisc) {
-               mutex_lock(&state->port.mutex);
+       mutex_lock(&state->port.mutex);
+       uport = uart_port_check(state);
+       if (uport && uport->ops->set_ldisc)
                uport->ops->set_ldisc(uport, &tty->termios);
-               mutex_unlock(&state->port.mutex);
-       }
+       mutex_unlock(&state->port.mutex);
 }
 
 static void uart_set_termios(struct tty_struct *tty,
                                                struct ktermios *old_termios)
 {
        struct uart_state *state = tty->driver_data;
-       struct uart_port *uport = state->uart_port;
+       struct uart_port *uport;
        unsigned int cflag = tty->termios.c_cflag;
        unsigned int iflag_mask = IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK;
        bool sw_changed = false;
 
+       mutex_lock(&state->port.mutex);
+       uport = uart_port_check(state);
+       if (!uport)
+               goto out;
+
        /*
         * Drivers doing software flow control also need to know
         * about changes to these input settings.
@@ -1335,12 +1435,10 @@ static void uart_set_termios(struct tty_struct *tty,
            tty->termios.c_ispeed == old_termios->c_ispeed &&
            ((tty->termios.c_iflag ^ old_termios->c_iflag) & iflag_mask) == 0 &&
            !sw_changed) {
-               return;
+               goto out;
        }
 
-       mutex_lock(&state->port.mutex);
        uart_change_speed(tty, state, old_termios);
-       mutex_unlock(&state->port.mutex);
        /* reload cflag from termios; port driver may have overriden flags */
        cflag = tty->termios.c_cflag;
 
@@ -1350,17 +1448,18 @@ static void uart_set_termios(struct tty_struct *tty,
        /* Handle transition away from B0 status */
        else if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
                unsigned int mask = TIOCM_DTR;
-               if (!(cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags))
+               if (!(cflag & CRTSCTS) || !tty_throttled(tty))
                        mask |= TIOCM_RTS;
                uart_set_mctrl(uport, mask);
        }
+out:
+       mutex_unlock(&state->port.mutex);
 }
 
 /*
  * Calls to uart_close() are serialised via the tty_lock in
  *   drivers/tty/tty_io.c:tty_release()
  *   drivers/tty/tty_io.c:do_tty_hangup()
- * This runs from a workqueue and can sleep for a _short_ time only.
  */
 static void uart_close(struct tty_struct *tty, struct file *filp)
 {
@@ -1379,18 +1478,21 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
                return;
        }
 
-       uport = state->uart_port;
        port = &state->port;
        pr_debug("uart_close(%d) called\n", tty->index);
 
-       if (!port->count || tty_port_close_start(port, tty, filp) == 0)
+       if (tty_port_close_start(port, tty, filp) == 0)
                return;
 
+       mutex_lock(&port->mutex);
+       uport = uart_port_check(state);
+
        /*
         * At this point, we stop accepting input.  To do this, we
         * disable the receive line status interrupts.
         */
-       if (port->flags & ASYNC_INITIALIZED) {
+       if (tty_port_initialized(port) &&
+           !WARN(!uport, "detached port still initialized!\n")) {
                spin_lock_irq(&uport->lock);
                uport->ops->stop_rx(uport);
                spin_unlock_irq(&uport->lock);
@@ -1402,7 +1504,6 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
                uart_wait_until_sent(tty, uport->timeout);
        }
 
-       mutex_lock(&port->mutex);
        uart_shutdown(tty, state);
        tty_port_tty_set(port, NULL);
 
@@ -1413,17 +1514,17 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
                if (port->close_delay)
                        msleep_interruptible(jiffies_to_msecs(port->close_delay));
                spin_lock_irq(&port->lock);
-       } else if (!uart_console(uport)) {
+       } else if (uport && !uart_console(uport)) {
                spin_unlock_irq(&port->lock);
                uart_change_pm(state, UART_PM_STATE_OFF);
                spin_lock_irq(&port->lock);
        }
+       spin_unlock_irq(&port->lock);
+       tty_port_set_active(port, 0);
 
        /*
         * Wake up anyone trying to open this port.
         */
-       clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
-       spin_unlock_irq(&port->lock);
        wake_up_interruptible(&port->open_wait);
 
        mutex_unlock(&port->mutex);
@@ -1435,11 +1536,14 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
 static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
 {
        struct uart_state *state = tty->driver_data;
-       struct uart_port *port = state->uart_port;
+       struct uart_port *port;
        unsigned long char_time, expire;
 
-       if (port->type == PORT_UNKNOWN || port->fifosize == 0)
+       port = uart_port_ref(state);
+       if (!port || port->type == PORT_UNKNOWN || port->fifosize == 0) {
+               uart_port_deref(port);
                return;
+       }
 
        /*
         * Set the check interval to be 1/5 of the estimated time to
@@ -1485,6 +1589,7 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
                if (time_after(jiffies, expire))
                        break;
        }
+       uart_port_deref(port);
 }
 
 /*
@@ -1496,20 +1601,24 @@ static void uart_hangup(struct tty_struct *tty)
 {
        struct uart_state *state = tty->driver_data;
        struct tty_port *port = &state->port;
+       struct uart_port *uport;
        unsigned long flags;
 
        pr_debug("uart_hangup(%d)\n", tty->index);
 
        mutex_lock(&port->mutex);
-       if (port->flags & ASYNC_NORMAL_ACTIVE) {
+       uport = uart_port_check(state);
+       WARN(!uport, "hangup of detached port!\n");
+
+       if (tty_port_active(port)) {
                uart_flush_buffer(tty);
                uart_shutdown(tty, state);
                spin_lock_irqsave(&port->lock, flags);
                port->count = 0;
-               clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
                spin_unlock_irqrestore(&port->lock, flags);
+               tty_port_set_active(port, 0);
                tty_port_tty_set(port, NULL);
-               if (!uart_console(state->uart_port))
+               if (uport && !uart_console(uport))
                        uart_change_pm(state, UART_PM_STATE_OFF);
                wake_up_interruptible(&port->open_wait);
                wake_up_interruptible(&port->delta_msr_wait);
@@ -1517,10 +1626,11 @@ static void uart_hangup(struct tty_struct *tty)
        mutex_unlock(&port->mutex);
 }
 
+/* uport == NULL if uart_port has already been removed */
 static void uart_port_shutdown(struct tty_port *port)
 {
        struct uart_state *state = container_of(port, struct uart_state, port);
-       struct uart_port *uport = state->uart_port;
+       struct uart_port *uport = uart_port_check(state);
 
        /*
         * clear delta_msr_wait queue to avoid mem leaks: we may free
@@ -1534,23 +1644,36 @@ static void uart_port_shutdown(struct tty_port *port)
        /*
         * Free the IRQ and disable the port.
         */
-       uport->ops->shutdown(uport);
+       if (uport)
+               uport->ops->shutdown(uport);
 
        /*
         * Ensure that the IRQ handler isn't running on another CPU.
         */
-       synchronize_irq(uport->irq);
+       if (uport)
+               synchronize_irq(uport->irq);
 }
 
 static int uart_carrier_raised(struct tty_port *port)
 {
        struct uart_state *state = container_of(port, struct uart_state, port);
-       struct uart_port *uport = state->uart_port;
+       struct uart_port *uport;
        int mctrl;
+
+       uport = uart_port_ref(state);
+       /*
+        * Should never observe uport == NULL since checks for hangup should
+        * abort the tty_port_block_til_ready() loop before checking for carrier
+        * raised -- but report carrier raised if it does anyway so open will
+        * continue and not sleep
+        */
+       if (WARN_ON(!uport))
+               return 1;
        spin_lock_irq(&uport->lock);
        uart_enable_ms(uport);
        mctrl = uport->ops->get_mctrl(uport);
        spin_unlock_irq(&uport->lock);
+       uart_port_deref(uport);
        if (mctrl & TIOCM_CAR)
                return 1;
        return 0;
@@ -1559,12 +1682,18 @@ static int uart_carrier_raised(struct tty_port *port)
 static void uart_dtr_rts(struct tty_port *port, int onoff)
 {
        struct uart_state *state = container_of(port, struct uart_state, port);
-       struct uart_port *uport = state->uart_port;
+       struct uart_port *uport;
+
+       uport = uart_port_ref(state);
+       if (!uport)
+               return;
 
        if (onoff)
                uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
        else
                uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
+
+       uart_port_deref(uport);
 }
 
 /*
@@ -1583,6 +1712,7 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
        int retval, line = tty->index;
        struct uart_state *state = drv->state + line;
        struct tty_port *port = &state->port;
+       struct uart_port *uport;
 
        pr_debug("uart_open(%d) called\n", line);
 
@@ -1602,15 +1732,15 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
                goto end;
        }
 
-       if (!state->uart_port || state->uart_port->flags & UPF_DEAD) {
+       uport = uart_port_check(state);
+       if (!uport || uport->flags & UPF_DEAD) {
                retval = -ENXIO;
                goto err_unlock;
        }
 
        tty->driver_data = state;
-       state->uart_port->state = state;
-       state->port.low_latency =
-               (state->uart_port->flags & UPF_LOW_LATENCY) ? 1 : 0;
+       uport->state = state;
+       port->low_latency = (uport->flags & UPF_LOW_LATENCY) ? 1 : 0;
        tty_port_tty_set(port, tty);
 
        /*
@@ -1649,13 +1779,15 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
        struct uart_state *state = drv->state + i;
        struct tty_port *port = &state->port;
        enum uart_pm_state pm_state;
-       struct uart_port *uport = state->uart_port;
+       struct uart_port *uport;
        char stat_buf[32];
        unsigned int status;
        int mmio;
 
+       mutex_lock(&port->mutex);
+       uport = uart_port_check(state);
        if (!uport)
-               return;
+               goto out;
 
        mmio = uport->iotype >= UPIO_MEM;
        seq_printf(m, "%d: uart:%s %s%08llX irq:%d",
@@ -1667,11 +1799,10 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
 
        if (uport->type == PORT_UNKNOWN) {
                seq_putc(m, '\n');
-               return;
+               goto out;
        }
 
        if (capable(CAP_SYS_ADMIN)) {
-               mutex_lock(&port->mutex);
                pm_state = state->pm_state;
                if (pm_state != UART_PM_STATE_ON)
                        uart_change_pm(state, UART_PM_STATE_ON);
@@ -1680,7 +1811,6 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
                spin_unlock_irq(&uport->lock);
                if (pm_state != UART_PM_STATE_ON)
                        uart_change_pm(state, pm_state);
-               mutex_unlock(&port->mutex);
 
                seq_printf(m, " tx:%d rx:%d",
                                uport->icount.tx, uport->icount.rx);
@@ -1718,6 +1848,8 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
        seq_putc(m, '\n');
 #undef STATBIT
 #undef INFOBIT
+out:
+       mutex_unlock(&port->mutex);
 }
 
 static int uart_proc_show(struct seq_file *m, void *v)
@@ -1954,10 +2086,10 @@ EXPORT_SYMBOL_GPL(uart_set_options);
 static void uart_change_pm(struct uart_state *state,
                           enum uart_pm_state pm_state)
 {
-       struct uart_port *port = state->uart_port;
+       struct uart_port *port = uart_port_check(state);
 
        if (state->pm_state != pm_state) {
-               if (port->ops->pm)
+               if (port && port->ops->pm)
                        port->ops->pm(port, pm_state, state->pm_state);
                state->pm_state = pm_state;
        }
@@ -2003,12 +2135,12 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
 
        uport->suspended = 1;
 
-       if (port->flags & ASYNC_INITIALIZED) {
+       if (tty_port_initialized(port)) {
                const struct uart_ops *ops = uport->ops;
                int tries;
 
-               set_bit(ASYNCB_SUSPENDED, &port->flags);
-               clear_bit(ASYNCB_INITIALIZED, &port->flags);
+               tty_port_set_suspended(port, 1);
+               tty_port_set_initialized(port, 0);
 
                spin_lock_irq(&uport->lock);
                ops->stop_tx(uport);
@@ -2088,7 +2220,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
                        console_start(uport->cons);
        }
 
-       if (port->flags & ASYNC_SUSPENDED) {
+       if (tty_port_suspended(port)) {
                const struct uart_ops *ops = uport->ops;
                int ret;
 
@@ -2107,7 +2239,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
                                ops->set_mctrl(uport, uport->mctrl);
                                ops->start_tx(uport);
                                spin_unlock_irq(&uport->lock);
-                               set_bit(ASYNCB_INITIALIZED, &port->flags);
+                               tty_port_set_initialized(port, 1);
                        } else {
                                /*
                                 * Failed to resume - maybe hardware went away?
@@ -2118,7 +2250,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
                        }
                }
 
-               clear_bit(ASYNCB_SUSPENDED, &port->flags);
+               tty_port_set_suspended(port, 0);
        }
 
        mutex_unlock(&port->mutex);
@@ -2228,42 +2360,42 @@ static int uart_poll_init(struct tty_driver *driver, int line, char *options)
 {
        struct uart_driver *drv = driver->driver_state;
        struct uart_state *state = drv->state + line;
+       struct tty_port *tport;
        struct uart_port *port;
        int baud = 9600;
        int bits = 8;
        int parity = 'n';
        int flow = 'n';
-       int ret;
+       int ret = 0;
 
-       if (!state || !state->uart_port)
+       if (!state)
                return -1;
 
-       port = state->uart_port;
-       if (!(port->ops->poll_get_char && port->ops->poll_put_char))
-               return -1;
+       tport = &state->port;
+       mutex_lock(&tport->mutex);
 
-       if (port->ops->poll_init) {
-               struct tty_port *tport = &state->port;
+       port = uart_port_check(state);
+       if (!port || !(port->ops->poll_get_char && port->ops->poll_put_char)) {
+               ret = -1;
+               goto out;
+       }
 
-               ret = 0;
-               mutex_lock(&tport->mutex);
+       if (port->ops->poll_init) {
                /*
-                * We don't set ASYNCB_INITIALIZED as we only initialized the
-                * hw, e.g. state->xmit is still uninitialized.
+                * We don't set initialized as we only initialized the hw,
+                * e.g. state->xmit is still uninitialized.
                 */
-               if (!test_bit(ASYNCB_INITIALIZED, &tport->flags))
+               if (!tty_port_initialized(tport))
                        ret = port->ops->poll_init(port);
-               mutex_unlock(&tport->mutex);
-               if (ret)
-                       return ret;
        }
 
-       if (options) {
+       if (!ret && options) {
                uart_parse_options(options, &baud, &parity, &bits, &flow);
-               return uart_set_options(port, NULL, baud, parity, bits, flow);
+               ret = uart_set_options(port, NULL, baud, parity, bits, flow);
        }
-
-       return 0;
+out:
+       mutex_unlock(&tport->mutex);
+       return ret;
 }
 
 static int uart_poll_get_char(struct tty_driver *driver, int line)
@@ -2271,12 +2403,15 @@ static int uart_poll_get_char(struct tty_driver *driver, int line)
        struct uart_driver *drv = driver->driver_state;
        struct uart_state *state = drv->state + line;
        struct uart_port *port;
+       int ret = -1;
 
-       if (!state || !state->uart_port)
-               return -1;
-
-       port = state->uart_port;
-       return port->ops->poll_get_char(port);
+       if (state) {
+               port = uart_port_ref(state);
+               if (port)
+                       ret = port->ops->poll_get_char(port);
+               uart_port_deref(port);
+       }
+       return ret;
 }
 
 static void uart_poll_put_char(struct tty_driver *driver, int line, char ch)
@@ -2285,14 +2420,17 @@ static void uart_poll_put_char(struct tty_driver *driver, int line, char ch)
        struct uart_state *state = drv->state + line;
        struct uart_port *port;
 
-       if (!state || !state->uart_port)
+       if (!state)
                return;
 
-       port = state->uart_port;
+       port = uart_port_ref(state);
+       if (!port)
+               return;
 
        if (ch == '\n')
                port->ops->poll_put_char(port, '\r');
        port->ops->poll_put_char(port, ch);
+       uart_port_deref(port);
 }
 #endif
 
@@ -2639,6 +2777,8 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
        }
 
        /* Link the port to the driver state table and vice versa */
+       atomic_set(&state->refcount, 1);
+       init_waitqueue_head(&state->remove_wait);
        state->uart_port = uport;
        uport->state = state;
 
@@ -2711,15 +2851,12 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
 {
        struct uart_state *state = drv->state + uport->line;
        struct tty_port *port = &state->port;
+       struct uart_port *uart_port;
        struct tty_struct *tty;
        int ret = 0;
 
        BUG_ON(in_interrupt());
 
-       if (state->uart_port != uport)
-               dev_alert(uport->dev, "Removing wrong port: %p != %p\n",
-                       state->uart_port, uport);
-
        mutex_lock(&port_mutex);
 
        /*
@@ -2727,7 +2864,12 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
         * succeeding while we shut down the port.
         */
        mutex_lock(&port->mutex);
-       if (!state->uart_port) {
+       uart_port = uart_port_check(state);
+       if (uart_port != uport)
+               dev_alert(uport->dev, "Removing wrong port: %p != %p\n",
+                         uart_port, uport);
+
+       if (!uart_port) {
                mutex_unlock(&port->mutex);
                ret = -EINVAL;
                goto out;
@@ -2764,7 +2906,11 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
         */
        uport->type = PORT_UNKNOWN;
 
+       mutex_lock(&port->mutex);
+       WARN_ON(atomic_dec_return(&state->refcount) < 0);
+       wait_event(state->remove_wait, !atomic_read(&state->refcount));
        state->uart_port = NULL;
+       mutex_unlock(&port->mutex);
 out:
        mutex_unlock(&port_mutex);
 
index 0214736..e8dd509 100644 (file)
@@ -43,8 +43,6 @@ static const struct {
        { "rng", TIOCM_RNG, false, },
        { "rts", TIOCM_RTS, true, },
        { "dtr", TIOCM_DTR, true, },
-       { "out1", TIOCM_OUT1, true, },
-       { "out2", TIOCM_OUT2, true, },
 };
 
 void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
@@ -125,9 +123,12 @@ static irqreturn_t mctrl_gpio_irq_handle(int irq, void *context)
        struct uart_port *port = gpios->port;
        u32 mctrl = gpios->mctrl_prev;
        u32 mctrl_diff;
+       unsigned long flags;
 
        mctrl_gpio_get(gpios, &mctrl);
 
+       spin_lock_irqsave(&port->lock, flags);
+
        mctrl_diff = mctrl ^ gpios->mctrl_prev;
        gpios->mctrl_prev = mctrl;
 
@@ -147,6 +148,8 @@ static irqreturn_t mctrl_gpio_irq_handle(int irq, void *context)
                wake_up_interruptible(&port->state->port.delta_msr_wait);
        }
 
+       spin_unlock_irqrestore(&port->lock, flags);
+
        return IRQ_HANDLED;
 }
 
index bcfad5d..332a33a 100644 (file)
@@ -32,8 +32,6 @@ enum mctrl_gpio_idx {
        UART_GPIO_RI = UART_GPIO_RNG,
        UART_GPIO_RTS,
        UART_GPIO_DTR,
-       UART_GPIO_OUT1,
-       UART_GPIO_OUT2,
        UART_GPIO_MAX,
 };
 
index c6657de..b186c9c 100644 (file)
@@ -1264,6 +1264,7 @@ MODULE_DEVICE_TABLE(of, sirfsoc_uart_ids);
 
 static int sirfsoc_uart_probe(struct platform_device *pdev)
 {
+       struct device_node *np = pdev->dev.of_node;
        struct sirfsoc_uart_port *sirfport;
        struct uart_port *port;
        struct resource *res;
@@ -1276,13 +1277,13 @@ static int sirfsoc_uart_probe(struct platform_device *pdev)
        };
        const struct of_device_id *match;
 
-       match = of_match_node(sirfsoc_uart_ids, pdev->dev.of_node);
+       match = of_match_node(sirfsoc_uart_ids, np);
        sirfport = devm_kzalloc(&pdev->dev, sizeof(*sirfport), GFP_KERNEL);
        if (!sirfport) {
                ret = -ENOMEM;
                goto err;
        }
-       sirfport->port.line = of_alias_get_id(pdev->dev.of_node, "serial");
+       sirfport->port.line = of_alias_get_id(np, "serial");
        sirf_ports[sirfport->port.line] = sirfport;
        sirfport->port.iotype = UPIO_MEM;
        sirfport->port.flags = UPF_BOOT_AUTOCONF;
@@ -1291,25 +1292,25 @@ static int sirfsoc_uart_probe(struct platform_device *pdev)
        port->private_data = sirfport;
        sirfport->uart_reg = (struct sirfsoc_uart_register *)match->data;
 
-       sirfport->hw_flow_ctrl = of_property_read_bool(pdev->dev.of_node,
-               "sirf,uart-has-rtscts");
-       if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-uart") ||
-               of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-uart"))
+       sirfport->hw_flow_ctrl =
+               of_property_read_bool(np, "uart-has-rtscts") ||
+               of_property_read_bool(np, "sirf,uart-has-rtscts") /* deprecated */;
+       if (of_device_is_compatible(np, "sirf,prima2-uart") ||
+               of_device_is_compatible(np, "sirf,atlas7-uart"))
                sirfport->uart_reg->uart_type = SIRF_REAL_UART;
-       if (of_device_is_compatible(pdev->dev.of_node,
-               "sirf,prima2-usp-uart") || of_device_is_compatible(
-               pdev->dev.of_node, "sirf,atlas7-usp-uart")) {
+       if (of_device_is_compatible(np, "sirf,prima2-usp-uart") ||
+           of_device_is_compatible(np, "sirf,atlas7-usp-uart")) {
                sirfport->uart_reg->uart_type = SIRF_USP_UART;
                if (!sirfport->hw_flow_ctrl)
                        goto usp_no_flow_control;
-               if (of_find_property(pdev->dev.of_node, "cts-gpios", NULL))
-                       sirfport->cts_gpio = of_get_named_gpio(
-                                       pdev->dev.of_node, "cts-gpios", 0);
+               if (of_find_property(np, "cts-gpios", NULL))
+                       sirfport->cts_gpio =
+                               of_get_named_gpio(np, "cts-gpios", 0);
                else
                        sirfport->cts_gpio = -1;
-               if (of_find_property(pdev->dev.of_node, "rts-gpios", NULL))
-                       sirfport->rts_gpio = of_get_named_gpio(
-                                       pdev->dev.of_node, "rts-gpios", 0);
+               if (of_find_property(np, "rts-gpios", NULL))
+                       sirfport->rts_gpio =
+                               of_get_named_gpio(np, "rts-gpios", 0);
                else
                        sirfport->rts_gpio = -1;
 
@@ -1336,13 +1337,11 @@ static int sirfsoc_uart_probe(struct platform_device *pdev)
                gpio_direction_output(sirfport->rts_gpio, 1);
        }
 usp_no_flow_control:
-       if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-uart") ||
-           of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-usp-uart"))
+       if (of_device_is_compatible(np, "sirf,atlas7-uart") ||
+           of_device_is_compatible(np, "sirf,atlas7-usp-uart"))
                sirfport->is_atlas7 = true;
 
-       if (of_property_read_u32(pdev->dev.of_node,
-                       "fifosize",
-                       &port->fifosize)) {
+       if (of_property_read_u32(np, "fifosize", &port->fifosize)) {
                dev_err(&pdev->dev,
                        "Unable to find fifosize in uart node.\n");
                ret = -EFAULT;
index d08baa6..05089b6 100644 (file)
@@ -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);
 }
@@ -345,13 +345,13 @@ static int ulite_request_port(struct uart_port *port)
                return -EBUSY;
        }
 
-       port->private_data = &uartlite_be;
+       port->private_data = (void *)&uartlite_be;
        ret = uart_in32(ULITE_CONTROL, port);
        uart_out32(ULITE_CONTROL_RST_TX, ULITE_CONTROL, port);
        ret = uart_in32(ULITE_STATUS, port);
        /* Endianess detection */
        if ((ret & ULITE_STATUS_TXEMPTY) != ULITE_STATUS_TXEMPTY)
-               port->private_data = &uartlite_le;
+               port->private_data = (void *)&uartlite_le;
 
        return 0;
 }
index 1a7dc3c..481eb29 100644 (file)
@@ -1478,6 +1478,9 @@ static const struct of_device_id ucc_uart_match[] = {
                .type = "serial",
                .compatible = "ucc_uart",
        },
+       {
+               .compatible = "fsl,t1040-ucc-uart",
+       },
        {},
 };
 MODULE_DEVICE_TABLE(of, ucc_uart_match);
index c8c7601..c13e27e 100644 (file)
@@ -1340,7 +1340,7 @@ static void mgsl_isr_io_pin( struct mgsl_struct *info )
                wake_up_interruptible(&info->status_event_wait_q);
                wake_up_interruptible(&info->event_wait_q);
 
-               if ( (info->port.flags & ASYNC_CHECK_CD) && 
+               if (tty_port_check_carrier(&info->port) &&
                     (status & MISCSTATUS_DCD_LATCHED) ) {
                        if ( debug_level >= DEBUG_LEVEL_ISR )
                                printk("%s CD now %s...", info->device_name,
@@ -1361,8 +1361,7 @@ static void mgsl_isr_io_pin( struct mgsl_struct *info )
                                if (status & MISCSTATUS_CTS) {
                                        if ( debug_level >= DEBUG_LEVEL_ISR )
                                                printk("CTS tx start...");
-                                       if (info->port.tty)
-                                               info->port.tty->hw_stopped = 0;
+                                       info->port.tty->hw_stopped = 0;
                                        usc_start_transmitter(info);
                                        info->pending_bh |= BH_TRANSMIT;
                                        return;
@@ -1749,13 +1748,13 @@ static irqreturn_t mgsl_interrupt(int dummy, void *dev_id)
 static int startup(struct mgsl_struct * info)
 {
        int retval = 0;
-       
+
        if ( debug_level >= DEBUG_LEVEL_INFO )
                printk("%s(%d):mgsl_startup(%s)\n",__FILE__,__LINE__,info->device_name);
-               
-       if (info->port.flags & ASYNC_INITIALIZED)
+
+       if (tty_port_initialized(&info->port))
                return 0;
-       
+
        if (!info->xmit_buf) {
                /* allocate a page of memory for a transmit buffer */
                info->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
@@ -1788,14 +1787,13 @@ static int startup(struct mgsl_struct * info)
 
        /* program hardware for current parameters */
        mgsl_change_params(info);
-       
+
        if (info->port.tty)
                clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
 
-       info->port.flags |= ASYNC_INITIALIZED;
-       
+       tty_port_set_initialized(&info->port, 1);
+
        return 0;
-       
 }      /* end of startup() */
 
 /* shutdown()
@@ -1808,8 +1806,8 @@ static int startup(struct mgsl_struct * info)
 static void shutdown(struct mgsl_struct * info)
 {
        unsigned long flags;
-       
-       if (!(info->port.flags & ASYNC_INITIALIZED))
+
+       if (!tty_port_initialized(&info->port))
                return;
 
        if (debug_level >= DEBUG_LEVEL_INFO)
@@ -1853,13 +1851,12 @@ static void shutdown(struct mgsl_struct * info)
 
        spin_unlock_irqrestore(&info->irq_spinlock,flags);
 
-       mgsl_release_resources(info);   
-       
+       mgsl_release_resources(info);
+
        if (info->port.tty)
                set_bit(TTY_IO_ERROR, &info->port.tty->flags);
 
-       info->port.flags &= ~ASYNC_INITIALIZED;
-       
+       tty_port_set_initialized(&info->port, 0);
 }      /* end of shutdown() */
 
 static void mgsl_program_hw(struct mgsl_struct *info)
@@ -1966,15 +1963,8 @@ static void mgsl_change_params(struct mgsl_struct *info)
        }
        info->timeout += HZ/50;         /* Add .02 seconds of slop */
 
-       if (cflag & CRTSCTS)
-               info->port.flags |= ASYNC_CTS_FLOW;
-       else
-               info->port.flags &= ~ASYNC_CTS_FLOW;
-               
-       if (cflag & CLOCAL)
-               info->port.flags &= ~ASYNC_CHECK_CD;
-       else
-               info->port.flags |= ASYNC_CHECK_CD;
+       tty_port_set_cts_flow(&info->port, cflag & CRTSCTS);
+       tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL);
 
        /* process tty input control flags */
        
@@ -2972,7 +2962,7 @@ static int mgsl_ioctl(struct tty_struct *tty,
 
        if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
            (cmd != TIOCMIWAIT)) {
-               if (tty->flags & (1 << TTY_IO_ERROR))
+               if (tty_io_error(tty))
                    return -EIO;
        }
 
@@ -3049,7 +3039,7 @@ static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termio
        /* Handle transition away from B0 status */
        if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) {
                info->serial_signals |= SerialSignal_DTR;
-               if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags))
+               if (!C_CRTSCTS(tty) || !tty_throttled(tty))
                        info->serial_signals |= SerialSignal_RTS;
                spin_lock_irqsave(&info->irq_spinlock,flags);
                usc_set_serial_signals(info);
@@ -3091,7 +3081,7 @@ static void mgsl_close(struct tty_struct *tty, struct file * filp)
                goto cleanup;
 
        mutex_lock(&info->port.mutex);
-       if (info->port.flags & ASYNC_INITIALIZED)
+       if (tty_port_initialized(&info->port))
                mgsl_wait_until_sent(tty, info->timeout);
        mgsl_flush_buffer(tty);
        tty_ldisc_flush(tty);
@@ -3129,15 +3119,15 @@ static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout)
        if (debug_level >= DEBUG_LEVEL_INFO)
                printk("%s(%d):mgsl_wait_until_sent(%s) entry\n",
                         __FILE__,__LINE__, info->device_name );
-      
+
        if (mgsl_paranoia_check(info, tty->name, "mgsl_wait_until_sent"))
                return;
 
-       if (!(info->port.flags & ASYNC_INITIALIZED))
+       if (!tty_port_initialized(&info->port))
                goto exit;
-        
+
        orig_jiffies = jiffies;
-      
+
        /* Set check interval to 1/5 of estimated time to
         * send a character, and make it at least 1. The check
         * interval should also be less than the timeout.
@@ -3204,7 +3194,7 @@ static void mgsl_hangup(struct tty_struct *tty)
        shutdown(info);
        
        info->port.count = 0;   
-       info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
+       tty_port_set_active(&info->port, 0);
        info->port.tty = NULL;
 
        wake_up_interruptible(&info->port.open_wait);
@@ -3270,9 +3260,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
                printk("%s(%d):block_til_ready on %s\n",
                         __FILE__,__LINE__, tty->driver->name );
 
-       if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
+       if (filp->f_flags & O_NONBLOCK || tty_io_error(tty)) {
                /* nonblock mode is set or port is not enabled */
-               port->flags |= ASYNC_NORMAL_ACTIVE;
+               tty_port_set_active(port, 1);
                return 0;
        }
 
@@ -3297,14 +3287,14 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
        port->count--;
        spin_unlock_irqrestore(&info->irq_spinlock, flags);
        port->blocked_open++;
-       
+
        while (1) {
-               if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags))
+               if (C_BAUD(tty) && tty_port_initialized(port))
                        tty_port_raise_dtr_rts(port);
-               
+
                set_current_state(TASK_INTERRUPTIBLE);
-               
-               if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)){
+
+               if (tty_hung_up_p(filp) || !tty_port_initialized(port)) {
                        retval = (port->flags & ASYNC_HUP_NOTIFY) ?
                                        -EAGAIN : -ERESTARTSYS;
                        break;
@@ -3341,7 +3331,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
                         __FILE__,__LINE__, tty->driver->name, port->count );
                         
        if (!retval)
-               port->flags |= ASYNC_NORMAL_ACTIVE;
+               tty_port_set_active(port, 1);
                
        return retval;
        
index d5b6471..7aca2d4 100644 (file)
@@ -726,7 +726,7 @@ static void close(struct tty_struct *tty, struct file *filp)
                goto cleanup;
 
        mutex_lock(&info->port.mutex);
-       if (info->port.flags & ASYNC_INITIALIZED)
+       if (tty_port_initialized(&info->port))
                wait_until_sent(tty, info->timeout);
        flush_buffer(tty);
        tty_ldisc_flush(tty);
@@ -756,9 +756,9 @@ static void hangup(struct tty_struct *tty)
 
        spin_lock_irqsave(&info->port.lock, flags);
        info->port.count = 0;
-       info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
        info->port.tty = NULL;
        spin_unlock_irqrestore(&info->port.lock, flags);
+       tty_port_set_active(&info->port, 0);
        mutex_unlock(&info->port.mutex);
 
        wake_up_interruptible(&info->port.open_wait);
@@ -784,7 +784,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
        /* Handle transition away from B0 status */
        if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) {
                info->signals |= SerialSignal_DTR;
-               if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags))
+               if (!C_CRTSCTS(tty) || !tty_throttled(tty))
                        info->signals |= SerialSignal_RTS;
                spin_lock_irqsave(&info->lock,flags);
                set_signals(info);
@@ -893,7 +893,7 @@ static void wait_until_sent(struct tty_struct *tty, int timeout)
        if (sanity_check(info, tty->name, "wait_until_sent"))
                return;
        DBGINFO(("%s wait_until_sent entry\n", info->device_name));
-       if (!(info->port.flags & ASYNC_INITIALIZED))
+       if (!tty_port_initialized(&info->port))
                goto exit;
 
        orig_jiffies = jiffies;
@@ -1032,7 +1032,7 @@ static int ioctl(struct tty_struct *tty,
 
        if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
            (cmd != TIOCMIWAIT)) {
-               if (tty->flags & (1 << TTY_IO_ERROR))
+               if (tty_io_error(tty))
                    return -EIO;
        }
 
@@ -2080,7 +2080,7 @@ static void dcd_change(struct slgt_info *info, unsigned short status)
        wake_up_interruptible(&info->event_wait_q);
        info->pending_bh |= BH_STATUS;
 
-       if (info->port.flags & ASYNC_CHECK_CD) {
+       if (tty_port_check_carrier(&info->port)) {
                if (info->signals & SerialSignal_DCD)
                        wake_up_interruptible(&info->port.open_wait);
                else {
@@ -2421,7 +2421,7 @@ static int startup(struct slgt_info *info)
 {
        DBGINFO(("%s startup\n", info->device_name));
 
-       if (info->port.flags & ASYNC_INITIALIZED)
+       if (tty_port_initialized(&info->port))
                return 0;
 
        if (!info->tx_buf) {
@@ -2442,7 +2442,7 @@ static int startup(struct slgt_info *info)
        if (info->port.tty)
                clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
 
-       info->port.flags |= ASYNC_INITIALIZED;
+       tty_port_set_initialized(&info->port, 1);
 
        return 0;
 }
@@ -2454,7 +2454,7 @@ static void shutdown(struct slgt_info *info)
 {
        unsigned long flags;
 
-       if (!(info->port.flags & ASYNC_INITIALIZED))
+       if (!tty_port_initialized(&info->port))
                return;
 
        DBGINFO(("%s shutdown\n", info->device_name));
@@ -2489,7 +2489,7 @@ static void shutdown(struct slgt_info *info)
        if (info->port.tty)
                set_bit(TTY_IO_ERROR, &info->port.tty->flags);
 
-       info->port.flags &= ~ASYNC_INITIALIZED;
+       tty_port_set_initialized(&info->port, 0);
 }
 
 static void program_hw(struct slgt_info *info)
@@ -2576,15 +2576,8 @@ static void change_params(struct slgt_info *info)
        }
        info->timeout += HZ/50;         /* Add .02 seconds of slop */
 
-       if (cflag & CRTSCTS)
-               info->port.flags |= ASYNC_CTS_FLOW;
-       else
-               info->port.flags &= ~ASYNC_CTS_FLOW;
-
-       if (cflag & CLOCAL)
-               info->port.flags &= ~ASYNC_CHECK_CD;
-       else
-               info->port.flags |= ASYNC_CHECK_CD;
+       tty_port_set_cts_flow(&info->port, cflag & CRTSCTS);
+       tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL);
 
        /* process tty input control flags */
 
@@ -3269,9 +3262,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
 
        DBGINFO(("%s block_til_ready\n", tty->driver->name));
 
-       if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
+       if (filp->f_flags & O_NONBLOCK || tty_io_error(tty)) {
                /* nonblock mode is set or port is not enabled */
-               port->flags |= ASYNC_NORMAL_ACTIVE;
+               tty_port_set_active(port, 1);
                return 0;
        }
 
@@ -3294,12 +3287,12 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
        port->blocked_open++;
 
        while (1) {
-               if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags))
+               if (C_BAUD(tty) && tty_port_initialized(port))
                        tty_port_raise_dtr_rts(port);
 
                set_current_state(TASK_INTERRUPTIBLE);
 
-               if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)){
+               if (tty_hung_up_p(filp) || !tty_port_initialized(port)) {
                        retval = (port->flags & ASYNC_HUP_NOTIFY) ?
                                        -EAGAIN : -ERESTARTSYS;
                        break;
@@ -3328,7 +3321,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
        port->blocked_open--;
 
        if (!retval)
-               port->flags |= ASYNC_NORMAL_ACTIVE;
+               tty_port_set_active(port, 1);
 
        DBGINFO(("%s block_til_ready ready, rc=%d\n", tty->driver->name, retval));
        return retval;
index 3f89685..dec1565 100644 (file)
@@ -812,7 +812,7 @@ static void close(struct tty_struct *tty, struct file *filp)
                goto cleanup;
 
        mutex_lock(&info->port.mutex);
-       if (info->port.flags & ASYNC_INITIALIZED)
+       if (tty_port_initialized(&info->port))
                wait_until_sent(tty, info->timeout);
 
        flush_buffer(tty);
@@ -849,9 +849,9 @@ static void hangup(struct tty_struct *tty)
 
        spin_lock_irqsave(&info->port.lock, flags);
        info->port.count = 0;
-       info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
        info->port.tty = NULL;
        spin_unlock_irqrestore(&info->port.lock, flags);
+       tty_port_set_active(&info->port, 1);
        mutex_unlock(&info->port.mutex);
 
        wake_up_interruptible(&info->port.open_wait);
@@ -881,7 +881,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
        /* Handle transition away from B0 status */
        if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) {
                info->serial_signals |= SerialSignal_DTR;
-               if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags))
+               if (!C_CRTSCTS(tty) || !tty_throttled(tty))
                        info->serial_signals |= SerialSignal_RTS;
                spin_lock_irqsave(&info->lock,flags);
                set_signals(info);
@@ -1061,7 +1061,7 @@ static void wait_until_sent(struct tty_struct *tty, int timeout)
        if (sanity_check(info, tty->name, "wait_until_sent"))
                return;
 
-       if (!test_bit(ASYNCB_INITIALIZED, &info->port.flags))
+       if (!tty_port_initialized(&info->port))
                goto exit;
 
        orig_jiffies = jiffies;
@@ -1261,7 +1261,7 @@ static int ioctl(struct tty_struct *tty,
 
        if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
            (cmd != TIOCMIWAIT)) {
-               if (tty->flags & (1 << TTY_IO_ERROR))
+               if (tty_io_error(tty))
                    return -EIO;
        }
 
@@ -2463,7 +2463,7 @@ static void isr_io_pin( SLMP_INFO *info, u16 status )
                wake_up_interruptible(&info->status_event_wait_q);
                wake_up_interruptible(&info->event_wait_q);
 
-               if ( (info->port.flags & ASYNC_CHECK_CD) &&
+               if (tty_port_check_carrier(&info->port) &&
                     (status & MISCSTATUS_DCD_LATCHED) ) {
                        if ( debug_level >= DEBUG_LEVEL_ISR )
                                printk("%s CD now %s...", info->device_name,
@@ -2636,7 +2636,7 @@ static int startup(SLMP_INFO * info)
        if ( debug_level >= DEBUG_LEVEL_INFO )
                printk("%s(%d):%s tx_releaseup()\n",__FILE__,__LINE__,info->device_name);
 
-       if (info->port.flags & ASYNC_INITIALIZED)
+       if (tty_port_initialized(&info->port))
                return 0;
 
        if (!info->tx_buf) {
@@ -2662,7 +2662,7 @@ static int startup(SLMP_INFO * info)
        if (info->port.tty)
                clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
 
-       info->port.flags |= ASYNC_INITIALIZED;
+       tty_port_set_initialized(&info->port, 1);
 
        return 0;
 }
@@ -2673,7 +2673,7 @@ static void shutdown(SLMP_INFO * info)
 {
        unsigned long flags;
 
-       if (!(info->port.flags & ASYNC_INITIALIZED))
+       if (!tty_port_initialized(&info->port))
                return;
 
        if (debug_level >= DEBUG_LEVEL_INFO)
@@ -2705,7 +2705,7 @@ static void shutdown(SLMP_INFO * info)
        if (info->port.tty)
                set_bit(TTY_IO_ERROR, &info->port.tty->flags);
 
-       info->port.flags &= ~ASYNC_INITIALIZED;
+       tty_port_set_initialized(&info->port, 0);
 }
 
 static void program_hw(SLMP_INFO *info)
@@ -2813,15 +2813,8 @@ static void change_params(SLMP_INFO *info)
        }
        info->timeout += HZ/50;         /* Add .02 seconds of slop */
 
-       if (cflag & CRTSCTS)
-               info->port.flags |= ASYNC_CTS_FLOW;
-       else
-               info->port.flags &= ~ASYNC_CTS_FLOW;
-
-       if (cflag & CLOCAL)
-               info->port.flags &= ~ASYNC_CHECK_CD;
-       else
-               info->port.flags |= ASYNC_CHECK_CD;
+       tty_port_set_cts_flow(&info->port, cflag & CRTSCTS);
+       tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL);
 
        /* process tty input control flags */
 
@@ -3285,10 +3278,10 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
                printk("%s(%d):%s block_til_ready()\n",
                         __FILE__,__LINE__, tty->driver->name );
 
-       if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
+       if (filp->f_flags & O_NONBLOCK || tty_io_error(tty)) {
                /* nonblock mode is set or port is not enabled */
                /* just verify that callout device is not active */
-               port->flags |= ASYNC_NORMAL_ACTIVE;
+               tty_port_set_active(port, 1);
                return 0;
        }
 
@@ -3315,12 +3308,12 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
        port->blocked_open++;
 
        while (1) {
-               if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags))
+               if (C_BAUD(tty) && tty_port_initialized(port))
                        tty_port_raise_dtr_rts(port);
 
                set_current_state(TASK_INTERRUPTIBLE);
 
-               if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)){
+               if (tty_hung_up_p(filp) || !tty_port_initialized(port)) {
                        retval = (port->flags & ASYNC_HUP_NOTIFY) ?
                                        -EAGAIN : -ERESTARTSYS;
                        break;
@@ -3355,7 +3348,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
                         __FILE__,__LINE__, tty->driver->name, port->count );
 
        if (!retval)
-               port->flags |= ASYNC_NORMAL_ACTIVE;
+               tty_port_set_active(port, 1);
 
        return retval;
 }
index a946e49..aa80dc9 100644 (file)
 
 #define TTY_BUFFER_PAGE        (((PAGE_SIZE - sizeof(struct tty_buffer)) / 2) & ~0xFF)
 
-/*
- * If all tty flip buffers have been processed by flush_to_ldisc() or
- * dropped by tty_buffer_flush(), check if the linked pty has been closed.
- * If so, wake the reader/poll to process
- */
-static inline void check_other_closed(struct tty_struct *tty)
-{
-       unsigned long flags, old;
-
-       /* transition from TTY_OTHER_CLOSED => TTY_OTHER_DONE must be atomic */
-       for (flags = ACCESS_ONCE(tty->flags);
-            test_bit(TTY_OTHER_CLOSED, &flags);
-            ) {
-               old = flags;
-               __set_bit(TTY_OTHER_DONE, &flags);
-               flags = cmpxchg(&tty->flags, old, flags);
-               if (old == flags) {
-                       wake_up_interruptible(&tty->read_wait);
-                       break;
-               }
-       }
-}
-
 /**
  *     tty_buffer_lock_exclusive       -       gain exclusive access to buffer
  *     tty_buffer_unlock_exclusive     -       release exclusive access
@@ -254,8 +231,6 @@ void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld)
        if (ld && ld->ops->flush_buffer)
                ld->ops->flush_buffer(tty);
 
-       check_other_closed(tty);
-
        atomic_dec(&buf->priority);
        mutex_unlock(&buf->lock);
 }
@@ -522,10 +497,8 @@ static void flush_to_ldisc(struct work_struct *work)
                 */
                count = smp_load_acquire(&head->commit) - head->read;
                if (!count) {
-                       if (next == NULL) {
-                               check_other_closed(tty);
+                       if (next == NULL)
                                break;
-                       }
                        buf->head = next;
                        tty_buffer_free(port, head);
                        continue;
@@ -614,3 +587,8 @@ bool tty_buffer_cancel_work(struct tty_port *port)
 {
        return cancel_work_sync(&port->buf.work);
 }
+
+void tty_buffer_flush_work(struct tty_port *port)
+{
+       flush_work(&port->buf.work);
+}
index 24d5491..734a635 100644 (file)
@@ -230,9 +230,6 @@ static void tty_del_file(struct file *file)
        tty_free_file(file);
 }
 
-
-#define TTY_NUMBER(tty) ((tty)->index + (tty)->driver->name_base)
-
 /**
  *     tty_name        -       return tty naming
  *     @tty: tty structure
@@ -1070,7 +1067,7 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
 
        if (tty_paranoia_check(tty, inode, "tty_read"))
                return -EIO;
-       if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))
+       if (!tty || tty_io_error(tty))
                return -EIO;
 
        /* We want to wait for the line discipline to sort out in this
@@ -1245,8 +1242,7 @@ static ssize_t tty_write(struct file *file, const char __user *buf,
 
        if (tty_paranoia_check(tty, file_inode(file), "tty_write"))
                return -EIO;
-       if (!tty || !tty->ops->write ||
-               (test_bit(TTY_IO_ERROR, &tty->flags)))
+       if (!tty || !tty->ops->write || tty_io_error(tty))
                        return -EIO;
        /* Short term debug to catch buggy drivers */
        if (tty->ops->write_room == NULL)
@@ -1964,7 +1960,6 @@ static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp)
  *     tty_lookup_driver - lookup a tty driver for a given device file
  *     @device: device number
  *     @filp: file pointer to tty
- *     @noctty: set if the device should not become a controlling tty
  *     @index: index for the device in the @return driver
  *     @return: driver for this inode (with increased refcount)
  *
index 23bf5bb..bf36ac9 100644 (file)
@@ -158,7 +158,7 @@ int tty_throttle_safe(struct tty_struct *tty)
        int ret = 0;
 
        mutex_lock(&tty->throttle_mutex);
-       if (!test_bit(TTY_THROTTLED, &tty->flags)) {
+       if (!tty_throttled(tty)) {
                if (tty->flow_change != TTY_THROTTLE_SAFE)
                        ret = 1;
                else {
@@ -189,7 +189,7 @@ int tty_unthrottle_safe(struct tty_struct *tty)
        int ret = 0;
 
        mutex_lock(&tty->throttle_mutex);
-       if (test_bit(TTY_THROTTLED, &tty->flags)) {
+       if (tty_throttled(tty)) {
                if (tty->flow_change != TTY_UNTHROTTLE_SAFE)
                        ret = 1;
                else {
index dbcca30..c3f9d93 100644 (file)
@@ -204,7 +204,8 @@ static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty)
        if (port->console)
                goto out;
 
-       if (test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags)) {
+       if (tty_port_initialized(port)) {
+               tty_port_set_initialized(port, 0);
                /*
                 * Drop DTR/RTS if HUPCL is set. This causes any attached
                 * modem to hang up the line.
@@ -236,12 +237,12 @@ void tty_port_hangup(struct tty_port *port)
 
        spin_lock_irqsave(&port->lock, flags);
        port->count = 0;
-       port->flags &= ~ASYNC_NORMAL_ACTIVE;
        tty = port->tty;
        if (tty)
                set_bit(TTY_IO_ERROR, &tty->flags);
        port->tty = NULL;
        spin_unlock_irqrestore(&port->lock, flags);
+       tty_port_set_active(port, 0);
        tty_port_shutdown(port, tty);
        tty_kref_put(tty);
        wake_up_interruptible(&port->open_wait);
@@ -364,15 +365,15 @@ int tty_port_block_til_ready(struct tty_port *port,
 
        /* if non-blocking mode is set we can pass directly to open unless
           the port has just hung up or is in another error state */
-       if (tty->flags & (1 << TTY_IO_ERROR)) {
-               port->flags |= ASYNC_NORMAL_ACTIVE;
+       if (tty_io_error(tty)) {
+               tty_port_set_active(port, 1);
                return 0;
        }
        if (filp->f_flags & O_NONBLOCK) {
                /* Indicate we are open */
                if (C_BAUD(tty))
                        tty_port_raise_dtr_rts(port);
-               port->flags |= ASYNC_NORMAL_ACTIVE;
+               tty_port_set_active(port, 1);
                return 0;
        }
 
@@ -393,13 +394,13 @@ int tty_port_block_til_ready(struct tty_port *port,
 
        while (1) {
                /* Indicate we are open */
-               if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags))
+               if (C_BAUD(tty) && tty_port_initialized(port))
                        tty_port_raise_dtr_rts(port);
 
                prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
                /* Check for a hangup or uninitialised port.
                                                        Return accordingly */
-               if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
+               if (tty_hung_up_p(filp) || !tty_port_initialized(port)) {
                        if (port->flags & ASYNC_HUP_NOTIFY)
                                retval = -EAGAIN;
                        else
@@ -430,9 +431,9 @@ int tty_port_block_til_ready(struct tty_port *port,
        if (!tty_hung_up_p(filp))
                port->count++;
        port->blocked_open--;
-       if (retval == 0)
-               port->flags |= ASYNC_NORMAL_ACTIVE;
        spin_unlock_irqrestore(&port->lock, flags);
+       if (retval == 0)
+               tty_port_set_active(port, 1);
        return retval;
 }
 EXPORT_SYMBOL(tty_port_block_til_ready);
@@ -480,7 +481,7 @@ int tty_port_close_start(struct tty_port *port,
 
        tty->closing = 1;
 
-       if (test_bit(ASYNCB_INITIALIZED, &port->flags)) {
+       if (tty_port_initialized(port)) {
                /* Don't block on a stalled port, just pull the chain */
                if (tty->flow_stopped)
                        tty_driver_flush_buffer(tty);
@@ -514,8 +515,8 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
                spin_lock_irqsave(&port->lock, flags);
                wake_up_interruptible(&port->open_wait);
        }
-       port->flags &= ~ASYNC_NORMAL_ACTIVE;
        spin_unlock_irqrestore(&port->lock, flags);
+       tty_port_set_active(port, 0);
 }
 EXPORT_SYMBOL(tty_port_close_end);
 
@@ -578,7 +579,7 @@ int tty_port_open(struct tty_port *port, struct tty_struct *tty,
 
        mutex_lock(&port->mutex);
 
-       if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) {
+       if (!tty_port_initialized(port)) {
                clear_bit(TTY_IO_ERROR, &tty->flags);
                if (port->ops->activate) {
                        int retval = port->ops->activate(port, tty);
@@ -587,7 +588,7 @@ int tty_port_open(struct tty_port *port, struct tty_struct *tty,
                                return retval;
                        }
                }
-               set_bit(ASYNCB_INITIALIZED, &port->flags);
+               tty_port_set_initialized(port, 1);
        }
        mutex_unlock(&port->mutex);
        return tty_port_block_til_ready(port, tty, filp);
index 4dd9dd2..368ce18 100644 (file)
@@ -354,7 +354,7 @@ int paste_selection(struct tty_struct *tty)
        add_wait_queue(&vc->paste_wait, &wait);
        while (sel_buffer && sel_buffer_lth > pasted) {
                set_current_state(TASK_INTERRUPTIBLE);
-               if (test_bit(TTY_THROTTLED, &tty->flags)) {
+               if (tty_throttled(tty)) {
                        schedule();
                        continue;
                }
index 3e3c757..dc12532 100644 (file)
@@ -760,50 +760,54 @@ static void visual_init(struct vc_data *vc, int num, int init)
 
 int vc_allocate(unsigned int currcons) /* return 0 on success */
 {
+       struct vt_notifier_param param;
+       struct vc_data *vc;
+
        WARN_CONSOLE_UNLOCKED();
 
        if (currcons >= MAX_NR_CONSOLES)
                return -ENXIO;
-       if (!vc_cons[currcons].d) {
-           struct vc_data *vc;
-           struct vt_notifier_param param;
-
-           /* prevent users from taking too much memory */
-           if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE))
-             return -EPERM;
-
-           /* due to the granularity of kmalloc, we waste some memory here */
-           /* the alloc is done in two steps, to optimize the common situation
-              of a 25x80 console (structsize=216, screenbuf_size=4000) */
-           /* although the numbers above are not valid since long ago, the
-              point is still up-to-date and the comment still has its value
-              even if only as a historical artifact.  --mj, July 1998 */
-           param.vc = vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL);
-           if (!vc)
+
+       if (vc_cons[currcons].d)
+               return 0;
+
+       /* due to the granularity of kmalloc, we waste some memory here */
+       /* the alloc is done in two steps, to optimize the common situation
+          of a 25x80 console (structsize=216, screenbuf_size=4000) */
+       /* although the numbers above are not valid since long ago, the
+          point is still up-to-date and the comment still has its value
+          even if only as a historical artifact.  --mj, July 1998 */
+       param.vc = vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL);
+       if (!vc)
                return -ENOMEM;
-           vc_cons[currcons].d = vc;
-           tty_port_init(&vc->port);
-           INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
-           visual_init(vc, currcons, 1);
-           if (!*vc->vc_uni_pagedir_loc)
+
+       vc_cons[currcons].d = vc;
+       tty_port_init(&vc->port);
+       INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
+
+       visual_init(vc, currcons, 1);
+
+       if (!*vc->vc_uni_pagedir_loc)
                con_set_default_unimap(vc);
-           vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
-           if (!vc->vc_screenbuf) {
-               kfree(vc);
-               vc_cons[currcons].d = NULL;
-               return -ENOMEM;
-           }
 
-           /* If no drivers have overridden us and the user didn't pass a
-              boot option, default to displaying the cursor */
-           if (global_cursor_default == -1)
-                   global_cursor_default = 1;
+       vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
+       if (!vc->vc_screenbuf)
+               goto err_free;
+
+       /* If no drivers have overridden us and the user didn't pass a
+          boot option, default to displaying the cursor */
+       if (global_cursor_default == -1)
+               global_cursor_default = 1;
+
+       vc_init(vc, vc->vc_rows, vc->vc_cols, 1);
+       vcs_make_sysfs(currcons);
+       atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, &param);
 
-           vc_init(vc, vc->vc_rows, vc->vc_cols, 1);
-           vcs_make_sysfs(currcons);
-           atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, &param);
-       }
        return 0;
+err_free:
+       kfree(vc);
+       vc_cons[currcons].d = NULL;
+       return -ENOMEM;
 }
 
 static inline int resize_screen(struct vc_data *vc, int width, int height,
@@ -1035,20 +1039,27 @@ struct vc_data *vc_deallocate(unsigned int currcons)
 #define VT100ID "\033[?1;2c"
 #define VT102ID "\033[?6c"
 
-unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
+const unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
                                       8,12,10,14, 9,13,11,15 };
 
 /* the default colour table, for VGA+ colour systems */
-int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa,
-    0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff};
-int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa,
-    0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff};
-int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,
-    0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff};
+unsigned char default_red[] = {
+       0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa,
+       0x55, 0xff, 0x55, 0xff, 0x55, 0xff, 0x55, 0xff
+};
+module_param_array(default_red, byte, NULL, S_IRUGO | S_IWUSR);
 
-module_param_array(default_red, int, NULL, S_IRUGO | S_IWUSR);
-module_param_array(default_grn, int, NULL, S_IRUGO | S_IWUSR);
-module_param_array(default_blu, int, NULL, S_IRUGO | S_IWUSR);
+unsigned char default_grn[] = {
+       0x00, 0x00, 0xaa, 0x55, 0x00, 0x00, 0xaa, 0xaa,
+       0x55, 0x55, 0xff, 0xff, 0x55, 0x55, 0xff, 0xff
+};
+module_param_array(default_grn, byte, NULL, S_IRUGO | S_IWUSR);
+
+unsigned char default_blu[] = {
+       0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa,
+       0x55, 0x55, 0x55, 0x55, 0xff, 0xff, 0xff, 0xff
+};
+module_param_array(default_blu, byte, NULL, S_IRUGO | S_IWUSR);
 
 /*
  * gotoxy() must verify all boundaries, because the arguments
@@ -3564,7 +3575,7 @@ static int do_register_con_driver(const struct consw *csw, int first, int last)
        struct module *owner = csw->owner;
        struct con_driver *con_driver;
        const char *desc;
-       int i, retval = 0;
+       int i, retval;
 
        WARN_CONSOLE_UNLOCKED();
 
@@ -3575,17 +3586,17 @@ static int do_register_con_driver(const struct consw *csw, int first, int last)
                con_driver = &registered_con_driver[i];
 
                /* already registered */
-               if (con_driver->con == csw)
+               if (con_driver->con == csw) {
                        retval = -EBUSY;
+                       goto err;
+               }
        }
 
-       if (retval)
-               goto err;
-
        desc = csw->con_startup();
-
-       if (!desc)
+       if (!desc) {
+               retval = -ENODEV;
                goto err;
+       }
 
        retval = -EINVAL;
 
index a6c4a1b..94a14f5 100644 (file)
@@ -1680,7 +1680,7 @@ static int acm_resume(struct usb_interface *intf)
        if (--acm->susp_count)
                goto out;
 
-       if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) {
+       if (tty_port_initialized(&acm->port)) {
                rv = usb_submit_urb(acm->ctrlurb, GFP_ATOMIC);
 
                for (;;) {
@@ -1710,7 +1710,7 @@ static int acm_reset_resume(struct usb_interface *intf)
 {
        struct acm *acm = usb_get_intfdata(intf);
 
-       if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags))
+       if (tty_port_initialized(&acm->port))
                tty_port_tty_hangup(&acm->port, false);
 
        return acm_resume(intf);
index 6af145f..3580f19 100644 (file)
@@ -512,7 +512,7 @@ static void gs_rx_push(unsigned long _port)
                req = list_first_entry(queue, struct usb_request, list);
 
                /* leave data queued if tty was rx throttled */
-               if (tty && test_bit(TTY_THROTTLED, &tty->flags))
+               if (tty && tty_throttled(tty))
                        break;
 
                switch (req->status) {
@@ -579,7 +579,7 @@ static void gs_rx_push(unsigned long _port)
         * from starving ... but it's not clear that case ever happens.
         */
        if (!list_empty(queue) && tty) {
-               if (!test_bit(TTY_THROTTLED, &tty->flags)) {
+               if (!tty_throttled(tty)) {
                        if (do_push)
                                tasklet_schedule(&port->push);
                        else
index ace3430..afa8532 100644 (file)
@@ -601,7 +601,7 @@ sisusbcon_save_screen(struct vc_data *c)
 
 /* interface routine */
 static int
-sisusbcon_set_palette(struct vc_data *c, unsigned char *table)
+sisusbcon_set_palette(struct vc_data *c, const unsigned char *table)
 {
        struct sisusb_usb_data *sisusb;
        int i, j;
index a66b01b..8967715 100644 (file)
@@ -127,7 +127,7 @@ static int usb_console_setup(struct console *co, char *options)
        info->port = port;
 
        ++port->port.count;
-       if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) {
+       if (!tty_port_initialized(&port->port)) {
                if (serial->type->set_termios) {
                        /*
                         * allocate a fake tty so the driver can initialize
@@ -168,7 +168,7 @@ static int usb_console_setup(struct console *co, char *options)
                        tty_port_tty_set(&port->port, NULL);
                        tty_kref_put(tty);
                }
-               set_bit(ASYNCB_INITIALIZED, &port->port.flags);
+               tty_port_set_initialized(&port->port, 1);
        }
        /* Now that any required fake tty operations are completed restore
         * the tty port count */
index 16e8e37..6a1df9e 100644 (file)
@@ -699,8 +699,7 @@ static void digi_set_termios(struct tty_struct *tty,
                        /* don't set RTS if using hardware flow control */
                        /* and throttling input */
                        modem_signals = TIOCM_DTR;
-                       if (!C_CRTSCTS(tty) ||
-                           !test_bit(TTY_THROTTLED, &tty->flags))
+                       if (!C_CRTSCTS(tty) || !tty_throttled(tty))
                                modem_signals |= TIOCM_RTS;
                        digi_set_modem_signals(port, modem_signals, 1);
                }
index 54e170d..ae8c036 100644 (file)
@@ -473,7 +473,7 @@ static bool usb_serial_generic_msr_changed(struct tty_struct *tty,
         * Use tty-port initialised flag to detect all hangups including the
         * one generated at USB-device disconnect.
         */
-       if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
+       if (!tty_port_initialized(&port->port))
                return true;
 
        spin_lock_irqsave(&port->lock, flags);
@@ -503,7 +503,7 @@ int usb_serial_generic_tiocmiwait(struct tty_struct *tty, unsigned long arg)
 
        ret = wait_event_interruptible(port->port.delta_msr_wait,
                        usb_serial_generic_msr_changed(tty, arg, &cnow));
-       if (!ret && !test_bit(ASYNCB_INITIALIZED, &port->port.flags))
+       if (!ret && !tty_port_initialized(&port->port))
                ret = -EIO;
 
        return ret;
@@ -606,7 +606,7 @@ int usb_serial_generic_resume(struct usb_serial *serial)
 
        for (i = 0; i < serial->num_ports; i++) {
                port = serial->port[i];
-               if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
+               if (!tty_port_initialized(&port->port))
                        continue;
 
                if (port->bulk_in_size) {
index 31a8b47..3722d6c 100644 (file)
@@ -503,7 +503,7 @@ static void mxuport_process_read_urb_demux_data(struct urb *urb)
                        return;
                }
 
-               if (test_bit(ASYNCB_INITIALIZED, &demux_port->port.flags)) {
+               if (tty_port_initialized(&demux_port->port)) {
                        ch = data + HEADER_SIZE;
                        mxuport_process_read_urb_data(demux_port, ch, rcv_len);
                } else {
@@ -544,7 +544,7 @@ static void mxuport_process_read_urb_demux_event(struct urb *urb)
                }
 
                demux_port = serial->port[rcv_port];
-               if (test_bit(ASYNCB_INITIALIZED, &demux_port->port.flags)) {
+               if (tty_port_initialized(&demux_port->port)) {
                        ch = data + HEADER_SIZE;
                        rcv_event = get_unaligned_be16(data + 2);
                        mxuport_process_read_urb_event(demux_port, ch,
@@ -1339,7 +1339,7 @@ static int mxuport_resume(struct usb_serial *serial)
 
        for (i = 0; i < serial->num_ports; i++) {
                port = serial->port[i];
-               if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
+               if (!tty_port_initialized(&port->port))
                        continue;
 
                r = usb_serial_generic_write_start(port, GFP_NOIO);
index 07d1ecd..e1994e2 100644 (file)
@@ -776,7 +776,7 @@ static void sierra_close(struct usb_serial_port *port)
 
        /*
         * Need to take susp_lock to make sure port is not already being
-        * resumed, but no need to hold it due to ASYNC_INITIALIZED.
+        * resumed, but no need to hold it due to initialized
         */
        spin_lock_irq(&intfdata->susp_lock);
        if (--intfdata->open_ports == 0)
@@ -1039,7 +1039,7 @@ static int sierra_resume(struct usb_serial *serial)
        for (i = 0; i < serial->num_ports; i++) {
                port = serial->port[i];
 
-               if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
+               if (!tty_port_initialized(&port->port))
                        continue;
 
                err = sierra_submit_delayed_urbs(port);
index 46f1f13..3f253ae 100644 (file)
@@ -254,7 +254,7 @@ static int serial_open(struct tty_struct *tty, struct file *filp)
  *
  * Shut down a USB serial port. Serialized against activate by the
  * tport mutex and kept to matching open/close pairs
- * of calls by the ASYNCB_INITIALIZED flag.
+ * of calls by the initialized flag.
  *
  * Not called if tty is console.
  */
index be9cb61..3dfdfc8 100644 (file)
@@ -464,7 +464,7 @@ void usb_wwan_close(struct usb_serial_port *port)
 
        /*
         * Need to take susp_lock to make sure port is not already being
-        * resumed, but no need to hold it due to ASYNC_INITIALIZED.
+        * resumed, but no need to hold it due to initialized
         */
        spin_lock_irq(&intfdata->susp_lock);
        if (--intfdata->open_ports == 0)
@@ -682,7 +682,7 @@ int usb_wwan_resume(struct usb_serial *serial)
        for (i = 0; i < serial->num_ports; i++) {
                port = serial->port[i];
 
-               if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
+               if (!tty_port_initialized(&port->port))
                        continue;
 
                portdata = usb_get_serial_port_data(port);
index 6e92917..afd3301 100644 (file)
@@ -170,7 +170,7 @@ static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx,
                        int height, int width);
 static int fbcon_switch(struct vc_data *vc);
 static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch);
-static int fbcon_set_palette(struct vc_data *vc, unsigned char *table);
+static int fbcon_set_palette(struct vc_data *vc, const unsigned char *table);
 static int fbcon_scrolldelta(struct vc_data *vc, int lines);
 
 /*
@@ -2652,7 +2652,7 @@ static struct fb_cmap palette_cmap = {
        0, 16, palette_red, palette_green, palette_blue, NULL
 };
 
-static int fbcon_set_palette(struct vc_data *vc, unsigned char *table)
+static int fbcon_set_palette(struct vc_data *vc, const unsigned char *table)
 {
        struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
        int i, j, k, depth;
index 296e945..8edc062 100644 (file)
@@ -481,7 +481,7 @@ static int mdacon_switch(struct vc_data *c)
        return 1;       /* redrawing needed */
 }
 
-static int mdacon_set_palette(struct vc_data *c, unsigned char *table)
+static int mdacon_set_palette(struct vc_data *c, const unsigned char *table)
 {
        return -EINVAL;
 }
index bb4e962..0553dfe 100644 (file)
@@ -574,7 +574,7 @@ static int newport_font_set(struct vc_data *vc, struct console_font *font, unsig
        return newport_set_font(vc->vc_num, font);
 }
 
-static int newport_set_palette(struct vc_data *vc, unsigned char *table)
+static int newport_set_palette(struct vc_data *vc, const unsigned char *table)
 {
        return -EINVAL;
 }
index 026fd12..e440c2d 100644 (file)
@@ -79,7 +79,7 @@ static const char *sticon_startup(void)
     return "STI console";
 }
 
-static int sticon_set_palette(struct vc_data *c, unsigned char *table)
+static int sticon_set_palette(struct vc_data *c, const unsigned char *table)
 {
     return -EINVAL;
 }
index 517f565..8bf9110 100644 (file)
@@ -80,7 +80,6 @@ static void vgacon_deinit(struct vc_data *c);
 static void vgacon_cursor(struct vc_data *c, int mode);
 static int vgacon_switch(struct vc_data *c);
 static int vgacon_blank(struct vc_data *c, int blank, int mode_switch);
-static int vgacon_set_palette(struct vc_data *vc, unsigned char *table);
 static int vgacon_scrolldelta(struct vc_data *c, int lines);
 static int vgacon_set_origin(struct vc_data *c);
 static void vgacon_save_screen(struct vc_data *c);
@@ -847,7 +846,7 @@ static int vgacon_switch(struct vc_data *c)
        return 0;               /* Redrawing not needed */
 }
 
-static void vga_set_palette(struct vc_data *vc, unsigned char *table)
+static void vga_set_palette(struct vc_data *vc, const unsigned char *table)
 {
        int i, j;
 
@@ -860,7 +859,7 @@ static void vga_set_palette(struct vc_data *vc, unsigned char *table)
        }
 }
 
-static int vgacon_set_palette(struct vc_data *vc, unsigned char *table)
+static int vgacon_set_palette(struct vc_data *vc, const unsigned char *table)
 {
 #ifdef CAN_LOAD_PALETTE
        if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked
index ea731af..137ac1a 100644 (file)
@@ -47,7 +47,7 @@ struct consw {
        int     (*con_font_copy)(struct vc_data *, int);
        int     (*con_resize)(struct vc_data *, unsigned int, unsigned int,
                               unsigned int);
-       int     (*con_set_palette)(struct vc_data *, unsigned char *);
+       int     (*con_set_palette)(struct vc_data *, const unsigned char *);
        int     (*con_scrolldelta)(struct vc_data *, int);
        int     (*con_set_origin)(struct vc_data *);
        void    (*con_save_screen)(struct vc_data *);
index 85193aa..8e4624e 100644 (file)
@@ -24,10 +24,10 @@ extern void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry);
 
 extern int console_blanked;
 
-extern unsigned char color_table[];
-extern int default_red[];
-extern int default_grn[];
-extern int default_blu[];
+extern const unsigned char color_table[];
+extern unsigned char default_red[];
+extern unsigned char default_grn[];
+extern unsigned char default_blu[];
 
 extern unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed);
 extern u16 screen_glyph(struct vc_data *vc, int offset);
index 4348797..48ec765 100644 (file)
@@ -36,6 +36,7 @@ struct plat_serial8250_port {
        void            (*set_termios)(struct uart_port *,
                                       struct ktermios *new,
                                       struct ktermios *old);
+       unsigned int    (*get_mctrl)(struct uart_port *);
        int             (*handle_irq)(struct uart_port *);
        void            (*pm)(struct uart_port *, unsigned int state,
                              unsigned old);
@@ -148,6 +149,7 @@ extern int early_serial8250_setup(struct earlycon_device *device,
                                         const char *options);
 extern void serial8250_do_set_termios(struct uart_port *port,
                struct ktermios *termios, struct ktermios *old);
+extern unsigned int serial8250_do_get_mctrl(struct uart_port *port);
 extern int serial8250_do_startup(struct uart_port *port);
 extern void serial8250_do_shutdown(struct uart_port *port);
 extern void serial8250_do_pm(struct uart_port *port, unsigned int state,
index cbfcf38..a3d7c0d 100644 (file)
@@ -123,6 +123,7 @@ struct uart_port {
        void                    (*set_termios)(struct uart_port *,
                                               struct ktermios *new,
                                               struct ktermios *old);
+       unsigned int            (*get_mctrl)(struct uart_port *);
        void                    (*set_mctrl)(struct uart_port *, unsigned int);
        int                     (*startup)(struct uart_port *port);
        void                    (*shutdown)(struct uart_port *port);
@@ -281,6 +282,8 @@ struct uart_state {
        enum uart_pm_state      pm_state;
        struct circ_buf         xmit;
 
+       atomic_t                refcount;
+       wait_queue_head_t       remove_wait;
        struct uart_port        *uart_port;
 };
 
index 17b247c..40144f3 100644 (file)
@@ -228,7 +228,8 @@ struct tty_port {
        int                     count;          /* Usage count */
        wait_queue_head_t       open_wait;      /* Open waiters */
        wait_queue_head_t       delta_msr_wait; /* Modem status change */
-       unsigned long           flags;          /* TTY flags ASY_*/
+       unsigned long           flags;          /* User TTY flags ASYNC_ */
+       unsigned long           iflags;         /* Internal flags TTY_PORT_ */
        unsigned char           console:1,      /* port is a console */
                                low_latency:1;  /* optional: tune for latency */
        struct mutex            mutex;          /* Locking */
@@ -242,6 +243,18 @@ struct tty_port {
        struct kref             kref;           /* Ref counter */
 };
 
+/* tty_port::iflags bits -- use atomic bit ops */
+#define TTY_PORT_INITIALIZED   0       /* device is initialized */
+#define TTY_PORT_SUSPENDED     1       /* device is suspended */
+#define TTY_PORT_ACTIVE                2       /* device is open */
+
+/*
+ * uart drivers: use the uart_port::status field and the UPSTAT_* defines
+ * for s/w-based flow control steering and carrier detection status
+ */
+#define TTY_PORT_CTS_FLOW      3       /* h/w flow control enabled */
+#define TTY_PORT_CHECK_CD      4       /* carrier detect enabled */
+
 /*
  * Where all of the state associated with a tty is kept while the tty
  * is open.  Since the termios state should be kept even if the tty
@@ -338,7 +351,6 @@ struct tty_file_private {
 #define TTY_OTHER_CLOSED       2       /* Other side (if any) has closed */
 #define TTY_EXCLUSIVE          3       /* Exclusive open mode */
 #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 */
 #define TTY_PTY_LOCK           16      /* pty private */
 #define TTY_NO_WRITE_SPLIT     17      /* Preserve write boundaries to driver */
@@ -360,6 +372,16 @@ static inline void tty_set_flow_change(struct tty_struct *tty, int val)
        smp_mb();
 }
 
+static inline bool tty_io_error(struct tty_struct *tty)
+{
+       return test_bit(TTY_IO_ERROR, &tty->flags);
+}
+
+static inline bool tty_throttled(struct tty_struct *tty)
+{
+       return test_bit(TTY_THROTTLED, &tty->flags);
+}
+
 #ifdef CONFIG_TTY
 extern void console_init(void);
 extern void tty_kref_put(struct tty_struct *tty);
@@ -459,6 +481,7 @@ extern void tty_buffer_init(struct tty_port *port);
 extern void tty_buffer_set_lock_subclass(struct tty_port *port);
 extern bool tty_buffer_restart_work(struct tty_port *port);
 extern bool tty_buffer_cancel_work(struct tty_port *port);
+extern void tty_buffer_flush_work(struct tty_port *port);
 extern speed_t tty_termios_baud_rate(struct ktermios *termios);
 extern speed_t tty_termios_input_baud_rate(struct ktermios *termios);
 extern void tty_termios_encode_baud_rate(struct ktermios *termios,
@@ -539,7 +562,67 @@ static inline struct tty_port *tty_port_get(struct tty_port *port)
 /* If the cts flow control is enabled, return true. */
 static inline bool tty_port_cts_enabled(struct tty_port *port)
 {
-       return port->flags & ASYNC_CTS_FLOW;
+       return test_bit(TTY_PORT_CTS_FLOW, &port->iflags);
+}
+
+static inline void tty_port_set_cts_flow(struct tty_port *port, bool val)
+{
+       if (val)
+               set_bit(TTY_PORT_CTS_FLOW, &port->iflags);
+       else
+               clear_bit(TTY_PORT_CTS_FLOW, &port->iflags);
+}
+
+static inline bool tty_port_active(struct tty_port *port)
+{
+       return test_bit(TTY_PORT_ACTIVE, &port->iflags);
+}
+
+static inline void tty_port_set_active(struct tty_port *port, bool val)
+{
+       if (val)
+               set_bit(TTY_PORT_ACTIVE, &port->iflags);
+       else
+               clear_bit(TTY_PORT_ACTIVE, &port->iflags);
+}
+
+static inline bool tty_port_check_carrier(struct tty_port *port)
+{
+       return test_bit(TTY_PORT_CHECK_CD, &port->iflags);
+}
+
+static inline void tty_port_set_check_carrier(struct tty_port *port, bool val)
+{
+       if (val)
+               set_bit(TTY_PORT_CHECK_CD, &port->iflags);
+       else
+               clear_bit(TTY_PORT_CHECK_CD, &port->iflags);
+}
+
+static inline bool tty_port_suspended(struct tty_port *port)
+{
+       return test_bit(TTY_PORT_SUSPENDED, &port->iflags);
+}
+
+static inline void tty_port_set_suspended(struct tty_port *port, bool val)
+{
+       if (val)
+               set_bit(TTY_PORT_SUSPENDED, &port->iflags);
+       else
+               clear_bit(TTY_PORT_SUSPENDED, &port->iflags);
+}
+
+static inline bool tty_port_initialized(struct tty_port *port)
+{
+       return test_bit(TTY_PORT_INITIALIZED, &port->iflags);
+}
+
+static inline void tty_port_set_initialized(struct tty_port *port, bool val)
+{
+       if (val)
+               set_bit(TTY_PORT_INITIALIZED, &port->iflags);
+       else
+               clear_bit(TTY_PORT_INITIALIZED, &port->iflags);
 }
 
 extern struct tty_struct *tty_port_tty_get(struct tty_port *port);
index 24da334..99dbed8 100644 (file)
 /* Microchip PIC32 UART */
 #define PORT_PIC32     115
 
+/* MPS2 UART */
+#define PORT_MPS2UART  116
+
 #endif /* _UAPILINUX_SERIAL_CORE_H */
index 072e41e..66e4d8b 100644 (file)
 #define ASYNCB_MAGIC_MULTIPLIER        16 /* Use special CLK or divisor */
 #define ASYNCB_LAST_USER       16
 
-/* Internal flags used only by kernel */
+/*
+ * Internal flags used only by kernel (read-only)
+ *
+ * WARNING: These flags are no longer used and have been superceded by the
+ *         TTY_PORT_ flags in the iflags field (and not userspace-visible)
+ */
+#ifndef _KERNEL_
 #define ASYNCB_INITIALIZED     31 /* Serial port was initialized */
 #define ASYNCB_SUSPENDED       30 /* Serial port is suspended */
 #define ASYNCB_NORMAL_ACTIVE   29 /* Normal device is active */
@@ -43,7 +49,9 @@
 #define ASYNCB_SHARE_IRQ       24 /* for multifunction cards, no longer used */
 #define ASYNCB_CONS_FLOW       23 /* flow control for console  */
 #define ASYNCB_FIRST_KERNEL    22
+#endif
 
+/* Masks */
 #define ASYNC_HUP_NOTIFY       (1U << ASYNCB_HUP_NOTIFY)
 #define ASYNC_SUSPENDED                (1U << ASYNCB_SUSPENDED)
 #define ASYNC_FOURPORT         (1U << ASYNCB_FOURPORT)
@@ -72,6 +80,8 @@
 #define ASYNC_SPD_WARP         (ASYNC_SPD_HI|ASYNC_SPD_SHI)
 #define ASYNC_SPD_MASK         (ASYNC_SPD_HI|ASYNC_SPD_VHI|ASYNC_SPD_SHI)
 
+#ifndef _KERNEL_
+/* These flags are no longer used (and were always masked from userspace) */
 #define ASYNC_INITIALIZED      (1U << ASYNCB_INITIALIZED)
 #define ASYNC_NORMAL_ACTIVE    (1U << ASYNCB_NORMAL_ACTIVE)
 #define ASYNC_BOOT_AUTOCONF    (1U << ASYNCB_BOOT_AUTOCONF)
@@ -81,5 +91,6 @@
 #define ASYNC_SHARE_IRQ                (1U << ASYNCB_SHARE_IRQ)
 #define ASYNC_CONS_FLOW                (1U << ASYNCB_CONS_FLOW)
 #define ASYNC_INTERNAL_FLAGS   (~((1U << ASYNCB_FIRST_KERNEL) - 1))
+#endif
 
 #endif
index 978578b..f690348 100644 (file)
@@ -8,7 +8,6 @@
  */
 #define MIN_NR_CONSOLES 1       /* must be at least 1 */
 #define MAX_NR_CONSOLES        63      /* serial lines start at 64 */
-#define MAX_NR_USER_CONSOLES 63        /* must be root to allocate above this */
                /* Note: the ioctl VT_GETSTATE does not work for
                   consoles 16 and higher (since it returns a short) */
 
index da126ee..873c4b7 100644 (file)
@@ -220,10 +220,11 @@ static int ircomm_tty_startup(struct ircomm_tty_cb *self)
        IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
        /* Check if already open */
-       if (test_and_set_bit(ASYNCB_INITIALIZED, &self->port.flags)) {
+       if (tty_port_initialized(&self->port)) {
                pr_debug("%s(), already open so break out!\n", __func__);
                return 0;
        }
+       tty_port_set_initialized(&self->port, 1);
 
        /* Register with IrCOMM */
        irda_notify_init(&notify);
@@ -257,7 +258,7 @@ static int ircomm_tty_startup(struct ircomm_tty_cb *self)
 
        return 0;
 err:
-       clear_bit(ASYNCB_INITIALIZED, &self->port.flags);
+       tty_port_set_initialized(&self->port, 0);
        return ret;
 }
 
@@ -280,8 +281,8 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
         * If non-blocking mode is set, or the port is not enabled,
         * then make the check up front and then exit.
         */
-       if (test_bit(TTY_IO_ERROR, &tty->flags)) {
-               port->flags |= ASYNC_NORMAL_ACTIVE;
+       if (tty_io_error(tty)) {
+               tty_port_set_active(port, 1);
                return 0;
        }
 
@@ -289,7 +290,7 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
                /* nonblock mode is set */
                if (C_BAUD(tty))
                        tty_port_raise_dtr_rts(port);
-               port->flags |= ASYNC_NORMAL_ACTIVE;
+               tty_port_set_active(port, 1);
                pr_debug("%s(), O_NONBLOCK requested!\n", __func__);
                return 0;
        }
@@ -318,13 +319,12 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
        spin_unlock_irqrestore(&port->lock, flags);
 
        while (1) {
-               if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags))
+               if (C_BAUD(tty) && tty_port_initialized(port))
                        tty_port_raise_dtr_rts(port);
 
                set_current_state(TASK_INTERRUPTIBLE);
 
-               if (tty_hung_up_p(filp) ||
-                   !test_bit(ASYNCB_INITIALIZED, &port->flags)) {
+               if (tty_hung_up_p(filp) || !tty_port_initialized(port)) {
                        retval = (port->flags & ASYNC_HUP_NOTIFY) ?
                                        -EAGAIN : -ERESTARTSYS;
                        break;
@@ -365,7 +365,7 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
                 __FILE__, __LINE__, tty->driver->name, port->count);
 
        if (!retval)
-               port->flags |= ASYNC_NORMAL_ACTIVE;
+               tty_port_set_active(port, 1);
 
        return retval;
 }
@@ -876,8 +876,9 @@ static void ircomm_tty_shutdown(struct ircomm_tty_cb *self)
        IRDA_ASSERT(self != NULL, return;);
        IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
-       if (!test_and_clear_bit(ASYNCB_INITIALIZED, &self->port.flags))
+       if (!tty_port_initialized(&self->port))
                return;
+       tty_port_set_initialized(&self->port, 0);
 
        ircomm_tty_detach_cable(self);
 
@@ -925,7 +926,6 @@ static void ircomm_tty_hangup(struct tty_struct *tty)
        ircomm_tty_shutdown(self);
 
        spin_lock_irqsave(&port->lock, flags);
-       port->flags &= ~ASYNC_NORMAL_ACTIVE;
        if (port->tty) {
                set_bit(TTY_IO_ERROR, &port->tty->flags);
                tty_kref_put(port->tty);
@@ -933,6 +933,7 @@ static void ircomm_tty_hangup(struct tty_struct *tty)
        port->tty = NULL;
        port->count = 0;
        spin_unlock_irqrestore(&port->lock, flags);
+       tty_port_set_active(port, 0);
 
        wake_up_interruptible(&port->open_wait);
 }
@@ -999,7 +1000,7 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self)
        if (status & IRCOMM_DCE_DELTA_ANY) {
                /*wake_up_interruptible(&self->delta_msr_wait);*/
        }
-       if ((self->port.flags & ASYNC_CHECK_CD) && (status & IRCOMM_DELTA_CD)) {
+       if (tty_port_check_carrier(&self->port) && (status & IRCOMM_DELTA_CD)) {
                pr_debug("%s(), ircomm%d CD now %s...\n", __func__ , self->line,
                         (status & IRCOMM_CD) ? "on" : "off");
 
@@ -1255,11 +1256,11 @@ static void ircomm_tty_line_info(struct ircomm_tty_cb *self, struct seq_file *m)
                seq_printf(m, "%cASYNC_CTS_FLOW", sep);
                sep = '|';
        }
-       if (self->port.flags & ASYNC_CHECK_CD) {
+       if (tty_port_check_carrier(&self->port)) {
                seq_printf(m, "%cASYNC_CHECK_CD", sep);
                sep = '|';
        }
-       if (self->port.flags & ASYNC_INITIALIZED) {
+       if (tty_port_initialized(&self->port)) {
                seq_printf(m, "%cASYNC_INITIALIZED", sep);
                sep = '|';
        }
@@ -1267,7 +1268,7 @@ 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_NORMAL_ACTIVE) {
+       if (tty_port_active(&self->port)) {
                seq_printf(m, "%cASYNC_NORMAL_ACTIVE", sep);
                sep = '|';
        }
index 61137f8..0a41101 100644 (file)
@@ -968,7 +968,7 @@ static int ircomm_tty_state_ready(struct ircomm_tty_cb *self,
                ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
                ircomm_tty_start_watchdog_timer(self, 3*HZ);
 
-               if (self->port.flags & ASYNC_CHECK_CD) {
+               if (tty_port_check_carrier(&self->port)) {
                        /* Drop carrier */
                        self->settings.dce = IRCOMM_DELTA_CD;
                        ircomm_tty_check_modem_status(self);
index d3687aa..d4fdf8f 100644 (file)
@@ -86,21 +86,17 @@ static void ircomm_tty_change_speed(struct ircomm_tty_cb *self,
        ircomm_param_request(self, IRCOMM_DATA_RATE, FALSE);
 
        /* CTS flow control flag and modem status interrupts */
+       tty_port_set_cts_flow(&self->port, cflag & CRTSCTS);
        if (cflag & CRTSCTS) {
-               self->port.flags |= ASYNC_CTS_FLOW;
                self->settings.flow_control |= IRCOMM_RTS_CTS_IN;
                /* This got me. Bummer. Jean II */
                if (self->service_type == IRCOMM_3_WIRE_RAW)
                        net_warn_ratelimited("%s(), enabling RTS/CTS on link that doesn't support it (3-wire-raw)\n",
                                             __func__);
        } else {
-               self->port.flags &= ~ASYNC_CTS_FLOW;
                self->settings.flow_control &= ~IRCOMM_RTS_CTS_IN;
        }
-       if (cflag & CLOCAL)
-               self->port.flags &= ~ASYNC_CHECK_CD;
-       else
-               self->port.flags |= ASYNC_CHECK_CD;
+       tty_port_set_check_carrier(&self->port, ~cflag & CLOCAL);
 #if 0
        /*
         * Set up parity check flag
@@ -166,7 +162,7 @@ void ircomm_tty_set_termios(struct tty_struct *tty,
        /* Handle transition away from B0 status */
        if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
                self->settings.dte |= IRCOMM_DTR;
-               if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags))
+               if (!C_CRTSCTS(tty) || !tty_throttled(tty))
                        self->settings.dte |= IRCOMM_RTS;
                ircomm_param_request(self, IRCOMM_DTE, TRUE);
        }
@@ -190,7 +186,7 @@ int ircomm_tty_tiocmget(struct tty_struct *tty)
        struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
        unsigned int result;
 
-       if (tty->flags & (1 << TTY_IO_ERROR))
+       if (tty_io_error(tty))
                return -EIO;
 
        result =  ((self->settings.dte & IRCOMM_RTS) ? TIOCM_RTS : 0)
@@ -213,7 +209,7 @@ int ircomm_tty_tiocmset(struct tty_struct *tty,
 {
        struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
 
-       if (tty->flags & (1 << TTY_IO_ERROR))
+       if (tty_io_error(tty))
                return -EIO;
 
        IRDA_ASSERT(self != NULL, return -1;);
@@ -328,7 +324,7 @@ static int ircomm_tty_set_serial_info(struct ircomm_tty_cb *self,
 
  check_and_exit:
 
-       if (self->flags & ASYNC_INITIALIZED) {
+       if (tty_port_initialized(self)) {
                if (((old_state.flags & ASYNC_SPD_MASK) !=
                     (self->flags & ASYNC_SPD_MASK)) ||
                    (old_driver.custom_divisor != driver->custom_divisor)) {
@@ -362,7 +358,7 @@ int ircomm_tty_ioctl(struct tty_struct *tty,
        if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
            (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
            (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
-               if (tty->flags & (1 << TTY_IO_ERROR))
+               if (tty_io_error(tty))
                    return -EIO;
        }