浏览代码

Merge tag 'tty-4.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

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
  ...
Linus Torvalds 9 年之前
父节点
当前提交
e10abc629f
共有 100 个文件被更改,包括 2504 次插入1146 次删除
  1. 19 0
      Documentation/devicetree/bindings/serial/arm,mps2-uart.txt
  2. 2 2
      Documentation/devicetree/bindings/serial/fsl-imx-uart.txt
  3. 12 4
      Documentation/devicetree/bindings/serial/fsl-mxs-auart.txt
  4. 57 0
      Documentation/devicetree/bindings/serial/serial.txt
  5. 4 4
      Documentation/devicetree/bindings/serial/sirf-uart.txt
  6. 6 0
      Documentation/kernel-parameters.txt
  7. 0 3
      Documentation/serial/tty.txt
  8. 0 1
      MAINTAINERS
  9. 1 1
      arch/ia64/hp/sim/simserial.c
  10. 4 2
      arch/mips/ath79/early_printk.c
  11. 11 18
      drivers/char/pcmcia/synclink_cs.c
  12. 2 3
      drivers/ipack/devices/ipoctal.c
  13. 19 25
      drivers/isdn/i4l/isdn_tty.c
  14. 1 1
      drivers/mmc/card/sdio_uart.c
  15. 1 1
      drivers/net/usb/hso.c
  16. 10 12
      drivers/s390/char/con3215.c
  17. 2 2
      drivers/s390/char/tty3270.c
  18. 1 1
      drivers/staging/dgnc/dgnc_tty.c
  19. 1 1
      drivers/staging/fwserial/fwserial.c
  20. 1 1
      drivers/staging/speakup/selection.c
  21. 17 22
      drivers/tty/amiserial.c
  22. 15 23
      drivers/tty/cyclades.c
  23. 2 2
      drivers/tty/hvc/hvc_console.c
  24. 1 1
      drivers/tty/hvc/hvcs.c
  25. 1 1
      drivers/tty/hvc/hvsi.c
  26. 5 0
      drivers/tty/ipwireless/hardware.c
  27. 7 12
      drivers/tty/isicom.c
  28. 6 6
      drivers/tty/moxa.c
  29. 13 22
      drivers/tty/mxser.c
  30. 6 6
      drivers/tty/n_gsm.c
  31. 2 2
      drivers/tty/n_hdlc.c
  32. 33 37
      drivers/tty/n_tty.c
  33. 1 1
      drivers/tty/nozomi.c
  34. 2 4
      drivers/tty/pty.c
  35. 9 7
      drivers/tty/rocket.c
  36. 11 4
      drivers/tty/serial/8250/8250.h
  37. 3 0
      drivers/tty/serial/8250/8250_core.c
  38. 42 26
      drivers/tty/serial/8250/8250_dma.c
  39. 5 3
      drivers/tty/serial/8250/8250_dw.c
  40. 16 102
      drivers/tty/serial/8250/8250_fintek.c
  41. 29 15
      drivers/tty/serial/8250/8250_mid.c
  42. 1 1
      drivers/tty/serial/8250/8250_of.c
  43. 34 59
      drivers/tty/serial/8250/8250_omap.c
  44. 15 0
      drivers/tty/serial/8250/8250_pci.c
  45. 30 8
      drivers/tty/serial/8250/8250_port.c
  46. 1 1
      drivers/tty/serial/8250/8250_uniphier.c
  47. 15 9
      drivers/tty/serial/8250/Kconfig
  48. 1 1
      drivers/tty/serial/8250/Makefile
  49. 18 2
      drivers/tty/serial/Kconfig
  50. 1 0
      drivers/tty/serial/Makefile
  51. 1 0
      drivers/tty/serial/amba-pl011.c
  52. 13 1
      drivers/tty/serial/atmel_serial.c
  53. 14 16
      drivers/tty/serial/crisv10.c
  54. 1 1
      drivers/tty/serial/ifx6x60.c
  55. 114 60
      drivers/tty/serial/imx.c
  56. 35 7
      drivers/tty/serial/meson_uart.c
  57. 625 0
      drivers/tty/serial/mps2-uart.c
  58. 66 35
      drivers/tty/serial/msm_serial.c
  59. 3 26
      drivers/tty/serial/mvebu-uart.c
  60. 519 125
      drivers/tty/serial/mxs-auart.c
  61. 2 2
      drivers/tty/serial/samsung.c
  62. 3 10
      drivers/tty/serial/sc16is7xx.c
  63. 0 2
      drivers/tty/serial/serial-tegra.c
  64. 288 142
      drivers/tty/serial/serial_core.c
  65. 5 2
      drivers/tty/serial/serial_mctrl_gpio.c
  66. 0 2
      drivers/tty/serial/serial_mctrl_gpio.h
  67. 19 20
      drivers/tty/serial/sirfsoc_uart.c
  68. 6 6
      drivers/tty/serial/uartlite.c
  69. 3 0
      drivers/tty/serial/ucc_uart.c
  70. 32 42
      drivers/tty/synclink.c
  71. 17 24
      drivers/tty/synclink_gt.c
  72. 17 24
      drivers/tty/synclinkmp.c
  73. 6 28
      drivers/tty/tty_buffer.c
  74. 2 7
      drivers/tty/tty_io.c
  75. 2 2
      drivers/tty/tty_ioctl.c
  76. 14 13
      drivers/tty/tty_port.c
  77. 1 1
      drivers/tty/vt/selection.c
  78. 63 52
      drivers/tty/vt/vt.c
  79. 2 2
      drivers/usb/class/cdc-acm.c
  80. 2 2
      drivers/usb/gadget/function/u_serial.c
  81. 1 1
      drivers/usb/misc/sisusbvga/sisusb_con.c
  82. 2 2
      drivers/usb/serial/console.c
  83. 1 2
      drivers/usb/serial/digi_acceleport.c
  84. 3 3
      drivers/usb/serial/generic.c
  85. 3 3
      drivers/usb/serial/mxuport.c
  86. 2 2
      drivers/usb/serial/sierra.c
  87. 1 1
      drivers/usb/serial/usb-serial.c
  88. 2 2
      drivers/usb/serial/usb_wwan.c
  89. 2 2
      drivers/video/console/fbcon.c
  90. 1 1
      drivers/video/console/mdacon.c
  91. 1 1
      drivers/video/console/newport_con.c
  92. 1 1
      drivers/video/console/sticon.c
  93. 2 3
      drivers/video/console/vgacon.c
  94. 1 1
      include/linux/console.h
  95. 4 4
      include/linux/selection.h
  96. 2 0
      include/linux/serial_8250.h
  97. 3 0
      include/linux/serial_core.h
  98. 86 3
      include/linux/tty.h
  99. 3 0
      include/uapi/linux/serial_core.h
  100. 12 1
      include/uapi/linux/tty_flags.h

+ 19 - 0
Documentation/devicetree/bindings/serial/arm,mps2-uart.txt

@@ -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>;
+};

+ 2 - 2
Documentation/devicetree/bindings/serial/fsl-imx-uart.txt

@@ -6,7 +6,7 @@ Required properties:
 - interrupts : Should contain uart interrupt
 - interrupts : Should contain uart interrupt
 
 
 Optional properties:
 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,irda-mode : Indicate the uart supports irda mode
 - fsl,dte-mode : Indicate the uart works in DTE mode. The uart works
 - fsl,dte-mode : Indicate the uart works in DTE mode. The uart works
                   in DCE mode by default.
                   in DCE mode by default.
@@ -24,6 +24,6 @@ uart1: serial@73fbc000 {
 	compatible = "fsl,imx51-uart", "fsl,imx21-uart";
 	compatible = "fsl,imx51-uart", "fsl,imx21-uart";
 	reg = <0x73fbc000 0x4000>;
 	reg = <0x73fbc000 0x4000>;
 	interrupts = <31>;
 	interrupts = <31>;
-	fsl,uart-has-rtscts;
+	uart-has-rtscts;
 	fsl,dte-mode;
 	fsl,dte-mode;
 };
 };

+ 12 - 4
Documentation/devicetree/bindings/serial/fsl-mxs-auart.txt

@@ -1,8 +1,10 @@
 * Freescale MXS Application UART (AUART)
 * 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
 - reg : Address and length of the register set for the device
 - interrupts : Should contain the auart interrupt numbers
 - interrupts : Should contain the auart interrupt numbers
 - dmas: DMA specifier, consisting of a phandle to DMA controller node
 - 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.
   Refer to dma.txt and fsl-mxs-dma.txt for details.
 - dma-names: "rx" for RX channel, "tx" for TX channel.
 - 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:
 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,
   for hardware flow control,
 	it also means you enable the DMA support for this UART.
 	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
 - {rts,cts,dtr,dsr,rng,dcd}-gpios: specify a GPIO for RTS/CTS/DTR/DSR/RI/DCD

+ 57 - 0
Documentation/devicetree/bindings/serial/serial.txt

@@ -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";
+	};

+ 4 - 4
Documentation/devicetree/bindings/serial/sirf-uart.txt

@@ -9,9 +9,9 @@ Required properties:
 - clocks : Should contain uart clock number
 - clocks : Should contain uart clock number
 
 
 Optional properties:
 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:
 Example:
 
 
@@ -28,7 +28,7 @@ On the board-specific dts, we can put rts-gpios and cts-gpios like
 
 
 usp@b0090000 {
 usp@b0090000 {
 	compatible = "sirf,prima2-usp-uart";
 	compatible = "sirf,prima2-usp-uart";
-	sirf,uart-has-rtscts;
+	uart-has-rtscts;
 	rts-gpios = <&gpio 15 0>;
 	rts-gpios = <&gpio 15 0>;
 	cts-gpios = <&gpio 46 0>;
 	cts-gpios = <&gpio 46 0>;
 };
 };

+ 6 - 0
Documentation/kernel-parameters.txt

@@ -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 driver will use only 32-bit accessors to read/write
 			the device registers.
 			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>
 		msm_serial,<addr>
 			Start an early, polled-mode console on an msm serial
 			Start an early, polled-mode console on an msm serial
 			port at the specified address. The serial port
 			port at the specified address. The serial port

+ 0 - 3
Documentation/serial/tty.txt

@@ -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_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
 TTY_NO_WRITE_SPLIT	Prevent driver from splitting up writes into
 			smaller chunks.
 			smaller chunks.
 
 

+ 0 - 1
MAINTAINERS

@@ -175,7 +175,6 @@ F:	drivers/net/ethernet/realtek/r8169.c
 8250/16?50 (AND CLONE UARTS) SERIAL DRIVER
 8250/16?50 (AND CLONE UARTS) SERIAL DRIVER
 M:	Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 M:	Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 L:	linux-serial@vger.kernel.org
 L:	linux-serial@vger.kernel.org
-W:	http://serial.sourceforge.net
 S:	Maintained
 S:	Maintained
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git
 F:	drivers/tty/serial/8250*
 F:	drivers/tty/serial/8250*

+ 1 - 1
arch/ia64/hp/sim/simserial.c

@@ -300,7 +300,7 @@ static int rs_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
 	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
 	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
 	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
 	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
 	    (cmd != TIOCMIWAIT)) {
 	    (cmd != TIOCMIWAIT)) {
-		if (tty->flags & (1 << TTY_IO_ERROR))
+		if (tty_io_error(tty))
 		    return -EIO;
 		    return -EIO;
 	}
 	}
 
 

+ 4 - 2
arch/mips/ath79/early_printk.c

@@ -31,13 +31,15 @@ static inline void prom_putchar_wait(void __iomem *reg, u32 mask, u32 val)
 	} while (1);
 	} while (1);
 }
 }
 
 
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
 static void prom_putchar_ar71xx(unsigned char ch)
 static void prom_putchar_ar71xx(unsigned char ch)
 {
 {
 	void __iomem *base = (void __iomem *)(KSEG1ADDR(AR71XX_UART_BASE));
 	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);
 	__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)
 static void prom_putchar_ar933x(unsigned char ch)

+ 11 - 18
drivers/char/pcmcia/synclink_cs.c

@@ -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->status_event_wait_q);
 	wake_up_interruptible(&info->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)
 		if (debug_level >= DEBUG_LEVEL_ISR)
 			printk("%s CD now %s...", info->device_name,
 			printk("%s CD now %s...", info->device_name,
 			       (info->serial_signals & SerialSignal_DCD) ? "on" : "off");
 			       (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)
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("%s(%d):startup(%s)\n", __FILE__, __LINE__, info->device_name);
 		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;
 		return 0;
 
 
 	if (!info->tx_buf) {
 	if (!info->tx_buf) {
@@ -1311,7 +1311,7 @@ static int startup(MGSLPC_INFO * info, struct tty_struct *tty)
 	if (tty)
 	if (tty)
 		clear_bit(TTY_IO_ERROR, &tty->flags);
 		clear_bit(TTY_IO_ERROR, &tty->flags);
 
 
-	info->port.flags |= ASYNC_INITIALIZED;
+	tty_port_set_initialized(&info->port, 1);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -1322,7 +1322,7 @@ static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty)
 {
 {
 	unsigned long flags;
 	unsigned long flags;
 
 
-	if (!(info->port.flags & ASYNC_INITIALIZED))
+	if (!tty_port_initialized(&info->port))
 		return;
 		return;
 
 
 	if (debug_level >= DEBUG_LEVEL_INFO)
 	if (debug_level >= DEBUG_LEVEL_INFO)
@@ -1361,7 +1361,7 @@ static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty)
 	if (tty)
 	if (tty)
 		set_bit(TTY_IO_ERROR, &tty->flags);
 		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)
 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 */
 	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 */
 	/* process tty input control flags */
 
 
@@ -2246,7 +2239,7 @@ static int mgslpc_ioctl(struct tty_struct *tty,
 
 
 	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
 	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
 	    (cmd != TIOCMIWAIT)) {
 	    (cmd != TIOCMIWAIT)) {
-		if (tty->flags & (1 << TTY_IO_ERROR))
+		if (tty_io_error(tty))
 		    return -EIO;
 		    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 */
 	/* Handle transition away from B0 status */
 	if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) {
 	if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) {
 		info->serial_signals |= SerialSignal_DTR;
 		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;
 			info->serial_signals |= SerialSignal_RTS;
 		spin_lock_irqsave(&info->lock, flags);
 		spin_lock_irqsave(&info->lock, flags);
 		set_signals(info);
 		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)
 	if (tty_port_close_start(port, tty, filp) == 0)
 		goto cleanup;
 		goto cleanup;
 
 
-	if (port->flags & ASYNC_INITIALIZED)
+	if (tty_port_initialized(port))
 		mgslpc_wait_until_sent(tty, info->timeout);
 		mgslpc_wait_until_sent(tty, info->timeout);
 
 
 	mgslpc_flush_buffer(tty);
 	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"))
 	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_wait_until_sent"))
 		return;
 		return;
 
 
-	if (!(info->port.flags & ASYNC_INITIALIZED))
+	if (!tty_port_initialized(&info->port))
 		goto exit;
 		goto exit;
 
 
 	orig_jiffies = jiffies;
 	orig_jiffies = jiffies;

+ 2 - 3
drivers/ipack/devices/ipoctal.c

@@ -629,8 +629,7 @@ static void ipoctal_hangup(struct tty_struct *tty)
 	tty_port_hangup(&channel->tty_port);
 	tty_port_hangup(&channel->tty_port);
 
 
 	ipoctal_reset_channel(channel);
 	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);
 	wake_up_interruptible(&channel->tty_port.open_wait);
 }
 }
 
 
@@ -642,7 +641,7 @@ static void ipoctal_shutdown(struct tty_struct *tty)
 		return;
 		return;
 
 
 	ipoctal_reset_channel(channel);
 	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)
 static void ipoctal_cleanup(struct tty_struct *tty)

+ 19 - 25
drivers/isdn/i4l/isdn_tty.c

@@ -1043,17 +1043,13 @@ isdn_tty_change_speed(modem_info *info)
 	if (!(cflag & PARODD))
 	if (!(cflag & PARODD))
 		cval |= UART_LCR_EPAR;
 		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
 static int
 isdn_tty_startup(modem_info *info)
 isdn_tty_startup(modem_info *info)
 {
 {
-	if (info->port.flags & ASYNC_INITIALIZED)
+	if (tty_port_initialized(&info->port))
 		return 0;
 		return 0;
 	isdn_lock_drivers();
 	isdn_lock_drivers();
 #ifdef ISDN_DEBUG_MODEM_OPEN
 #ifdef ISDN_DEBUG_MODEM_OPEN
@@ -1070,7 +1066,7 @@ isdn_tty_startup(modem_info *info)
 	 */
 	 */
 	isdn_tty_change_speed(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->msr |= (UART_MSR_DSR | UART_MSR_CTS);
 	info->send_outstanding = 0;
 	info->send_outstanding = 0;
 	return 0;
 	return 0;
@@ -1083,7 +1079,7 @@ isdn_tty_startup(modem_info *info)
 static void
 static void
 isdn_tty_shutdown(modem_info *info)
 isdn_tty_shutdown(modem_info *info)
 {
 {
-	if (!(info->port.flags & ASYNC_INITIALIZED))
+	if (!tty_port_initialized(&info->port))
 		return;
 		return;
 #ifdef ISDN_DEBUG_MODEM_OPEN
 #ifdef ISDN_DEBUG_MODEM_OPEN
 	printk(KERN_DEBUG "Shutting down isdnmodem port %d ....\n", info->line);
 	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)
 	if (info->port.tty)
 		set_bit(TTY_IO_ERROR, &info->port.tty->flags);
 		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
 /* 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__))
 	if (isdn_tty_paranoia_check(info, tty->name, __func__))
 		return -ENODEV;
 		return -ENODEV;
-	if (tty->flags & (1 << TTY_IO_ERROR))
+	if (tty_io_error(tty))
 		return -EIO;
 		return -EIO;
 
 
 	mutex_lock(&modem_info_mutex);
 	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__))
 	if (isdn_tty_paranoia_check(info, tty->name, __func__))
 		return -ENODEV;
 		return -ENODEV;
-	if (tty->flags & (1 << TTY_IO_ERROR))
+	if (tty_io_error(tty))
 		return -EIO;
 		return -EIO;
 
 
 #ifdef ISDN_DEBUG_MODEM_IOCTL
 #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"))
 	if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_ioctl"))
 		return -ENODEV;
 		return -ENODEV;
-	if (tty->flags & (1 << TTY_IO_ERROR))
+	if (tty_io_error(tty))
 		return -EIO;
 		return -EIO;
 	switch (cmd) {
 	switch (cmd) {
 	case TCSBRK:   /* SVID version: non-zero arg --> no break */
 	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
 	 * interrupt driver to stop checking the data ready bit in the
 	 * line status register.
 	 * line status register.
 	 */
 	 */
-	if (port->flags & ASYNC_INITIALIZED) {
+	if (tty_port_initialized(port)) {
 		tty_wait_until_sent(tty, 3000);	/* 30 seconds timeout */
 		tty_wait_until_sent(tty, 3000);	/* 30 seconds timeout */
 		/*
 		/*
 		 * Before we drop DTR, make sure the UART transmitter
 		 * Before we drop DTR, make sure the UART transmitter
@@ -1622,7 +1618,7 @@ isdn_tty_hangup(struct tty_struct *tty)
 		return;
 		return;
 	isdn_tty_shutdown(info);
 	isdn_tty_shutdown(info);
 	port->count = 0;
 	port->count = 0;
-	port->flags &= ~ASYNC_NORMAL_ACTIVE;
+	tty_port_set_active(port, 0);
 	port->tty = NULL;
 	port->tty = NULL;
 	wake_up_interruptible(&port->open_wait);
 	wake_up_interruptible(&port->open_wait);
 }
 }
@@ -1979,7 +1975,7 @@ isdn_tty_find_icall(int di, int ch, setup_parm *setup)
 #endif
 #endif
 			if (
 			if (
 #ifndef FIX_FILE_TRANSFER
 #ifndef FIX_FILE_TRANSFER
-				(info->port.flags & ASYNC_NORMAL_ACTIVE) &&
+			    tty_port_active(&info->port) &&
 #endif
 #endif
 				(info->isdn_driver == -1) &&
 				(info->isdn_driver == -1) &&
 				(info->isdn_channel == -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;
 	return (wret == 2) ? 3 : 0;
 }
 }
 
 
-#define TTY_IS_ACTIVE(info)	(info->port.flags & ASYNC_NORMAL_ACTIVE)
-
 int
 int
 isdn_tty_stat_callback(int i, isdn_ctrl *c)
 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
 #ifdef ISDN_TTY_STAT_DEBUG
 			printk(KERN_DEBUG "tty_STAT_DCONN ttyI%d\n", info->line);
 			printk(KERN_DEBUG "tty_STAT_DCONN ttyI%d\n", info->line);
 #endif
 #endif
-			if (TTY_IS_ACTIVE(info)) {
+			if (tty_port_active(&info->port)) {
 				if (info->dialing == 1) {
 				if (info->dialing == 1) {
 					info->dialing = 2;
 					info->dialing = 2;
 					return 1;
 					return 1;
@@ -2088,7 +2082,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
 #ifdef ISDN_TTY_STAT_DEBUG
 #ifdef ISDN_TTY_STAT_DEBUG
 			printk(KERN_DEBUG "tty_STAT_DHUP ttyI%d\n", info->line);
 			printk(KERN_DEBUG "tty_STAT_DHUP ttyI%d\n", info->line);
 #endif
 #endif
-			if (TTY_IS_ACTIVE(info)) {
+			if (tty_port_active(&info->port)) {
 				if (info->dialing == 1)
 				if (info->dialing == 1)
 					isdn_tty_modem_result(RESULT_BUSY, info);
 					isdn_tty_modem_result(RESULT_BUSY, info);
 				if (info->dialing > 1)
 				if (info->dialing > 1)
@@ -2118,7 +2112,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
 			 * waiting for it and
 			 * waiting for it and
 			 * set DCD-bit of its modem-status.
 			 * set DCD-bit of its modem-status.
 			 */
 			 */
-			if (TTY_IS_ACTIVE(info) ||
+			if (tty_port_active(&info->port) ||
 			    (info->port.blocked_open &&
 			    (info->port.blocked_open &&
 			     (info->emu.mdmreg[REG_DCD] & BIT_DCD))) {
 			     (info->emu.mdmreg[REG_DCD] & BIT_DCD))) {
 				info->msr |= UART_MSR_DCD;
 				info->msr |= UART_MSR_DCD;
@@ -2145,7 +2139,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
 #ifdef ISDN_TTY_STAT_DEBUG
 #ifdef ISDN_TTY_STAT_DEBUG
 			printk(KERN_DEBUG "tty_STAT_BHUP ttyI%d\n", info->line);
 			printk(KERN_DEBUG "tty_STAT_BHUP ttyI%d\n", info->line);
 #endif
 #endif
-			if (TTY_IS_ACTIVE(info)) {
+			if (tty_port_active(&info->port)) {
 #ifdef ISDN_DEBUG_MODEM_HUP
 #ifdef ISDN_DEBUG_MODEM_HUP
 				printk(KERN_DEBUG "Mhup in ISDN_STAT_BHUP\n");
 				printk(KERN_DEBUG "Mhup in ISDN_STAT_BHUP\n");
 #endif
 #endif
@@ -2157,7 +2151,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
 #ifdef ISDN_TTY_STAT_DEBUG
 #ifdef ISDN_TTY_STAT_DEBUG
 			printk(KERN_DEBUG "tty_STAT_NODCH ttyI%d\n", info->line);
 			printk(KERN_DEBUG "tty_STAT_NODCH ttyI%d\n", info->line);
 #endif
 #endif
-			if (TTY_IS_ACTIVE(info)) {
+			if (tty_port_active(&info->port)) {
 				if (info->dialing) {
 				if (info->dialing) {
 					info->dialing = 0;
 					info->dialing = 0;
 					info->last_l2 = -1;
 					info->last_l2 = -1;
@@ -2183,14 +2177,14 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
 			return 1;
 			return 1;
 #ifdef CONFIG_ISDN_TTY_FAX
 #ifdef CONFIG_ISDN_TTY_FAX
 		case ISDN_STAT_FAXIND:
 		case ISDN_STAT_FAXIND:
-			if (TTY_IS_ACTIVE(info)) {
+			if (tty_port_active(&info->port)) {
 				isdn_tty_fax_command(info, c);
 				isdn_tty_fax_command(info, c);
 			}
 			}
 			break;
 			break;
 #endif
 #endif
 #ifdef CONFIG_ISDN_AUDIO
 #ifdef CONFIG_ISDN_AUDIO
 		case ISDN_STAT_AUDIO:
 		case ISDN_STAT_AUDIO:
-			if (TTY_IS_ACTIVE(info)) {
+			if (tty_port_active(&info->port)) {
 				switch (c->parm.num[0]) {
 				switch (c->parm.num[0]) {
 				case ISDN_AUDIO_DTMF:
 				case ISDN_AUDIO_DTMF:
 					if (info->vonline) {
 					if (info->vonline) {
@@ -2528,7 +2522,7 @@ isdn_tty_modem_result(int code, modem_info *info)
 		if (info->closing || (!info->port.tty))
 		if (info->closing || (!info->port.tty))
 			return;
 			return;
 
 
-		if (info->port.flags & ASYNC_CHECK_CD)
+		if (tty_port_check_carrier(&info->port))
 			tty_hangup(info->port.tty);
 			tty_hangup(info->port.tty);
 	}
 	}
 }
 }

+ 1 - 1
drivers/mmc/card/sdio_uart.c

@@ -895,7 +895,7 @@ static void sdio_uart_set_termios(struct tty_struct *tty,
 	/* Handle transition away from B0 status */
 	/* Handle transition away from B0 status */
 	if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
 	if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
 		unsigned int mask = TIOCM_DTR;
 		unsigned int mask = TIOCM_DTR;
-		if (!(cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags))
+		if (!(cflag & CRTSCTS) || !tty_throttled(tty))
 			mask |= TIOCM_RTS;
 			mask |= TIOCM_RTS;
 		sdio_uart_set_mctrl(port, mask);
 		sdio_uart_set_mctrl(port, mask);
 	}
 	}

+ 1 - 1
drivers/net/usb/hso.c

@@ -2029,7 +2029,7 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
 
 
 	tty = tty_port_tty_get(&serial->port);
 	tty = tty_port_tty_get(&serial->port);
 
 
-	if (tty && test_bit(TTY_THROTTLED, &tty->flags)) {
+	if (tty && tty_throttled(tty)) {
 		tty_kref_put(tty);
 		tty_kref_put(tty);
 		return -1;
 		return -1;
 	}
 	}

+ 10 - 12
drivers/s390/char/con3215.c

@@ -289,7 +289,7 @@ static void raw3215_timeout(unsigned long __data)
 
 
 	spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
 	spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
 	raw->flags &= ~RAW3215_TIMER_RUNS;
 	raw->flags &= ~RAW3215_TIMER_RUNS;
-	if (!(raw->port.flags & ASYNC_SUSPENDED)) {
+	if (!tty_port_suspended(&raw->port)) {
 		raw3215_mk_write_req(raw);
 		raw3215_mk_write_req(raw);
 		raw3215_start_io(raw);
 		raw3215_start_io(raw);
 		if ((raw->queued_read || raw->queued_write) &&
 		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)
 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;
 		return;
 	if (raw->queued_read != NULL)
 	if (raw->queued_read != NULL)
 		raw3215_start_io(raw);
 		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
 		/* While console is frozen for suspend we have no other
 		 * choice but to drop message from the buffer to make
 		 * choice but to drop message from the buffer to make
 		 * room for even more messages. */
 		 * room for even more messages. */
-		if (raw->port.flags & ASYNC_SUSPENDED) {
+		if (tty_port_suspended(&raw->port)) {
 			raw3215_drop_line(raw);
 			raw3215_drop_line(raw);
 			continue;
 			continue;
 		}
 		}
@@ -616,10 +615,10 @@ static int raw3215_startup(struct raw3215_info *raw)
 {
 {
 	unsigned long flags;
 	unsigned long flags;
 
 
-	if (raw->port.flags & ASYNC_INITIALIZED)
+	if (tty_port_initialized(&raw->port))
 		return 0;
 		return 0;
 	raw->line_pos = 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);
 	spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
 	raw3215_try_io(raw);
 	raw3215_try_io(raw);
 	spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
 	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);
 	DECLARE_WAITQUEUE(wait, current);
 	unsigned long flags;
 	unsigned long flags;
 
 
-	if (!(raw->port.flags & ASYNC_INITIALIZED) ||
-	    (raw->flags & RAW3215_FIXED))
+	if (!tty_port_initialized(&raw->port) || (raw->flags & RAW3215_FIXED))
 		return;
 		return;
 	/* Wait for outstanding requests, then free irq */
 	/* Wait for outstanding requests, then free irq */
 	spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
 	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);
 		spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
 		remove_wait_queue(&raw->empty_wait, &wait);
 		remove_wait_queue(&raw->empty_wait, &wait);
 		set_current_state(TASK_RUNNING);
 		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);
 	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);
 	raw = dev_get_drvdata(&cdev->dev);
 	spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
 	spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
 	raw3215_make_room(raw, RAW3215_BUFFER_SIZE);
 	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);
 	spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
 	return 0;
 	return 0;
 }
 }
@@ -786,7 +784,7 @@ static int raw3215_pm_start(struct ccw_device *cdev)
 	/* Allow I/O again and flush output buffer. */
 	/* Allow I/O again and flush output buffer. */
 	raw = dev_get_drvdata(&cdev->dev);
 	raw = dev_get_drvdata(&cdev->dev);
 	spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
 	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;
 	raw->flags |= RAW3215_FLUSHING;
 	raw3215_try_io(raw);
 	raw3215_try_io(raw);
 	raw->flags &= ~RAW3215_FLUSHING;
 	raw->flags &= ~RAW3215_FLUSHING;
@@ -859,7 +857,7 @@ static void con3215_flush(void)
 	unsigned long flags;
 	unsigned long flags;
 
 
 	raw = raw3215[0];  /* console 3215 is the first one */
 	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. */
 		/* The console is still frozen for suspend. */
 		if (ccw_device_force_console(raw->cdev))
 		if (ccw_device_force_console(raw->cdev))
 			/* Forcing didn't work, no panic message .. */
 			/* Forcing didn't work, no panic message .. */

+ 2 - 2
drivers/s390/char/tty3270.c

@@ -1860,7 +1860,7 @@ static int tty3270_ioctl(struct tty_struct *tty, unsigned int cmd,
 	tp = tty->driver_data;
 	tp = tty->driver_data;
 	if (!tp)
 	if (!tp)
 		return -ENODEV;
 		return -ENODEV;
-	if (tty->flags & (1 << TTY_IO_ERROR))
+	if (tty_io_error(tty))
 		return -EIO;
 		return -EIO;
 	return kbd_ioctl(tp->kbd, cmd, arg);
 	return kbd_ioctl(tp->kbd, cmd, arg);
 }
 }
@@ -1874,7 +1874,7 @@ static long tty3270_compat_ioctl(struct tty_struct *tty,
 	tp = tty->driver_data;
 	tp = tty->driver_data;
 	if (!tp)
 	if (!tp)
 		return -ENODEV;
 		return -ENODEV;
-	if (tty->flags & (1 << TTY_IO_ERROR))
+	if (tty_io_error(tty))
 		return -EIO;
 		return -EIO;
 	return kbd_ioctl(tp->kbd, cmd, (unsigned long)compat_ptr(arg));
 	return kbd_ioctl(tp->kbd, cmd, (unsigned long)compat_ptr(arg));
 }
 }

+ 1 - 1
drivers/staging/dgnc/dgnc_tty.c

@@ -1255,7 +1255,7 @@ static int dgnc_block_til_ready(struct tty_struct *tty,
 			if (file->f_flags & O_NONBLOCK)
 			if (file->f_flags & O_NONBLOCK)
 				break;
 				break;
 
 
-			if (tty->flags & (1 << TTY_IO_ERROR)) {
+			if (tty_io_error(tty)) {
 				retval = -EIO;
 				retval = -EIO;
 				break;
 				break;
 			}
 			}

+ 1 - 1
drivers/staging/fwserial/fwserial.c

@@ -1305,7 +1305,7 @@ static void fwtty_set_termios(struct tty_struct *tty, struct ktermios *old)
 	if ((baud == 0) && (old->c_cflag & CBAUD)) {
 	if ((baud == 0) && (old->c_cflag & CBAUD)) {
 		port->mctrl &= ~(TIOCM_DTR | TIOCM_RTS);
 		port->mctrl &= ~(TIOCM_DTR | TIOCM_RTS);
 	} else if ((baud != 0) && !(old->c_cflag & CBAUD)) {
 	} 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;
 			port->mctrl |= TIOCM_DTR | TIOCM_RTS;
 		else
 		else
 			port->mctrl |= TIOCM_DTR;
 			port->mctrl |= TIOCM_DTR;

+ 1 - 1
drivers/staging/speakup/selection.c

@@ -150,7 +150,7 @@ static void __speakup_paste_selection(struct work_struct *work)
 	add_wait_queue(&vc->paste_wait, &wait);
 	add_wait_queue(&vc->paste_wait, &wait);
 	while (sel_buffer && sel_buffer_lth > pasted) {
 	while (sel_buffer && sel_buffer_lth > pasted) {
 		set_current_state(TASK_INTERRUPTIBLE);
 		set_current_state(TASK_INTERRUPTIBLE);
-		if (test_bit(TTY_THROTTLED, &tty->flags)) {
+		if (tty_throttled(tty)) {
 			schedule();
 			schedule();
 			continue;
 			continue;
 		}
 		}

+ 17 - 22
drivers/tty/amiserial.c

@@ -398,7 +398,7 @@ static void check_modem_status(struct serial_state *info)
 		wake_up_interruptible(&port->delta_msr_wait);
 		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))
 #if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
 		printk("ttyS%d CD now %s...", info->line,
 		printk("ttyS%d CD now %s...", info->line,
 		       (!(status & SER_DCD)) ? "on" : "off");
 		       (!(status & SER_DCD)) ? "on" : "off");
@@ -525,7 +525,7 @@ static int startup(struct tty_struct *tty, struct serial_state *info)
 
 
 	local_irq_save(flags);
 	local_irq_save(flags);
 
 
-	if (port->flags & ASYNC_INITIALIZED) {
+	if (tty_port_initialized(port)) {
 		free_page(page);
 		free_page(page);
 		goto errout;
 		goto errout;
 	}
 	}
@@ -586,7 +586,7 @@ static int startup(struct tty_struct *tty, struct serial_state *info)
 	 */
 	 */
 	change_speed(tty, info, NULL);
 	change_speed(tty, info, NULL);
 
 
-	port->flags |= ASYNC_INITIALIZED;
+	tty_port_set_initialized(port, 1);
 	local_irq_restore(flags);
 	local_irq_restore(flags);
 	return 0;
 	return 0;
 
 
@@ -604,7 +604,7 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info)
 	unsigned long	flags;
 	unsigned long	flags;
 	struct serial_state *state;
 	struct serial_state *state;
 
 
-	if (!(info->tport.flags & ASYNC_INITIALIZED))
+	if (!tty_port_initialized(&info->tport))
 		return;
 		return;
 
 
 	state = info;
 	state = info;
@@ -645,7 +645,7 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info)
 
 
 	set_bit(TTY_IO_ERROR, &tty->flags);
 	set_bit(TTY_IO_ERROR, &tty->flags);
 
 
-	info->tport.flags &= ~ASYNC_INITIALIZED;
+	tty_port_set_initialized(&info->tport, 0);
 	local_irq_restore(flags);
 	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;
 	info->IER &= ~UART_IER_MSI;
 	if (port->flags & ASYNC_HARDPPS_CD)
 	if (port->flags & ASYNC_HARDPPS_CD)
 		info->IER |= UART_IER_MSI;
 		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;
 		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;
 		info->IER |= UART_IER_MSI;
-	}
 	/* TBD:
 	/* TBD:
 	 * Does clearing IER_MSI imply that we should disable the VBL interrupt ?
 	 * 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;
 	port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
 
 check_and_exit:
 check_and_exit:
-	if (port->flags & ASYNC_INITIALIZED) {
+	if (tty_port_initialized(port)) {
 		if (change_spd) {
 		if (change_spd) {
 			if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
 			if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
 				tty->alt_speed = 57600;
 				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"))
 	if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
 		return -ENODEV;
 		return -ENODEV;
-	if (tty->flags & (1 << TTY_IO_ERROR))
+	if (tty_io_error(tty))
 		return -EIO;
 		return -EIO;
 
 
 	control = info->MCR;
 	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"))
 	if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
 		return -ENODEV;
 		return -ENODEV;
-	if (tty->flags & (1 << TTY_IO_ERROR))
+	if (tty_io_error(tty))
 		return -EIO;
 		return -EIO;
 
 
 	local_irq_save(flags);
 	local_irq_save(flags);
@@ -1250,7 +1245,7 @@ static int rs_ioctl(struct tty_struct *tty,
 	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
 	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
 	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
 	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
 	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
 	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
-		if (tty->flags & (1 << TTY_IO_ERROR))
+		if (tty_io_error(tty))
 		    return -EIO;
 		    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 */
 	/* Handle transition away from B0 status */
 	if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
 	if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
 		info->MCR |= SER_DTR;
 		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;
 			info->MCR |= SER_RTS;
 		local_irq_save(flags);
 		local_irq_save(flags);
 		rtsdtr_ctrl(info->MCR);
 		rtsdtr_ctrl(info->MCR);
@@ -1395,7 +1390,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
 	 * line status register.
 	 * line status register.
 	 */
 	 */
 	state->read_status_mask &= ~UART_LSR_DR;
 	state->read_status_mask &= ~UART_LSR_DR;
-	if (port->flags & ASYNC_INITIALIZED) {
+	if (tty_port_initialized(port)) {
 	        /* disable receive interrupts */
 	        /* disable receive interrupts */
 	        custom.intena = IF_RBF;
 	        custom.intena = IF_RBF;
 		mb();
 		mb();
@@ -1495,7 +1490,7 @@ static void rs_hangup(struct tty_struct *tty)
 	rs_flush_buffer(tty);
 	rs_flush_buffer(tty);
 	shutdown(tty, info);
 	shutdown(tty, info);
 	info->tport.count = 0;
 	info->tport.count = 0;
-	info->tport.flags &= ~ASYNC_NORMAL_ACTIVE;
+	tty_port_set_active(&info->tport, 0);
 	info->tport.tty = NULL;
 	info->tport.tty = NULL;
 	wake_up_interruptible(&info->tport.open_wait);
 	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);
 	local_irq_save(flags);
 	status = ciab.pra;
 	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);
 	local_irq_restore(flags);
 
 
 	stat_buf[0] = 0;
 	stat_buf[0] = 0;

+ 15 - 23
drivers/tty/cyclades.c

@@ -714,7 +714,7 @@ static void cyy_chip_modem(struct cyclades_card *cinfo, int chip,
 		wake_up_interruptible(&info->port.delta_msr_wait);
 		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)
 		if (mdm_status & CyDCD)
 			wake_up_interruptible(&info->port.open_wait);
 			wake_up_interruptible(&info->port.open_wait);
 		else
 		else
@@ -1119,7 +1119,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
 		case C_CM_MDCD:
 		case C_CM_MDCD:
 			info->icount.dcd++;
 			info->icount.dcd++;
 			delta_count++;
 			delta_count++;
-			if (info->port.flags & ASYNC_CHECK_CD) {
+			if (tty_port_check_carrier(&info->port)) {
 				u32 dcd = fw_ver > 241 ? param :
 				u32 dcd = fw_ver > 241 ? param :
 					readl(&info->u.cyz.ch_ctrl->rs_status);
 					readl(&info->u.cyz.ch_ctrl->rs_status);
 				if (dcd & C_RS_DCD)
 				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);
 	spin_lock_irqsave(&card->card_lock, flags);
 
 
-	if (info->port.flags & ASYNC_INITIALIZED)
+	if (tty_port_initialized(&info->port))
 		goto errout;
 		goto errout;
 
 
 	if (!info->type) {
 	if (!info->type) {
@@ -1364,7 +1364,7 @@ static int cy_startup(struct cyclades_port *info, struct tty_struct *tty)
 		/* enable send, recv, modem !!! */
 		/* enable send, recv, modem !!! */
 	}
 	}
 
 
-	info->port.flags |= ASYNC_INITIALIZED;
+	tty_port_set_initialized(&info->port, 1);
 
 
 	clear_bit(TTY_IO_ERROR, &tty->flags);
 	clear_bit(TTY_IO_ERROR, &tty->flags);
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 	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;
 	struct cyclades_card *card;
 	unsigned long flags;
 	unsigned long flags;
 
 
-	if (!(info->port.flags & ASYNC_INITIALIZED))
+	if (!tty_port_initialized(&info->port))
 		return;
 		return;
 
 
 	card = info->card;
 	card = info->card;
@@ -1448,7 +1448,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
 		   some later date (after testing)!!! */
 		   some later date (after testing)!!! */
 
 
 		set_bit(TTY_IO_ERROR, &tty->flags);
 		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);
 		spin_unlock_irqrestore(&card->card_lock, flags);
 	} else {
 	} else {
 #ifdef CY_DEBUG_OPEN
 #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);
 			tty_port_lower_dtr_rts(&info->port);
 
 
 		set_bit(TTY_IO_ERROR, &tty->flags);
 		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);
 		spin_unlock_irqrestore(&card->card_lock, flags);
 	}
 	}
@@ -1711,7 +1711,7 @@ static void cy_do_close(struct tty_port *port)
 		/* Stop accepting input */
 		/* Stop accepting input */
 		cyy_writeb(info, CyCAR, channel & 0x03);
 		cyy_writeb(info, CyCAR, channel & 0x03);
 		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyRxData);
 		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
 			/* Waiting for on-board buffers to be empty before
 			   closing the port */
 			   closing the port */
 			spin_unlock_irqrestore(&card->card_lock, flags);
 			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;
 			info->cor1 |= CyPARITY_NONE;
 
 
 		/* CTS flow control flag */
 		/* 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;
 			info->cor2 |= CyCtsAE;
-		} else {
-			info->port.flags &= ~ASYNC_CTS_FLOW;
-			info->cor2 &= ~CyCtsAE;
-		}
-		if (cflag & CLOCAL)
-			info->port.flags &= ~ASYNC_CHECK_CD;
 		else
 		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
 	    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
 		/* As the HW flow control is done in firmware, the driver
 		   doesn't need to care about it */
 		   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 */
 		/* XON/XOFF/XANY flow control flags */
 		sw_flow = 0;
 		sw_flow = 0;
@@ -2252,10 +2247,7 @@ static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
 		}
 		}
 
 
 		/* CD sensitivity */
 		/* 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 */
 		if (baud == 0) {	/* baud rate is zero, turn off line */
 			cy_writel(&ch_ctrl->rs_control,
 			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;
 	info->port.closing_wait = new_serial.closing_wait * HZ / 100;
 
 
 check_and_exit:
 check_and_exit:
-	if (info->port.flags & ASYNC_INITIALIZED) {
+	if (tty_port_initialized(&info->port)) {
 		cy_set_line_char(info, tty);
 		cy_set_line_char(info, tty);
 		ret = 0;
 		ret = 0;
 	} else {
 	} else {

+ 2 - 2
drivers/tty/hvc/hvc_console.c

@@ -632,7 +632,7 @@ int hvc_poll(struct hvc_struct *hp)
 		goto bail;
 		goto bail;
 
 
 	/* Now check if we can get data (are we throttled ?) */
 	/* Now check if we can get data (are we throttled ?) */
-	if (test_bit(TTY_THROTTLED, &tty->flags))
+	if (tty_throttled(tty))
 		goto throttled;
 		goto throttled;
 
 
 	/* If we aren't notifier driven and aren't throttled, we always
 	/* 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);
 	n = hp->ops->get_chars(hp->vtermno, &ch, 1);
 
 
-	if (n == 0)
+	if (n <= 0)
 		return NO_POLL_CHAR;
 		return NO_POLL_CHAR;
 
 
 	return ch;
 	return ch;

+ 1 - 1
drivers/tty/hvc/hvcs.c

@@ -600,7 +600,7 @@ static int hvcs_io(struct hvcs_struct *hvcsd)
 
 
 	hvcs_try_write(hvcsd);
 	hvcs_try_write(hvcsd);
 
 
-	if (!tty || test_bit(TTY_THROTTLED, &tty->flags)) {
+	if (!tty || tty_throttled(tty)) {
 		hvcsd->todo_mask &= ~(HVCS_READ_MASK);
 		hvcsd->todo_mask &= ~(HVCS_READ_MASK);
 		goto bail;
 		goto bail;
 	} else if (!(hvcsd->todo_mask & (HVCS_READ_MASK)))
 	} else if (!(hvcsd->todo_mask & (HVCS_READ_MASK)))

+ 1 - 1
drivers/tty/hvc/hvsi.c

@@ -509,7 +509,7 @@ static irqreturn_t hvsi_interrupt(int irq, void *arg)
 	}
 	}
 
 
 	spin_lock_irqsave(&hp->lock, flags);
 	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
 		/* we weren't hung up and we weren't throttled, so we can
 		 * deliver the rest now */
 		 * deliver the rest now */
 		hvsi_send_overflow(hp);
 		hvsi_send_overflow(hp);

+ 5 - 0
drivers/tty/ipwireless/hardware.c

@@ -1572,6 +1572,11 @@ static void handle_received_SETUP_packet(struct ipw_hardware *hw,
 					sizeof(struct ipw_setup_reboot_msg_ack),
 					sizeof(struct ipw_setup_reboot_msg_ack),
 					ADDR_SETUP_PROT, TL_PROTOCOLID_SETUP,
 					ADDR_SETUP_PROT, TL_PROTOCOLID_SETUP,
 					TL_SETUP_SIGNO_REBOOT_MSG_ACK);
 					TL_SETUP_SIGNO_REBOOT_MSG_ACK);
+			if (!packet) {
+				pr_err(IPWIRELESS_PCCARD_NAME
+				       ": Not enough memory to send reboot packet");
+				break;
+			}
 			packet->header.length =
 			packet->header.length =
 				sizeof(struct TlSetupRebootMsgAck);
 				sizeof(struct TlSetupRebootMsgAck);
 			send_packet(hw, PRIO_SETUP, &packet->header);
 			send_packet(hw, PRIO_SETUP, &packet->header);

+ 7 - 12
drivers/tty/isicom.c

@@ -438,8 +438,8 @@ static void isicom_tx(unsigned long _data)
 
 
 	for (; count > 0; count--, port++) {
 	for (; count > 0; count--, port++) {
 		/* port not active or tx disabled to force flow control */
 		/* 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;
 			continue;
 
 
 		txcount = min_t(short, TX_SIZE, port->xmit_cnt);
 		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;
 		return IRQ_HANDLED;
 	}
 	}
 	port = card->ports + channel;
 	port = card->ports + channel;
-	if (!(port->port.flags & ASYNC_INITIALIZED)) {
+	if (!tty_port_initialized(&port->port)) {
 		outw(0x0000, base+0x04); /* enable interrupts */
 		outw(0x0000, base+0x04); /* enable interrupts */
 		spin_unlock(&card->card_lock);
 		spin_unlock(&card->card_lock);
 		return IRQ_HANDLED;
 		return IRQ_HANDLED;
@@ -577,7 +577,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
 		header = inw(base);
 		header = inw(base);
 		switch (header & 0xff) {
 		switch (header & 0xff) {
 		case 0:	/* Change in EIA signals */
 		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 (port->status & ISI_DCD) {
 					if (!(header & ISI_DCD)) {
 					if (!(header & ISI_DCD)) {
 					/* Carrier has been lost  */
 					/* Carrier has been lost  */
@@ -758,18 +758,13 @@ static void isicom_config_port(struct tty_struct *tty)
 		outw(channel_setup, base);
 		outw(channel_setup, base);
 		InterruptTheCard(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 control settings ...*/
 	flow_ctrl = 0;
 	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;
 		flow_ctrl |= ISICOM_CTSRTS;
-	}
 	if (I_IXON(tty))
 	if (I_IXON(tty))
 		flow_ctrl |= ISICOM_RESPOND_XONXOFF;
 		flow_ctrl |= ISICOM_RESPOND_XONXOFF;
 	if (I_IXOFF(tty))
 	if (I_IXOFF(tty))

+ 6 - 6
drivers/tty/moxa.c

@@ -912,7 +912,7 @@ static void moxa_board_deinit(struct moxa_board_conf *brd)
 
 
 	/* pci hot-un-plug support */
 	/* pci hot-un-plug support */
 	for (a = 0; a < brd->numPorts; a++)
 	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);
 			tty_port_tty_hangup(&brd->ports[a].port, false);
 
 
 	for (a = 0; a < MAX_PORTS_PER_BOARD; a++)
 	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) {
 	while (1) {
 		opened = 0;
 		opened = 0;
 		for (a = 0; a < brd->numPorts; a++)
 		for (a = 0; a < brd->numPorts; a++)
-			if (brd->ports[a].port.flags & ASYNC_INITIALIZED)
+			if (tty_port_initialized(&brd->ports[a].port))
 				opened++;
 				opened++;
 		mutex_unlock(&moxa_openlock);
 		mutex_unlock(&moxa_openlock);
 		if (!opened)
 		if (!opened)
@@ -1192,13 +1192,13 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
 	tty->driver_data = ch;
 	tty->driver_data = ch;
 	tty_port_tty_set(&ch->port, tty);
 	tty_port_tty_set(&ch->port, tty);
 	mutex_lock(&ch->port.mutex);
 	mutex_lock(&ch->port.mutex);
-	if (!(ch->port.flags & ASYNC_INITIALIZED)) {
+	if (!tty_port_initialized(&ch->port)) {
 		ch->statusflags = 0;
 		ch->statusflags = 0;
 		moxa_set_tty_param(tty, &tty->termios);
 		moxa_set_tty_param(tty, &tty->termios);
 		MoxaPortLineCtrl(ch, 1, 1);
 		MoxaPortLineCtrl(ch, 1, 1);
 		MoxaPortEnable(ch);
 		MoxaPortEnable(ch);
 		MoxaSetFifo(ch, ch->type == PORT_16550A);
 		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(&ch->port.mutex);
 	mutex_unlock(&moxa_openlock);
 	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);
 	struct tty_struct *tty = tty_port_tty_get(&p->port);
 	void __iomem *ofsAddr;
 	void __iomem *ofsAddr;
-	unsigned int inited = p->port.flags & ASYNC_INITIALIZED;
+	unsigned int inited = tty_port_initialized(&p->port);
 	u16 intr;
 	u16 intr;
 
 
 	if (tty) {
 	if (tty) {
@@ -1394,7 +1394,7 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
 			tty_wakeup(tty);
 			tty_wakeup(tty);
 		}
 		}
 
 
-		if (inited && !test_bit(TTY_THROTTLED, &tty->flags) &&
+		if (inited && !tty_throttled(tty) &&
 				MoxaPortRxQueue(p) > 0) { /* RX */
 				MoxaPortRxQueue(p) > 0) { /* RX */
 			MoxaPortReadData(p);
 			MoxaPortReadData(p);
 			tty_schedule_flip(&p->port);
 			tty_schedule_flip(&p->port);

+ 13 - 22
drivers/tty/mxser.c

@@ -711,8 +711,8 @@ static int mxser_change_speed(struct tty_struct *tty,
 	/* CTS flow control flag and modem status interrupts */
 	/* CTS flow control flag and modem status interrupts */
 	info->IER &= ~UART_IER_MSI;
 	info->IER &= ~UART_IER_MSI;
 	info->MCR &= ~UART_MCR_AFE;
 	info->MCR &= ~UART_MCR_AFE;
+	tty_port_set_cts_flow(&info->port, cflag & CRTSCTS);
 	if (cflag & CRTSCTS) {
 	if (cflag & CRTSCTS) {
-		info->port.flags |= ASYNC_CTS_FLOW;
 		info->IER |= UART_IER_MSI;
 		info->IER |= UART_IER_MSI;
 		if ((info->type == PORT_16550A) || (info->board->chip_flag)) {
 		if ((info->type == PORT_16550A) || (info->board->chip_flag)) {
 			info->MCR |= UART_MCR_AFE;
 			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);
 	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;
 		info->IER |= UART_IER_MSI;
-	}
 	outb(info->IER, info->ioaddr + UART_IER);
 	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;
 	port->mon_data.modem_status = status;
 	wake_up_interruptible(&port->port.delta_msr_wait);
 	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)
 		if (status & UART_MSR_DCD)
 			wake_up_interruptible(&port->port.open_wait);
 			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);
 	mutex_lock(&port->mutex);
 	mxser_close_port(port);
 	mxser_close_port(port);
 	mxser_flush_buffer(tty);
 	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);
 	mxser_shutdown_port(port);
-	clear_bit(ASYNCB_INITIALIZED, &port->flags);
+	tty_port_set_initialized(port, 0);
 	mutex_unlock(&port->mutex);
 	mutex_unlock(&port->mutex);
 	info->closing = 0;
 	info->closing = 0;
 	/* Right now the tty_port set is done outside of the close_end helper
 	/* 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);
 	process_txrx_fifo(info);
 
 
-	if (test_bit(ASYNCB_INITIALIZED, &port->flags)) {
+	if (tty_port_initialized(port)) {
 		if (flags != (port->flags & ASYNC_SPD_MASK)) {
 		if (flags != (port->flags & ASYNC_SPD_MASK)) {
 			spin_lock_irqsave(&info->slock, sl_flags);
 			spin_lock_irqsave(&info->slock, sl_flags);
 			mxser_change_speed(tty, NULL);
 			mxser_change_speed(tty, NULL);
@@ -1296,7 +1289,7 @@ static int mxser_set_serial_info(struct tty_struct *tty,
 	} else {
 	} else {
 		retval = mxser_activate(port, tty);
 		retval = mxser_activate(port, tty);
 		if (retval == 0)
 		if (retval == 0)
-			set_bit(ASYNCB_INITIALIZED, &port->flags);
+			tty_port_set_initialized(port, 1);
 	}
 	}
 	return retval;
 	return retval;
 }
 }
@@ -1334,7 +1327,7 @@ static int mxser_tiocmget(struct tty_struct *tty)
 
 
 	if (tty->index == MXSER_PORTS)
 	if (tty->index == MXSER_PORTS)
 		return -ENOIOCTLCMD;
 		return -ENOIOCTLCMD;
-	if (test_bit(TTY_IO_ERROR, &tty->flags))
+	if (tty_io_error(tty))
 		return -EIO;
 		return -EIO;
 
 
 	control = info->MCR;
 	control = info->MCR;
@@ -1361,7 +1354,7 @@ static int mxser_tiocmset(struct tty_struct *tty,
 
 
 	if (tty->index == MXSER_PORTS)
 	if (tty->index == MXSER_PORTS)
 		return -ENOIOCTLCMD;
 		return -ENOIOCTLCMD;
-	if (test_bit(TTY_IO_ERROR, &tty->flags))
+	if (tty_io_error(tty))
 		return -EIO;
 		return -EIO;
 
 
 	spin_lock_irqsave(&info->slock, flags);
 	spin_lock_irqsave(&info->slock, flags);
@@ -1715,8 +1708,7 @@ static int mxser_ioctl(struct tty_struct *tty,
 		return 0;
 		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;
 		return -EIO;
 
 
 	switch (cmd) {
 	switch (cmd) {
@@ -2257,7 +2249,7 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
 				iir &= MOXA_MUST_IIR_MASK;
 				iir &= MOXA_MUST_IIR_MASK;
 				tty = tty_port_tty_get(&port->port);
 				tty = tty_port_tty_get(&port->port);
 				if (!tty || port->closing ||
 				if (!tty || port->closing ||
-				    !(port->port.flags & ASYNC_INITIALIZED)) {
+				    !tty_port_initialized(&port->port)) {
 					status = inb(port->ioaddr + UART_LSR);
 					status = inb(port->ioaddr + UART_LSR);
 					outb(0x27, port->ioaddr + UART_FCR);
 					outb(0x27, port->ioaddr + UART_FCR);
 					inb(port->ioaddr + UART_MSR);
 					inb(port->ioaddr + UART_MSR);
@@ -2400,7 +2392,6 @@ static int mxser_initbrd(struct mxser_board *brd,
 		if (brd->chip_flag != MOXA_OTHER_UART)
 		if (brd->chip_flag != MOXA_OTHER_UART)
 			mxser_enable_must_enchance_mode(info->ioaddr);
 			mxser_enable_must_enchance_mode(info->ioaddr);
 
 
-		info->port.flags = ASYNC_SHARE_IRQ;
 		info->type = brd->uart_type;
 		info->type = brd->uart_type;
 
 
 		process_txrx_fifo(info);
 		process_txrx_fifo(info);

+ 6 - 6
drivers/tty/n_gsm.c

@@ -2045,7 +2045,9 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm)
 		}
 		}
 	}
 	}
 	spin_unlock(&gsm_mux_lock);
 	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
 	/* In theory disconnecting DLCI 0 is sufficient but for some
 	   modems this is apparently not the case. */
 	   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;
 	dlci->modem_rx = 0;
 	/* We could in theory open and close before we wait - eg if we get
 	/* 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 */
 	   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 */
 	/* Start sending off SABM messages */
 	gsm_dlci_begin_open(dlci);
 	gsm_dlci_begin_open(dlci);
 	/* And wait for virtual carrier */
 	/* 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)
 	if (tty_port_close_start(&dlci->port, tty, filp) == 0)
 		return;
 		return;
 	gsm_dlci_begin_close(dlci);
 	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_close_end(&dlci->port, tty);
 	tty_port_tty_set(&dlci->port, NULL);
 	tty_port_tty_set(&dlci->port, NULL);
 	return;
 	return;

+ 2 - 2
drivers/tty/n_hdlc.c

@@ -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);
 	add_wait_queue(&tty->read_wait, &wait);
 
 
 	for (;;) {
 	for (;;) {
-		if (test_bit(TTY_OTHER_DONE, &tty->flags)) {
+		if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
 			ret = -EIO;
 			ret = -EIO;
 			break;
 			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 */
 		/* set bits for operations that won't block */
 		if (n_hdlc->rx_buf_list.head)
 		if (n_hdlc->rx_buf_list.head)
 			mask |= POLLIN | POLLRDNORM;	/* readable */
 			mask |= POLLIN | POLLRDNORM;	/* readable */
-		if (test_bit(TTY_OTHER_DONE, &tty->flags))
+		if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
 			mask |= POLLHUP;
 			mask |= POLLHUP;
 		if (tty_hung_up_p(filp))
 		if (tty_hung_up_p(filp))
 			mask |= POLLHUP;
 			mask |= POLLHUP;

+ 33 - 37
drivers/tty/n_tty.c

@@ -1917,18 +1917,6 @@ static inline int input_available_p(struct tty_struct *tty, int poll)
 		return ldata->commit_head - ldata->read_tail >= amt;
 		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
  *	copy_from_read_buf	-	copy read data directly
  *	@tty: terminal device
  *	@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;
 	struct n_tty_data *ldata = tty->disc_data;
 	unsigned char __user *b = buf;
 	unsigned char __user *b = buf;
 	DEFINE_WAIT_FUNC(wait, woken_wake_function);
 	DEFINE_WAIT_FUNC(wait, woken_wake_function);
-	int c, done;
+	int c;
 	int minimum, time;
 	int minimum, time;
 	ssize_t retval = 0;
 	ssize_t retval = 0;
 	long timeout;
 	long timeout;
@@ -2183,32 +2171,35 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
 			break;
 			break;
 		}
 		}
 
 
-		done = check_other_done(tty);
-
 		if (!input_available_p(tty, 0)) {
 		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);
 			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)) {
 		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->read_wait, wait);
 	poll_wait(file, &tty->write_wait, wait);
 	poll_wait(file, &tty->write_wait, wait);
-	if (check_other_done(tty))
-		mask |= POLLHUP;
 	if (input_available_p(tty, 1))
 	if (input_available_p(tty, 1))
 		mask |= POLLIN | POLLRDNORM;
 		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)
 	if (tty->packet && tty->link->ctrl_status)
 		mask |= POLLPRI | POLLIN | POLLRDNORM;
 		mask |= POLLPRI | POLLIN | POLLRDNORM;
+	if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
+		mask |= POLLHUP;
 	if (tty_hung_up_p(file))
 	if (tty_hung_up_p(file))
 		mask |= POLLHUP;
 		mask |= POLLHUP;
 	if (tty->ops->write && !tty_is_writelocked(tty) &&
 	if (tty->ops->write && !tty_is_writelocked(tty) &&

+ 1 - 1
drivers/tty/nozomi.c

@@ -826,7 +826,7 @@ static int receive_data(enum port_type index, struct nozomi *dc)
 	size = __le32_to_cpu(readl(addr));
 	size = __le32_to_cpu(readl(addr));
 	/*  DBG1( "%d bytes port: %d", size, index); */
 	/*  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, "
 		DBG1("No room in tty, don't read data, don't ack interrupt, "
 			"disable interrupt");
 			"disable interrupt");
 
 

+ 2 - 4
drivers/tty/pty.c

@@ -44,7 +44,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
 	if (tty->driver->subtype == PTY_TYPE_MASTER)
 	if (tty->driver->subtype == PTY_TYPE_MASTER)
 		WARN_ON(tty->count > 1);
 		WARN_ON(tty->count > 1);
 	else {
 	else {
-		if (test_bit(TTY_IO_ERROR, &tty->flags))
+		if (tty_io_error(tty))
 			return;
 			return;
 		if (tty->count > 2)
 		if (tty->count > 2)
 			return;
 			return;
@@ -59,7 +59,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
 	if (!tty->link)
 	if (!tty->link)
 		return;
 		return;
 	set_bit(TTY_OTHER_CLOSED, &tty->link->flags);
 	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);
 	wake_up_interruptible(&tty->link->write_wait);
 	if (tty->driver->subtype == PTY_TYPE_MASTER) {
 	if (tty->driver->subtype == PTY_TYPE_MASTER) {
 		set_bit(TTY_OTHER_CLOSED, &tty->flags);
 		set_bit(TTY_OTHER_CLOSED, &tty->flags);
@@ -247,9 +247,7 @@ static int pty_open(struct tty_struct *tty, struct file *filp)
 		goto out;
 		goto out;
 
 
 	clear_bit(TTY_IO_ERROR, &tty->flags);
 	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_CLOSED, &tty->link->flags);
-	clear_bit(TTY_OTHER_DONE, &tty->link->flags);
 	set_bit(TTY_THROTTLED, &tty->flags);
 	set_bit(TTY_THROTTLED, &tty->flags);
 	return 0;
 	return 0;
 
 

+ 9 - 7
drivers/tty/rocket.c

@@ -495,7 +495,7 @@ static void rp_handle_port(struct r_port *info)
 	if (!info)
 	if (!info)
 		return;
 		return;
 
 
-	if ((info->port.flags & ASYNC_INITIALIZED) == 0) {
+	if (!tty_port_initialized(&info->port)) {
 		printk(KERN_WARNING "rp: WARNING: rp_handle_port called with "
 		printk(KERN_WARNING "rp: WARNING: rp_handle_port called with "
 				"info->flags & NOT_INIT\n");
 				"info->flags & NOT_INIT\n");
 		return;
 		return;
@@ -615,7 +615,8 @@ static void rp_do_poll(unsigned long dummy)
  *  the board.  
  *  the board.  
  *  Inputs:  board, aiop, chan numbers
  *  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;
 	unsigned rocketMode;
 	struct r_port *info;
 	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.
 	 * 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;
 		cp = &info->channel;
 		sSetRxTrigger(cp, TRIG_1);
 		sSetRxTrigger(cp, TRIG_1);
 		if (sGetChanStatus(cp) & CD_ACT)
 		if (sGetChanStatus(cp) & CD_ACT)
@@ -944,7 +945,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
 		sEnRxFIFO(cp);
 		sEnRxFIFO(cp);
 		sEnTransmit(cp);
 		sEnTransmit(cp);
 
 
-		set_bit(ASYNCB_INITIALIZED, &info->port.flags);
+		tty_port_set_initialized(&info->port, 1);
 
 
 		/*
 		/*
 		 * Set up the tty->alt_speed kludge
 		 * 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);
 	spin_lock_irq(&port->lock);
-	info->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_NORMAL_ACTIVE);
 	tty->closing = 0;
 	tty->closing = 0;
 	spin_unlock_irq(&port->lock);
 	spin_unlock_irq(&port->lock);
+	tty_port_set_initialized(port, 0);
+	tty_port_set_active(port, 0);
 	mutex_unlock(&port->mutex);
 	mutex_unlock(&port->mutex);
 	tty_port_tty_set(port, NULL);
 	tty_port_tty_set(port, NULL);
 
 
@@ -1512,7 +1514,7 @@ static void rp_hangup(struct tty_struct *tty)
 	sDisCTSFlowCtl(cp);
 	sDisCTSFlowCtl(cp);
 	sDisTxSoftFlowCtl(cp);
 	sDisTxSoftFlowCtl(cp);
 	sClrTxXOFF(cp);
 	sClrTxXOFF(cp);
-	clear_bit(ASYNCB_INITIALIZED, &info->port.flags);
+	tty_port_set_initialized(&info->port, 0);
 
 
 	wake_up_interruptible(&info->port.open_wait);
 	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 */
 	/*  Write remaining data into the port's xmit_buf */
 	while (1) {
 	while (1) {
 		/* Hung up ? */
 		/* Hung up ? */
-		if (!test_bit(ASYNCB_NORMAL_ACTIVE, &info->port.flags))
+		if (!tty_port_active(&info->port))
 			goto end;
 			goto end;
 		c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1);
 		c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1);
 		c = min(c, XMIT_BUF_SIZE - info->xmit_head);
 		c = min(c, XMIT_BUF_SIZE - info->xmit_head);

+ 11 - 4
drivers/tty/serial/8250/8250.h

@@ -17,7 +17,7 @@
 
 
 struct uart_8250_dma {
 struct uart_8250_dma {
 	int (*tx_dma)(struct uart_8250_port *p);
 	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 */
 	/* Filter function */
 	dma_filter_fn		fn;
 	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_THRE	(1 << 3)	/* UART has buggy THRE reassertion */
 #define UART_BUG_PARITY	(1 << 4)	/* UART mishandles parity if FIFO enabled */
 #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
 #ifdef CONFIG_SERIAL_8250_SHARE_IRQ
 #define SERIAL8250_SHARE_IRQS 1
 #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) { }
 static inline void serial8250_pnp_exit(void) { }
 #endif
 #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
 #ifdef CONFIG_ARCH_OMAP1
 static inline int is_omap1_8250(struct uart_8250_port *pt)
 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
 #ifdef CONFIG_SERIAL_8250_DMA
 extern int serial8250_tx_dma(struct uart_8250_port *);
 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 int serial8250_request_dma(struct uart_8250_port *);
 extern void serial8250_release_dma(struct uart_8250_port *);
 extern void serial8250_release_dma(struct uart_8250_port *);
 #else
 #else
@@ -198,10 +204,11 @@ static inline int serial8250_tx_dma(struct uart_8250_port *p)
 {
 {
 	return -1;
 	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;
 	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)
 static inline int serial8250_request_dma(struct uart_8250_port *p)
 {
 {
 	return -1;
 	return -1;

+ 3 - 0
drivers/tty/serial/8250/8250_core.c

@@ -830,6 +830,7 @@ static int serial8250_probe(struct platform_device *dev)
 		uart.port.handle_irq	= p->handle_irq;
 		uart.port.handle_irq	= p->handle_irq;
 		uart.port.handle_break	= p->handle_break;
 		uart.port.handle_break	= p->handle_break;
 		uart.port.set_termios	= p->set_termios;
 		uart.port.set_termios	= p->set_termios;
+		uart.port.get_mctrl	= p->get_mctrl;
 		uart.port.pm		= p->pm;
 		uart.port.pm		= p->pm;
 		uart.port.dev		= &dev->dev;
 		uart.port.dev		= &dev->dev;
 		uart.port.irqflags	|= irqflag;
 		uart.port.irqflags	|= irqflag;
@@ -1022,6 +1023,8 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
 		/*  Possibly override set_termios call */
 		/*  Possibly override set_termios call */
 		if (up->port.set_termios)
 		if (up->port.set_termios)
 			uart->port.set_termios = 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)
 		if (up->port.set_mctrl)
 			uart->port.set_mctrl = up->port.set_mctrl;
 			uart->port.set_mctrl = up->port.set_mctrl;
 		if (up->port.startup)
 		if (up->port.startup)

+ 42 - 26
drivers/tty/serial/8250/8250_dma.c

@@ -110,30 +110,11 @@ err:
 	return ret;
 	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 uart_8250_dma		*dma = p->dma;
 	struct dma_async_tx_descriptor	*desc;
 	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)
 	if (dma->rx_running)
 		return 0;
 		return 0;
 
 
@@ -154,10 +135,23 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
 	return 0;
 	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)
 int serial8250_request_dma(struct uart_8250_port *p)
 {
 {
 	struct uart_8250_dma	*dma = p->dma;
 	struct uart_8250_dma	*dma = p->dma;
 	dma_cap_mask_t		mask;
 	dma_cap_mask_t		mask;
+	struct dma_slave_caps	caps;
+	int			ret;
 
 
 	/* Default slave configuration parameters */
 	/* Default slave configuration parameters */
 	dma->rxconf.direction		= DMA_DEV_TO_MEM;
 	dma->rxconf.direction		= DMA_DEV_TO_MEM;
@@ -178,6 +172,16 @@ int serial8250_request_dma(struct uart_8250_port *p)
 	if (!dma->rxchan)
 	if (!dma->rxchan)
 		return -ENODEV;
 		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);
 	dmaengine_slave_config(dma->rxchan, &dma->rxconf);
 
 
 	/* Get a channel for TX */
 	/* Get a channel for TX */
@@ -185,8 +189,17 @@ int serial8250_request_dma(struct uart_8250_port *p)
 						       dma->fn, dma->tx_param,
 						       dma->fn, dma->tx_param,
 						       p->port.dev, "tx");
 						       p->port.dev, "tx");
 	if (!dma->txchan) {
 	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);
 	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_buf = dma_alloc_coherent(dma->rxchan->device->dev, dma->rx_size,
 					&dma->rx_addr, GFP_KERNEL);
 					&dma->rx_addr, GFP_KERNEL);
-	if (!dma->rx_buf)
+	if (!dma->rx_buf) {
+		ret = -ENOMEM;
 		goto err;
 		goto err;
+	}
 
 
 	/* TX buffer */
 	/* TX buffer */
 	dma->tx_addr = dma_map_single(dma->txchan->device->dev,
 	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)) {
 	if (dma_mapping_error(dma->txchan->device->dev, dma->tx_addr)) {
 		dma_free_coherent(dma->rxchan->device->dev, dma->rx_size,
 		dma_free_coherent(dma->rxchan->device->dev, dma->rx_size,
 				  dma->rx_buf, dma->rx_addr);
 				  dma->rx_buf, dma->rx_addr);
+		ret = -ENOMEM;
 		goto err;
 		goto err;
 	}
 	}
 
 
@@ -215,10 +231,10 @@ int serial8250_request_dma(struct uart_8250_port *p)
 
 
 	return 0;
 	return 0;
 err:
 err:
-	dma_release_channel(dma->rxchan);
 	dma_release_channel(dma->txchan);
 	dma_release_channel(dma->txchan);
-
-	return -ENOMEM;
+release_rx:
+	dma_release_channel(dma->rxchan);
+	return ret;
 }
 }
 EXPORT_SYMBOL_GPL(serial8250_request_dma);
 EXPORT_SYMBOL_GPL(serial8250_request_dma);
 
 

+ 5 - 3
drivers/tty/serial/8250/8250_dw.c

@@ -104,15 +104,16 @@ static void dw8250_check_lcr(struct uart_port *p, int value)
 		dw8250_force_idle(p);
 		dw8250_force_idle(p);
 
 
 #ifdef CONFIG_64BIT
 #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)
 		if (p->iotype == UPIO_MEM32)
 			writel(value, offset);
 			writel(value, offset);
 		else if (p->iotype == UPIO_MEM32BE)
 		else if (p->iotype == UPIO_MEM32BE)
 			iowrite32be(value, offset);
 			iowrite32be(value, offset);
 		else
 		else
 			writeb(value, offset);
 			writeb(value, offset);
-#endif
 	}
 	}
 	/*
 	/*
 	 * FIXME: this deadlocks if port->lock is already held
 	 * FIXME: this deadlocks if port->lock is already held
@@ -617,6 +618,7 @@ static const struct acpi_device_id dw8250_acpi_match[] = {
 	{ "8086228A", 0 },
 	{ "8086228A", 0 },
 	{ "APMC0D08", 0},
 	{ "APMC0D08", 0},
 	{ "AMD0020", 0 },
 	{ "AMD0020", 0 },
+	{ "AMDI0020", 0 },
 	{ },
 	{ },
 };
 };
 MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
 MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);

+ 16 - 102
drivers/tty/serial/8250/8250_fintek.c

@@ -1,9 +1,7 @@
 /*
 /*
  *  Probe for F81216A LPC to 4 UART
  *  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
  * This program is free software; you can redistribute it and/or modify
@@ -38,19 +36,15 @@
 #define RXW4C_IRA BIT(3)
 #define RXW4C_IRA BIT(3)
 #define TXW4C_IRA BIT(2)
 #define TXW4C_IRA BIT(2)
 
 
-#define DRIVER_NAME "8250_fintek"
-
 struct fintek_8250 {
 struct fintek_8250 {
 	u16 base_port;
 	u16 base_port;
 	u8 index;
 	u8 index;
 	u8 key;
 	u8 key;
-	long line;
 };
 };
 
 
 static int fintek_8250_enter_key(u16 base_port, u8 key)
 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;
 		return -EBUSY;
 
 
 	outb(key, base_port + ADDR_PORT);
 	outb(key, base_port + ADDR_PORT);
@@ -138,7 +132,7 @@ static int fintek_8250_rs485_config(struct uart_port *port,
 	return 0;
 	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 u16 addr[] = {0x4e, 0x2e};
 	static const u8 keys[] = {0x77, 0xa0, 0x87, 0x67};
 	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;
 					continue;
 
 
 				fintek_8250_exit_key(addr[i]);
 				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]);
 			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;
 	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;
 	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;
 		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)
 	if (!pdata)
 		return -ENOMEM;
 		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;
 	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");

+ 29 - 15
drivers/tty/serial/8250/8250_mid.c

@@ -9,11 +9,13 @@
  * published by the Free Software Foundation.
  * published by the Free Software Foundation.
  */
  */
 
 
-#include <linux/rational.h>
+#include <linux/bitops.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/pci.h>
+#include <linux/rational.h>
 
 
 #include <linux/dma/hsu.h>
 #include <linux/dma/hsu.h>
+#include <linux/8250_pci.h>
 
 
 #include "8250.h"
 #include "8250.h"
 
 
@@ -24,6 +26,7 @@
 #define PCI_DEVICE_ID_INTEL_DNV_UART	0x19d8
 #define PCI_DEVICE_ID_INTEL_DNV_UART	0x19d8
 
 
 /* Intel MID Specific registers */
 /* Intel MID Specific registers */
+#define INTEL_MID_UART_DNV_FISR		0x08
 #define INTEL_MID_UART_PS		0x30
 #define INTEL_MID_UART_PS		0x30
 #define INTEL_MID_UART_MUL		0x34
 #define INTEL_MID_UART_MUL		0x34
 #define INTEL_MID_UART_DIV		0x38
 #define INTEL_MID_UART_DIV		0x38
@@ -31,6 +34,7 @@
 struct mid8250;
 struct mid8250;
 
 
 struct mid8250_board {
 struct mid8250_board {
+	unsigned int flags;
 	unsigned long freq;
 	unsigned long freq;
 	unsigned int base_baud;
 	unsigned int base_baud;
 	int (*setup)(struct mid8250 *, struct uart_port *p);
 	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);
 	struct pci_dev *pdev = to_pci_dev(p->dev);
 	int index = PCI_FUNC(pdev->devfn);
 	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)
 	if (index-- == 0)
 		return -ENODEV;
 		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)
 static int dnv_handle_irq(struct uart_port *p)
 {
 {
 	struct mid8250 *mid = p->private_data;
 	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
 #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 hsu_dma_chip *chip = &mid->dma_chip;
 	struct pci_dev *pdev = to_pci_dev(p->dev);
 	struct pci_dev *pdev = to_pci_dev(p->dev);
+	unsigned int bar = FL_GET_BASE(mid->board->flags);
 	int ret;
 	int ret;
 
 
 	chip->dev = &pdev->dev;
 	chip->dev = &pdev->dev;
 	chip->irq = pdev->irq;
 	chip->irq = pdev->irq;
 	chip->regs = p->membase;
 	chip->regs = p->membase;
-	chip->length = pci_resource_len(pdev, 0);
+	chip->length = pci_resource_len(pdev, bar);
 	chip->offset = DNV_DMA_CHAN_OFFSET;
 	chip->offset = DNV_DMA_CHAN_OFFSET;
 
 
 	/* Falling back to PIO mode if DMA probing fails */
 	/* 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 uart_8250_port uart;
 	struct mid8250 *mid;
 	struct mid8250 *mid;
+	unsigned int bar;
 	int ret;
 	int ret;
 
 
 	ret = pcim_enable_device(pdev);
 	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;
 		return -ENOMEM;
 
 
 	mid->board = (struct mid8250_board *)id->driver_data;
 	mid->board = (struct mid8250_board *)id->driver_data;
+	bar = FL_GET_BASE(mid->board->flags);
 
 
 	memset(&uart, 0, sizeof(struct uart_8250_port));
 	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.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE;
 	uart.port.set_termios = mid8250_set_termios;
 	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)
 	if (!uart.port.membase)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
@@ -282,18 +293,21 @@ static void mid8250_remove(struct pci_dev *pdev)
 }
 }
 
 
 static const struct mid8250_board pnw_board = {
 static const struct mid8250_board pnw_board = {
+	.flags = FL_BASE0,
 	.freq = 50000000,
 	.freq = 50000000,
 	.base_baud = 115200,
 	.base_baud = 115200,
 	.setup = pnw_setup,
 	.setup = pnw_setup,
 };
 };
 
 
 static const struct mid8250_board tng_board = {
 static const struct mid8250_board tng_board = {
+	.flags = FL_BASE0,
 	.freq = 38400000,
 	.freq = 38400000,
 	.base_baud = 1843200,
 	.base_baud = 1843200,
 	.setup = tng_setup,
 	.setup = tng_setup,
 };
 };
 
 
 static const struct mid8250_board dnv_board = {
 static const struct mid8250_board dnv_board = {
+	.flags = FL_BASE1,
 	.freq = 133333333,
 	.freq = 133333333,
 	.base_baud = 115200,
 	.base_baud = 115200,
 	.setup = dnv_setup,
 	.setup = dnv_setup,

+ 1 - 1
drivers/tty/serial/8250/8250_of.c

@@ -29,7 +29,7 @@ struct of_serial_info {
 };
 };
 
 
 #ifdef CONFIG_ARCH_TEGRA
 #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;
 	unsigned int status, tmout = 10000;
 
 

+ 34 - 59
drivers/tty/serial/8250/8250_omap.c

@@ -115,6 +115,12 @@ struct omap8250_priv {
 	bool rx_dma_broken;
 	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)
 static u32 uart_read(struct uart_8250_port *up, u32 reg)
 {
 {
 	return readl(up->port.membase + (reg << up->port.regshift));
 	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);
 	serial_out(up, UART_OMAP_WER, priv->wer);
 
 
 	if (up->dma)
 	if (up->dma)
-		up->dma->rx_dma(up, 0);
+		up->dma->rx_dma(up);
 
 
 	pm_runtime_mark_last_busy(port->dev);
 	pm_runtime_mark_last_busy(port->dev);
 	pm_runtime_put_autosuspend(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);
 	flush_work(&priv->qos_work);
 	if (up->dma)
 	if (up->dma)
-		up->dma->rx_dma(up, UART_IIR_RX_TIMEOUT);
+		omap_8250_rx_dma_flush(up);
 
 
 	pm_runtime_get_sync(port->dev);
 	pm_runtime_get_sync(port->dev);
 
 
@@ -742,9 +748,9 @@ static void omap_8250_unthrottle(struct uart_port *port)
 }
 }
 
 
 #ifdef CONFIG_SERIAL_8250_DMA
 #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 omap8250_priv	*priv = p->port.private_data;
 	struct uart_8250_dma    *dma = p->dma;
 	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;
 	unsigned long		flags;
 	int			ret;
 	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);
 	spin_lock_irqsave(&priv->rx_dma_lock, flags);
 
 
 	if (!dma->rx_running)
 	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;
 	dma->rx_running = 0;
 	dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
 	dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
-	dmaengine_terminate_all(dma->rxchan);
 
 
 	count = dma->rx_size - state.residue;
 	count = dma->rx_size - state.residue;
 
 
@@ -775,15 +777,13 @@ static void __dma_rx_do_complete(struct uart_8250_port *p, bool error)
 unlock:
 unlock:
 	spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
 	spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
 
 
-	if (!error)
-		omap_8250_rx_dma(p, 0);
-
 	tty_flip_buffer_push(tty_port);
 	tty_flip_buffer_push(tty_port);
 }
 }
 
 
 static void __dma_rx_complete(void *param)
 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)
 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);
 	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 omap8250_priv		*priv = p->port.private_data;
 	struct uart_8250_dma            *dma = p->dma;
 	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;
 	struct dma_async_tx_descriptor  *desc;
 	unsigned long			flags;
 	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)
 	if (priv->rx_dma_broken)
 		return -EINVAL;
 		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->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);
 	dma_async_issue_pending(dma->rxchan);
 out:
 out:
 	spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
 	spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
@@ -1022,6 +991,18 @@ err:
 	return ret;
 	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
  * 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
  * 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 char status;
 	unsigned long flags;
 	unsigned long flags;
 	u8 iir;
 	u8 iir;
-	int dma_err = 0;
 
 
 	serial8250_rpm_get(up);
 	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);
 	status = serial_port_in(port, UART_LSR);
 
 
 	if (status & (UART_LSR_DR | UART_LSR_BI)) {
 	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);
 			status = serial8250_rx_chars(up, status);
-			omap_8250_rx_dma(up, 0);
+			omap_8250_rx_dma(up);
 		}
 		}
 	}
 	}
 	serial8250_modem_status(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
 			 * try again due to an earlier failer which
 			 * might have been resolved by now.
 			 * 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);
 				serial8250_tx_chars(up);
 		}
 		}
 	}
 	}
@@ -1084,7 +1061,7 @@ static bool the_no_dma_filter_fn(struct dma_chan *chan, void *param)
 
 
 #else
 #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;
 	return -EINVAL;
 }
 }
@@ -1395,7 +1372,7 @@ static int omap8250_runtime_suspend(struct device *dev)
 	}
 	}
 
 
 	if (up->dma && up->dma->rxchan)
 	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;
 	priv->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;
 	schedule_work(&priv->qos_work);
 	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 omap8250_priv *priv = dev_get_drvdata(dev);
 	struct uart_8250_port *up;
 	struct uart_8250_port *up;
-	int loss_cntx;
 
 
 	/* In case runtime-pm tries this before we are setup */
 	/* In case runtime-pm tries this before we are setup */
 	if (!priv)
 	if (!priv)
 		return 0;
 		return 0;
 
 
 	up = serial8250_get_port(priv->line);
 	up = serial8250_get_port(priv->line);
-	loss_cntx = omap8250_lost_context(up);
 
 
-	if (loss_cntx)
+	if (omap8250_lost_context(up))
 		omap8250_restore_regs(up);
 		omap8250_restore_regs(up);
 
 
 	if (up->dma && up->dma->rxchan)
 	if (up->dma && up->dma->rxchan)
-		omap_8250_rx_dma(up, 0);
+		omap_8250_rx_dma(up);
 
 
 	priv->latency = priv->calc_latency;
 	priv->latency = priv->calc_latency;
 	schedule_work(&priv->qos_work);
 	schedule_work(&priv->qos_work);

+ 15 - 0
drivers/tty/serial/8250/8250_pci.c

@@ -1377,6 +1377,9 @@ byt_set_termios(struct uart_port *p, struct ktermios *termios,
 	unsigned long m, n;
 	unsigned long m, n;
 	u32 reg;
 	u32 reg;
 
 
+	/* Gracefully handle the B0 case: fall back to B9600 */
+	fuart = fuart ? fuart : 9600 * 16;
+
 	/* Get Fuart closer to Fref */
 	/* Get Fuart closer to Fref */
 	fuart *= rounddown_pow_of_two(fref / fuart);
 	fuart *= rounddown_pow_of_two(fref / fuart);
 
 
@@ -1413,6 +1416,17 @@ static bool byt_dma_filter(struct dma_chan *chan, void *param)
 	return true;
 	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
 static int
 byt_serial_setup(struct serial_private *priv,
 byt_serial_setup(struct serial_private *priv,
 		 const struct pciserial_board *board,
 		 const struct pciserial_board *board,
@@ -1477,6 +1491,7 @@ byt_serial_setup(struct serial_private *priv,
 	port->port.type = PORT_16550A;
 	port->port.type = PORT_16550A;
 	port->port.flags = (port->port.flags | UPF_FIXED_PORT | UPF_FIXED_TYPE);
 	port->port.flags = (port->port.flags | UPF_FIXED_PORT | UPF_FIXED_TYPE);
 	port->port.set_termios = byt_set_termios;
 	port->port.set_termios = byt_set_termios;
+	port->port.get_mctrl = byt_get_mctrl;
 	port->port.fifosize = 64;
 	port->port.fifosize = 64;
 	port->tx_loadsz = 64;
 	port->tx_loadsz = 64;
 	port->dma = dma;
 	port->dma = dma;

+ 30 - 8
drivers/tty/serial/8250/8250_port.c

@@ -1315,6 +1315,13 @@ static void autoconfig(struct uart_8250_port *up)
 
 
 out_lock:
 out_lock:
 	spin_unlock_irqrestore(&port->lock, flags);
 	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) {
 	if (up->capabilities != old_capabilities) {
 		pr_warn("ttyS%d: detected caps %08x should be %08x\n",
 		pr_warn("ttyS%d: detected caps %08x should be %08x\n",
 		       serial_index(port), old_capabilities,
 		       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);
 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.
  * 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 char status;
 	unsigned long flags;
 	unsigned long flags;
 	struct uart_8250_port *up = up_to_u8250p(port);
 	struct uart_8250_port *up = up_to_u8250p(port);
-	int dma_err = 0;
 
 
 	if (iir & UART_IIR_NO_INT)
 	if (iir & UART_IIR_NO_INT)
 		return 0;
 		return 0;
@@ -1808,15 +1826,11 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
 	DEBUG_INTR("status = %x...", status);
 	DEBUG_INTR("status = %x...", status);
 
 
 	if (status & (UART_LSR_DR | UART_LSR_BI)) {
 	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);
 			status = serial8250_rx_chars(up, status);
 	}
 	}
 	serial8250_modem_status(up);
 	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);
 		serial8250_tx_chars(up);
 
 
 	spin_unlock_irqrestore(&port->lock, flags);
 	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;
 	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);
 	struct uart_8250_port *up = up_to_u8250p(port);
 	unsigned int status;
 	unsigned int status;
@@ -1903,6 +1917,14 @@ static unsigned int serial8250_get_mctrl(struct uart_port *port)
 		ret |= TIOCM_CTS;
 		ret |= TIOCM_CTS;
 	return ret;
 	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)
 void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
 {

+ 1 - 1
drivers/tty/serial/8250/8250_uniphier.c

@@ -209,7 +209,7 @@ static int uniphier_uart_probe(struct platform_device *pdev)
 
 
 	irq = platform_get_irq(pdev, 0);
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
 	if (irq < 0) {
-		dev_err(dev, "failed to get IRQ number");
+		dev_err(dev, "failed to get IRQ number\n");
 		return irq;
 		return irq;
 	}
 	}
 
 

+ 15 - 9
drivers/tty/serial/8250/Kconfig

@@ -57,6 +57,18 @@ config SERIAL_8250_PNP
 	  This builds standard PNP serial support. You may be able to
 	  This builds standard PNP serial support. You may be able to
 	  disable this feature if you only need legacy serial support.
 	  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
 config SERIAL_8250_CONSOLE
 	bool "Console on 8250/16550 and compatible serial port"
 	bool "Console on 8250/16550 and compatible serial port"
 	depends on SERIAL_8250=y
 	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
 	  not booting kernel because the serial console remains silent in case
 	  they forgot to update the command line.
 	  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
 config SERIAL_8250_LPC18XX
 	tristate "NXP LPC18xx/43xx serial port support"
 	tristate "NXP LPC18xx/43xx serial port support"
 	depends on SERIAL_8250 && OF && (ARCH_LPC18XX || COMPILE_TEST)
 	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.
 	  its UARTs, say Y to this option. If unsure, say N.
 
 
 config SERIAL_8250_MID
 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 SERIAL_8250 && PCI
+	depends on X86 || COMPILE_TEST
 	select HSU_DMA if SERIAL_8250_DMA
 	select HSU_DMA if SERIAL_8250_DMA
 	select HSU_DMA_PCI if (HSU_DMA && X86_INTEL_MID)
 	select HSU_DMA_PCI if (HSU_DMA && X86_INTEL_MID)
 	select RATIONAL
 	select RATIONAL

+ 1 - 1
drivers/tty/serial/8250/Makefile

@@ -7,6 +7,7 @@ obj-$(CONFIG_SERIAL_8250)		+= 8250.o 8250_base.o
 8250-$(CONFIG_SERIAL_8250_PNP)		+= 8250_pnp.o
 8250-$(CONFIG_SERIAL_8250_PNP)		+= 8250_pnp.o
 8250_base-y				:= 8250_port.o
 8250_base-y				:= 8250_port.o
 8250_base-$(CONFIG_SERIAL_8250_DMA)	+= 8250_dma.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_GSC)		+= 8250_gsc.o
 obj-$(CONFIG_SERIAL_8250_PCI)		+= 8250_pci.o
 obj-$(CONFIG_SERIAL_8250_PCI)		+= 8250_pci.o
 obj-$(CONFIG_SERIAL_8250_HP300)		+= 8250_hp300.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_DW)		+= 8250_dw.o
 obj-$(CONFIG_SERIAL_8250_EM)		+= 8250_em.o
 obj-$(CONFIG_SERIAL_8250_EM)		+= 8250_em.o
 obj-$(CONFIG_SERIAL_8250_OMAP)		+= 8250_omap.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_LPC18XX)	+= 8250_lpc18xx.o
 obj-$(CONFIG_SERIAL_8250_MT6577)	+= 8250_mtk.o
 obj-$(CONFIG_SERIAL_8250_MT6577)	+= 8250_mtk.o
 obj-$(CONFIG_SERIAL_8250_UNIPHIER)	+= 8250_uniphier.o
 obj-$(CONFIG_SERIAL_8250_UNIPHIER)	+= 8250_uniphier.o

+ 18 - 2
drivers/tty/serial/Kconfig

@@ -213,6 +213,7 @@ config SERIAL_MESON_CONSOLE
 	bool "Support for console on meson"
 	bool "Support for console on meson"
 	depends on SERIAL_MESON=y
 	depends on SERIAL_MESON=y
 	select SERIAL_CORE_CONSOLE
 	select SERIAL_CORE_CONSOLE
+	select SERIAL_EARLYCON
 	help
 	help
 	  Say Y here if you wish to use a Amlogic MesonX UART as the
 	  Say Y here if you wish to use a Amlogic MesonX UART as the
 	  system console (the system console is the device which
 	  system console (the system console is the device which
@@ -1404,11 +1405,12 @@ config SERIAL_PCH_UART_CONSOLE
 config SERIAL_MXS_AUART
 config SERIAL_MXS_AUART
 	tristate "MXS AUART support"
 	tristate "MXS AUART support"
 	depends on HAS_DMA
 	depends on HAS_DMA
-	depends on ARCH_MXS || COMPILE_TEST
+	depends on ARCH_MXS || MACH_ASM9260 || COMPILE_TEST
 	select SERIAL_CORE
 	select SERIAL_CORE
 	select SERIAL_MCTRL_GPIO if GPIOLIB
 	select SERIAL_MCTRL_GPIO if GPIOLIB
 	help
 	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
 config SERIAL_MXS_AUART_CONSOLE
 	bool "MXS AUART console support"
 	bool "MXS AUART console support"
@@ -1467,6 +1469,19 @@ config SERIAL_EFM32_UART
 	  This driver support the USART and UART ports on
 	  This driver support the USART and UART ports on
 	  Energy Micro's efm32 SoCs.
 	  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
 config SERIAL_EFM32_UART_CONSOLE
 	bool "EFM32 UART/USART console support"
 	bool "EFM32 UART/USART console support"
 	depends on SERIAL_EFM32_UART=y
 	depends on SERIAL_EFM32_UART=y
@@ -1625,6 +1640,7 @@ config SERIAL_STM32_CONSOLE
 
 
 config SERIAL_MVEBU_UART
 config SERIAL_MVEBU_UART
 	bool "Marvell EBU serial port support"
 	bool "Marvell EBU serial port support"
+	depends on ARCH_MVEBU || COMPILE_TEST
 	select SERIAL_CORE
 	select SERIAL_CORE
 	help
 	help
 	  This driver is for Marvell EBU SoC's UART. If you have a machine
 	  This driver is for Marvell EBU SoC's UART. If you have a machine

+ 1 - 0
drivers/tty/serial/Makefile

@@ -92,6 +92,7 @@ obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
 obj-$(CONFIG_SERIAL_STM32)	+= stm32-usart.o
 obj-$(CONFIG_SERIAL_STM32)	+= stm32-usart.o
 obj-$(CONFIG_SERIAL_MVEBU_UART)	+= mvebu-uart.o
 obj-$(CONFIG_SERIAL_MVEBU_UART)	+= mvebu-uart.o
 obj-$(CONFIG_SERIAL_PIC32)	+= pic32_uart.o
 obj-$(CONFIG_SERIAL_PIC32)	+= pic32_uart.o
+obj-$(CONFIG_SERIAL_MPS2_UART)	+= mps2-uart.o
 
 
 # GPIOLIB helpers for modem control lines
 # GPIOLIB helpers for modem control lines
 obj-$(CONFIG_SERIAL_MCTRL_GPIO)	+= serial_mctrl_gpio.o
 obj-$(CONFIG_SERIAL_MCTRL_GPIO)	+= serial_mctrl_gpio.o

+ 1 - 0
drivers/tty/serial/amba-pl011.c

@@ -121,6 +121,7 @@ static struct vendor_data vendor_arm = {
 
 
 static struct vendor_data vendor_sbsa = {
 static struct vendor_data vendor_sbsa = {
 	.reg_offset		= pl011_std_offsets,
 	.reg_offset		= pl011_std_offsets,
+	.access_32b		= true,
 	.oversampling		= false,
 	.oversampling		= false,
 	.dma_threshold		= false,
 	.dma_threshold		= false,
 	.cts_event_workaround	= false,
 	.cts_event_workaround	= false,

+ 13 - 1
drivers/tty/serial/atmel_serial.c

@@ -274,6 +274,13 @@ static bool atmel_use_dma_rx(struct uart_port *port)
 	return atmel_port->use_dma_rx;
 	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)
 static unsigned int atmel_get_lines_status(struct uart_port *port)
 {
 {
 	struct atmel_uart_port *atmel_port = to_atmel_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;
 		mode |= ATMEL_US_USMODE_RS485;
 	} else if (termios->c_cflag & CRTSCTS) {
 	} else if (termios->c_cflag & CRTSCTS) {
 		/* RS232 with hardware handshake (RTS/CTS) */
 		/* 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 {
 	} else {
 		/* RS232 without hadware handshake */
 		/* RS232 without hadware handshake */
 		mode |= ATMEL_US_USMODE_NORMAL;
 		mode |= ATMEL_US_USMODE_NORMAL;

+ 14 - 16
drivers/tty/serial/crisv10.c

@@ -2599,7 +2599,7 @@ startup(struct e100_serial * info)
 
 
 	/* if it was already initialized, skip this */
 	/* if it was already initialized, skip this */
 
 
-	if (info->port.flags & ASYNC_INITIALIZED) {
+	if (tty_port_initialized(&info->port)) {
 		local_irq_restore(flags);
 		local_irq_restore(flags);
 		free_page(xmit_page);
 		free_page(xmit_page);
 		return 0;
 		return 0;
@@ -2703,7 +2703,7 @@ startup(struct e100_serial * info)
 	e100_rts(info, 1);
 	e100_rts(info, 1);
 	e100_dtr(info, 1);
 	e100_dtr(info, 1);
 
 
-	info->port.flags |= ASYNC_INITIALIZED;
+	tty_port_set_initialized(&info->port, 1);
 
 
 	local_irq_restore(flags);
 	local_irq_restore(flags);
 	return 0;
 	return 0;
@@ -2745,7 +2745,7 @@ shutdown(struct e100_serial * info)
 		info->tr_running = 0;
 		info->tr_running = 0;
 	}
 	}
 
 
-	if (!(info->port.flags & ASYNC_INITIALIZED))
+	if (!tty_port_initialized(&info->port))
 		return;
 		return;
 
 
 #ifdef SERIAL_DEBUG_OPEN
 #ifdef SERIAL_DEBUG_OPEN
@@ -2776,7 +2776,7 @@ shutdown(struct e100_serial * info)
 	if (info->port.tty)
 	if (info->port.tty)
 		set_bit(TTY_IO_ERROR, &info->port.tty->flags);
 		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);
 	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;
 	info->port.low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
 
  check_and_exit:
  check_and_exit:
-	if (info->port.flags & ASYNC_INITIALIZED) {
+	if (tty_port_initialized(&info->port))
 		change_speed(info);
 		change_speed(info);
-	} else
+	else
 		retval = startup(info);
 		retval = startup(info);
 	return retval;
 	return retval;
 }
 }
@@ -3445,7 +3445,7 @@ rs_ioctl(struct tty_struct *tty,
 	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
 	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
 	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
 	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
 	    (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
 	    (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
-		if (tty->flags & (1 << TTY_IO_ERROR))
+		if (tty_io_error(tty))
 			return -EIO;
 			return -EIO;
 	}
 	}
 
 
@@ -3628,7 +3628,7 @@ rs_close(struct tty_struct *tty, struct file * filp)
 	e100_disable_rx(info);
 	e100_disable_rx(info);
 	e100_disable_rx_irq(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
 		 * Before we drop DTR, make sure the UART transmitter
 		 * has completely drained; this is especially
 		 * 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);
 			schedule_timeout_interruptible(info->port.close_delay);
 		wake_up_interruptible(&info->port.open_wait);
 		wake_up_interruptible(&info->port.open_wait);
 	}
 	}
-	info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
 	local_irq_restore(flags);
 	local_irq_restore(flags);
+	tty_port_set_active(&info->port, 0);
 
 
 	/* port closed */
 	/* port closed */
 
 
@@ -3732,7 +3732,7 @@ rs_hangup(struct tty_struct *tty)
 	shutdown(info);
 	shutdown(info);
 	info->event = 0;
 	info->event = 0;
 	info->port.count = 0;
 	info->port.count = 0;
-	info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
+	tty_port_set_active(&info->port, 0);
 	info->port.tty = NULL;
 	info->port.tty = NULL;
 	wake_up_interruptible(&info->port.open_wait);
 	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,
 	 * If non-blocking mode is set, or the port is not enabled,
 	 * then make the check up front and then exit.
 	 * 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;
 		return 0;
 	}
 	}
 
 
@@ -3788,8 +3787,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
 		e100_dtr(info, 1);
 		e100_dtr(info, 1);
 		local_irq_restore(flags);
 		local_irq_restore(flags);
 		set_current_state(TASK_INTERRUPTIBLE);
 		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
 #ifdef SERIAL_DO_RESTART
 			if (info->port.flags & ASYNC_HUP_NOTIFY)
 			if (info->port.flags & ASYNC_HUP_NOTIFY)
 				retval = -EAGAIN;
 				retval = -EAGAIN;
@@ -3826,7 +3824,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
 #endif
 #endif
 	if (retval)
 	if (retval)
 		return retval;
 		return retval;
-	info->port.flags |= ASYNC_NORMAL_ACTIVE;
+	tty_port_set_active(&info->port, 1);
 	return 0;
 	return 0;
 }
 }
 
 

+ 1 - 1
drivers/tty/serial/ifx6x60.c

@@ -651,7 +651,7 @@ static void ifx_spi_complete(void *ctx)
 	struct ifx_spi_device *ifx_dev = ctx;
 	struct ifx_spi_device *ifx_dev = ctx;
 	int length;
 	int length;
 	int actual_length;
 	int actual_length;
-	unsigned char more;
+	unsigned char more = 0;
 	unsigned char cts;
 	unsigned char cts;
 	int local_write_pending = 0;
 	int local_write_pending = 0;
 	int queue_length;
 	int queue_length;

+ 114 - 60
drivers/tty/serial/imx.c

@@ -114,6 +114,7 @@
 #define UCR3_RXDSEN	(1<<6)	/* Receive status interrupt enable */
 #define UCR3_RXDSEN	(1<<6)	/* Receive status interrupt enable */
 #define UCR3_AIRINTEN	(1<<5)	/* Async IR wake interrupt enable */
 #define UCR3_AIRINTEN	(1<<5)	/* Async IR wake interrupt enable */
 #define UCR3_AWAKEN	(1<<4)	/* Async 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 IMX21_UCR3_RXDMUXSEL	(1<<2)	/* RXD Muxed Input Select */
 #define UCR3_INVT	(1<<1)	/* Inverted Infrared transmission */
 #define UCR3_INVT	(1<<1)	/* Inverted Infrared transmission */
 #define UCR3_BPEN	(1<<0)	/* Preset registers enable */
 #define UCR3_BPEN	(1<<0)	/* Preset registers enable */
@@ -142,7 +143,7 @@
 #define USR1_FRAMERR	(1<<10) /* Frame error interrupt flag */
 #define USR1_FRAMERR	(1<<10) /* Frame error interrupt flag */
 #define USR1_RRDY	(1<<9)	 /* Receiver ready interrupt/dma flag */
 #define USR1_RRDY	(1<<9)	 /* Receiver ready interrupt/dma flag */
 #define USR1_AGTIM	(1<<8)	 /* Ageing timer interrupt 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_RXDS	 (1<<6)	 /* Receiver idle interrupt flag */
 #define USR1_AIRINT	 (1<<5)	 /* Async IR wake interrupt flag */
 #define USR1_AIRINT	 (1<<5)	 /* Async IR wake interrupt flag */
 #define USR1_AWAKE	 (1<<4)	 /* Aysnc 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);
 			imx_port_rts_inactive(sport, &temp);
 		else
 		else
 			imx_port_rts_active(sport, &temp);
 			imx_port_rts_active(sport, &temp);
+		temp |= UCR2_RXEN;
 		writel(temp, port->membase + UCR2);
 		writel(temp, port->membase + UCR2);
 
 
 		temp = readl(port->membase + UCR4);
 		temp = readl(port->membase + UCR4);
@@ -568,6 +570,8 @@ static void imx_start_tx(struct uart_port *port)
 			imx_port_rts_inactive(sport, &temp);
 			imx_port_rts_inactive(sport, &temp);
 		else
 		else
 			imx_port_rts_active(sport, &temp);
 			imx_port_rts_active(sport, &temp);
+		if (!(port->rs485.flags & SER_RS485_RX_DURING_TX))
+			temp &= ~UCR2_RXEN;
 		writel(temp, port->membase + UCR2);
 		writel(temp, port->membase + UCR2);
 
 
 		/* enable transmitter and shifter empty irq */
 		/* 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);
 	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)
 static irqreturn_t imx_int(int irq, void *dev_id)
 {
 {
 	struct imx_port *sport = dev_id;
 	struct imx_port *sport = dev_id;
 	unsigned int sts;
 	unsigned int sts;
 	unsigned int sts2;
 	unsigned int sts2;
+	irqreturn_t ret = IRQ_NONE;
 
 
 	sts = readl(sport->port.membase + USR1);
 	sts = readl(sport->port.membase + USR1);
 	sts2 = readl(sport->port.membase + USR2);
 	sts2 = readl(sport->port.membase + USR2);
@@ -743,26 +797,47 @@ static irqreturn_t imx_int(int irq, void *dev_id)
 			imx_dma_rxint(sport);
 			imx_dma_rxint(sport);
 		else
 		else
 			imx_rxint(irq, dev_id);
 			imx_rxint(irq, dev_id);
+		ret = IRQ_HANDLED;
 	}
 	}
 
 
 	if ((sts & USR1_TRDY &&
 	if ((sts & USR1_TRDY &&
 	     readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN) ||
 	     readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN) ||
 	    (sts2 & USR2_TXDC &&
 	    (sts2 & USR2_TXDC &&
-	     readl(sport->port.membase + UCR4) & UCR4_TCEN))
+	     readl(sport->port.membase + UCR4) & UCR4_TCEN)) {
 		imx_txint(irq, dev_id);
 		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);
 		imx_rtsint(irq, dev_id);
+		ret = IRQ_HANDLED;
+	}
 
 
-	if (sts & USR1_AWAKE)
+	if (sts & USR1_AWAKE) {
 		writel(USR1_AWAKE, sport->port.membase + USR1);
 		writel(USR1_AWAKE, sport->port.membase + USR1);
+		ret = IRQ_HANDLED;
+	}
 
 
 	if (sts2 & USR2_ORE) {
 	if (sts2 & USR2_ORE) {
 		sport->port.icount.overrun++;
 		sport->port.icount.overrun++;
 		writel(USR2_ORE, sport->port.membase + USR2);
 		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;
 	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)
 static unsigned int imx_get_mctrl(struct uart_port *port)
 {
 {
 	struct imx_port *sport = (struct imx_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);
 	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
  * This is our per-port timeout handler, for checking the
  * modem status signals.
  * modem status signals.
@@ -1193,7 +1219,7 @@ static int imx_startup(struct uart_port *port)
 	/*
 	/*
 	 * Finally, clear and enable interrupts
 	 * 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);
 	writel(USR2_ORE, sport->port.membase + USR2);
 
 
 	if (sport->dma_is_inited && !sport->dma_is_enabled)
 	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);
 	temp |= (UCR2_RXEN | UCR2_TXEN);
 	if (!sport->have_rtscts)
 	if (!sport->have_rtscts)
 		temp |= UCR2_IRTS;
 		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);
 	writel(temp, sport->port.membase + UCR2);
 
 
 	if (!is_imx1_uart(sport)) {
 	if (!is_imx1_uart(sport)) {
 		temp = readl(sport->port.membase + UCR3);
 		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);
 		writel(temp, sport->port.membase + UCR3);
 	}
 	}
 
 
@@ -1610,19 +1657,17 @@ static int imx_rs485_config(struct uart_port *port,
 			    struct serial_rs485 *rs485conf)
 			    struct serial_rs485 *rs485conf)
 {
 {
 	struct imx_port *sport = (struct imx_port *)port;
 	struct imx_port *sport = (struct imx_port *)port;
+	unsigned long temp;
 
 
 	/* unimplemented */
 	/* unimplemented */
 	rs485conf->delay_rts_before_send = 0;
 	rs485conf->delay_rts_before_send = 0;
 	rs485conf->delay_rts_after_send = 0;
 	rs485conf->delay_rts_after_send = 0;
-	rs485conf->flags |= SER_RS485_RX_DURING_TX;
 
 
 	/* RTS is required to control the transmitter */
 	/* RTS is required to control the transmitter */
 	if (!sport->have_rtscts)
 	if (!sport->have_rtscts)
 		rs485conf->flags &= ~SER_RS485_ENABLED;
 		rs485conf->flags &= ~SER_RS485_ENABLED;
 
 
 	if (rs485conf->flags & SER_RS485_ENABLED) {
 	if (rs485conf->flags & SER_RS485_ENABLED) {
-		unsigned long temp;
-
 		/* disable transmitter */
 		/* disable transmitter */
 		temp = readl(sport->port.membase + UCR2);
 		temp = readl(sport->port.membase + UCR2);
 		if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND)
 		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);
 		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;
 	port->rs485 = *rs485conf;
 
 
 	return 0;
 	return 0;
@@ -1927,7 +1980,8 @@ static int serial_imx_probe_dt(struct imx_port *sport,
 	}
 	}
 	sport->port.line = ret;
 	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;
 		sport->have_rtscts = 1;
 
 
 	if (of_get_property(np, "fsl,dte-mode", NULL))
 	if (of_get_property(np, "fsl,dte-mode", NULL))

+ 35 - 7
drivers/tty/serial/meson_uart.c

@@ -481,18 +481,13 @@ static void meson_console_putchar(struct uart_port *port, int ch)
 	writel(ch, port->membase + AML_UART_WFIFO);
 	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;
 	unsigned long flags;
 	int locked;
 	int locked;
 	u32 val, tmp;
 	u32 val, tmp;
 
 
-	port = meson_ports[co->index];
-	if (!port)
-		return;
-
 	local_irq_save(flags);
 	local_irq_save(flags);
 	if (port->sysrq) {
 	if (port->sysrq) {
 		locked = 0;
 		locked = 0;
@@ -516,6 +511,18 @@ static void meson_serial_console_write(struct console *co, const char *s,
 	local_irq_restore(flags);
 	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)
 static int meson_serial_console_setup(struct console *co, char *options)
 {
 {
 	struct uart_port *port;
 	struct uart_port *port;
@@ -554,6 +561,27 @@ static int __init meson_serial_console_init(void)
 }
 }
 console_initcall(meson_serial_console_init);
 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)
 #define MESON_SERIAL_CONSOLE	(&meson_serial_console)
 #else
 #else
 #define MESON_SERIAL_CONSOLE	NULL
 #define MESON_SERIAL_CONSOLE	NULL

+ 625 - 0
drivers/tty/serial/mps2-uart.c

@@ -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);

+ 66 - 35
drivers/tty/serial/msm_serial.c

@@ -861,37 +861,72 @@ struct msm_baud_map {
 };
 };
 
 
 static const 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[] = {
 	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 },
 		{    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,
 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;
 	unsigned int rxstale, watermark, mask;
 	struct msm_port *msm_port = UART_TO_MSM(port);
 	struct msm_port *msm_port = UART_TO_MSM(port);
 	const struct msm_baud_map *entry;
 	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;
 	flags = *saved_flags;
 	spin_unlock_irqrestore(&port->lock, 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);
 	spin_lock_irqsave(&port->lock, flags);
 	*saved_flags = flags;
 	*saved_flags = flags;
+	port->uartclk = rate;
+
+	msm_write(port, entry->code, UART_CSR);
 
 
 	/* RX stale watermark */
 	/* RX stale watermark */
 	rxstale = entry->rxstale;
 	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");
 		msm_port->pclk = devm_clk_get(&pdev->dev, "iface");
 		if (IS_ERR(msm_port->pclk))
 		if (IS_ERR(msm_port->pclk))
 			return PTR_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);
 	port->uartclk = clk_get_rate(msm_port->clk);

+ 3 - 26
drivers/tty/serial/mvebu-uart.c

@@ -1,5 +1,7 @@
 /*
 /*
 * ***************************************************************************
 * ***************************************************************************
+* Marvell Armada-3700 Serial Driver
+* Author: Wilson Ding <dingwei@marvell.com>
 * Copyright (C) 2015 Marvell International Ltd.
 * Copyright (C) 2015 Marvell International Ltd.
 * ***************************************************************************
 * ***************************************************************************
 * This program is free software: you can redistribute it and/or modify it
 * This program is free software: you can redistribute it and/or modify it
@@ -23,7 +25,6 @@
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
 #include <linux/iopoll.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
 #include <linux/of_device.h>
@@ -594,30 +595,18 @@ static int mvebu_uart_probe(struct platform_device *pdev)
 	return 0;
 	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 */
 /* Match table for of_platform binding */
 static const struct of_device_id mvebu_uart_of_match[] = {
 static const struct of_device_id mvebu_uart_of_match[] = {
 	{ .compatible = "marvell,armada-3700-uart", },
 	{ .compatible = "marvell,armada-3700-uart", },
 	{}
 	{}
 };
 };
-MODULE_DEVICE_TABLE(of, mvebu_uart_of_match);
 
 
 static struct platform_driver mvebu_uart_platform_driver = {
 static struct platform_driver mvebu_uart_platform_driver = {
 	.probe	= mvebu_uart_probe,
 	.probe	= mvebu_uart_probe,
-	.remove	= mvebu_uart_remove,
 	.driver	= {
 	.driver	= {
-		.owner	= THIS_MODULE,
 		.name  = "mvebu-uart",
 		.name  = "mvebu-uart",
 		.of_match_table = of_match_ptr(mvebu_uart_of_match),
 		.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;
 	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);
 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");

+ 519 - 125
drivers/tty/serial/mxs-auart.c

@@ -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>
  * 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-2010 Freescale Semiconductor, Inc.
  * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
  * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
  *
  *
  * The code contained herein is licensed under the GNU General Public
  * The code contained herein is licensed under the GNU General Public
  * License. You may obtain a copy of the GNU General Public License
  * License. You may obtain a copy of the GNU General Public License
  * Version 2 or later at the following locations:
  * 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)
 #if defined(CONFIG_SERIAL_MXS_AUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
@@ -51,30 +52,16 @@
 #define MXS_AUART_PORTS 5
 #define MXS_AUART_PORTS 5
 #define MXS_AUART_FIFO_SIZE		16
 #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			0x00000000
-#define AUART_CTRL0_SET			0x00000004
-#define AUART_CTRL0_CLR			0x00000008
-#define AUART_CTRL0_TOG			0x0000000c
 #define AUART_CTRL1			0x00000010
 #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			0x00000020
-#define AUART_CTRL2_SET			0x00000024
-#define AUART_CTRL2_CLR			0x00000028
-#define AUART_CTRL2_TOG			0x0000002c
 #define AUART_LINECTRL			0x00000030
 #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			0x00000040
-#define AUART_LINECTRL2_SET		0x00000044
-#define AUART_LINECTRL2_CLR		0x00000048
-#define AUART_LINECTRL2_TOG		0x0000004c
 #define AUART_INTR			0x00000050
 #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_DATA			0x00000060
 #define AUART_STAT			0x00000070
 #define AUART_STAT			0x00000070
 #define AUART_DEBUG			0x00000080
 #define AUART_DEBUG			0x00000080
@@ -136,11 +123,301 @@
 #define AUART_STAT_FERR				(1 << 16)
 #define AUART_STAT_FERR				(1 << 16)
 #define AUART_STAT_RXCOUNT_MASK			0xffff
 #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;
 static struct uart_driver auart_driver;
 
 
 enum mxs_auart_type {
 enum mxs_auart_type {
 	IMX23_AUART,
 	IMX23_AUART,
 	IMX28_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 {
 struct mxs_auart_port {
@@ -153,8 +430,10 @@ struct mxs_auart_port {
 	unsigned long flags;
 	unsigned long flags;
 	unsigned int mctrl_prev;
 	unsigned int mctrl_prev;
 	enum mxs_auart_type devtype;
 	enum mxs_auart_type devtype;
+	const struct vendor_data *vendor;
 
 
 	struct clk *clk;
 	struct clk *clk;
+	struct clk *clk_ahb;
 	struct device *dev;
 	struct device *dev;
 
 
 	/* for DMA */
 	/* for DMA */
@@ -174,6 +453,7 @@ struct mxs_auart_port {
 static const struct platform_device_id mxs_auart_devtype[] = {
 static const struct platform_device_id mxs_auart_devtype[] = {
 	{ .name = "mxs-auart-imx23", .driver_data = IMX23_AUART },
 	{ .name = "mxs-auart-imx23", .driver_data = IMX23_AUART },
 	{ .name = "mxs-auart-imx28", .driver_data = IMX28_AUART },
 	{ .name = "mxs-auart-imx28", .driver_data = IMX28_AUART },
+	{ .name = "as-auart-asm9260", .driver_data = ASM9260_AUART },
 	{ /* sentinel */ }
 	{ /* sentinel */ }
 };
 };
 MODULE_DEVICE_TABLE(platform, mxs_auart_devtype);
 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",
 		.compatible = "fsl,imx23-auart",
 		.data = &mxs_auart_devtype[IMX23_AUART]
 		.data = &mxs_auart_devtype[IMX23_AUART]
+	}, {
+		.compatible = "alphascale,asm9260-auart",
+		.data = &mxs_auart_devtype[ASM9260_AUART]
 	}, { /* sentinel */ }
 	}, { /* sentinel */ }
 };
 };
 MODULE_DEVICE_TABLE(of, mxs_auart_dt_ids);
 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;
 	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)
 static inline bool auart_dma_enabled(struct mxs_auart_port *s)
 {
 {
 	return s->flags & MXS_AUART_DMA_ENABLED;
 	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);
 static void mxs_auart_stop_tx(struct uart_port *u);
 
 
 #define to_auart_port(u) container_of(u, struct mxs_auart_port, port)
 #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) {
 		if (s->port.x_char) {
 			s->port.icount.tx++;
 			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;
 			s->port.x_char = 0;
 			continue;
 			continue;
 		}
 		}
 		if (!uart_circ_empty(xmit) && !uart_tx_stopped(&s->port)) {
 		if (!uart_circ_empty(xmit) && !uart_tx_stopped(&s->port)) {
 			s->port.icount.tx++;
 			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);
 			xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
 		} else
 		} else
 			break;
 			break;
@@ -316,11 +639,9 @@ static void mxs_auart_tx_chars(struct mxs_auart_port *s)
 		uart_write_wakeup(&s->port);
 		uart_write_wakeup(&s->port);
 
 
 	if (uart_circ_empty(&(s->port.state->xmit)))
 	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
 	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))
 	if (uart_tx_stopped(&s->port))
 		mxs_auart_stop_tx(&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;
 	u32 stat;
 	u8 c;
 	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;
 	flag = TTY_NORMAL;
 	s->port.icount.rx++;
 	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);
 	uart_insert_char(&s->port, stat, AUART_STAT_OERR, c, flag);
 out:
 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)
 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;
 	u32 stat = 0;
 
 
 	for (;;) {
 	for (;;) {
-		stat = readl(s->port.membase + AUART_STAT);
+		stat = mxs_read(s, REG_STAT);
 		if (stat & AUART_STAT_RXFE)
 		if (stat & AUART_STAT_RXFE)
 			break;
 			break;
 		mxs_auart_rx_char(s);
 		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);
 	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);
 	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);
 	ctrl &= ~(AUART_CTRL2_RTSEN | AUART_CTRL2_RTS);
 	if (mctrl & TIOCM_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;
 			ctrl |= AUART_CTRL2_RTS;
 	}
 	}
 
 
-	writel(ctrl, u->membase + AUART_CTRL2);
+	mxs_write(ctrl, s, REG_CTRL2);
 
 
 	mctrl_gpio_set(s->gpios, mctrl);
 	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)
 static u32 mxs_auart_get_mctrl(struct uart_port *u)
 {
 {
 	struct mxs_auart_port *s = to_auart_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;
 	u32 mctrl = 0;
 
 
 	if (stat & AUART_STAT_CTS)
 	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);
 	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 |
 	stat &= ~(AUART_STAT_OERR | AUART_STAT_BERR |
 			AUART_STAT_PERR | AUART_STAT_FERR);
 			AUART_STAT_PERR | AUART_STAT_FERR);
 
 
 	count = stat & AUART_STAT_RXCOUNT_MASK;
 	count = stat & AUART_STAT_RXCOUNT_MASK;
 	tty_insert_flip_string(port, s->rx_dma_buf, count);
 	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);
 	tty_flip_buffer_push(port);
 
 
 	/* start the next DMA for RX. */
 	/* 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)
 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);
 	mxs_auart_dma_exit_channel(s);
 	s->flags &= ~MXS_AUART_DMA_ENABLED;
 	s->flags &= ~MXS_AUART_DMA_ENABLED;
@@ -666,7 +987,7 @@ static void mxs_auart_settermios(struct uart_port *u,
 	cflag = termios->c_cflag;
 	cflag = termios->c_cflag;
 
 
 	ctrl = AUART_LINECTRL_FEN;
 	ctrl = AUART_LINECTRL_FEN;
-	ctrl2 = readl(u->membase + AUART_CTRL2);
+	ctrl2 = mxs_read(s, REG_CTRL2);
 
 
 	/* byte size */
 	/* byte size */
 	switch (cflag & CSIZE) {
 	switch (cflag & CSIZE) {
@@ -754,15 +1075,24 @@ static void mxs_auart_settermios(struct uart_port *u,
 	}
 	}
 
 
 	/* set baud rate */
 	/* 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_DIVFRAC(div & 0x3F);
 	ctrl |= AUART_LINECTRL_BAUD_DIVINT(div >> 6);
 	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);
 	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)) {
 		!test_and_set_bit(MXS_AUART_DMA_RX_READY, &s->flags)) {
 		if (!mxs_auart_dma_prep_rx(s)) {
 		if (!mxs_auart_dma_prep_rx(s)) {
 			/* Disable the normal RX interrupt. */
 			/* 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 {
 		} else {
 			mxs_auart_dma_exit(s);
 			mxs_auart_dma_exit(s);
 			dev_err(s->dev, "We can not start up the DMA.\n");
 			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;
 	u32 istat;
 	struct mxs_auart_port *s = context;
 	struct mxs_auart_port *s = context;
 	u32 mctrl_temp = s->mctrl_prev;
 	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 */
 	/* 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
 	 * 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)
 		if (CTS_AT_AUART() && s->ms_irq_enabled)
 			uart_handle_cts_change(&s->port,
 			uart_handle_cts_change(&s->port,
 					stat & AUART_STAT_CTS);
 					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;
 		istat &= ~AUART_INTR_CTSMIS;
 	}
 	}
 
 
@@ -846,44 +1172,44 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
 	return IRQ_HANDLED;
 	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;
 	int i;
 	unsigned int reg;
 	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++) {
 	for (i = 0; i < 10000; i++) {
-		reg = readl(u->membase + AUART_CTRL0);
+		reg = mxs_read(s, REG_CTRL0);
 		if (!(reg & AUART_CTRL0_SFTRST))
 		if (!(reg & AUART_CTRL0_SFTRST))
 			break;
 			break;
 		udelay(3);
 		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;
 	int i;
 	u32 reg;
 	u32 reg;
 
 
-	reg = readl(u->membase + AUART_CTRL0);
+	reg = mxs_read(s, REG_CTRL0);
 	/* if already in reset state, keep it untouched */
 	/* if already in reset state, keep it untouched */
 	if (reg & AUART_CTRL0_SFTRST)
 	if (reg & AUART_CTRL0_SFTRST)
 		return;
 		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++) {
 	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 */
 		/* reset is finished when the clock is gated */
 		if (reg & AUART_CTRL0_CLKGATE)
 		if (reg & AUART_CTRL0_CLKGATE)
 			return;
 			return;
 		udelay(10);
 		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)
 static int mxs_auart_startup(struct uart_port *u)
@@ -896,17 +1222,17 @@ static int mxs_auart_startup(struct uart_port *u)
 		return ret;
 		return ret;
 
 
 	if (uart_console(u)) {
 	if (uart_console(u)) {
-		writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_CLR);
+		mxs_clr(AUART_CTRL0_CLKGATE, s, REG_CTRL0);
 	} else {
 	} else {
 		/* reset the unit to a well known state */
 		/* 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) */
 	/* Reset FIFO size (it could have changed if DMA was enabled) */
 	u->fifosize = MXS_AUART_FIFO_SIZE;
 	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
 	 * 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)
 	 * 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 */
 	/* get initial status of modem lines */
 	mctrl_gpio_get(s->gpios, &s->mctrl_prev);
 	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);
 		mxs_auart_dma_exit(s);
 
 
 	if (uart_console(u)) {
 	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 {
 	} else {
-		mxs_auart_reset_assert(u);
+		mxs_auart_reset_assert(s);
 	}
 	}
 
 
 	clk_disable_unprepare(s->clk);
 	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)
 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)
 		 (AUART_STAT_TXFE | AUART_STAT_BUSY)) == AUART_STAT_TXFE)
 		return TIOCSER_TEMT;
 		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);
 	struct mxs_auart_port *s = to_auart_port(u);
 
 
 	/* enable transmitter */
 	/* enable transmitter */
-	writel(AUART_CTRL2_TXE, u->membase + AUART_CTRL2_SET);
+	mxs_set(AUART_CTRL2_TXE, s, REG_CTRL2);
 
 
 	mxs_auart_tx_chars(s);
 	mxs_auart_tx_chars(s);
 }
 }
 
 
 static void mxs_auart_stop_tx(struct uart_port *u)
 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)
 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)
 static void mxs_auart_break_ctl(struct uart_port *u, int ctl)
 {
 {
+	struct mxs_auart_port *s = to_auart_port(u);
+
 	if (ctl)
 	if (ctl)
-		writel(AUART_LINECTRL_BRK,
-			     u->membase + AUART_LINECTRL_SET);
+		mxs_set(AUART_LINECTRL_BRK, s, REG_LINECTRL);
 	else
 	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 = {
 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
 #ifdef CONFIG_SERIAL_MXS_AUART_CONSOLE
 static void mxs_auart_console_putchar(struct uart_port *port, int ch)
 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;
 	unsigned int to = 1000;
 
 
-	while (readl(port->membase + AUART_STAT) & AUART_STAT_TXFF) {
+	while (mxs_read(s, REG_STAT) & AUART_STAT_TXFF) {
 		if (!to--)
 		if (!to--)
 			break;
 			break;
 		udelay(1);
 		udelay(1);
 	}
 	}
 
 
-	writel(ch, port->membase + AUART_DATA);
+	mxs_write(ch, s, REG_DATA);
 }
 }
 
 
 static void
 static void
@@ -1037,18 +1371,16 @@ auart_console_write(struct console *co, const char *str, unsigned int count)
 	clk_enable(s->clk);
 	clk_enable(s->clk);
 
 
 	/* First save the CR then disable the interrupts */
 	/* 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);
 	uart_console_write(port, str, count, mxs_auart_console_putchar);
 
 
 	/* Finally, wait for transmitter to become empty ... */
 	/* 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);
 		udelay(1);
 		if (!to--)
 		if (!to--)
 			break;
 			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
 	 * unused, but that is better than to disable it while it is still
 	 * transmitting.
 	 * 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);
 	clk_disable(s->clk);
 }
 }
 
 
 static void __init
 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)
 			  int *parity, int *bits)
 {
 {
+	struct uart_port *port = &s->port;
 	unsigned int lcr_h, quot;
 	unsigned int lcr_h, quot;
 
 
-	if (!(readl(port->membase + AUART_CTRL2) & AUART_CTRL2_UARTEN))
+	if (!(mxs_read(s, REG_CTRL2) & AUART_CTRL2_UARTEN))
 		return;
 		return;
 
 
-	lcr_h = readl(port->membase + AUART_LINECTRL);
+	lcr_h = mxs_read(s, REG_LINECTRL);
 
 
 	*parity = 'n';
 	*parity = 'n';
 	if (lcr_h & AUART_LINECTRL_PEN) {
 	if (lcr_h & AUART_LINECTRL_PEN) {
@@ -1092,12 +1425,10 @@ auart_console_get_options(struct uart_port *port, int *baud,
 	else
 	else
 		*bits = 8;
 		*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)
 	if (quot == 0)
 		quot = 1;
 		quot = 1;
 
 
@@ -1132,7 +1463,7 @@ auart_console_setup(struct console *co, char *options)
 	if (options)
 	if (options)
 		uart_parse_options(options, &baud, &parity, &bits, &flow);
 		uart_parse_options(options, &baud, &parity, &bits, &flow);
 	else
 	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);
 	ret = uart_set_options(&s->port, co, baud, parity, bits, flow);
 
 
@@ -1164,6 +1495,60 @@ static struct uart_driver auart_driver = {
 #endif
 #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
  * 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.
  * 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;
 	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);
 		set_bit(MXS_AUART_RTSCTS, &s->flags);
 
 
 	return 0;
 	return 0;
@@ -1269,6 +1655,9 @@ static int mxs_auart_probe(struct platform_device *pdev)
 	if (!s)
 	if (!s)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
+	s->port.dev = &pdev->dev;
+	s->dev = &pdev->dev;
+
 	ret = serial_mxs_probe_dt(s, pdev);
 	ret = serial_mxs_probe_dt(s, pdev);
 	if (ret > 0)
 	if (ret > 0)
 		s->port.line = pdev->id < 0 ? 0 : pdev->id;
 		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->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);
 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!r)
 	if (!r)
 		return -ENXIO;
 		return -ENXIO;
 
 
-
 	s->port.mapbase = r->start;
 	s->port.mapbase = r->start;
 	s->port.membase = ioremap(r->start, resource_size(r));
 	s->port.membase = ioremap(r->start, resource_size(r));
 	s->port.ops = &mxs_auart_ops;
 	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.fifosize = MXS_AUART_FIFO_SIZE;
 	s->port.uartclk = clk_get_rate(s->clk);
 	s->port.uartclk = clk_get_rate(s->clk);
 	s->port.type = PORT_IMX;
 	s->port.type = PORT_IMX;
-	s->port.dev = s->dev = &pdev->dev;
+
+	mxs_init_regs(s);
 
 
 	s->mctrl_prev = 0;
 	s->mctrl_prev = 0;
 
 
@@ -1327,16 +1716,21 @@ static int mxs_auart_probe(struct platform_device *pdev)
 
 
 	auart_port[s->port.line] = s;
 	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);
 	ret = uart_add_one_port(&auart_driver, &s->port);
 	if (ret)
 	if (ret)
 		goto out_free_gpio_irq;
 		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;
 	return 0;
 
 

+ 2 - 2
drivers/tty/serial/samsung.c

@@ -1271,6 +1271,8 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
 	/* check to see if we need  to change clock source */
 	/* check to see if we need  to change clock source */
 
 
 	if (ourport->baudclk != clk) {
 	if (ourport->baudclk != clk) {
+		clk_prepare_enable(clk);
+
 		s3c24xx_serial_setsource(port, clk_sel);
 		s3c24xx_serial_setsource(port, clk_sel);
 
 
 		if (!IS_ERR(ourport->baudclk)) {
 		if (!IS_ERR(ourport->baudclk)) {
@@ -1278,8 +1280,6 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
 			ourport->baudclk = ERR_PTR(-EINVAL);
 			ourport->baudclk = ERR_PTR(-EINVAL);
 		}
 		}
 
 
-		clk_prepare_enable(clk);
-
 		ourport->baudclk = clk;
 		ourport->baudclk = clk;
 		ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0;
 		ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0;
 	}
 	}

+ 3 - 10
drivers/tty/serial/sc16is7xx.c

@@ -666,7 +666,7 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
 	struct uart_port *port = &s->p[portno].port;
 	struct uart_port *port = &s->p[portno].port;
 
 
 	do {
 	do {
-		unsigned int iir, msr, rxlen;
+		unsigned int iir, rxlen;
 
 
 		iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG);
 		iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG);
 		if (iir & SC16IS7XX_IIR_NO_INT_BIT)
 		if (iir & SC16IS7XX_IIR_NO_INT_BIT)
@@ -683,12 +683,6 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
 			if (rxlen)
 			if (rxlen)
 				sc16is7xx_handle_rx(port, rxlen, iir);
 				sc16is7xx_handle_rx(port, rxlen, iir);
 			break;
 			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:
 		case SC16IS7XX_IIR_THRI_SRC:
 			sc16is7xx_handle_tx(port);
 			sc16is7xx_handle_tx(port);
 			break;
 			break;
@@ -1014,9 +1008,8 @@ static int sc16is7xx_startup(struct uart_port *port)
 			      SC16IS7XX_EFCR_TXDISABLE_BIT,
 			      SC16IS7XX_EFCR_TXDISABLE_BIT,
 			      0);
 			      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);
 	sc16is7xx_port_write(port, SC16IS7XX_IER_REG, val);
 
 
 	return 0;
 	return 0;

+ 0 - 2
drivers/tty/serial/serial-tegra.c

@@ -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)
 static void tegra_uart_set_mctrl(struct uart_port *u, unsigned int mctrl)
 {
 {
 	struct tegra_uart_port *tup = to_tegra_uport(u);
 	struct tegra_uart_port *tup = to_tegra_uport(u);
-	unsigned long mcr;
 	int dtr_enable;
 	int dtr_enable;
 
 
-	mcr = tup->mcr_shadow;
 	tup->rts_active = !!(mctrl & TIOCM_RTS);
 	tup->rts_active = !!(mctrl & TIOCM_RTS);
 	set_rts(tup, tup->rts_active);
 	set_rts(tup, tup->rts_active);
 
 

+ 288 - 142
drivers/tty/serial/serial_core.c

@@ -64,6 +64,41 @@ static int uart_dcd_enabled(struct uart_port *uport)
 	return !!(uport->status & UPSTAT_DCD_ENABLE);
 	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
  * This routine is used by the interrupt handler to schedule processing in
  * the software interrupt portion of the driver.
  * 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)
 static void uart_stop(struct tty_struct *tty)
 {
 {
 	struct uart_state *state = tty->driver_data;
 	struct uart_state *state = tty->driver_data;
-	struct uart_port *port = state->uart_port;
+	struct uart_port *port;
 	unsigned long flags;
 	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)
 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_state *state = tty->driver_data;
 	struct uart_port *port = state->uart_port;
 	struct uart_port *port = state->uart_port;
 
 
-	if (!uart_tx_stopped(port))
+	if (port && !uart_tx_stopped(port))
 		port->ops->start_tx(port);
 		port->ops->start_tx(port);
 }
 }
 
 
 static void uart_start(struct tty_struct *tty)
 static void uart_start(struct tty_struct *tty)
 {
 {
 	struct uart_state *state = tty->driver_data;
 	struct uart_state *state = tty->driver_data;
-	struct uart_port *port = state->uart_port;
+	struct uart_port *port;
 	unsigned long flags;
 	unsigned long flags;
 
 
-	spin_lock_irqsave(&port->lock, flags);
+	port = uart_port_lock(state, flags);
 	__uart_start(tty);
 	__uart_start(tty);
-	spin_unlock_irqrestore(&port->lock, flags);
+	uart_port_unlock(port, flags);
 }
 }
 
 
 static void
 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,
 static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
 		int init_hw)
 		int init_hw)
 {
 {
-	struct uart_port *uport = state->uart_port;
+	struct uart_port *uport = uart_port_check(state);
 	unsigned long page;
 	unsigned long page;
 	int retval = 0;
 	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;
 	struct tty_port *port = &state->port;
 	int retval;
 	int retval;
 
 
-	if (port->flags & ASYNC_INITIALIZED)
+	if (tty_port_initialized(port))
 		return 0;
 		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);
 	retval = uart_port_startup(tty, state, init_hw);
 	if (!retval) {
 	if (!retval) {
-		set_bit(ASYNCB_INITIALIZED, &port->flags);
+		tty_port_set_initialized(port, 1);
 		clear_bit(TTY_IO_ERROR, &tty->flags);
 		clear_bit(TTY_IO_ERROR, &tty->flags);
 	} else if (retval > 0)
 	} else if (retval > 0)
 		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
  * 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
  * DTR is dropped if the hangup on close termio flag is on.  Calls to
  * uart_shutdown are serialised by the per-port semaphore.
  * 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)
 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;
 	struct tty_port *port = &state->port;
 
 
 	/*
 	/*
@@ -231,11 +269,13 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
 	if (tty)
 	if (tty)
 		set_bit(TTY_IO_ERROR, &tty->flags);
 		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.
 		 * Turn off DTR and RTS early.
 		 */
 		 */
-		if (uart_console(uport) && tty)
+		if (uport && uart_console(uport) && tty)
 			uport->cons->cflag = tty->termios.c_cflag;
 			uport->cons->cflag = tty->termios.c_cflag;
 
 
 		if (!tty || C_HUPCL(tty))
 		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
 	 * 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.
 	 * 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.
 	 * 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,
 static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
 					struct ktermios *old_termios)
 					struct ktermios *old_termios)
 {
 {
-	struct uart_port *uport = state->uart_port;
+	struct uart_port *uport = uart_port_check(state);
 	struct ktermios *termios;
 	struct ktermios *termios;
 	int hw_stopped;
 	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)
 static int uart_put_char(struct tty_struct *tty, unsigned char c)
 {
 {
 	struct uart_state *state = tty->driver_data;
 	struct uart_state *state = tty->driver_data;
-	struct uart_port *port = state->uart_port;
+	struct uart_port *port;
 	struct circ_buf *circ;
 	struct circ_buf *circ;
 	unsigned long flags;
 	unsigned long flags;
 	int ret = 0;
 	int ret = 0;
@@ -495,13 +535,13 @@ static int uart_put_char(struct tty_struct *tty, unsigned char c)
 	if (!circ->buf)
 	if (!circ->buf)
 		return 0;
 		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->buf[circ->head] = c;
 		circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1);
 		circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1);
 		ret = 1;
 		ret = 1;
 	}
 	}
-	spin_unlock_irqrestore(&port->lock, flags);
+	uart_port_unlock(port, flags);
 	return ret;
 	return ret;
 }
 }
 
 
@@ -528,14 +568,12 @@ static int uart_write(struct tty_struct *tty,
 		return -EL3HLT;
 		return -EL3HLT;
 	}
 	}
 
 
-	port = state->uart_port;
 	circ = &state->xmit;
 	circ = &state->xmit;
-
 	if (!circ->buf)
 	if (!circ->buf)
 		return 0;
 		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);
 		c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
 		if (count < c)
 		if (count < c)
 			c = count;
 			c = count;
@@ -549,32 +587,33 @@ static int uart_write(struct tty_struct *tty,
 	}
 	}
 
 
 	__uart_start(tty);
 	__uart_start(tty);
-	spin_unlock_irqrestore(&port->lock, flags);
-
+	uart_port_unlock(port, flags);
 	return ret;
 	return ret;
 }
 }
 
 
 static int uart_write_room(struct tty_struct *tty)
 static int uart_write_room(struct tty_struct *tty)
 {
 {
 	struct uart_state *state = tty->driver_data;
 	struct uart_state *state = tty->driver_data;
+	struct uart_port *port;
 	unsigned long flags;
 	unsigned long flags;
 	int ret;
 	int ret;
 
 
-	spin_lock_irqsave(&state->uart_port->lock, flags);
+	port = uart_port_lock(state, flags);
 	ret = uart_circ_chars_free(&state->xmit);
 	ret = uart_circ_chars_free(&state->xmit);
-	spin_unlock_irqrestore(&state->uart_port->lock, flags);
+	uart_port_unlock(port, flags);
 	return ret;
 	return ret;
 }
 }
 
 
 static int uart_chars_in_buffer(struct tty_struct *tty)
 static int uart_chars_in_buffer(struct tty_struct *tty)
 {
 {
 	struct uart_state *state = tty->driver_data;
 	struct uart_state *state = tty->driver_data;
+	struct uart_port *port;
 	unsigned long flags;
 	unsigned long flags;
 	int ret;
 	int ret;
 
 
-	spin_lock_irqsave(&state->uart_port->lock, flags);
+	port = uart_port_lock(state, flags);
 	ret = uart_circ_chars_pending(&state->xmit);
 	ret = uart_circ_chars_pending(&state->xmit);
-	spin_unlock_irqrestore(&state->uart_port->lock, flags);
+	uart_port_unlock(port, flags);
 	return ret;
 	return ret;
 }
 }
 
 
@@ -593,14 +632,15 @@ static void uart_flush_buffer(struct tty_struct *tty)
 		return;
 		return;
 	}
 	}
 
 
-	port = state->uart_port;
 	pr_debug("uart_flush_buffer(%d) called\n", tty->index);
 	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);
 	uart_circ_clear(&state->xmit);
 	if (port->ops->flush_buffer)
 	if (port->ops->flush_buffer)
 		port->ops->flush_buffer(port);
 		port->ops->flush_buffer(port);
-	spin_unlock_irqrestore(&port->lock, flags);
+	uart_port_unlock(port, flags);
 	tty_wakeup(tty);
 	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)
 static void uart_send_xchar(struct tty_struct *tty, char ch)
 {
 {
 	struct uart_state *state = tty->driver_data;
 	struct uart_state *state = tty->driver_data;
-	struct uart_port *port = state->uart_port;
+	struct uart_port *port;
 	unsigned long flags;
 	unsigned long flags;
 
 
+	port = uart_port_ref(state);
+	if (!port)
+		return;
+
 	if (port->ops->send_xchar)
 	if (port->ops->send_xchar)
 		port->ops->send_xchar(port, ch);
 		port->ops->send_xchar(port, ch);
 	else {
 	else {
@@ -623,14 +667,19 @@ static void uart_send_xchar(struct tty_struct *tty, char ch)
 			port->ops->start_tx(port);
 			port->ops->start_tx(port);
 		spin_unlock_irqrestore(&port->lock, flags);
 		spin_unlock_irqrestore(&port->lock, flags);
 	}
 	}
+	uart_port_deref(port);
 }
 }
 
 
 static void uart_throttle(struct tty_struct *tty)
 static void uart_throttle(struct tty_struct *tty)
 {
 {
 	struct uart_state *state = tty->driver_data;
 	struct uart_state *state = tty->driver_data;
-	struct uart_port *port = state->uart_port;
+	struct uart_port *port;
 	upstat_t mask = 0;
 	upstat_t mask = 0;
 
 
+	port = uart_port_ref(state);
+	if (!port)
+		return;
+
 	if (I_IXOFF(tty))
 	if (I_IXOFF(tty))
 		mask |= UPSTAT_AUTOXOFF;
 		mask |= UPSTAT_AUTOXOFF;
 	if (C_CRTSCTS(tty))
 	if (C_CRTSCTS(tty))
@@ -646,14 +695,20 @@ static void uart_throttle(struct tty_struct *tty)
 
 
 	if (mask & UPSTAT_AUTOXOFF)
 	if (mask & UPSTAT_AUTOXOFF)
 		uart_send_xchar(tty, STOP_CHAR(tty));
 		uart_send_xchar(tty, STOP_CHAR(tty));
+
+	uart_port_deref(port);
 }
 }
 
 
 static void uart_unthrottle(struct tty_struct *tty)
 static void uart_unthrottle(struct tty_struct *tty)
 {
 {
 	struct uart_state *state = tty->driver_data;
 	struct uart_state *state = tty->driver_data;
-	struct uart_port *port = state->uart_port;
+	struct uart_port *port;
 	upstat_t mask = 0;
 	upstat_t mask = 0;
 
 
+	port = uart_port_ref(state);
+	if (!port)
+		return;
+
 	if (I_IXOFF(tty))
 	if (I_IXOFF(tty))
 		mask |= UPSTAT_AUTOXOFF;
 		mask |= UPSTAT_AUTOXOFF;
 	if (C_CRTSCTS(tty))
 	if (C_CRTSCTS(tty))
@@ -669,12 +724,15 @@ static void uart_unthrottle(struct tty_struct *tty)
 
 
 	if (mask & UPSTAT_AUTOXOFF)
 	if (mask & UPSTAT_AUTOXOFF)
 		uart_send_xchar(tty, START_CHAR(tty));
 		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_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));
 	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
 	 * occur as we go
 	 */
 	 */
 	mutex_lock(&port->mutex);
 	mutex_lock(&port->mutex);
+	uport = uart_port_check(state);
+	if (!uport)
+		goto out;
+
 	retinfo->type	    = uport->type;
 	retinfo->type	    = uport->type;
 	retinfo->line	    = uport->line;
 	retinfo->line	    = uport->line;
 	retinfo->port	    = uport->iobase;
 	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->io_type         = uport->iotype;
 	retinfo->iomem_reg_shift = uport->regshift;
 	retinfo->iomem_reg_shift = uport->regshift;
 	retinfo->iomem_base      = (void *)(unsigned long)uport->mapbase;
 	retinfo->iomem_base      = (void *)(unsigned long)uport->mapbase;
+
+	ret = 0;
+out:
 	mutex_unlock(&port->mutex);
 	mutex_unlock(&port->mutex);
+	return ret;
 }
 }
 
 
 static int uart_get_info_user(struct tty_port *port,
 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;
 	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)))
 	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
 		return -EFAULT;
 		return -EFAULT;
@@ -720,13 +787,16 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
 			 struct uart_state *state,
 			 struct uart_state *state,
 			 struct serial_struct *new_info)
 			 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 long new_port;
 	unsigned int change_irq, change_port, closing_wait;
 	unsigned int change_irq, change_port, closing_wait;
 	unsigned int old_custom_divisor, close_delay;
 	unsigned int old_custom_divisor, close_delay;
 	upf_t old_flags, new_flags;
 	upf_t old_flags, new_flags;
 	int retval = 0;
 	int retval = 0;
 
 
+	if (!uport)
+		return -EIO;
+
 	new_port = new_info->port;
 	new_port = new_info->port;
 	if (HIGH_BITS_OFFSET)
 	if (HIGH_BITS_OFFSET)
 		new_port += (unsigned long) new_info->port_high << 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;
 	retval = 0;
 	if (uport->type == PORT_UNKNOWN)
 	if (uport->type == PORT_UNKNOWN)
 		goto exit;
 		goto exit;
-	if (port->flags & ASYNC_INITIALIZED) {
+	if (tty_port_initialized(port)) {
 		if (((old_flags ^ uport->flags) & UPF_SPD_MASK) ||
 		if (((old_flags ^ uport->flags) & UPF_SPD_MASK) ||
 		    old_custom_divisor != uport->custom_divisor) {
 		    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
  *	@tty: tty associated with the UART
  *	@state: UART being queried
  *	@state: UART being queried
  *	@value: returned modem value
  *	@value: returned modem value
- *
- *	Note: uart_ioctl protects us against hangups.
  */
  */
 static int uart_get_lsr_info(struct tty_struct *tty,
 static int uart_get_lsr_info(struct tty_struct *tty,
 			struct uart_state *state, unsigned int __user *value)
 			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;
 	unsigned int result;
 
 
 	result = uport->ops->tx_empty(uport);
 	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 uart_state *state = tty->driver_data;
 	struct tty_port *port = &state->port;
 	struct tty_port *port = &state->port;
-	struct uart_port *uport = state->uart_port;
+	struct uart_port *uport;
 	int result = -EIO;
 	int result = -EIO;
 
 
 	mutex_lock(&port->mutex);
 	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;
 		result = uport->mctrl;
 		spin_lock_irq(&uport->lock);
 		spin_lock_irq(&uport->lock);
 		result |= uport->ops->get_mctrl(uport);
 		result |= uport->ops->get_mctrl(uport);
 		spin_unlock_irq(&uport->lock);
 		spin_unlock_irq(&uport->lock);
 	}
 	}
+out:
 	mutex_unlock(&port->mutex);
 	mutex_unlock(&port->mutex);
-
 	return result;
 	return result;
 }
 }
 
 
@@ -984,15 +1056,20 @@ static int
 uart_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear)
 uart_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear)
 {
 {
 	struct uart_state *state = tty->driver_data;
 	struct uart_state *state = tty->driver_data;
-	struct uart_port *uport = state->uart_port;
 	struct tty_port *port = &state->port;
 	struct tty_port *port = &state->port;
+	struct uart_port *uport;
 	int ret = -EIO;
 	int ret = -EIO;
 
 
 	mutex_lock(&port->mutex);
 	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);
 		uart_update_mctrl(uport, set, clear);
 		ret = 0;
 		ret = 0;
 	}
 	}
+out:
 	mutex_unlock(&port->mutex);
 	mutex_unlock(&port->mutex);
 	return ret;
 	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 uart_state *state = tty->driver_data;
 	struct tty_port *port = &state->port;
 	struct tty_port *port = &state->port;
-	struct uart_port *uport = state->uart_port;
+	struct uart_port *uport;
+	int ret = -EIO;
 
 
 	mutex_lock(&port->mutex);
 	mutex_lock(&port->mutex);
+	uport = uart_port_check(state);
+	if (!uport)
+		goto out;
 
 
 	if (uport->type != PORT_UNKNOWN)
 	if (uport->type != PORT_UNKNOWN)
 		uport->ops->break_ctl(uport, break_state);
 		uport->ops->break_ctl(uport, break_state);
-
+	ret = 0;
+out:
 	mutex_unlock(&port->mutex);
 	mutex_unlock(&port->mutex);
-	return 0;
+	return ret;
 }
 }
 
 
 static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state)
 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 tty_port *port = &state->port;
+	struct uart_port *uport;
 	int flags, ret;
 	int flags, ret;
 
 
 	if (!capable(CAP_SYS_ADMIN))
 	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))
 	if (mutex_lock_interruptible(&port->mutex))
 		return -ERESTARTSYS;
 		return -ERESTARTSYS;
 
 
+	uport = uart_port_check(state);
+	if (!uport) {
+		ret = -EIO;
+		goto out;
+	}
+
 	ret = -EBUSY;
 	ret = -EBUSY;
 	if (tty_port_users(port) == 1) {
 	if (tty_port_users(port) == 1) {
 		uart_shutdown(tty, state);
 		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);
 		ret = uart_startup(tty, state, 1);
 	}
 	}
+out:
 	mutex_unlock(&port->mutex);
 	mutex_unlock(&port->mutex);
 	return ret;
 	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
  * FIXME: This wants extracting into a common all driver implementation
  * of TIOCMWAIT using tty_port.
  * 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;
 	struct tty_port *port = &state->port;
 	DECLARE_WAITQUEUE(wait, current);
 	DECLARE_WAITQUEUE(wait, current);
 	struct uart_icount cprev, cnow;
 	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
 	 * note the counters on entry
 	 */
 	 */
+	uport = uart_port_ref(state);
+	if (!uport)
+		return -EIO;
 	spin_lock_irq(&uport->lock);
 	spin_lock_irq(&uport->lock);
 	memcpy(&cprev, &uport->icount, sizeof(struct uart_icount));
 	memcpy(&cprev, &uport->icount, sizeof(struct uart_icount));
 	uart_enable_ms(uport);
 	uart_enable_ms(uport);
@@ -1119,6 +1210,7 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg)
 	}
 	}
 	__set_current_state(TASK_RUNNING);
 	__set_current_state(TASK_RUNNING);
 	remove_wait_queue(&port->delta_msr_wait, &wait);
 	remove_wait_queue(&port->delta_msr_wait, &wait);
+	uart_port_deref(uport);
 
 
 	return ret;
 	return ret;
 }
 }
@@ -1134,11 +1226,15 @@ static int uart_get_icount(struct tty_struct *tty,
 {
 {
 	struct uart_state *state = tty->driver_data;
 	struct uart_state *state = tty->driver_data;
 	struct uart_icount cnow;
 	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);
 	spin_lock_irq(&uport->lock);
 	memcpy(&cnow, &uport->icount, sizeof(struct uart_icount));
 	memcpy(&cnow, &uport->icount, sizeof(struct uart_icount));
 	spin_unlock_irq(&uport->lock);
 	spin_unlock_irq(&uport->lock);
+	uart_port_deref(uport);
 
 
 	icount->cts         = cnow.cts;
 	icount->cts         = cnow.cts;
 	icount->dsr         = cnow.dsr;
 	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.
  * Called via sys_ioctl.  We can use spin_lock_irq() here.
  */
  */
 static int
 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 uart_state *state = tty->driver_data;
 	struct tty_port *port = &state->port;
 	struct tty_port *port = &state->port;
+	struct uart_port *uport;
 	void __user *uarg = (void __user *)arg;
 	void __user *uarg = (void __user *)arg;
 	int ret = -ENOIOCTLCMD;
 	int ret = -ENOIOCTLCMD;
 
 
@@ -1238,7 +1334,7 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd,
 	if (ret != -ENOIOCTLCMD)
 	if (ret != -ENOIOCTLCMD)
 		goto out;
 		goto out;
 
 
-	if (tty->flags & (1 << TTY_IO_ERROR)) {
+	if (tty_io_error(tty)) {
 		ret = -EIO;
 		ret = -EIO;
 		goto out;
 		goto out;
 	}
 	}
@@ -1256,8 +1352,9 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd,
 		goto out;
 		goto out;
 
 
 	mutex_lock(&port->mutex);
 	mutex_lock(&port->mutex);
+	uport = uart_port_check(state);
 
 
-	if (tty->flags & (1 << TTY_IO_ERROR)) {
+	if (!uport || tty_io_error(tty)) {
 		ret = -EIO;
 		ret = -EIO;
 		goto out_up;
 		goto out_up;
 	}
 	}
@@ -1273,19 +1370,17 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd,
 		break;
 		break;
 
 
 	case TIOCGRS485:
 	case TIOCGRS485:
-		ret = uart_get_rs485_config(state->uart_port, uarg);
+		ret = uart_get_rs485_config(uport, uarg);
 		break;
 		break;
 
 
 	case TIOCSRS485:
 	case TIOCSRS485:
-		ret = uart_set_rs485_config(state->uart_port, uarg);
+		ret = uart_set_rs485_config(uport, uarg);
 		break;
 		break;
-	default: {
-		struct uart_port *uport = state->uart_port;
+	default:
 		if (uport->ops->ioctl)
 		if (uport->ops->ioctl)
 			ret = uport->ops->ioctl(uport, cmd, arg);
 			ret = uport->ops->ioctl(uport, cmd, arg);
 		break;
 		break;
 	}
 	}
-	}
 out_up:
 out_up:
 	mutex_unlock(&port->mutex);
 	mutex_unlock(&port->mutex);
 out:
 out:
@@ -1295,24 +1390,29 @@ out:
 static void uart_set_ldisc(struct tty_struct *tty)
 static void uart_set_ldisc(struct tty_struct *tty)
 {
 {
 	struct uart_state *state = tty->driver_data;
 	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);
 		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,
 static void uart_set_termios(struct tty_struct *tty,
 						struct ktermios *old_termios)
 						struct ktermios *old_termios)
 {
 {
 	struct uart_state *state = tty->driver_data;
 	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 cflag = tty->termios.c_cflag;
 	unsigned int iflag_mask = IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK;
 	unsigned int iflag_mask = IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK;
 	bool sw_changed = false;
 	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
 	 * Drivers doing software flow control also need to know
 	 * about changes to these input settings.
 	 * 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_ispeed == old_termios->c_ispeed &&
 	    ((tty->termios.c_iflag ^ old_termios->c_iflag) & iflag_mask) == 0 &&
 	    ((tty->termios.c_iflag ^ old_termios->c_iflag) & iflag_mask) == 0 &&
 	    !sw_changed) {
 	    !sw_changed) {
-		return;
+		goto out;
 	}
 	}
 
 
-	mutex_lock(&state->port.mutex);
 	uart_change_speed(tty, state, old_termios);
 	uart_change_speed(tty, state, old_termios);
-	mutex_unlock(&state->port.mutex);
 	/* reload cflag from termios; port driver may have overriden flags */
 	/* reload cflag from termios; port driver may have overriden flags */
 	cflag = tty->termios.c_cflag;
 	cflag = tty->termios.c_cflag;
 
 
@@ -1350,17 +1448,18 @@ static void uart_set_termios(struct tty_struct *tty,
 	/* Handle transition away from B0 status */
 	/* Handle transition away from B0 status */
 	else if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
 	else if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
 		unsigned int mask = TIOCM_DTR;
 		unsigned int mask = TIOCM_DTR;
-		if (!(cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags))
+		if (!(cflag & CRTSCTS) || !tty_throttled(tty))
 			mask |= TIOCM_RTS;
 			mask |= TIOCM_RTS;
 		uart_set_mctrl(uport, mask);
 		uart_set_mctrl(uport, mask);
 	}
 	}
+out:
+	mutex_unlock(&state->port.mutex);
 }
 }
 
 
 /*
 /*
  * Calls to uart_close() are serialised via the tty_lock in
  * Calls to uart_close() are serialised via the tty_lock in
  *   drivers/tty/tty_io.c:tty_release()
  *   drivers/tty/tty_io.c:tty_release()
  *   drivers/tty/tty_io.c:do_tty_hangup()
  *   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)
 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;
 		return;
 	}
 	}
 
 
-	uport = state->uart_port;
 	port = &state->port;
 	port = &state->port;
 	pr_debug("uart_close(%d) called\n", tty->index);
 	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;
 		return;
 
 
+	mutex_lock(&port->mutex);
+	uport = uart_port_check(state);
+
 	/*
 	/*
 	 * At this point, we stop accepting input.  To do this, we
 	 * At this point, we stop accepting input.  To do this, we
 	 * disable the receive line status interrupts.
 	 * 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);
 		spin_lock_irq(&uport->lock);
 		uport->ops->stop_rx(uport);
 		uport->ops->stop_rx(uport);
 		spin_unlock_irq(&uport->lock);
 		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);
 		uart_wait_until_sent(tty, uport->timeout);
 	}
 	}
 
 
-	mutex_lock(&port->mutex);
 	uart_shutdown(tty, state);
 	uart_shutdown(tty, state);
 	tty_port_tty_set(port, NULL);
 	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)
 		if (port->close_delay)
 			msleep_interruptible(jiffies_to_msecs(port->close_delay));
 			msleep_interruptible(jiffies_to_msecs(port->close_delay));
 		spin_lock_irq(&port->lock);
 		spin_lock_irq(&port->lock);
-	} else if (!uart_console(uport)) {
+	} else if (uport && !uart_console(uport)) {
 		spin_unlock_irq(&port->lock);
 		spin_unlock_irq(&port->lock);
 		uart_change_pm(state, UART_PM_STATE_OFF);
 		uart_change_pm(state, UART_PM_STATE_OFF);
 		spin_lock_irq(&port->lock);
 		spin_lock_irq(&port->lock);
 	}
 	}
+	spin_unlock_irq(&port->lock);
+	tty_port_set_active(port, 0);
 
 
 	/*
 	/*
 	 * Wake up anyone trying to open this port.
 	 * 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);
 	wake_up_interruptible(&port->open_wait);
 
 
 	mutex_unlock(&port->mutex);
 	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)
 static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
 {
 {
 	struct uart_state *state = tty->driver_data;
 	struct uart_state *state = tty->driver_data;
-	struct uart_port *port = state->uart_port;
+	struct uart_port *port;
 	unsigned long char_time, expire;
 	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;
 		return;
+	}
 
 
 	/*
 	/*
 	 * Set the check interval to be 1/5 of the estimated time to
 	 * 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))
 		if (time_after(jiffies, expire))
 			break;
 			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 uart_state *state = tty->driver_data;
 	struct tty_port *port = &state->port;
 	struct tty_port *port = &state->port;
+	struct uart_port *uport;
 	unsigned long flags;
 	unsigned long flags;
 
 
 	pr_debug("uart_hangup(%d)\n", tty->index);
 	pr_debug("uart_hangup(%d)\n", tty->index);
 
 
 	mutex_lock(&port->mutex);
 	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_flush_buffer(tty);
 		uart_shutdown(tty, state);
 		uart_shutdown(tty, state);
 		spin_lock_irqsave(&port->lock, flags);
 		spin_lock_irqsave(&port->lock, flags);
 		port->count = 0;
 		port->count = 0;
-		clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
 		spin_unlock_irqrestore(&port->lock, flags);
 		spin_unlock_irqrestore(&port->lock, flags);
+		tty_port_set_active(port, 0);
 		tty_port_tty_set(port, NULL);
 		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);
 			uart_change_pm(state, UART_PM_STATE_OFF);
 		wake_up_interruptible(&port->open_wait);
 		wake_up_interruptible(&port->open_wait);
 		wake_up_interruptible(&port->delta_msr_wait);
 		wake_up_interruptible(&port->delta_msr_wait);
@@ -1517,10 +1626,11 @@ static void uart_hangup(struct tty_struct *tty)
 	mutex_unlock(&port->mutex);
 	mutex_unlock(&port->mutex);
 }
 }
 
 
+/* uport == NULL if uart_port has already been removed */
 static void uart_port_shutdown(struct tty_port *port)
 static void uart_port_shutdown(struct tty_port *port)
 {
 {
 	struct uart_state *state = container_of(port, struct uart_state, 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
 	 * 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.
 	 * 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.
 	 * 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)
 static int uart_carrier_raised(struct tty_port *port)
 {
 {
 	struct uart_state *state = container_of(port, struct uart_state, 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;
 	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);
 	spin_lock_irq(&uport->lock);
 	uart_enable_ms(uport);
 	uart_enable_ms(uport);
 	mctrl = uport->ops->get_mctrl(uport);
 	mctrl = uport->ops->get_mctrl(uport);
 	spin_unlock_irq(&uport->lock);
 	spin_unlock_irq(&uport->lock);
+	uart_port_deref(uport);
 	if (mctrl & TIOCM_CAR)
 	if (mctrl & TIOCM_CAR)
 		return 1;
 		return 1;
 	return 0;
 	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)
 static void uart_dtr_rts(struct tty_port *port, int onoff)
 {
 {
 	struct uart_state *state = container_of(port, struct uart_state, port);
 	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)
 	if (onoff)
 		uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
 		uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
 	else
 	else
 		uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
 		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;
 	int retval, line = tty->index;
 	struct uart_state *state = drv->state + line;
 	struct uart_state *state = drv->state + line;
 	struct tty_port *port = &state->port;
 	struct tty_port *port = &state->port;
+	struct uart_port *uport;
 
 
 	pr_debug("uart_open(%d) called\n", line);
 	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;
 		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;
 		retval = -ENXIO;
 		goto err_unlock;
 		goto err_unlock;
 	}
 	}
 
 
 	tty->driver_data = state;
 	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);
 	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 uart_state *state = drv->state + i;
 	struct tty_port *port = &state->port;
 	struct tty_port *port = &state->port;
 	enum uart_pm_state pm_state;
 	enum uart_pm_state pm_state;
-	struct uart_port *uport = state->uart_port;
+	struct uart_port *uport;
 	char stat_buf[32];
 	char stat_buf[32];
 	unsigned int status;
 	unsigned int status;
 	int mmio;
 	int mmio;
 
 
+	mutex_lock(&port->mutex);
+	uport = uart_port_check(state);
 	if (!uport)
 	if (!uport)
-		return;
+		goto out;
 
 
 	mmio = uport->iotype >= UPIO_MEM;
 	mmio = uport->iotype >= UPIO_MEM;
 	seq_printf(m, "%d: uart:%s %s%08llX irq:%d",
 	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) {
 	if (uport->type == PORT_UNKNOWN) {
 		seq_putc(m, '\n');
 		seq_putc(m, '\n');
-		return;
+		goto out;
 	}
 	}
 
 
 	if (capable(CAP_SYS_ADMIN)) {
 	if (capable(CAP_SYS_ADMIN)) {
-		mutex_lock(&port->mutex);
 		pm_state = state->pm_state;
 		pm_state = state->pm_state;
 		if (pm_state != UART_PM_STATE_ON)
 		if (pm_state != UART_PM_STATE_ON)
 			uart_change_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);
 		spin_unlock_irq(&uport->lock);
 		if (pm_state != UART_PM_STATE_ON)
 		if (pm_state != UART_PM_STATE_ON)
 			uart_change_pm(state, pm_state);
 			uart_change_pm(state, pm_state);
-		mutex_unlock(&port->mutex);
 
 
 		seq_printf(m, " tx:%d rx:%d",
 		seq_printf(m, " tx:%d rx:%d",
 				uport->icount.tx, uport->icount.rx);
 				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');
 	seq_putc(m, '\n');
 #undef STATBIT
 #undef STATBIT
 #undef INFOBIT
 #undef INFOBIT
+out:
+	mutex_unlock(&port->mutex);
 }
 }
 
 
 static int uart_proc_show(struct seq_file *m, void *v)
 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,
 static void uart_change_pm(struct uart_state *state,
 			   enum uart_pm_state pm_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 (state->pm_state != pm_state) {
-		if (port->ops->pm)
+		if (port && port->ops->pm)
 			port->ops->pm(port, pm_state, state->pm_state);
 			port->ops->pm(port, pm_state, state->pm_state);
 		state->pm_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;
 	uport->suspended = 1;
 
 
-	if (port->flags & ASYNC_INITIALIZED) {
+	if (tty_port_initialized(port)) {
 		const struct uart_ops *ops = uport->ops;
 		const struct uart_ops *ops = uport->ops;
 		int tries;
 		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);
 		spin_lock_irq(&uport->lock);
 		ops->stop_tx(uport);
 		ops->stop_tx(uport);
@@ -2088,7 +2220,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
 			console_start(uport->cons);
 			console_start(uport->cons);
 	}
 	}
 
 
-	if (port->flags & ASYNC_SUSPENDED) {
+	if (tty_port_suspended(port)) {
 		const struct uart_ops *ops = uport->ops;
 		const struct uart_ops *ops = uport->ops;
 		int ret;
 		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->set_mctrl(uport, uport->mctrl);
 				ops->start_tx(uport);
 				ops->start_tx(uport);
 				spin_unlock_irq(&uport->lock);
 				spin_unlock_irq(&uport->lock);
-				set_bit(ASYNCB_INITIALIZED, &port->flags);
+				tty_port_set_initialized(port, 1);
 			} else {
 			} else {
 				/*
 				/*
 				 * Failed to resume - maybe hardware went away?
 				 * 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);
 	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_driver *drv = driver->driver_state;
 	struct uart_state *state = drv->state + line;
 	struct uart_state *state = drv->state + line;
+	struct tty_port *tport;
 	struct uart_port *port;
 	struct uart_port *port;
 	int baud = 9600;
 	int baud = 9600;
 	int bits = 8;
 	int bits = 8;
 	int parity = 'n';
 	int parity = 'n';
 	int flow = 'n';
 	int flow = 'n';
-	int ret;
+	int ret = 0;
 
 
-	if (!state || !state->uart_port)
+	if (!state)
 		return -1;
 		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);
 			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);
 		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)
 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_driver *drv = driver->driver_state;
 	struct uart_state *state = drv->state + line;
 	struct uart_state *state = drv->state + line;
 	struct uart_port *port;
 	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)
 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_state *state = drv->state + line;
 	struct uart_port *port;
 	struct uart_port *port;
 
 
-	if (!state || !state->uart_port)
+	if (!state)
 		return;
 		return;
 
 
-	port = state->uart_port;
+	port = uart_port_ref(state);
+	if (!port)
+		return;
 
 
 	if (ch == '\n')
 	if (ch == '\n')
 		port->ops->poll_put_char(port, '\r');
 		port->ops->poll_put_char(port, '\r');
 	port->ops->poll_put_char(port, ch);
 	port->ops->poll_put_char(port, ch);
+	uart_port_deref(port);
 }
 }
 #endif
 #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 */
 	/* 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;
 	state->uart_port = uport;
 	uport->state = state;
 	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 uart_state *state = drv->state + uport->line;
 	struct tty_port *port = &state->port;
 	struct tty_port *port = &state->port;
+	struct uart_port *uart_port;
 	struct tty_struct *tty;
 	struct tty_struct *tty;
 	int ret = 0;
 	int ret = 0;
 
 
 	BUG_ON(in_interrupt());
 	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);
 	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.
 	 * succeeding while we shut down the port.
 	 */
 	 */
 	mutex_lock(&port->mutex);
 	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);
 		mutex_unlock(&port->mutex);
 		ret = -EINVAL;
 		ret = -EINVAL;
 		goto out;
 		goto out;
@@ -2764,7 +2906,11 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
 	 */
 	 */
 	uport->type = PORT_UNKNOWN;
 	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;
 	state->uart_port = NULL;
+	mutex_unlock(&port->mutex);
 out:
 out:
 	mutex_unlock(&port_mutex);
 	mutex_unlock(&port_mutex);
 
 

+ 5 - 2
drivers/tty/serial/serial_mctrl_gpio.c

@@ -43,8 +43,6 @@ static const struct {
 	{ "rng", TIOCM_RNG, false, },
 	{ "rng", TIOCM_RNG, false, },
 	{ "rts", TIOCM_RTS, true, },
 	{ "rts", TIOCM_RTS, true, },
 	{ "dtr", TIOCM_DTR, true, },
 	{ "dtr", TIOCM_DTR, true, },
-	{ "out1", TIOCM_OUT1, true, },
-	{ "out2", TIOCM_OUT2, true, },
 };
 };
 
 
 void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
 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;
 	struct uart_port *port = gpios->port;
 	u32 mctrl = gpios->mctrl_prev;
 	u32 mctrl = gpios->mctrl_prev;
 	u32 mctrl_diff;
 	u32 mctrl_diff;
+	unsigned long flags;
 
 
 	mctrl_gpio_get(gpios, &mctrl);
 	mctrl_gpio_get(gpios, &mctrl);
 
 
+	spin_lock_irqsave(&port->lock, flags);
+
 	mctrl_diff = mctrl ^ gpios->mctrl_prev;
 	mctrl_diff = mctrl ^ gpios->mctrl_prev;
 	gpios->mctrl_prev = mctrl;
 	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);
 		wake_up_interruptible(&port->state->port.delta_msr_wait);
 	}
 	}
 
 
+	spin_unlock_irqrestore(&port->lock, flags);
+
 	return IRQ_HANDLED;
 	return IRQ_HANDLED;
 }
 }
 
 

+ 0 - 2
drivers/tty/serial/serial_mctrl_gpio.h

@@ -32,8 +32,6 @@ enum mctrl_gpio_idx {
 	UART_GPIO_RI = UART_GPIO_RNG,
 	UART_GPIO_RI = UART_GPIO_RNG,
 	UART_GPIO_RTS,
 	UART_GPIO_RTS,
 	UART_GPIO_DTR,
 	UART_GPIO_DTR,
-	UART_GPIO_OUT1,
-	UART_GPIO_OUT2,
 	UART_GPIO_MAX,
 	UART_GPIO_MAX,
 };
 };
 
 

+ 19 - 20
drivers/tty/serial/sirfsoc_uart.c

@@ -1264,6 +1264,7 @@ MODULE_DEVICE_TABLE(of, sirfsoc_uart_ids);
 
 
 static int sirfsoc_uart_probe(struct platform_device *pdev)
 static int sirfsoc_uart_probe(struct platform_device *pdev)
 {
 {
+	struct device_node *np = pdev->dev.of_node;
 	struct sirfsoc_uart_port *sirfport;
 	struct sirfsoc_uart_port *sirfport;
 	struct uart_port *port;
 	struct uart_port *port;
 	struct resource *res;
 	struct resource *res;
@@ -1276,13 +1277,13 @@ static int sirfsoc_uart_probe(struct platform_device *pdev)
 	};
 	};
 	const struct of_device_id *match;
 	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);
 	sirfport = devm_kzalloc(&pdev->dev, sizeof(*sirfport), GFP_KERNEL);
 	if (!sirfport) {
 	if (!sirfport) {
 		ret = -ENOMEM;
 		ret = -ENOMEM;
 		goto err;
 		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;
 	sirf_ports[sirfport->port.line] = sirfport;
 	sirfport->port.iotype = UPIO_MEM;
 	sirfport->port.iotype = UPIO_MEM;
 	sirfport->port.flags = UPF_BOOT_AUTOCONF;
 	sirfport->port.flags = UPF_BOOT_AUTOCONF;
@@ -1291,25 +1292,25 @@ static int sirfsoc_uart_probe(struct platform_device *pdev)
 	port->private_data = sirfport;
 	port->private_data = sirfport;
 	sirfport->uart_reg = (struct sirfsoc_uart_register *)match->data;
 	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;
 		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;
 		sirfport->uart_reg->uart_type =	SIRF_USP_UART;
 		if (!sirfport->hw_flow_ctrl)
 		if (!sirfport->hw_flow_ctrl)
 			goto usp_no_flow_control;
 			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
 		else
 			sirfport->cts_gpio = -1;
 			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
 		else
 			sirfport->rts_gpio = -1;
 			sirfport->rts_gpio = -1;
 
 
@@ -1336,13 +1337,11 @@ static int sirfsoc_uart_probe(struct platform_device *pdev)
 		gpio_direction_output(sirfport->rts_gpio, 1);
 		gpio_direction_output(sirfport->rts_gpio, 1);
 	}
 	}
 usp_no_flow_control:
 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;
 		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,
 		dev_err(&pdev->dev,
 			"Unable to find fifosize in uart node.\n");
 			"Unable to find fifosize in uart node.\n");
 		ret = -EFAULT;
 		ret = -EFAULT;

+ 6 - 6
drivers/tty/serial/uartlite.c

@@ -72,7 +72,7 @@ static void uartlite_outbe32(u32 val, void __iomem *addr)
 	iowrite32be(val, addr);
 	iowrite32be(val, addr);
 }
 }
 
 
-static struct uartlite_reg_ops uartlite_be = {
+static const struct uartlite_reg_ops uartlite_be = {
 	.in = uartlite_inbe32,
 	.in = uartlite_inbe32,
 	.out = uartlite_outbe32,
 	.out = uartlite_outbe32,
 };
 };
@@ -87,21 +87,21 @@ static void uartlite_outle32(u32 val, void __iomem *addr)
 	iowrite32(val, addr);
 	iowrite32(val, addr);
 }
 }
 
 
-static struct uartlite_reg_ops uartlite_le = {
+static const struct uartlite_reg_ops uartlite_le = {
 	.in = uartlite_inle32,
 	.in = uartlite_inle32,
 	.out = uartlite_outle32,
 	.out = uartlite_outle32,
 };
 };
 
 
 static inline u32 uart_in32(u32 offset, struct uart_port *port)
 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);
 	return reg_ops->in(port->membase + offset);
 }
 }
 
 
 static inline void uart_out32(u32 val, u32 offset, struct uart_port *port)
 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);
 	reg_ops->out(val, port->membase + offset);
 }
 }
@@ -345,13 +345,13 @@ static int ulite_request_port(struct uart_port *port)
 		return -EBUSY;
 		return -EBUSY;
 	}
 	}
 
 
-	port->private_data = &uartlite_be;
+	port->private_data = (void *)&uartlite_be;
 	ret = uart_in32(ULITE_CONTROL, port);
 	ret = uart_in32(ULITE_CONTROL, port);
 	uart_out32(ULITE_CONTROL_RST_TX, ULITE_CONTROL, port);
 	uart_out32(ULITE_CONTROL_RST_TX, ULITE_CONTROL, port);
 	ret = uart_in32(ULITE_STATUS, port);
 	ret = uart_in32(ULITE_STATUS, port);
 	/* Endianess detection */
 	/* Endianess detection */
 	if ((ret & ULITE_STATUS_TXEMPTY) != ULITE_STATUS_TXEMPTY)
 	if ((ret & ULITE_STATUS_TXEMPTY) != ULITE_STATUS_TXEMPTY)
-		port->private_data = &uartlite_le;
+		port->private_data = (void *)&uartlite_le;
 
 
 	return 0;
 	return 0;
 }
 }

+ 3 - 0
drivers/tty/serial/ucc_uart.c

@@ -1478,6 +1478,9 @@ static const struct of_device_id ucc_uart_match[] = {
 		.type = "serial",
 		.type = "serial",
 		.compatible = "ucc_uart",
 		.compatible = "ucc_uart",
 	},
 	},
+	{
+		.compatible = "fsl,t1040-ucc-uart",
+	},
 	{},
 	{},
 };
 };
 MODULE_DEVICE_TABLE(of, ucc_uart_match);
 MODULE_DEVICE_TABLE(of, ucc_uart_match);

+ 32 - 42
drivers/tty/synclink.c

@@ -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->status_event_wait_q);
 		wake_up_interruptible(&info->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) ) {
 		     (status & MISCSTATUS_DCD_LATCHED) ) {
 			if ( debug_level >= DEBUG_LEVEL_ISR )
 			if ( debug_level >= DEBUG_LEVEL_ISR )
 				printk("%s CD now %s...", info->device_name,
 				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 (status & MISCSTATUS_CTS) {
 					if ( debug_level >= DEBUG_LEVEL_ISR )
 					if ( debug_level >= DEBUG_LEVEL_ISR )
 						printk("CTS tx start...");
 						printk("CTS tx start...");
-					if (info->port.tty)
-						info->port.tty->hw_stopped = 0;
+					info->port.tty->hw_stopped = 0;
 					usc_start_transmitter(info);
 					usc_start_transmitter(info);
 					info->pending_bh |= BH_TRANSMIT;
 					info->pending_bh |= BH_TRANSMIT;
 					return;
 					return;
@@ -1749,13 +1748,13 @@ static irqreturn_t mgsl_interrupt(int dummy, void *dev_id)
 static int startup(struct mgsl_struct * info)
 static int startup(struct mgsl_struct * info)
 {
 {
 	int retval = 0;
 	int retval = 0;
-	
+
 	if ( debug_level >= DEBUG_LEVEL_INFO )
 	if ( debug_level >= DEBUG_LEVEL_INFO )
 		printk("%s(%d):mgsl_startup(%s)\n",__FILE__,__LINE__,info->device_name);
 		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;
 		return 0;
-	
+
 	if (!info->xmit_buf) {
 	if (!info->xmit_buf) {
 		/* allocate a page of memory for a transmit buffer */
 		/* allocate a page of memory for a transmit buffer */
 		info->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
 		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 */
 	/* program hardware for current parameters */
 	mgsl_change_params(info);
 	mgsl_change_params(info);
-	
+
 	if (info->port.tty)
 	if (info->port.tty)
 		clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
 		clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
 
 
-	info->port.flags |= ASYNC_INITIALIZED;
-	
+	tty_port_set_initialized(&info->port, 1);
+
 	return 0;
 	return 0;
-	
 }	/* end of startup() */
 }	/* end of startup() */
 
 
 /* shutdown()
 /* shutdown()
@@ -1808,8 +1806,8 @@ static int startup(struct mgsl_struct * info)
 static void shutdown(struct mgsl_struct * info)
 static void shutdown(struct mgsl_struct * info)
 {
 {
 	unsigned long flags;
 	unsigned long flags;
-	
-	if (!(info->port.flags & ASYNC_INITIALIZED))
+
+	if (!tty_port_initialized(&info->port))
 		return;
 		return;
 
 
 	if (debug_level >= DEBUG_LEVEL_INFO)
 	if (debug_level >= DEBUG_LEVEL_INFO)
@@ -1853,13 +1851,12 @@ static void shutdown(struct mgsl_struct * info)
 
 
 	spin_unlock_irqrestore(&info->irq_spinlock,flags);
 	spin_unlock_irqrestore(&info->irq_spinlock,flags);
 
 
-	mgsl_release_resources(info);	
-	
+	mgsl_release_resources(info);
+
 	if (info->port.tty)
 	if (info->port.tty)
 		set_bit(TTY_IO_ERROR, &info->port.tty->flags);
 		set_bit(TTY_IO_ERROR, &info->port.tty->flags);
 
 
-	info->port.flags &= ~ASYNC_INITIALIZED;
-	
+	tty_port_set_initialized(&info->port, 0);
 }	/* end of shutdown() */
 }	/* end of shutdown() */
 
 
 static void mgsl_program_hw(struct mgsl_struct *info)
 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 */
 	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 */
 	/* process tty input control flags */
 	
 	
@@ -2972,7 +2962,7 @@ static int mgsl_ioctl(struct tty_struct *tty,
 
 
 	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
 	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
 	    (cmd != TIOCMIWAIT)) {
 	    (cmd != TIOCMIWAIT)) {
-		if (tty->flags & (1 << TTY_IO_ERROR))
+		if (tty_io_error(tty))
 		    return -EIO;
 		    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 */
 	/* Handle transition away from B0 status */
 	if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) {
 	if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) {
 		info->serial_signals |= SerialSignal_DTR;
 		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;
 			info->serial_signals |= SerialSignal_RTS;
 		spin_lock_irqsave(&info->irq_spinlock,flags);
 		spin_lock_irqsave(&info->irq_spinlock,flags);
 	 	usc_set_serial_signals(info);
 	 	usc_set_serial_signals(info);
@@ -3091,7 +3081,7 @@ static void mgsl_close(struct tty_struct *tty, struct file * filp)
 		goto cleanup;
 		goto cleanup;
 
 
 	mutex_lock(&info->port.mutex);
 	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_wait_until_sent(tty, info->timeout);
 	mgsl_flush_buffer(tty);
 	mgsl_flush_buffer(tty);
 	tty_ldisc_flush(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)
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("%s(%d):mgsl_wait_until_sent(%s) entry\n",
 		printk("%s(%d):mgsl_wait_until_sent(%s) entry\n",
 			 __FILE__,__LINE__, info->device_name );
 			 __FILE__,__LINE__, info->device_name );
-      
+
 	if (mgsl_paranoia_check(info, tty->name, "mgsl_wait_until_sent"))
 	if (mgsl_paranoia_check(info, tty->name, "mgsl_wait_until_sent"))
 		return;
 		return;
 
 
-	if (!(info->port.flags & ASYNC_INITIALIZED))
+	if (!tty_port_initialized(&info->port))
 		goto exit;
 		goto exit;
-	 
+
 	orig_jiffies = jiffies;
 	orig_jiffies = jiffies;
-      
+
 	/* Set check interval to 1/5 of estimated time to
 	/* Set check interval to 1/5 of estimated time to
 	 * send a character, and make it at least 1. The check
 	 * send a character, and make it at least 1. The check
 	 * interval should also be less than the timeout.
 	 * interval should also be less than the timeout.
@@ -3204,7 +3194,7 @@ static void mgsl_hangup(struct tty_struct *tty)
 	shutdown(info);
 	shutdown(info);
 	
 	
 	info->port.count = 0;	
 	info->port.count = 0;	
-	info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
+	tty_port_set_active(&info->port, 0);
 	info->port.tty = NULL;
 	info->port.tty = NULL;
 
 
 	wake_up_interruptible(&info->port.open_wait);
 	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",
 		printk("%s(%d):block_til_ready on %s\n",
 			 __FILE__,__LINE__, tty->driver->name );
 			 __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 */
 		/* nonblock mode is set or port is not enabled */
-		port->flags |= ASYNC_NORMAL_ACTIVE;
+		tty_port_set_active(port, 1);
 		return 0;
 		return 0;
 	}
 	}
 
 
@@ -3297,14 +3287,14 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
 	port->count--;
 	port->count--;
 	spin_unlock_irqrestore(&info->irq_spinlock, flags);
 	spin_unlock_irqrestore(&info->irq_spinlock, flags);
 	port->blocked_open++;
 	port->blocked_open++;
-	
+
 	while (1) {
 	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);
 			tty_port_raise_dtr_rts(port);
-		
+
 		set_current_state(TASK_INTERRUPTIBLE);
 		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) ?
 			retval = (port->flags & ASYNC_HUP_NOTIFY) ?
 					-EAGAIN : -ERESTARTSYS;
 					-EAGAIN : -ERESTARTSYS;
 			break;
 			break;
@@ -3341,7 +3331,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
 			 __FILE__,__LINE__, tty->driver->name, port->count );
 			 __FILE__,__LINE__, tty->driver->name, port->count );
 			 
 			 
 	if (!retval)
 	if (!retval)
-		port->flags |= ASYNC_NORMAL_ACTIVE;
+		tty_port_set_active(port, 1);
 		
 		
 	return retval;
 	return retval;
 	
 	

+ 17 - 24
drivers/tty/synclink_gt.c

@@ -726,7 +726,7 @@ static void close(struct tty_struct *tty, struct file *filp)
 		goto cleanup;
 		goto cleanup;
 
 
 	mutex_lock(&info->port.mutex);
 	mutex_lock(&info->port.mutex);
- 	if (info->port.flags & ASYNC_INITIALIZED)
+	if (tty_port_initialized(&info->port))
  		wait_until_sent(tty, info->timeout);
  		wait_until_sent(tty, info->timeout);
 	flush_buffer(tty);
 	flush_buffer(tty);
 	tty_ldisc_flush(tty);
 	tty_ldisc_flush(tty);
@@ -756,9 +756,9 @@ static void hangup(struct tty_struct *tty)
 
 
 	spin_lock_irqsave(&info->port.lock, flags);
 	spin_lock_irqsave(&info->port.lock, flags);
 	info->port.count = 0;
 	info->port.count = 0;
-	info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
 	info->port.tty = NULL;
 	info->port.tty = NULL;
 	spin_unlock_irqrestore(&info->port.lock, flags);
 	spin_unlock_irqrestore(&info->port.lock, flags);
+	tty_port_set_active(&info->port, 0);
 	mutex_unlock(&info->port.mutex);
 	mutex_unlock(&info->port.mutex);
 
 
 	wake_up_interruptible(&info->port.open_wait);
 	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 */
 	/* Handle transition away from B0 status */
 	if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) {
 	if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) {
 		info->signals |= SerialSignal_DTR;
 		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;
 			info->signals |= SerialSignal_RTS;
 		spin_lock_irqsave(&info->lock,flags);
 		spin_lock_irqsave(&info->lock,flags);
 	 	set_signals(info);
 	 	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"))
 	if (sanity_check(info, tty->name, "wait_until_sent"))
 		return;
 		return;
 	DBGINFO(("%s wait_until_sent entry\n", info->device_name));
 	DBGINFO(("%s wait_until_sent entry\n", info->device_name));
-	if (!(info->port.flags & ASYNC_INITIALIZED))
+	if (!tty_port_initialized(&info->port))
 		goto exit;
 		goto exit;
 
 
 	orig_jiffies = jiffies;
 	orig_jiffies = jiffies;
@@ -1032,7 +1032,7 @@ static int ioctl(struct tty_struct *tty,
 
 
 	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
 	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
 	    (cmd != TIOCMIWAIT)) {
 	    (cmd != TIOCMIWAIT)) {
-		if (tty->flags & (1 << TTY_IO_ERROR))
+		if (tty_io_error(tty))
 		    return -EIO;
 		    return -EIO;
 	}
 	}
 
 
@@ -2080,7 +2080,7 @@ static void dcd_change(struct slgt_info *info, unsigned short status)
 	wake_up_interruptible(&info->event_wait_q);
 	wake_up_interruptible(&info->event_wait_q);
 	info->pending_bh |= BH_STATUS;
 	info->pending_bh |= BH_STATUS;
 
 
-	if (info->port.flags & ASYNC_CHECK_CD) {
+	if (tty_port_check_carrier(&info->port)) {
 		if (info->signals & SerialSignal_DCD)
 		if (info->signals & SerialSignal_DCD)
 			wake_up_interruptible(&info->port.open_wait);
 			wake_up_interruptible(&info->port.open_wait);
 		else {
 		else {
@@ -2421,7 +2421,7 @@ static int startup(struct slgt_info *info)
 {
 {
 	DBGINFO(("%s startup\n", info->device_name));
 	DBGINFO(("%s startup\n", info->device_name));
 
 
-	if (info->port.flags & ASYNC_INITIALIZED)
+	if (tty_port_initialized(&info->port))
 		return 0;
 		return 0;
 
 
 	if (!info->tx_buf) {
 	if (!info->tx_buf) {
@@ -2442,7 +2442,7 @@ static int startup(struct slgt_info *info)
 	if (info->port.tty)
 	if (info->port.tty)
 		clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
 		clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
 
 
-	info->port.flags |= ASYNC_INITIALIZED;
+	tty_port_set_initialized(&info->port, 1);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -2454,7 +2454,7 @@ static void shutdown(struct slgt_info *info)
 {
 {
 	unsigned long flags;
 	unsigned long flags;
 
 
-	if (!(info->port.flags & ASYNC_INITIALIZED))
+	if (!tty_port_initialized(&info->port))
 		return;
 		return;
 
 
 	DBGINFO(("%s shutdown\n", info->device_name));
 	DBGINFO(("%s shutdown\n", info->device_name));
@@ -2489,7 +2489,7 @@ static void shutdown(struct slgt_info *info)
 	if (info->port.tty)
 	if (info->port.tty)
 		set_bit(TTY_IO_ERROR, &info->port.tty->flags);
 		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)
 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 */
 	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 */
 	/* 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));
 	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 */
 		/* nonblock mode is set or port is not enabled */
-		port->flags |= ASYNC_NORMAL_ACTIVE;
+		tty_port_set_active(port, 1);
 		return 0;
 		return 0;
 	}
 	}
 
 
@@ -3294,12 +3287,12 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
 	port->blocked_open++;
 	port->blocked_open++;
 
 
 	while (1) {
 	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);
 			tty_port_raise_dtr_rts(port);
 
 
 		set_current_state(TASK_INTERRUPTIBLE);
 		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) ?
 			retval = (port->flags & ASYNC_HUP_NOTIFY) ?
 					-EAGAIN : -ERESTARTSYS;
 					-EAGAIN : -ERESTARTSYS;
 			break;
 			break;
@@ -3328,7 +3321,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
 	port->blocked_open--;
 	port->blocked_open--;
 
 
 	if (!retval)
 	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));
 	DBGINFO(("%s block_til_ready ready, rc=%d\n", tty->driver->name, retval));
 	return retval;
 	return retval;

+ 17 - 24
drivers/tty/synclinkmp.c

@@ -812,7 +812,7 @@ static void close(struct tty_struct *tty, struct file *filp)
 		goto cleanup;
 		goto cleanup;
 
 
 	mutex_lock(&info->port.mutex);
 	mutex_lock(&info->port.mutex);
- 	if (info->port.flags & ASYNC_INITIALIZED)
+	if (tty_port_initialized(&info->port))
  		wait_until_sent(tty, info->timeout);
  		wait_until_sent(tty, info->timeout);
 
 
 	flush_buffer(tty);
 	flush_buffer(tty);
@@ -849,9 +849,9 @@ static void hangup(struct tty_struct *tty)
 
 
 	spin_lock_irqsave(&info->port.lock, flags);
 	spin_lock_irqsave(&info->port.lock, flags);
 	info->port.count = 0;
 	info->port.count = 0;
-	info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
 	info->port.tty = NULL;
 	info->port.tty = NULL;
 	spin_unlock_irqrestore(&info->port.lock, flags);
 	spin_unlock_irqrestore(&info->port.lock, flags);
+	tty_port_set_active(&info->port, 1);
 	mutex_unlock(&info->port.mutex);
 	mutex_unlock(&info->port.mutex);
 
 
 	wake_up_interruptible(&info->port.open_wait);
 	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 */
 	/* Handle transition away from B0 status */
 	if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) {
 	if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) {
 		info->serial_signals |= SerialSignal_DTR;
 		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;
 			info->serial_signals |= SerialSignal_RTS;
 		spin_lock_irqsave(&info->lock,flags);
 		spin_lock_irqsave(&info->lock,flags);
 	 	set_signals(info);
 	 	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"))
 	if (sanity_check(info, tty->name, "wait_until_sent"))
 		return;
 		return;
 
 
-	if (!test_bit(ASYNCB_INITIALIZED, &info->port.flags))
+	if (!tty_port_initialized(&info->port))
 		goto exit;
 		goto exit;
 
 
 	orig_jiffies = jiffies;
 	orig_jiffies = jiffies;
@@ -1261,7 +1261,7 @@ static int ioctl(struct tty_struct *tty,
 
 
 	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
 	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
 	    (cmd != TIOCMIWAIT)) {
 	    (cmd != TIOCMIWAIT)) {
-		if (tty->flags & (1 << TTY_IO_ERROR))
+		if (tty_io_error(tty))
 		    return -EIO;
 		    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->status_event_wait_q);
 		wake_up_interruptible(&info->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) ) {
 		     (status & MISCSTATUS_DCD_LATCHED) ) {
 			if ( debug_level >= DEBUG_LEVEL_ISR )
 			if ( debug_level >= DEBUG_LEVEL_ISR )
 				printk("%s CD now %s...", info->device_name,
 				printk("%s CD now %s...", info->device_name,
@@ -2636,7 +2636,7 @@ static int startup(SLMP_INFO * info)
 	if ( debug_level >= DEBUG_LEVEL_INFO )
 	if ( debug_level >= DEBUG_LEVEL_INFO )
 		printk("%s(%d):%s tx_releaseup()\n",__FILE__,__LINE__,info->device_name);
 		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;
 		return 0;
 
 
 	if (!info->tx_buf) {
 	if (!info->tx_buf) {
@@ -2662,7 +2662,7 @@ static int startup(SLMP_INFO * info)
 	if (info->port.tty)
 	if (info->port.tty)
 		clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
 		clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
 
 
-	info->port.flags |= ASYNC_INITIALIZED;
+	tty_port_set_initialized(&info->port, 1);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -2673,7 +2673,7 @@ static void shutdown(SLMP_INFO * info)
 {
 {
 	unsigned long flags;
 	unsigned long flags;
 
 
-	if (!(info->port.flags & ASYNC_INITIALIZED))
+	if (!tty_port_initialized(&info->port))
 		return;
 		return;
 
 
 	if (debug_level >= DEBUG_LEVEL_INFO)
 	if (debug_level >= DEBUG_LEVEL_INFO)
@@ -2705,7 +2705,7 @@ static void shutdown(SLMP_INFO * info)
 	if (info->port.tty)
 	if (info->port.tty)
 		set_bit(TTY_IO_ERROR, &info->port.tty->flags);
 		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)
 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 */
 	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 */
 	/* 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",
 		printk("%s(%d):%s block_til_ready()\n",
 			 __FILE__,__LINE__, tty->driver->name );
 			 __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 */
 		/* nonblock mode is set or port is not enabled */
 		/* just verify that callout device is not active */
 		/* just verify that callout device is not active */
-		port->flags |= ASYNC_NORMAL_ACTIVE;
+		tty_port_set_active(port, 1);
 		return 0;
 		return 0;
 	}
 	}
 
 
@@ -3315,12 +3308,12 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
 	port->blocked_open++;
 	port->blocked_open++;
 
 
 	while (1) {
 	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);
 			tty_port_raise_dtr_rts(port);
 
 
 		set_current_state(TASK_INTERRUPTIBLE);
 		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) ?
 			retval = (port->flags & ASYNC_HUP_NOTIFY) ?
 					-EAGAIN : -ERESTARTSYS;
 					-EAGAIN : -ERESTARTSYS;
 			break;
 			break;
@@ -3355,7 +3348,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
 			 __FILE__,__LINE__, tty->driver->name, port->count );
 			 __FILE__,__LINE__, tty->driver->name, port->count );
 
 
 	if (!retval)
 	if (!retval)
-		port->flags |= ASYNC_NORMAL_ACTIVE;
+		tty_port_set_active(port, 1);
 
 
 	return retval;
 	return retval;
 }
 }

+ 6 - 28
drivers/tty/tty_buffer.c

@@ -37,29 +37,6 @@
 
 
 #define TTY_BUFFER_PAGE	(((PAGE_SIZE - sizeof(struct tty_buffer)) / 2) & ~0xFF)
 #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_lock_exclusive	-	gain exclusive access to buffer
  *	tty_buffer_unlock_exclusive	-	release exclusive access
  *	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)
 	if (ld && ld->ops->flush_buffer)
 		ld->ops->flush_buffer(tty);
 		ld->ops->flush_buffer(tty);
 
 
-	check_other_closed(tty);
-
 	atomic_dec(&buf->priority);
 	atomic_dec(&buf->priority);
 	mutex_unlock(&buf->lock);
 	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;
 		count = smp_load_acquire(&head->commit) - head->read;
 		if (!count) {
 		if (!count) {
-			if (next == NULL) {
-				check_other_closed(tty);
+			if (next == NULL)
 				break;
 				break;
-			}
 			buf->head = next;
 			buf->head = next;
 			tty_buffer_free(port, head);
 			tty_buffer_free(port, head);
 			continue;
 			continue;
@@ -614,3 +587,8 @@ bool tty_buffer_cancel_work(struct tty_port *port)
 {
 {
 	return cancel_work_sync(&port->buf.work);
 	return cancel_work_sync(&port->buf.work);
 }
 }
+
+void tty_buffer_flush_work(struct tty_port *port)
+{
+	flush_work(&port->buf.work);
+}

+ 2 - 7
drivers/tty/tty_io.c

@@ -230,9 +230,6 @@ static void tty_del_file(struct file *file)
 	tty_free_file(file);
 	tty_free_file(file);
 }
 }
 
 
-
-#define TTY_NUMBER(tty) ((tty)->index + (tty)->driver->name_base)
-
 /**
 /**
  *	tty_name	-	return tty naming
  *	tty_name	-	return tty naming
  *	@tty: tty structure
  *	@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"))
 	if (tty_paranoia_check(tty, inode, "tty_read"))
 		return -EIO;
 		return -EIO;
-	if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))
+	if (!tty || tty_io_error(tty))
 		return -EIO;
 		return -EIO;
 
 
 	/* We want to wait for the line discipline to sort out in this
 	/* 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"))
 	if (tty_paranoia_check(tty, file_inode(file), "tty_write"))
 		return -EIO;
 		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;
 			return -EIO;
 	/* Short term debug to catch buggy drivers */
 	/* Short term debug to catch buggy drivers */
 	if (tty->ops->write_room == NULL)
 	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
  *	tty_lookup_driver - lookup a tty driver for a given device file
  *	@device: device number
  *	@device: device number
  *	@filp: file pointer to tty
  *	@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
  *	@index: index for the device in the @return driver
  *	@return: driver for this inode (with increased refcount)
  *	@return: driver for this inode (with increased refcount)
  *
  *

+ 2 - 2
drivers/tty/tty_ioctl.c

@@ -158,7 +158,7 @@ int tty_throttle_safe(struct tty_struct *tty)
 	int ret = 0;
 	int ret = 0;
 
 
 	mutex_lock(&tty->throttle_mutex);
 	mutex_lock(&tty->throttle_mutex);
-	if (!test_bit(TTY_THROTTLED, &tty->flags)) {
+	if (!tty_throttled(tty)) {
 		if (tty->flow_change != TTY_THROTTLE_SAFE)
 		if (tty->flow_change != TTY_THROTTLE_SAFE)
 			ret = 1;
 			ret = 1;
 		else {
 		else {
@@ -189,7 +189,7 @@ int tty_unthrottle_safe(struct tty_struct *tty)
 	int ret = 0;
 	int ret = 0;
 
 
 	mutex_lock(&tty->throttle_mutex);
 	mutex_lock(&tty->throttle_mutex);
-	if (test_bit(TTY_THROTTLED, &tty->flags)) {
+	if (tty_throttled(tty)) {
 		if (tty->flow_change != TTY_UNTHROTTLE_SAFE)
 		if (tty->flow_change != TTY_UNTHROTTLE_SAFE)
 			ret = 1;
 			ret = 1;
 		else {
 		else {

+ 14 - 13
drivers/tty/tty_port.c

@@ -204,7 +204,8 @@ static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty)
 	if (port->console)
 	if (port->console)
 		goto out;
 		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
 		 * Drop DTR/RTS if HUPCL is set. This causes any attached
 		 * modem to hang up the line.
 		 * modem to hang up the line.
@@ -236,12 +237,12 @@ void tty_port_hangup(struct tty_port *port)
 
 
 	spin_lock_irqsave(&port->lock, flags);
 	spin_lock_irqsave(&port->lock, flags);
 	port->count = 0;
 	port->count = 0;
-	port->flags &= ~ASYNC_NORMAL_ACTIVE;
 	tty = port->tty;
 	tty = port->tty;
 	if (tty)
 	if (tty)
 		set_bit(TTY_IO_ERROR, &tty->flags);
 		set_bit(TTY_IO_ERROR, &tty->flags);
 	port->tty = NULL;
 	port->tty = NULL;
 	spin_unlock_irqrestore(&port->lock, flags);
 	spin_unlock_irqrestore(&port->lock, flags);
+	tty_port_set_active(port, 0);
 	tty_port_shutdown(port, tty);
 	tty_port_shutdown(port, tty);
 	tty_kref_put(tty);
 	tty_kref_put(tty);
 	wake_up_interruptible(&port->open_wait);
 	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
 	/* 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 */
 	   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;
 		return 0;
 	}
 	}
 	if (filp->f_flags & O_NONBLOCK) {
 	if (filp->f_flags & O_NONBLOCK) {
 		/* Indicate we are open */
 		/* Indicate we are open */
 		if (C_BAUD(tty))
 		if (C_BAUD(tty))
 			tty_port_raise_dtr_rts(port);
 			tty_port_raise_dtr_rts(port);
-		port->flags |= ASYNC_NORMAL_ACTIVE;
+		tty_port_set_active(port, 1);
 		return 0;
 		return 0;
 	}
 	}
 
 
@@ -393,13 +394,13 @@ int tty_port_block_til_ready(struct tty_port *port,
 
 
 	while (1) {
 	while (1) {
 		/* Indicate we are open */
 		/* 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);
 			tty_port_raise_dtr_rts(port);
 
 
 		prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
 		prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
 		/* Check for a hangup or uninitialised port.
 		/* Check for a hangup or uninitialised port.
 							Return accordingly */
 							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)
 			if (port->flags & ASYNC_HUP_NOTIFY)
 				retval = -EAGAIN;
 				retval = -EAGAIN;
 			else
 			else
@@ -430,9 +431,9 @@ int tty_port_block_til_ready(struct tty_port *port,
 	if (!tty_hung_up_p(filp))
 	if (!tty_hung_up_p(filp))
 		port->count++;
 		port->count++;
 	port->blocked_open--;
 	port->blocked_open--;
-	if (retval == 0)
-		port->flags |= ASYNC_NORMAL_ACTIVE;
 	spin_unlock_irqrestore(&port->lock, flags);
 	spin_unlock_irqrestore(&port->lock, flags);
+	if (retval == 0)
+		tty_port_set_active(port, 1);
 	return retval;
 	return retval;
 }
 }
 EXPORT_SYMBOL(tty_port_block_til_ready);
 EXPORT_SYMBOL(tty_port_block_til_ready);
@@ -480,7 +481,7 @@ int tty_port_close_start(struct tty_port *port,
 
 
 	tty->closing = 1;
 	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 */
 		/* Don't block on a stalled port, just pull the chain */
 		if (tty->flow_stopped)
 		if (tty->flow_stopped)
 			tty_driver_flush_buffer(tty);
 			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);
 		spin_lock_irqsave(&port->lock, flags);
 		wake_up_interruptible(&port->open_wait);
 		wake_up_interruptible(&port->open_wait);
 	}
 	}
-	port->flags &= ~ASYNC_NORMAL_ACTIVE;
 	spin_unlock_irqrestore(&port->lock, flags);
 	spin_unlock_irqrestore(&port->lock, flags);
+	tty_port_set_active(port, 0);
 }
 }
 EXPORT_SYMBOL(tty_port_close_end);
 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);
 	mutex_lock(&port->mutex);
 
 
-	if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) {
+	if (!tty_port_initialized(port)) {
 		clear_bit(TTY_IO_ERROR, &tty->flags);
 		clear_bit(TTY_IO_ERROR, &tty->flags);
 		if (port->ops->activate) {
 		if (port->ops->activate) {
 			int retval = port->ops->activate(port, tty);
 			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;
 				return retval;
 			}
 			}
 		}
 		}
-		set_bit(ASYNCB_INITIALIZED, &port->flags);
+		tty_port_set_initialized(port, 1);
 	}
 	}
 	mutex_unlock(&port->mutex);
 	mutex_unlock(&port->mutex);
 	return tty_port_block_til_ready(port, tty, filp);
 	return tty_port_block_til_ready(port, tty, filp);

+ 1 - 1
drivers/tty/vt/selection.c

@@ -354,7 +354,7 @@ int paste_selection(struct tty_struct *tty)
 	add_wait_queue(&vc->paste_wait, &wait);
 	add_wait_queue(&vc->paste_wait, &wait);
 	while (sel_buffer && sel_buffer_lth > pasted) {
 	while (sel_buffer && sel_buffer_lth > pasted) {
 		set_current_state(TASK_INTERRUPTIBLE);
 		set_current_state(TASK_INTERRUPTIBLE);
-		if (test_bit(TTY_THROTTLED, &tty->flags)) {
+		if (tty_throttled(tty)) {
 			schedule();
 			schedule();
 			continue;
 			continue;
 		}
 		}

+ 63 - 52
drivers/tty/vt/vt.c

@@ -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 */
 int vc_allocate(unsigned int currcons)	/* return 0 on success */
 {
 {
+	struct vt_notifier_param param;
+	struct vc_data *vc;
+
 	WARN_CONSOLE_UNLOCKED();
 	WARN_CONSOLE_UNLOCKED();
 
 
 	if (currcons >= MAX_NR_CONSOLES)
 	if (currcons >= MAX_NR_CONSOLES)
 		return -ENXIO;
 		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;
 		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);
 		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;
 	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,
 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 VT100ID "\033[?1;2c"
 #define VT102ID "\033[?6c"
 #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 };
 				       8,12,10,14, 9,13,11,15 };
 
 
 /* the default colour table, for VGA+ colour systems */
 /* 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
  * 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 module *owner = csw->owner;
 	struct con_driver *con_driver;
 	struct con_driver *con_driver;
 	const char *desc;
 	const char *desc;
-	int i, retval = 0;
+	int i, retval;
 
 
 	WARN_CONSOLE_UNLOCKED();
 	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];
 		con_driver = &registered_con_driver[i];
 
 
 		/* already registered */
 		/* already registered */
-		if (con_driver->con == csw)
+		if (con_driver->con == csw) {
 			retval = -EBUSY;
 			retval = -EBUSY;
+			goto err;
+		}
 	}
 	}
 
 
-	if (retval)
-		goto err;
-
 	desc = csw->con_startup();
 	desc = csw->con_startup();
-
-	if (!desc)
+	if (!desc) {
+		retval = -ENODEV;
 		goto err;
 		goto err;
+	}
 
 
 	retval = -EINVAL;
 	retval = -EINVAL;
 
 

+ 2 - 2
drivers/usb/class/cdc-acm.c

@@ -1680,7 +1680,7 @@ static int acm_resume(struct usb_interface *intf)
 	if (--acm->susp_count)
 	if (--acm->susp_count)
 		goto out;
 		goto out;
 
 
-	if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) {
+	if (tty_port_initialized(&acm->port)) {
 		rv = usb_submit_urb(acm->ctrlurb, GFP_ATOMIC);
 		rv = usb_submit_urb(acm->ctrlurb, GFP_ATOMIC);
 
 
 		for (;;) {
 		for (;;) {
@@ -1710,7 +1710,7 @@ static int acm_reset_resume(struct usb_interface *intf)
 {
 {
 	struct acm *acm = usb_get_intfdata(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);
 		tty_port_tty_hangup(&acm->port, false);
 
 
 	return acm_resume(intf);
 	return acm_resume(intf);

+ 2 - 2
drivers/usb/gadget/function/u_serial.c

@@ -512,7 +512,7 @@ static void gs_rx_push(unsigned long _port)
 		req = list_first_entry(queue, struct usb_request, list);
 		req = list_first_entry(queue, struct usb_request, list);
 
 
 		/* leave data queued if tty was rx throttled */
 		/* leave data queued if tty was rx throttled */
-		if (tty && test_bit(TTY_THROTTLED, &tty->flags))
+		if (tty && tty_throttled(tty))
 			break;
 			break;
 
 
 		switch (req->status) {
 		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.
 	 * from starving ... but it's not clear that case ever happens.
 	 */
 	 */
 	if (!list_empty(queue) && tty) {
 	if (!list_empty(queue) && tty) {
-		if (!test_bit(TTY_THROTTLED, &tty->flags)) {
+		if (!tty_throttled(tty)) {
 			if (do_push)
 			if (do_push)
 				tasklet_schedule(&port->push);
 				tasklet_schedule(&port->push);
 			else
 			else

+ 1 - 1
drivers/usb/misc/sisusbvga/sisusb_con.c

@@ -601,7 +601,7 @@ sisusbcon_save_screen(struct vc_data *c)
 
 
 /* interface routine */
 /* interface routine */
 static int
 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;
 	struct sisusb_usb_data *sisusb;
 	int i, j;
 	int i, j;

+ 2 - 2
drivers/usb/serial/console.c

@@ -127,7 +127,7 @@ static int usb_console_setup(struct console *co, char *options)
 	info->port = port;
 	info->port = port;
 
 
 	++port->port.count;
 	++port->port.count;
-	if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) {
+	if (!tty_port_initialized(&port->port)) {
 		if (serial->type->set_termios) {
 		if (serial->type->set_termios) {
 			/*
 			/*
 			 * allocate a fake tty so the driver can initialize
 			 * 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_port_tty_set(&port->port, NULL);
 			tty_kref_put(tty);
 			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
 	/* Now that any required fake tty operations are completed restore
 	 * the tty port count */
 	 * the tty port count */

+ 1 - 2
drivers/usb/serial/digi_acceleport.c

@@ -699,8 +699,7 @@ static void digi_set_termios(struct tty_struct *tty,
 			/* don't set RTS if using hardware flow control */
 			/* don't set RTS if using hardware flow control */
 			/* and throttling input */
 			/* and throttling input */
 			modem_signals = TIOCM_DTR;
 			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;
 				modem_signals |= TIOCM_RTS;
 			digi_set_modem_signals(port, modem_signals, 1);
 			digi_set_modem_signals(port, modem_signals, 1);
 		}
 		}

+ 3 - 3
drivers/usb/serial/generic.c

@@ -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
 	 * Use tty-port initialised flag to detect all hangups including the
 	 * one generated at USB-device disconnect.
 	 * one generated at USB-device disconnect.
 	 */
 	 */
-	if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
+	if (!tty_port_initialized(&port->port))
 		return true;
 		return true;
 
 
 	spin_lock_irqsave(&port->lock, flags);
 	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,
 	ret = wait_event_interruptible(port->port.delta_msr_wait,
 			usb_serial_generic_msr_changed(tty, arg, &cnow));
 			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;
 		ret = -EIO;
 
 
 	return ret;
 	return ret;
@@ -606,7 +606,7 @@ int usb_serial_generic_resume(struct usb_serial *serial)
 
 
 	for (i = 0; i < serial->num_ports; i++) {
 	for (i = 0; i < serial->num_ports; i++) {
 		port = serial->port[i];
 		port = serial->port[i];
-		if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
+		if (!tty_port_initialized(&port->port))
 			continue;
 			continue;
 
 
 		if (port->bulk_in_size) {
 		if (port->bulk_in_size) {

+ 3 - 3
drivers/usb/serial/mxuport.c

@@ -503,7 +503,7 @@ static void mxuport_process_read_urb_demux_data(struct urb *urb)
 			return;
 			return;
 		}
 		}
 
 
-		if (test_bit(ASYNCB_INITIALIZED, &demux_port->port.flags)) {
+		if (tty_port_initialized(&demux_port->port)) {
 			ch = data + HEADER_SIZE;
 			ch = data + HEADER_SIZE;
 			mxuport_process_read_urb_data(demux_port, ch, rcv_len);
 			mxuport_process_read_urb_data(demux_port, ch, rcv_len);
 		} else {
 		} else {
@@ -544,7 +544,7 @@ static void mxuport_process_read_urb_demux_event(struct urb *urb)
 		}
 		}
 
 
 		demux_port = serial->port[rcv_port];
 		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;
 			ch = data + HEADER_SIZE;
 			rcv_event = get_unaligned_be16(data + 2);
 			rcv_event = get_unaligned_be16(data + 2);
 			mxuport_process_read_urb_event(demux_port, ch,
 			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++) {
 	for (i = 0; i < serial->num_ports; i++) {
 		port = serial->port[i];
 		port = serial->port[i];
-		if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
+		if (!tty_port_initialized(&port->port))
 			continue;
 			continue;
 
 
 		r = usb_serial_generic_write_start(port, GFP_NOIO);
 		r = usb_serial_generic_write_start(port, GFP_NOIO);

+ 2 - 2
drivers/usb/serial/sierra.c

@@ -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
 	 * 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);
 	spin_lock_irq(&intfdata->susp_lock);
 	if (--intfdata->open_ports == 0)
 	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++) {
 	for (i = 0; i < serial->num_ports; i++) {
 		port = serial->port[i];
 		port = serial->port[i];
 
 
-		if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
+		if (!tty_port_initialized(&port->port))
 			continue;
 			continue;
 
 
 		err = sierra_submit_delayed_urbs(port);
 		err = sierra_submit_delayed_urbs(port);

+ 1 - 1
drivers/usb/serial/usb-serial.c

@@ -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
  * Shut down a USB serial port. Serialized against activate by the
  * tport mutex and kept to matching open/close pairs
  * 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.
  * Not called if tty is console.
  */
  */

+ 2 - 2
drivers/usb/serial/usb_wwan.c

@@ -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
 	 * 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);
 	spin_lock_irq(&intfdata->susp_lock);
 	if (--intfdata->open_ports == 0)
 	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++) {
 	for (i = 0; i < serial->num_ports; i++) {
 		port = serial->port[i];
 		port = serial->port[i];
 
 
-		if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
+		if (!tty_port_initialized(&port->port))
 			continue;
 			continue;
 
 
 		portdata = usb_get_serial_port_data(port);
 		portdata = usb_get_serial_port_data(port);

+ 2 - 2
drivers/video/console/fbcon.c

@@ -170,7 +170,7 @@ static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx,
 			int height, int width);
 			int height, int width);
 static int fbcon_switch(struct vc_data *vc);
 static int fbcon_switch(struct vc_data *vc);
 static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch);
 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);
 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
 	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]];
 	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
 	int i, j, k, depth;
 	int i, j, k, depth;

+ 1 - 1
drivers/video/console/mdacon.c

@@ -481,7 +481,7 @@ static int mdacon_switch(struct vc_data *c)
 	return 1;	/* redrawing needed */
 	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;
 	return -EINVAL;
 }
 }

+ 1 - 1
drivers/video/console/newport_con.c

@@ -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);
 	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;
 	return -EINVAL;
 }
 }

+ 1 - 1
drivers/video/console/sticon.c

@@ -79,7 +79,7 @@ static const char *sticon_startup(void)
     return "STI console";
     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;
     return -EINVAL;
 }
 }

+ 2 - 3
drivers/video/console/vgacon.c

@@ -80,7 +80,6 @@ static void vgacon_deinit(struct vc_data *c);
 static void vgacon_cursor(struct vc_data *c, int mode);
 static void vgacon_cursor(struct vc_data *c, int mode);
 static int vgacon_switch(struct vc_data *c);
 static int vgacon_switch(struct vc_data *c);
 static int vgacon_blank(struct vc_data *c, int blank, int mode_switch);
 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_scrolldelta(struct vc_data *c, int lines);
 static int vgacon_set_origin(struct vc_data *c);
 static int vgacon_set_origin(struct vc_data *c);
 static void vgacon_save_screen(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 */
 	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;
 	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
 #ifdef CAN_LOAD_PALETTE
 	if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked
 	if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked

+ 1 - 1
include/linux/console.h

@@ -47,7 +47,7 @@ struct consw {
 	int	(*con_font_copy)(struct vc_data *, int);
 	int	(*con_font_copy)(struct vc_data *, int);
 	int     (*con_resize)(struct vc_data *, unsigned int, unsigned int,
 	int     (*con_resize)(struct vc_data *, unsigned int, 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_scrolldelta)(struct vc_data *, int);
 	int	(*con_set_origin)(struct vc_data *);
 	int	(*con_set_origin)(struct vc_data *);
 	void	(*con_save_screen)(struct vc_data *);
 	void	(*con_save_screen)(struct vc_data *);

+ 4 - 4
include/linux/selection.h

@@ -24,10 +24,10 @@ extern void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry);
 
 
 extern int console_blanked;
 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 unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed);
 extern u16 screen_glyph(struct vc_data *vc, int offset);
 extern u16 screen_glyph(struct vc_data *vc, int offset);

+ 2 - 0
include/linux/serial_8250.h

@@ -36,6 +36,7 @@ struct plat_serial8250_port {
 	void		(*set_termios)(struct uart_port *,
 	void		(*set_termios)(struct uart_port *,
 			               struct ktermios *new,
 			               struct ktermios *new,
 			               struct ktermios *old);
 			               struct ktermios *old);
+	unsigned int	(*get_mctrl)(struct uart_port *);
 	int		(*handle_irq)(struct uart_port *);
 	int		(*handle_irq)(struct uart_port *);
 	void		(*pm)(struct uart_port *, unsigned int state,
 	void		(*pm)(struct uart_port *, unsigned int state,
 			      unsigned old);
 			      unsigned old);
@@ -148,6 +149,7 @@ extern int early_serial8250_setup(struct earlycon_device *device,
 					 const char *options);
 					 const char *options);
 extern void serial8250_do_set_termios(struct uart_port *port,
 extern void serial8250_do_set_termios(struct uart_port *port,
 		struct ktermios *termios, struct ktermios *old);
 		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 int serial8250_do_startup(struct uart_port *port);
 extern void serial8250_do_shutdown(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,
 extern void serial8250_do_pm(struct uart_port *port, unsigned int state,

+ 3 - 0
include/linux/serial_core.h

@@ -123,6 +123,7 @@ struct uart_port {
 	void			(*set_termios)(struct uart_port *,
 	void			(*set_termios)(struct uart_port *,
 				               struct ktermios *new,
 				               struct ktermios *new,
 				               struct ktermios *old);
 				               struct ktermios *old);
+	unsigned int		(*get_mctrl)(struct uart_port *);
 	void			(*set_mctrl)(struct uart_port *, unsigned int);
 	void			(*set_mctrl)(struct uart_port *, unsigned int);
 	int			(*startup)(struct uart_port *port);
 	int			(*startup)(struct uart_port *port);
 	void			(*shutdown)(struct uart_port *port);
 	void			(*shutdown)(struct uart_port *port);
@@ -281,6 +282,8 @@ struct uart_state {
 	enum uart_pm_state	pm_state;
 	enum uart_pm_state	pm_state;
 	struct circ_buf		xmit;
 	struct circ_buf		xmit;
 
 
+	atomic_t		refcount;
+	wait_queue_head_t	remove_wait;
 	struct uart_port	*uart_port;
 	struct uart_port	*uart_port;
 };
 };
 
 

+ 86 - 3
include/linux/tty.h

@@ -228,7 +228,8 @@ struct tty_port {
 	int			count;		/* Usage count */
 	int			count;		/* Usage count */
 	wait_queue_head_t	open_wait;	/* Open waiters */
 	wait_queue_head_t	open_wait;	/* Open waiters */
 	wait_queue_head_t	delta_msr_wait;	/* Modem status change */
 	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 */
 	unsigned char		console:1,	/* port is a console */
 				low_latency:1;	/* optional: tune for latency */
 				low_latency:1;	/* optional: tune for latency */
 	struct mutex		mutex;		/* Locking */
 	struct mutex		mutex;		/* Locking */
@@ -242,6 +243,18 @@ struct tty_port {
 	struct kref		kref;		/* Ref counter */
 	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
  * 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
  * 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_OTHER_CLOSED 	2	/* Other side (if any) has closed */
 #define TTY_EXCLUSIVE 		3	/* Exclusive open mode */
 #define TTY_EXCLUSIVE 		3	/* Exclusive open mode */
 #define TTY_DO_WRITE_WAKEUP 	5	/* Call write_wakeup after queuing new */
 #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_LDISC_OPEN	 	11	/* Line discipline is open */
 #define TTY_PTY_LOCK 		16	/* pty private */
 #define TTY_PTY_LOCK 		16	/* pty private */
 #define TTY_NO_WRITE_SPLIT 	17	/* Preserve write boundaries to driver */
 #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();
 	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
 #ifdef CONFIG_TTY
 extern void console_init(void);
 extern void console_init(void);
 extern void tty_kref_put(struct tty_struct *tty);
 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 void tty_buffer_set_lock_subclass(struct tty_port *port);
 extern bool tty_buffer_restart_work(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 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_baud_rate(struct ktermios *termios);
 extern speed_t tty_termios_input_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,
 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. */
 /* If the cts flow control is enabled, return true. */
 static inline bool tty_port_cts_enabled(struct tty_port *port)
 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);
 extern struct tty_struct *tty_port_tty_get(struct tty_port *port);

+ 3 - 0
include/uapi/linux/serial_core.h

@@ -267,4 +267,7 @@
 /* Microchip PIC32 UART */
 /* Microchip PIC32 UART */
 #define PORT_PIC32	115
 #define PORT_PIC32	115
 
 
+/* MPS2 UART */
+#define PORT_MPS2UART	116
+
 #endif /* _UAPILINUX_SERIAL_CORE_H */
 #endif /* _UAPILINUX_SERIAL_CORE_H */

+ 12 - 1
include/uapi/linux/tty_flags.h

@@ -32,7 +32,13 @@
 #define ASYNCB_MAGIC_MULTIPLIER	16 /* Use special CLK or divisor */
 #define ASYNCB_MAGIC_MULTIPLIER	16 /* Use special CLK or divisor */
 #define ASYNCB_LAST_USER	16
 #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_INITIALIZED	31 /* Serial port was initialized */
 #define ASYNCB_SUSPENDED	30 /* Serial port is suspended */
 #define ASYNCB_SUSPENDED	30 /* Serial port is suspended */
 #define ASYNCB_NORMAL_ACTIVE	29 /* Normal device is active */
 #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_SHARE_IRQ	24 /* for multifunction cards, no longer used */
 #define ASYNCB_CONS_FLOW	23 /* flow control for console  */
 #define ASYNCB_CONS_FLOW	23 /* flow control for console  */
 #define ASYNCB_FIRST_KERNEL	22
 #define ASYNCB_FIRST_KERNEL	22
+#endif
 
 
+/* Masks */
 #define ASYNC_HUP_NOTIFY	(1U << ASYNCB_HUP_NOTIFY)
 #define ASYNC_HUP_NOTIFY	(1U << ASYNCB_HUP_NOTIFY)
 #define ASYNC_SUSPENDED		(1U << ASYNCB_SUSPENDED)
 #define ASYNC_SUSPENDED		(1U << ASYNCB_SUSPENDED)
 #define ASYNC_FOURPORT		(1U << ASYNCB_FOURPORT)
 #define ASYNC_FOURPORT		(1U << ASYNCB_FOURPORT)
@@ -72,6 +80,8 @@
 #define ASYNC_SPD_WARP		(ASYNC_SPD_HI|ASYNC_SPD_SHI)
 #define ASYNC_SPD_WARP		(ASYNC_SPD_HI|ASYNC_SPD_SHI)
 #define ASYNC_SPD_MASK		(ASYNC_SPD_HI|ASYNC_SPD_VHI|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_INITIALIZED	(1U << ASYNCB_INITIALIZED)
 #define ASYNC_NORMAL_ACTIVE	(1U << ASYNCB_NORMAL_ACTIVE)
 #define ASYNC_NORMAL_ACTIVE	(1U << ASYNCB_NORMAL_ACTIVE)
 #define ASYNC_BOOT_AUTOCONF	(1U << ASYNCB_BOOT_AUTOCONF)
 #define ASYNC_BOOT_AUTOCONF	(1U << ASYNCB_BOOT_AUTOCONF)
@@ -81,5 +91,6 @@
 #define ASYNC_SHARE_IRQ		(1U << ASYNCB_SHARE_IRQ)
 #define ASYNC_SHARE_IRQ		(1U << ASYNCB_SHARE_IRQ)
 #define ASYNC_CONS_FLOW		(1U << ASYNCB_CONS_FLOW)
 #define ASYNC_CONS_FLOW		(1U << ASYNCB_CONS_FLOW)
 #define ASYNC_INTERNAL_FLAGS	(~((1U << ASYNCB_FIRST_KERNEL) - 1))
 #define ASYNC_INTERNAL_FLAGS	(~((1U << ASYNCB_FIRST_KERNEL) - 1))
+#endif
 
 
 #endif
 #endif

部分文件因为文件数量过多而无法显示