summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/serial/cirrus,clps711x-uart.txt7
-rw-r--r--Documentation/devicetree/bindings/serial/mtk-uart.txt22
-rw-r--r--Documentation/devicetree/bindings/serial/of-serial.txt2
-rw-r--r--Documentation/devicetree/bindings/serial/via,vt8500-uart.txt17
-rw-r--r--Documentation/devicetree/bindings/serial/vt8500-uart.txt3
-rw-r--r--Documentation/kernel-parameters.txt18
-rw-r--r--Documentation/serial/driver2
-rw-r--r--arch/alpha/include/uapi/asm/ioctls.h2
-rw-r--r--arch/mips/include/uapi/asm/ioctls.h2
-rw-r--r--arch/parisc/include/uapi/asm/ioctls.h2
-rw-r--r--arch/sh/include/uapi/asm/ioctls.h2
-rw-r--r--arch/sparc/include/uapi/asm/ioctls.h2
-rw-r--r--arch/xtensa/include/uapi/asm/ioctls.h2
-rw-r--r--drivers/isdn/i4l/isdn_tty.c5
-rw-r--r--drivers/staging/dgnc/dgnc_driver.c13
-rw-r--r--drivers/tty/hvc/hvc_xen.c3
-rw-r--r--drivers/tty/metag_da.c14
-rw-r--r--drivers/tty/moxa.c2
-rw-r--r--drivers/tty/n_tty.c8
-rw-r--r--drivers/tty/nozomi.c6
-rw-r--r--drivers/tty/pty.c41
-rw-r--r--drivers/tty/serial/8250/8250.h3
-rw-r--r--drivers/tty/serial/8250/8250_core.c253
-rw-r--r--drivers/tty/serial/8250/8250_fintek.c249
-rw-r--r--drivers/tty/serial/8250/8250_hp300.c2
-rw-r--r--drivers/tty/serial/8250/8250_mtk.c294
-rw-r--r--drivers/tty/serial/8250/8250_pci.c34
-rw-r--r--drivers/tty/serial/8250/Kconfig15
-rw-r--r--drivers/tty/serial/8250/Makefile2
-rw-r--r--drivers/tty/serial/Kconfig23
-rw-r--r--drivers/tty/serial/Makefile1
-rw-r--r--drivers/tty/serial/altera_jtaguart.c2
-rw-r--r--drivers/tty/serial/altera_uart.c2
-rw-r--r--drivers/tty/serial/amba-pl011.c54
-rw-r--r--drivers/tty/serial/bfin_sport_uart.c1
-rw-r--r--drivers/tty/serial/bfin_uart.c15
-rw-r--r--drivers/tty/serial/clps711x.c32
-rw-r--r--drivers/tty/serial/imx.c99
-rw-r--r--drivers/tty/serial/jsm/jsm.h10
-rw-r--r--drivers/tty/serial/jsm/jsm_driver.c38
-rw-r--r--drivers/tty/serial/kgdb_nmi.c5
-rw-r--r--drivers/tty/serial/meson_uart.c634
-rw-r--r--drivers/tty/serial/mpc52xx_uart.c17
-rw-r--r--drivers/tty/serial/msm_serial.c122
-rw-r--r--drivers/tty/serial/mxs-auart.c2
-rw-r--r--drivers/tty/serial/nwpserial.c1
-rw-r--r--drivers/tty/serial/of_serial.c31
-rw-r--r--drivers/tty/serial/omap-serial.c34
-rw-r--r--drivers/tty/serial/serial_core.c135
-rw-r--r--drivers/tty/serial/serial_mctrl_gpio.c2
-rw-r--r--drivers/tty/serial/st-asc.c8
-rw-r--r--drivers/tty/serial/sunhv.c3
-rw-r--r--drivers/tty/serial/sunsab.c5
-rw-r--r--drivers/tty/serial/uartlite.c1
-rw-r--r--drivers/tty/serial/vr41xx_siu.c1
-rw-r--r--drivers/tty/serial/vt8500_serial.c136
-rw-r--r--drivers/tty/serial/xilinx_uartps.c20
-rw-r--r--drivers/tty/tty_io.c96
-rw-r--r--drivers/tty/tty_ioctl.c49
-rw-r--r--drivers/tty/vt/keyboard.c166
-rw-r--r--drivers/usb/serial/digi_acceleport.c7
-rw-r--r--drivers/usb/serial/io_ti.c7
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c7
-rw-r--r--include/linux/lockdep.h5
-rw-r--r--include/linux/serial_8250.h6
-rw-r--r--include/linux/serial_core.h20
-rw-r--r--include/linux/tty.h15
-rw-r--r--include/linux/tty_driver.h4
-rw-r--r--include/uapi/linux/serial_core.h3
69 files changed, 2296 insertions, 550 deletions
diff --git a/Documentation/devicetree/bindings/serial/cirrus,clps711x-uart.txt b/Documentation/devicetree/bindings/serial/cirrus,clps711x-uart.txt
index 12f3cf834deb..caaeb2583579 100644
--- a/Documentation/devicetree/bindings/serial/cirrus,clps711x-uart.txt
+++ b/Documentation/devicetree/bindings/serial/cirrus,clps711x-uart.txt
@@ -8,7 +8,8 @@ Required properties:
- syscon: Phandle to SYSCON node, which contain UART control bits.
Optional properties:
-- uart-use-ms: Indicate the UART has modem signal (DCD, DSR, CTS).
+- {rts,cts,dtr,dsr,rng,dcd}-gpios: specify a GPIO for RTS/CTS/DTR/DSR/RI/DCD
+ line respectively.
Note: Each UART port should have an alias correctly numbered
in "aliases" node.
@@ -24,5 +25,7 @@ Example:
interrupts = <12 13>;
clocks = <&clks 11>;
syscon = <&syscon1>;
- uart-use-ms;
+ cts-gpios = <&sysgpio 0 GPIO_ACTIVE_LOW>;
+ dsr-gpios = <&sysgpio 1 GPIO_ACTIVE_LOW>;
+ dcd-gpios = <&sysgpio 2 GPIO_ACTIVE_LOW>;
};
diff --git a/Documentation/devicetree/bindings/serial/mtk-uart.txt b/Documentation/devicetree/bindings/serial/mtk-uart.txt
new file mode 100644
index 000000000000..48358a33ea7d
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/mtk-uart.txt
@@ -0,0 +1,22 @@
+* Mediatek Universal Asynchronous Receiver/Transmitter (UART)
+
+Required properties:
+- compatible should contain:
+ * "mediatek,mt6589-uart" for MT6589 compatible UARTS
+ * "mediatek,mt6582-uart" for MT6582 compatible UARTS
+ * "mediatek,mt6577-uart" for all compatible UARTS (MT6589, MT6582, MT6577)
+
+- reg: The base address of the UART register bank.
+
+- interrupts: A single interrupt specifier.
+
+- clocks: Clock driving the hardware.
+
+Example:
+
+ uart0: serial@11006000 {
+ compatible = "mediatek,mt6589-uart", "mediatek,mt6577-uart";
+ reg = <0x11006000 0x400>;
+ interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&uart_clk>;
+ };
diff --git a/Documentation/devicetree/bindings/serial/of-serial.txt b/Documentation/devicetree/bindings/serial/of-serial.txt
index 77054772a8f4..8c4fd0332028 100644
--- a/Documentation/devicetree/bindings/serial/of-serial.txt
+++ b/Documentation/devicetree/bindings/serial/of-serial.txt
@@ -14,6 +14,7 @@ Required properties:
- "altr,16550-FIFO32"
- "altr,16550-FIFO64"
- "altr,16550-FIFO128"
+ - "fsl,16550-FIFO64"
- "serial" if the port type is unknown.
- reg : offset and length of the register set for the device.
- interrupts : should contain uart interrupt.
@@ -37,7 +38,6 @@ Optional properties:
- auto-flow-control: one way to enable automatic flow control support. The
driver is allowed to detect support for the capability even without this
property.
-- has-hw-flow-control: the hardware has flow control capability.
Example:
diff --git a/Documentation/devicetree/bindings/serial/via,vt8500-uart.txt b/Documentation/devicetree/bindings/serial/via,vt8500-uart.txt
deleted file mode 100644
index 5feef1ef167d..000000000000
--- a/Documentation/devicetree/bindings/serial/via,vt8500-uart.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-VIA/Wondermedia VT8500 UART Controller
------------------------------------------------------
-
-Required properties:
-- compatible : "via,vt8500-uart"
-- reg : Should contain 1 register ranges(address and length)
-- interrupts : UART interrupt
-- clocks : phandle to the uart source clock (usually a 24Mhz fixed clock)
-
-Example:
-
- uart@d8210000 {
- compatible = "via,vt8500-uart";
- reg = <0xd8210000 0x1040>;
- interrupts = <47>;
- clocks = <&ref24>;
- };
diff --git a/Documentation/devicetree/bindings/serial/vt8500-uart.txt b/Documentation/devicetree/bindings/serial/vt8500-uart.txt
index 795c393d09c4..2b64e6107fb3 100644
--- a/Documentation/devicetree/bindings/serial/vt8500-uart.txt
+++ b/Documentation/devicetree/bindings/serial/vt8500-uart.txt
@@ -1,7 +1,8 @@
* VIA VT8500 and WonderMedia WM8xxx UART Controller
Required properties:
-- compatible: should be "via,vt8500-uart"
+- compatible: should be "via,vt8500-uart" (for VIA/WonderMedia chips up to and
+ including WM8850/WM8950), or "wm,wm8880-uart" (for WM8880 and later)
- reg: base physical address of the controller and length of memory mapped
region.
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 1edd5fdc629d..d9a452e8fb9b 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -921,6 +921,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
earlycon= [KNL] Output early console device and options.
+ cdns,<addr>
+ Start an early, polled-mode console on a cadence serial
+ port at the specified address. The cadence serial port
+ must already be setup and configured. Options are not
+ yet supported.
+
uart[8250],io,<addr>[,options]
uart[8250],mmio,<addr>[,options]
uart[8250],mmio32,<addr>[,options]
@@ -936,6 +942,18 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
must already be setup and configured. Options are not
yet supported.
+ msm_serial,<addr>
+ Start an early, polled-mode console on an msm serial
+ port at the specified address. The serial port
+ must already be setup and configured. Options are not
+ yet supported.
+
+ msm_serial_dm,<addr>
+ Start an early, polled-mode console on an msm serial
+ dm port at the specified address. The serial port
+ must already be setup and configured. Options are not
+ yet supported.
+
smh Use ARM semihosting calls for early console.
earlyprintk= [X86,SH,BLACKFIN,ARM,M68k]
diff --git a/Documentation/serial/driver b/Documentation/serial/driver
index 3bba1aeb799c..ba64e4b892e9 100644
--- a/Documentation/serial/driver
+++ b/Documentation/serial/driver
@@ -140,6 +140,8 @@ hardware.
will append the character to the circular buffer and then call
start_tx() / stop_tx() to flush the data out.
+ Do not transmit if ch == '\0' (__DISABLED_CHAR).
+
Locking: none.
Interrupts: caller dependent.
diff --git a/arch/alpha/include/uapi/asm/ioctls.h b/arch/alpha/include/uapi/asm/ioctls.h
index 92c557be49fc..f30c94ae1bdb 100644
--- a/arch/alpha/include/uapi/asm/ioctls.h
+++ b/arch/alpha/include/uapi/asm/ioctls.h
@@ -90,6 +90,8 @@
#define TIOCSBRK 0x5427 /* BSD compatibility */
#define TIOCCBRK 0x5428 /* BSD compatibility */
#define TIOCGSID 0x5429 /* Return the session ID of FD */
+#define TIOCGRS485 _IOR('T', 0x2E, struct serial_rs485)
+#define TIOCSRS485 _IOWR('T', 0x2F, struct serial_rs485)
#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */
#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get primary device node of /dev/console */
diff --git a/arch/mips/include/uapi/asm/ioctls.h b/arch/mips/include/uapi/asm/ioctls.h
index b1e637757fe3..740219c2c894 100644
--- a/arch/mips/include/uapi/asm/ioctls.h
+++ b/arch/mips/include/uapi/asm/ioctls.h
@@ -81,6 +81,8 @@
#define TCSETS2 _IOW('T', 0x2B, struct termios2)
#define TCSETSW2 _IOW('T', 0x2C, struct termios2)
#define TCSETSF2 _IOW('T', 0x2D, struct termios2)
+#define TIOCGRS485 _IOR('T', 0x2E, struct serial_rs485)
+#define TIOCSRS485 _IOWR('T', 0x2F, struct serial_rs485)
#define TIOCGPTN _IOR('T', 0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
#define TIOCSPTLCK _IOW('T', 0x31, int) /* Lock/unlock Pty */
#define TIOCGDEV _IOR('T', 0x32, unsigned int) /* Get primary device node of /dev/console */
diff --git a/arch/parisc/include/uapi/asm/ioctls.h b/arch/parisc/include/uapi/asm/ioctls.h
index 66719c38a36b..b6572f051b67 100644
--- a/arch/parisc/include/uapi/asm/ioctls.h
+++ b/arch/parisc/include/uapi/asm/ioctls.h
@@ -50,6 +50,8 @@
#define TCSETS2 _IOW('T',0x2B, struct termios2)
#define TCSETSW2 _IOW('T',0x2C, struct termios2)
#define TCSETSF2 _IOW('T',0x2D, struct termios2)
+#define TIOCGRS485 _IOR('T', 0x2E, struct serial_rs485)
+#define TIOCSRS485 _IOWR('T', 0x2F, struct serial_rs485)
#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */
#define TIOCGDEV _IOR('T',0x32, int) /* Get primary device node of /dev/console */
diff --git a/arch/sh/include/uapi/asm/ioctls.h b/arch/sh/include/uapi/asm/ioctls.h
index 342241079760..c9903e56ccf4 100644
--- a/arch/sh/include/uapi/asm/ioctls.h
+++ b/arch/sh/include/uapi/asm/ioctls.h
@@ -83,6 +83,8 @@
#define TCSETS2 _IOW('T', 43, struct termios2)
#define TCSETSW2 _IOW('T', 44, struct termios2)
#define TCSETSF2 _IOW('T', 45, struct termios2)
+#define TIOCGRS485 _IOR('T', 46, struct serial_rs485)
+#define TIOCSRS485 _IOWR('T', 47, struct serial_rs485)
#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */
#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get primary device node of /dev/console */
diff --git a/arch/sparc/include/uapi/asm/ioctls.h b/arch/sparc/include/uapi/asm/ioctls.h
index 897d1723fa14..06b3f6c3bb9a 100644
--- a/arch/sparc/include/uapi/asm/ioctls.h
+++ b/arch/sparc/include/uapi/asm/ioctls.h
@@ -24,6 +24,8 @@
#define TIOCGPKT _IOR('T', 0x38, int) /* Get packet mode state */
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
+#define TIOCGRS485 _IOR('T', 0x41, struct serial_rs485)
+#define TIOCSRS485 _IOWR('T', 0x42, struct serial_rs485)
/* Note that all the ioctls that are not available in Linux have a
* double underscore on the front to: a) avoid some programs to
diff --git a/arch/xtensa/include/uapi/asm/ioctls.h b/arch/xtensa/include/uapi/asm/ioctls.h
index a47909f0c34b..518954e74e6d 100644
--- a/arch/xtensa/include/uapi/asm/ioctls.h
+++ b/arch/xtensa/include/uapi/asm/ioctls.h
@@ -95,6 +95,8 @@
#define TCSETS2 _IOW('T', 43, struct termios2)
#define TCSETSW2 _IOW('T', 44, struct termios2)
#define TCSETSF2 _IOW('T', 45, struct termios2)
+#define TIOCGRS485 _IOR('T', 46, struct serial_rs485)
+#define TIOCSRS485 _IOWR('T', 47, struct serial_rs485)
#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */
#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get primary device node of /dev/console */
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index 3c5f2491a16f..bc912611fe09 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -1043,11 +1043,6 @@ isdn_tty_change_speed(modem_info *info)
if (!(cflag & PARODD))
cval |= UART_LCR_EPAR;
- /* CTS flow control flag and modem status interrupts */
- if (cflag & CRTSCTS) {
- port->flags |= ASYNC_CTS_FLOW;
- } else
- port->flags &= ~ASYNC_CTS_FLOW;
if (cflag & CLOCAL)
port->flags &= ~ASYNC_CHECK_CD;
else {
diff --git a/drivers/staging/dgnc/dgnc_driver.c b/drivers/staging/dgnc/dgnc_driver.c
index 29cc2e4ba935..21546659ff07 100644
--- a/drivers/staging/dgnc/dgnc_driver.c
+++ b/drivers/staging/dgnc/dgnc_driver.c
@@ -112,19 +112,6 @@ static struct pci_device_id dgnc_pci_tbl[] = {
{ DIGI_VID, PCI_DEVICE_CLASSIC_4_422_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
{ DIGI_VID, PCI_DEVICE_CLASSIC_8_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
{ DIGI_VID, PCI_DEVICE_CLASSIC_8_422_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 },
- { DIGI_VID, PCI_DEVICE_NEO_4_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
- { DIGI_VID, PCI_DEVICE_NEO_8_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 },
- { DIGI_VID, PCI_DEVICE_NEO_2DB9_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 },
- { DIGI_VID, PCI_DEVICE_NEO_2DB9PRI_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7 },
- { DIGI_VID, PCI_DEVICE_NEO_2RJ45_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
- { DIGI_VID, PCI_DEVICE_NEO_2RJ45PRI_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9 },
- { DIGI_VID, PCI_DEVICE_NEO_1_422_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10 },
- { DIGI_VID, PCI_DEVICE_NEO_1_422_485_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11 },
- { DIGI_VID, PCI_DEVICE_NEO_2_422_485_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12 },
- { DIGI_VID, PCI_DEVICE_NEO_EXPRESS_8_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13 },
- { DIGI_VID, PCI_DEVICE_NEO_EXPRESS_4_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 },
- { DIGI_VID, PCI_DEVICE_NEO_EXPRESS_4RJ45_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15 },
- { DIGI_VID, PCI_DEVICE_NEO_EXPRESS_8RJ45_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16 },
{0,} /* 0 terminated list. */
};
MODULE_DEVICE_TABLE(pci, dgnc_pci_tbl);
diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c
index 2dc2831840ca..2967f0388d2c 100644
--- a/drivers/tty/hvc/hvc_xen.c
+++ b/drivers/tty/hvc/hvc_xen.c
@@ -402,9 +402,6 @@ static int xencons_connect_backend(struct xenbus_device *dev,
evtchn);
if (ret)
goto error_xenbus;
- ret = xenbus_printf(xbt, dev->nodename, "type", "ioemu");
- if (ret)
- goto error_xenbus;
ret = xenbus_transaction_end(xbt, 0);
if (ret) {
if (ret == -EAGAIN)
diff --git a/drivers/tty/metag_da.c b/drivers/tty/metag_da.c
index 7332e2ca4615..3774600741d8 100644
--- a/drivers/tty/metag_da.c
+++ b/drivers/tty/metag_da.c
@@ -17,6 +17,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
+#include <linux/moduleparam.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/serial.h>
@@ -70,6 +71,15 @@ static struct tty_driver *channel_driver;
static struct timer_list put_timer;
static struct task_struct *dashtty_thread;
+/*
+ * The console_poll parameter determines whether the console channel should be
+ * polled for input.
+ * By default the console channel isn't polled at all, in order to avoid the
+ * overhead, but that means it isn't possible to have a login on /dev/console.
+ */
+static bool console_poll;
+module_param(console_poll, bool, S_IRUGO);
+
#define RX_BUF_SIZE 1024
enum {
@@ -353,7 +363,7 @@ static int dashtty_port_activate(struct tty_port *port, struct tty_struct *tty)
* possible to have a login on /dev/console.
*
*/
- if (dport != &dashtty_ports[CONSOLE_CHANNEL])
+ if (console_poll || dport != &dashtty_ports[CONSOLE_CHANNEL])
if (atomic_inc_return(&num_channels_need_poll) == 1)
add_poll_timer(&poll_timer);
@@ -372,7 +382,7 @@ static void dashtty_port_shutdown(struct tty_port *port)
unsigned int count;
/* stop reading */
- if (dport != &dashtty_ports[CONSOLE_CHANNEL])
+ if (console_poll || dport != &dashtty_ports[CONSOLE_CHANNEL])
if (atomic_dec_and_test(&num_channels_need_poll))
del_timer_sync(&poll_timer);
diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c
index 1deaca4674e4..14c54e041065 100644
--- a/drivers/tty/moxa.c
+++ b/drivers/tty/moxa.c
@@ -1096,7 +1096,7 @@ static int __init moxa_init(void)
continue;
}
- printk(KERN_INFO "MOXA isa board found at 0x%.8lu and "
+ printk(KERN_INFO "MOXA isa board found at 0x%.8lx and "
"ready (%u ports, firmware loaded)\n",
baseaddr[i], brd->numPorts);
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index f44f1ba762c3..89c4cee253e3 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -1166,7 +1166,7 @@ static void n_tty_receive_break(struct tty_struct *tty)
}
put_tty_queue('\0', ldata);
if (waitqueue_active(&tty->read_wait))
- wake_up_interruptible(&tty->read_wait);
+ wake_up_interruptible_poll(&tty->read_wait, POLLIN);
}
/**
@@ -1226,7 +1226,7 @@ static void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c)
} else
put_tty_queue(c, ldata);
if (waitqueue_active(&tty->read_wait))
- wake_up_interruptible(&tty->read_wait);
+ wake_up_interruptible_poll(&tty->read_wait, POLLIN);
}
static void
@@ -1378,7 +1378,7 @@ handle_newline:
ldata->canon_head = ldata->read_head;
kill_fasync(&tty->fasync, SIGIO, POLL_IN);
if (waitqueue_active(&tty->read_wait))
- wake_up_interruptible(&tty->read_wait);
+ wake_up_interruptible_poll(&tty->read_wait, POLLIN);
return 0;
}
}
@@ -1679,7 +1679,7 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
L_EXTPROC(tty)) {
kill_fasync(&tty->fasync, SIGIO, POLL_IN);
if (waitqueue_active(&tty->read_wait))
- wake_up_interruptible(&tty->read_wait);
+ wake_up_interruptible_poll(&tty->read_wait, POLLIN);
}
}
diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c
index cd0429369557..74885af8c7bd 100644
--- a/drivers/tty/nozomi.c
+++ b/drivers/tty/nozomi.c
@@ -523,7 +523,7 @@ static u32 write_mem32(void __iomem *mem_addr_start, const u32 *buf,
}
/* Setup pointers to different channels and also setup buffer sizes. */
-static void setup_memory(struct nozomi *dc)
+static void nozomi_setup_memory(struct nozomi *dc)
{
void __iomem *offset = dc->base_addr + dc->config_table.dl_start;
/* The length reported is including the length field of 4 bytes,
@@ -671,7 +671,7 @@ static int nozomi_read_config_table(struct nozomi *dc)
int i;
DBG1("Second phase, configuring card");
- setup_memory(dc);
+ nozomi_setup_memory(dc);
dc->port[PORT_MDM].toggle_ul = dc->config_table.toggle.mdm_ul;
dc->port[PORT_MDM].toggle_dl = dc->config_table.toggle.mdm_dl;
@@ -705,7 +705,7 @@ static int nozomi_read_config_table(struct nozomi *dc)
dc->config_table.version);
/* Here we should disable all I/O over F32. */
- setup_memory(dc);
+ nozomi_setup_memory(dc);
/*
* We should send ALL channel pair tokens back along
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index 9bbdb1de12e2..7c4447a5c0f4 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -24,6 +24,7 @@
#include <linux/devpts_fs.h>
#include <linux/slab.h>
#include <linux/mutex.h>
+#include <linux/poll.h>
#ifdef CONFIG_UNIX98_PTYS
@@ -313,6 +314,42 @@ done:
}
/**
+ * pty_start - start() handler
+ * pty_stop - stop() handler
+ * @tty: tty being flow-controlled
+ *
+ * Propagates the TIOCPKT status to the master pty.
+ *
+ * NB: only the master pty can be in packet mode so only the slave
+ * needs start()/stop() handlers
+ */
+static void pty_start(struct tty_struct *tty)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
+ if (tty->link && tty->link->packet) {
+ tty->ctrl_status &= ~TIOCPKT_STOP;
+ tty->ctrl_status |= TIOCPKT_START;
+ wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
+ }
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+}
+
+static void pty_stop(struct tty_struct *tty)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
+ if (tty->link && tty->link->packet) {
+ tty->ctrl_status &= ~TIOCPKT_START;
+ tty->ctrl_status |= TIOCPKT_STOP;
+ wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
+ }
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+}
+
+/**
* pty_common_install - set up the pty pair
* @driver: the pty driver
* @tty: the tty being instantiated
@@ -471,6 +508,8 @@ static const struct tty_operations slave_pty_ops_bsd = {
.set_termios = pty_set_termios,
.cleanup = pty_cleanup,
.resize = pty_resize,
+ .start = pty_start,
+ .stop = pty_stop,
.remove = pty_remove
};
@@ -646,6 +685,8 @@ static const struct tty_operations pty_unix98_ops = {
.chars_in_buffer = pty_chars_in_buffer,
.unthrottle = pty_unthrottle,
.set_termios = pty_set_termios,
+ .start = pty_start,
+ .stop = pty_stop,
.shutdown = pty_unix98_shutdown,
.cleanup = pty_cleanup,
};
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index 1b08c918cd51..1bcb4b2141a6 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -72,6 +72,7 @@ struct serial8250_config {
#define UART_CAP_UUE (1 << 12) /* UART needs IER bit 6 set (Xscale) */
#define UART_CAP_RTOIE (1 << 13) /* UART needs IER bit 4 set (Xscale, Tegra) */
#define UART_CAP_HFIFO (1 << 14) /* UART has a "hidden" FIFO */
+#define UART_CAP_RPM (1 << 15) /* Runtime PM is active while idle */
#define UART_BUG_QUOT (1 << 0) /* UART has buggy quot LSB */
#define UART_BUG_TXEN (1 << 1) /* UART has buggy TX IIR status */
@@ -112,6 +113,8 @@ static inline void serial_dl_write(struct uart_8250_port *up, int value)
up->dl_write(up, value);
}
+struct uart_8250_port *serial8250_get_port(int line);
+
#if defined(__alpha__) && !defined(CONFIG_PCI)
/*
* Digital did something really horribly wrong with the OUT1 and OUT2
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index bd672948f2f1..ca5cfdc1459a 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -37,6 +37,8 @@
#include <linux/nmi.h>
#include <linux/mutex.h>
#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/pm_runtime.h>
#ifdef CONFIG_SPARC
#include <linux/sunserialcore.h>
#endif
@@ -539,6 +541,53 @@ void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p)
}
EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos);
+static void serial8250_rpm_get(struct uart_8250_port *p)
+{
+ if (!(p->capabilities & UART_CAP_RPM))
+ return;
+ pm_runtime_get_sync(p->port.dev);
+}
+
+static void serial8250_rpm_put(struct uart_8250_port *p)
+{
+ if (!(p->capabilities & UART_CAP_RPM))
+ return;
+ pm_runtime_mark_last_busy(p->port.dev);
+ pm_runtime_put_autosuspend(p->port.dev);
+}
+
+/*
+ * This two wrapper ensure, that enable_runtime_pm_tx() can be called more than
+ * once and disable_runtime_pm_tx() will still disable RPM because the fifo is
+ * empty and the HW can idle again.
+ */
+static void serial8250_rpm_get_tx(struct uart_8250_port *p)
+{
+ unsigned char rpm_active;
+
+ if (!(p->capabilities & UART_CAP_RPM))
+ return;
+
+ rpm_active = xchg(&p->rpm_tx_active, 1);
+ if (rpm_active)
+ return;
+ pm_runtime_get_sync(p->port.dev);
+}
+
+static void serial8250_rpm_put_tx(struct uart_8250_port *p)
+{
+ unsigned char rpm_active;
+
+ if (!(p->capabilities & UART_CAP_RPM))
+ return;
+
+ rpm_active = xchg(&p->rpm_tx_active, 0);
+ if (!rpm_active)
+ return;
+ pm_runtime_mark_last_busy(p->port.dev);
+ pm_runtime_put_autosuspend(p->port.dev);
+}
+
/*
* IER sleep support. UARTs which have EFRs need the "extended
* capability" bit enabled. Note that on XR16C850s, we need to
@@ -553,10 +602,11 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
* offset but the UART channel may only write to the corresponding
* bit.
*/
+ serial8250_rpm_get(p);
if ((p->port.type == PORT_XR17V35X) ||
(p->port.type == PORT_XR17D15X)) {
serial_out(p, UART_EXAR_SLEEP, sleep ? 0xff : 0);
- return;
+ goto out;
}
if (p->capabilities & UART_CAP_SLEEP) {
@@ -572,6 +622,8 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
serial_out(p, UART_LCR, 0);
}
}
+out:
+ serial8250_rpm_put(p);
}
#ifdef CONFIG_SERIAL_8250_RSA
@@ -1272,6 +1324,7 @@ static inline void __stop_tx(struct uart_8250_port *p)
if (p->ier & UART_IER_THRI) {
p->ier &= ~UART_IER_THRI;
serial_out(p, UART_IER, p->ier);
+ serial8250_rpm_put_tx(p);
}
}
@@ -1279,6 +1332,7 @@ static void serial8250_stop_tx(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
+ serial8250_rpm_get(up);
__stop_tx(up);
/*
@@ -1288,12 +1342,14 @@ static void serial8250_stop_tx(struct uart_port *port)
up->acr |= UART_ACR_TXDIS;
serial_icr_write(up, UART_ACR, up->acr);
}
+ serial8250_rpm_put(up);
}
static void serial8250_start_tx(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
+ serial8250_rpm_get_tx(up);
if (up->dma && !serial8250_tx_dma(up)) {
return;
} else if (!(up->ier & UART_IER_THRI)) {
@@ -1318,13 +1374,27 @@ static void serial8250_start_tx(struct uart_port *port)
}
}
+static void serial8250_throttle(struct uart_port *port)
+{
+ port->throttle(port);
+}
+
+static void serial8250_unthrottle(struct uart_port *port)
+{
+ port->unthrottle(port);
+}
+
static void serial8250_stop_rx(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
- up->ier &= ~UART_IER_RLSI;
+ serial8250_rpm_get(up);
+
+ up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
up->port.read_status_mask &= ~UART_LSR_DR;
serial_port_out(port, UART_IER, up->ier);
+
+ serial8250_rpm_put(up);
}
static void serial8250_enable_ms(struct uart_port *port)
@@ -1336,7 +1406,10 @@ static void serial8250_enable_ms(struct uart_port *port)
return;
up->ier |= UART_IER_MSI;
+
+ serial8250_rpm_get(up);
serial_port_out(port, UART_IER, up->ier);
+ serial8250_rpm_put(up);
}
/*
@@ -1458,11 +1531,17 @@ void serial8250_tx_chars(struct uart_8250_port *up)
DEBUG_INTR("THRE...");
- if (uart_circ_empty(xmit))
+ /*
+ * With RPM enabled, we have to wait once the FIFO is empty before the
+ * HW can go idle. So we get here once again with empty FIFO and disable
+ * the interrupt and RPM in __stop_tx()
+ */
+ if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM))
__stop_tx(up);
}
EXPORT_SYMBOL_GPL(serial8250_tx_chars);
+/* Caller holds uart port lock */
unsigned int serial8250_modem_status(struct uart_8250_port *up)
{
struct uart_port *port = &up->port;
@@ -1525,9 +1604,17 @@ EXPORT_SYMBOL_GPL(serial8250_handle_irq);
static int serial8250_default_handle_irq(struct uart_port *port)
{
- unsigned int iir = serial_port_in(port, UART_IIR);
+ struct uart_8250_port *up = up_to_u8250p(port);
+ unsigned int iir;
+ int ret;
+
+ serial8250_rpm_get(up);
- return serial8250_handle_irq(port, iir);
+ iir = serial_port_in(port, UART_IIR);
+ ret = serial8250_handle_irq(port, iir);
+
+ serial8250_rpm_put(up);
+ return ret;
}
/*
@@ -1784,11 +1871,15 @@ static unsigned int serial8250_tx_empty(struct uart_port *port)
unsigned long flags;
unsigned int lsr;
+ serial8250_rpm_get(up);
+
spin_lock_irqsave(&port->lock, flags);
lsr = serial_port_in(port, UART_LSR);
up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
spin_unlock_irqrestore(&port->lock, flags);
+ serial8250_rpm_put(up);
+
return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0;
}
@@ -1798,7 +1889,9 @@ static unsigned int serial8250_get_mctrl(struct uart_port *port)
unsigned int status;
unsigned int ret;
+ serial8250_rpm_get(up);
status = serial8250_modem_status(up);
+ serial8250_rpm_put(up);
ret = 0;
if (status & UART_MSR_DCD)
@@ -1838,6 +1931,7 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state)
struct uart_8250_port *up = up_to_u8250p(port);
unsigned long flags;
+ serial8250_rpm_get(up);
spin_lock_irqsave(&port->lock, flags);
if (break_state == -1)
up->lcr |= UART_LCR_SBC;
@@ -1845,6 +1939,7 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state)
up->lcr &= ~UART_LCR_SBC;
serial_port_out(port, UART_LCR, up->lcr);
spin_unlock_irqrestore(&port->lock, flags);
+ serial8250_rpm_put(up);
}
/*
@@ -1889,12 +1984,23 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits)
static int serial8250_get_poll_char(struct uart_port *port)
{
- unsigned char lsr = serial_port_in(port, UART_LSR);
+ struct uart_8250_port *up = up_to_u8250p(port);
+ unsigned char lsr;
+ int status;
+
+ serial8250_rpm_get(up);
+
+ lsr = serial_port_in(port, UART_LSR);
- if (!(lsr & UART_LSR_DR))
- return NO_POLL_CHAR;
+ if (!(lsr & UART_LSR_DR)) {
+ status = NO_POLL_CHAR;
+ goto out;
+ }
- return serial_port_in(port, UART_RX);
+ status = serial_port_in(port, UART_RX);
+out:
+ serial8250_rpm_put(up);
+ return status;
}
@@ -1904,6 +2010,7 @@ static void serial8250_put_poll_char(struct uart_port *port,
unsigned int ier;
struct uart_8250_port *up = up_to_u8250p(port);
+ serial8250_rpm_get(up);
/*
* First save the IER then disable the interrupts
*/
@@ -1925,11 +2032,12 @@ static void serial8250_put_poll_char(struct uart_port *port,
*/
wait_for_xmitr(up, BOTH_EMPTY);
serial_port_out(port, UART_IER, ier);
+ serial8250_rpm_put(up);
}
#endif /* CONFIG_CONSOLE_POLL */
-static int serial8250_startup(struct uart_port *port)
+int serial8250_do_startup(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
unsigned long flags;
@@ -1950,6 +2058,7 @@ static int serial8250_startup(struct uart_port *port)
if (port->iotype != up->cur_iotype)
set_io_from_upio(port);
+ serial8250_rpm_get(up);
if (port->type == PORT_16C950) {
/* Wake up and initialize UART */
up->acr = 0;
@@ -1970,7 +2079,6 @@ static int serial8250_startup(struct uart_port *port)
*/
enable_rsa(up);
#endif
-
/*
* Clear the FIFO buffers and disable them.
* (they will be reenabled in set_termios())
@@ -1980,8 +2088,8 @@ static int serial8250_startup(struct uart_port *port)
/*
* Clear the interrupt registers.
*/
- serial_port_in(port, UART_LSR);
- serial_port_in(port, UART_RX);
+ if (serial_port_in(port, UART_LSR) & UART_LSR_DR)
+ serial_port_in(port, UART_RX);
serial_port_in(port, UART_IIR);
serial_port_in(port, UART_MSR);
@@ -1994,7 +2102,8 @@ static int serial8250_startup(struct uart_port *port)
(serial_port_in(port, UART_LSR) == 0xff)) {
printk_ratelimited(KERN_INFO "ttyS%d: LSR safety check engaged!\n",
serial_index(port));
- return -ENODEV;
+ retval = -ENODEV;
+ goto out;
}
/*
@@ -2079,7 +2188,7 @@ static int serial8250_startup(struct uart_port *port)
} else {
retval = serial_link_irq_chain(up);
if (retval)
- return retval;
+ goto out;
}
/*
@@ -2141,8 +2250,8 @@ dont_test_tx_en:
* saved flags to avoid getting false values from polling
* routines or the previous session.
*/
- serial_port_in(port, UART_LSR);
- serial_port_in(port, UART_RX);
+ if (serial_port_in(port, UART_LSR) & UART_LSR_DR)
+ serial_port_in(port, UART_RX);
serial_port_in(port, UART_IIR);
serial_port_in(port, UART_MSR);
up->lsr_saved_flags = 0;
@@ -2177,15 +2286,26 @@ dont_test_tx_en:
outb_p(0x80, icp);
inb_p(icp);
}
+ retval = 0;
+out:
+ serial8250_rpm_put(up);
+ return retval;
+}
+EXPORT_SYMBOL_GPL(serial8250_do_startup);
- return 0;
+static int serial8250_startup(struct uart_port *port)
+{
+ if (port->startup)
+ return port->startup(port);
+ return serial8250_do_startup(port);
}
-static void serial8250_shutdown(struct uart_port *port)
+void serial8250_do_shutdown(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
unsigned long flags;
+ serial8250_rpm_get(up);
/*
* Disable interrupts from this port
*/
@@ -2224,13 +2344,24 @@ static void serial8250_shutdown(struct uart_port *port)
* Read data port to reset things, and then unlink from
* the IRQ chain.
*/
- serial_port_in(port, UART_RX);
+ if (serial_port_in(port, UART_LSR) & UART_LSR_DR)
+ serial_port_in(port, UART_RX);
+ serial8250_rpm_put(up);
del_timer_sync(&up->timer);
up->timer.function = serial8250_timeout;
if (port->irq)
serial_unlink_irq_chain(up);
}
+EXPORT_SYMBOL_GPL(serial8250_do_shutdown);
+
+static void serial8250_shutdown(struct uart_port *port)
+{
+ if (port->shutdown)
+ port->shutdown(port);
+ else
+ serial8250_do_shutdown(port);
+}
static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud)
{
@@ -2319,11 +2450,9 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
* the trigger, or the MCR RTS bit is cleared. In the case where
* the remote UART is not using CTS auto flow control, we must
* have sufficient FIFO entries for the latency of the remote
- * UART to respond. IOW, at least 32 bytes of FIFO. Also enable
- * AFE if hw flow control is supported
+ * UART to respond. IOW, at least 32 bytes of FIFO.
*/
- if ((up->capabilities & UART_CAP_AFE && (port->fifosize >= 32)) ||
- (port->flags & UPF_HARD_FLOW)) {
+ if (up->capabilities & UART_CAP_AFE && port->fifosize >= 32) {
up->mcr &= ~UART_MCR_AFE;
if (termios->c_cflag & CRTSCTS)
up->mcr |= UART_MCR_AFE;
@@ -2333,6 +2462,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
* Ok, we're now changing the port state. Do it with
* interrupts disabled.
*/
+ serial8250_rpm_get(up);
spin_lock_irqsave(&port->lock, flags);
/*
@@ -2454,6 +2584,8 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
}
serial8250_set_mctrl(port, port->mctrl);
spin_unlock_irqrestore(&port->lock, flags);
+ serial8250_rpm_put(up);
+
/* Don't rewrite B0 */
if (tty_termios_baud_rate(termios))
tty_termios_encode_baud_rate(termios, baud, baud);
@@ -2843,6 +2975,42 @@ serial8250_verify_port(struct uart_port *port, struct serial_struct *ser)
return 0;
}
+static int serial8250_ioctl(struct uart_port *port, unsigned int cmd,
+ unsigned long arg)
+{
+ struct uart_8250_port *up =
+ container_of(port, struct uart_8250_port, port);
+ int ret;
+ struct serial_rs485 rs485_config;
+
+ if (!up->rs485_config)
+ return -ENOIOCTLCMD;
+
+ switch (cmd) {
+ case TIOCSRS485:
+ if (copy_from_user(&rs485_config, (void __user *)arg,
+ sizeof(rs485_config)))
+ return -EFAULT;
+
+ ret = up->rs485_config(up, &rs485_config);
+ if (ret)
+ return ret;
+
+ memcpy(&up->rs485, &rs485_config, sizeof(rs485_config));
+
+ return 0;
+ case TIOCGRS485:
+ if (copy_to_user((void __user *)arg, &up->rs485,
+ sizeof(up->rs485)))
+ return -EFAULT;
+ return 0;
+ default:
+ break;
+ }
+
+ return -ENOIOCTLCMD;
+}
+
static const char *
serial8250_type(struct uart_port *port)
{
@@ -2859,6 +3027,8 @@ static struct uart_ops serial8250_pops = {
.get_mctrl = serial8250_get_mctrl,
.stop_tx = serial8250_stop_tx,
.start_tx = serial8250_start_tx,
+ .throttle = serial8250_throttle,
+ .unthrottle = serial8250_unthrottle,
.stop_rx = serial8250_stop_rx,
.enable_ms = serial8250_enable_ms,
.break_ctl = serial8250_break_ctl,
@@ -2872,6 +3042,7 @@ static struct uart_ops serial8250_pops = {
.request_port = serial8250_request_port,
.config_port = serial8250_config_port,
.verify_port = serial8250_verify_port,
+ .ioctl = serial8250_ioctl,
#ifdef CONFIG_CONSOLE_POLL
.poll_get_char = serial8250_get_poll_char,
.poll_put_char = serial8250_put_poll_char,
@@ -2880,6 +3051,24 @@ static struct uart_ops serial8250_pops = {
static struct uart_8250_port serial8250_ports[UART_NR];
+/**
+ * serial8250_get_port - retrieve struct uart_8250_port
+ * @line: serial line number
+ *
+ * This function retrieves struct uart_8250_port for the specific line.
+ * This struct *must* *not* be used to perform a 8250 or serial core operation
+ * which is not accessible otherwise. Its only purpose is to make the struct
+ * accessible to the runtime-pm callbacks for context suspend/restore.
+ * The lock assumption made here is none because runtime-pm suspend/resume
+ * callbacks should not be invoked if there is any operation performed on the
+ * port.
+ */
+struct uart_8250_port *serial8250_get_port(int line)
+{
+ return &serial8250_ports[line];
+}
+EXPORT_SYMBOL_GPL(serial8250_get_port);
+
static void (*serial8250_isa_config)(int port, struct uart_port *up,
unsigned short *capabilities);
@@ -3007,6 +3196,8 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
touch_nmi_watchdog();
+ serial8250_rpm_get(up);
+
if (port->sysrq || oops_in_progress)
locked = spin_trylock_irqsave(&port->lock, flags);
else
@@ -3043,6 +3234,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
if (locked)
spin_unlock_irqrestore(&port->lock, flags);
+ serial8250_rpm_put(up);
}
static int __init serial8250_console_setup(struct console *co, char *options)
@@ -3324,6 +3516,11 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
if (uart_match_port(&serial8250_ports[i].port, port))
return &serial8250_ports[i];
+ /* try line number first if still available */
+ i = port->line;
+ if (i < nr_uarts && serial8250_ports[i].port.type == PORT_UNKNOWN &&
+ serial8250_ports[i].port.iobase == 0)
+ return &serial8250_ports[i];
/*
* We didn't find a matching entry, so look for the first
* free entry. We look for one which hasn't been previously
@@ -3388,6 +3585,10 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
uart->port.fifosize = up->port.fifosize;
uart->tx_loadsz = up->tx_loadsz;
uart->capabilities = up->capabilities;
+ uart->rs485_config = up->rs485_config;
+ uart->rs485 = up->rs485;
+ uart->port.throttle = up->port.throttle;
+ uart->port.unthrottle = up->port.unthrottle;
/* Take tx_loadsz from fifosize if it wasn't set separately */
if (uart->port.fifosize && !uart->tx_loadsz)
@@ -3410,6 +3611,10 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
/* Possibly override set_termios call */
if (up->port.set_termios)
uart->port.set_termios = up->port.set_termios;
+ if (up->port.startup)
+ uart->port.startup = up->port.startup;
+ if (up->port.shutdown)
+ uart->port.shutdown = up->port.shutdown;
if (up->port.pm)
uart->port.pm = up->port.pm;
if (up->port.handle_break)
diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c
new file mode 100644
index 000000000000..1bb28cb69493
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_fintek.c
@@ -0,0 +1,249 @@
+/*
+ * 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
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ */
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/pnp.h>
+#include <linux/kernel.h>
+#include <linux/serial_core.h>
+#include "8250.h"
+
+#define ADDR_PORT 0x4E
+#define DATA_PORT 0x4F
+#define ENTRY_KEY 0x77
+#define EXIT_KEY 0xAA
+#define CHIP_ID1 0x20
+#define CHIP_ID1_VAL 0x02
+#define CHIP_ID2 0x21
+#define CHIP_ID2_VAL 0x16
+#define VENDOR_ID1 0x23
+#define VENDOR_ID1_VAL 0x19
+#define VENDOR_ID2 0x24
+#define VENDOR_ID2_VAL 0x34
+#define LDN 0x7
+
+#define RS485 0xF0
+#define RTS_INVERT BIT(5)
+#define RS485_URA BIT(4)
+#define RXW4C_IRA BIT(3)
+#define TXW4C_IRA BIT(2)
+
+#define DRIVER_NAME "8250_fintek"
+
+static int fintek_8250_enter_key(void){
+
+ if (!request_muxed_region(ADDR_PORT, 2, DRIVER_NAME))
+ return -EBUSY;
+
+ outb(ENTRY_KEY, ADDR_PORT);
+ outb(ENTRY_KEY, ADDR_PORT);
+ return 0;
+}
+
+static void fintek_8250_exit_key(void){
+
+ outb(EXIT_KEY, ADDR_PORT);
+ release_region(ADDR_PORT, 2);
+}
+
+static int fintek_8250_get_index(resource_size_t base_addr)
+{
+ resource_size_t base[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8};
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(base); i++)
+ if (base_addr == base[i])
+ return i;
+
+ return -ENODEV;
+}
+
+static int fintek_8250_check_id(void)
+{
+
+ outb(CHIP_ID1, ADDR_PORT);
+ if (inb(DATA_PORT) != CHIP_ID1_VAL)
+ return -ENODEV;
+
+ outb(CHIP_ID2, ADDR_PORT);
+ if (inb(DATA_PORT) != CHIP_ID2_VAL)
+ return -ENODEV;
+
+ outb(VENDOR_ID1, ADDR_PORT);
+ if (inb(DATA_PORT) != VENDOR_ID1_VAL)
+ return -ENODEV;
+
+ outb(VENDOR_ID2, ADDR_PORT);
+ if (inb(DATA_PORT) != VENDOR_ID2_VAL)
+ return -ENODEV;
+
+ return 0;
+}
+
+static int fintek_8250_rs4850_config(struct uart_8250_port *uart,
+ struct serial_rs485 *rs485)
+{
+ uint8_t config = 0;
+ int index = fintek_8250_get_index(uart->port.iobase);
+
+ if (index < 0)
+ return -EINVAL;
+
+ if (rs485->flags & SER_RS485_ENABLED)
+ memset(rs485->padding, 0, sizeof(rs485->padding));
+ else
+ memset(rs485, 0, sizeof(*rs485));
+
+ rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
+ SER_RS485_RTS_AFTER_SEND;
+
+ if (rs485->delay_rts_before_send) {
+ rs485->delay_rts_before_send = 1;
+ config |= TXW4C_IRA;
+ }
+
+ if (rs485->delay_rts_after_send) {
+ rs485->delay_rts_after_send = 1;
+ config |= RXW4C_IRA;
+ }
+
+ if ((!!(rs485->flags & SER_RS485_RTS_ON_SEND)) ==
+ (!!(rs485->flags & SER_RS485_RTS_AFTER_SEND)))
+ rs485->flags &= SER_RS485_ENABLED;
+ else
+ config |= RS485_URA;
+
+ if (rs485->flags & SER_RS485_RTS_ON_SEND)
+ config |= RTS_INVERT;
+
+ if (fintek_8250_enter_key())
+ return -EBUSY;
+
+ outb(LDN, ADDR_PORT);
+ outb(index, DATA_PORT);
+ outb(RS485, ADDR_PORT);
+ outb(config, DATA_PORT);
+ fintek_8250_exit_key();
+
+ return 0;
+}
+
+static int
+fintek_8250_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
+{
+ int line;
+ struct uart_8250_port uart;
+ int ret;
+
+ if (!pnp_port_valid(dev, 0))
+ return -ENODEV;
+
+ if (fintek_8250_get_index(pnp_port_start(dev, 0)) < 0)
+ return -ENODEV;
+
+ /* Enable configuration registers*/
+ if (fintek_8250_enter_key())
+ return -EBUSY;
+
+ /*Check ID*/
+ ret = fintek_8250_check_id();
+ fintek_8250_exit_key();
+ if (ret)
+ return ret;
+
+ memset(&uart, 0, sizeof(uart));
+ 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.rs485_config = fintek_8250_rs4850_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;
+
+ line = serial8250_register_8250_port(&uart);
+ if (line < 0)
+ return -ENODEV;
+
+ pnp_set_drvdata(dev, (void *)((long)line + 1));
+ return 0;
+}
+
+static void fintek_8250_remove(struct pnp_dev *dev)
+{
+ long line = (long)pnp_get_drvdata(dev);
+
+ if (line)
+ serial8250_unregister_port(line - 1);
+}
+
+#ifdef CONFIG_PM
+static int fintek_8250_suspend(struct pnp_dev *dev, pm_message_t state)
+{
+ long line = (long)pnp_get_drvdata(dev);
+
+ if (!line)
+ return -ENODEV;
+ serial8250_suspend_port(line - 1);
+ return 0;
+}
+
+static int fintek_8250_resume(struct pnp_dev *dev)
+{
+ long line = (long)pnp_get_drvdata(dev);
+
+ if (!line)
+ return -ENODEV;
+ serial8250_resume_port(line - 1);
+ 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,
+};
+
+static int fintek_8250_init(void)
+{
+ return pnp_register_driver(&fintek_8250_driver);
+}
+module_init(fintek_8250_init);
+
+static void fintek_8250_exit(void)
+{
+ pnp_unregister_driver(&fintek_8250_driver);
+}
+module_exit(fintek_8250_exit);
+
+MODULE_DESCRIPTION("Fintek F812164 module");
+MODULE_AUTHOR("Ricardo Ribalda <ricardo.ribalda@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250/8250_hp300.c b/drivers/tty/serial/8250/8250_hp300.c
index 5bdaf271d395..afffe4d1f034 100644
--- a/drivers/tty/serial/8250/8250_hp300.c
+++ b/drivers/tty/serial/8250/8250_hp300.c
@@ -21,7 +21,7 @@
#include "8250.h"
#if !defined(CONFIG_HPDCA) && !defined(CONFIG_HPAPCI)
-#warning CONFIG_8250 defined but neither CONFIG_HPDCA nor CONFIG_HPAPCI defined, are you sure?
+#warning CONFIG_SERIAL_8250 defined but neither CONFIG_HPDCA nor CONFIG_HPAPCI defined, are you sure?
#endif
#ifdef CONFIG_HPAPCI
diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c
new file mode 100644
index 000000000000..8f37d57165ec
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_mtk.c
@@ -0,0 +1,294 @@
+/*
+ * Mediatek 8250 driver.
+ *
+ * Copyright (c) 2014 MundoReader S.L.
+ * Author: Matthias Brugger <matthias.bgg@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/serial_8250.h>
+#include <linux/serial_reg.h>
+
+#include "8250.h"
+
+#define UART_MTK_HIGHS 0x09 /* Highspeed register */
+#define UART_MTK_SAMPLE_COUNT 0x0a /* Sample count register */
+#define UART_MTK_SAMPLE_POINT 0x0b /* Sample point register */
+#define MTK_UART_RATE_FIX 0x0d /* UART Rate Fix Register */
+
+struct mtk8250_data {
+ int line;
+ struct clk *uart_clk;
+};
+
+static void
+mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
+{
+ unsigned long flags;
+ unsigned int baud, quot;
+
+ struct uart_8250_port *up =
+ container_of(port, struct uart_8250_port, port);
+
+ serial8250_do_set_termios(port, termios, old);
+
+ /*
+ * Mediatek UARTs use an extra highspeed register (UART_MTK_HIGHS)
+ *
+ * We need to recalcualte the quot register, as the claculation depends
+ * on the vaule in the highspeed register.
+ *
+ * Some baudrates are not supported by the chip, so we use the next
+ * lower rate supported and update termios c_flag.
+ *
+ * If highspeed register is set to 3, we need to specify sample count
+ * and sample point to increase accuracy. If not, we reset the
+ * registers to their default values.
+ */
+ baud = uart_get_baud_rate(port, termios, old,
+ port->uartclk / 16 / 0xffff,
+ port->uartclk / 16);
+
+ if (baud <= 115200) {
+ serial_port_out(port, UART_MTK_HIGHS, 0x0);
+ quot = uart_get_divisor(port, baud);
+ } else if (baud <= 576000) {
+ serial_port_out(port, UART_MTK_HIGHS, 0x2);
+
+ /* Set to next lower baudrate supported */
+ if ((baud == 500000) || (baud == 576000))
+ baud = 460800;
+ quot = DIV_ROUND_CLOSEST(port->uartclk, 4 * baud);
+ } else {
+ serial_port_out(port, UART_MTK_HIGHS, 0x3);
+
+ /* Set to highest baudrate supported */
+ if (baud >= 1152000)
+ baud = 921600;
+ quot = DIV_ROUND_CLOSEST(port->uartclk, 256 * baud);
+ }
+
+ /*
+ * Ok, we're now changing the port state. Do it with
+ * interrupts disabled.
+ */
+ spin_lock_irqsave(&port->lock, flags);
+
+ /* set DLAB we have cval saved in up->lcr from the call to the core */
+ serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB);
+ serial_dl_write(up, quot);
+
+ /* reset DLAB */
+ serial_port_out(port, UART_LCR, up->lcr);
+
+ if (baud > 460800) {
+ unsigned int tmp;
+
+ tmp = DIV_ROUND_CLOSEST(port->uartclk, quot * baud);
+ serial_port_out(port, UART_MTK_SAMPLE_COUNT, tmp - 1);
+ serial_port_out(port, UART_MTK_SAMPLE_POINT,
+ (tmp - 2) >> 1);
+ } else {
+ serial_port_out(port, UART_MTK_SAMPLE_COUNT, 0x00);
+ serial_port_out(port, UART_MTK_SAMPLE_POINT, 0xff);
+ }
+
+ spin_unlock_irqrestore(&port->lock, flags);
+ /* Don't rewrite B0 */
+ if (tty_termios_baud_rate(termios))
+ tty_termios_encode_baud_rate(termios, baud, baud);
+}
+
+static void
+mtk8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old)
+{
+ if (!state)
+ pm_runtime_get_sync(port->dev);
+
+ serial8250_do_pm(port, state, old);
+
+ if (state)
+ pm_runtime_put_sync_suspend(port->dev);
+}
+
+static int mtk8250_probe_of(struct platform_device *pdev, struct uart_port *p,
+ struct mtk8250_data *data)
+{
+ int err;
+ struct device_node *np = pdev->dev.of_node;
+
+ data->uart_clk = of_clk_get(np, 0);
+ if (IS_ERR(data->uart_clk)) {
+ dev_warn(&pdev->dev, "Can't get timer clock\n");
+ return PTR_ERR(data->uart_clk);
+ }
+
+ err = clk_prepare_enable(data->uart_clk);
+ if (err) {
+ dev_warn(&pdev->dev, "Can't prepare clock\n");
+ clk_put(data->uart_clk);
+ return err;
+ }
+ p->uartclk = clk_get_rate(data->uart_clk);
+
+ return 0;
+}
+
+static int mtk8250_probe(struct platform_device *pdev)
+{
+ struct uart_8250_port uart = {};
+ struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ struct mtk8250_data *data;
+ int err;
+
+ if (!regs || !irq) {
+ dev_err(&pdev->dev, "no registers/irq defined\n");
+ return -EINVAL;
+ }
+
+ uart.port.membase = devm_ioremap(&pdev->dev, regs->start,
+ resource_size(regs));
+ if (!uart.port.membase)
+ return -ENOMEM;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ if (pdev->dev.of_node) {
+ err = mtk8250_probe_of(pdev, &uart.port, data);
+ if (err)
+ return err;
+ } else
+ return -ENODEV;
+
+ spin_lock_init(&uart.port.lock);
+ uart.port.mapbase = regs->start;
+ uart.port.irq = irq->start;
+ uart.port.pm = mtk8250_do_pm;
+ uart.port.type = PORT_16550;
+ uart.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
+ uart.port.dev = &pdev->dev;
+ uart.port.iotype = UPIO_MEM32;
+ uart.port.regshift = 2;
+ uart.port.private_data = data;
+ uart.port.set_termios = mtk8250_set_termios;
+
+ /* Disable Rate Fix function */
+ writel(0x0, uart.port.membase +
+ (MTK_UART_RATE_FIX << uart.port.regshift));
+
+ data->line = serial8250_register_8250_port(&uart);
+ if (data->line < 0)
+ return data->line;
+
+ platform_set_drvdata(pdev, data);
+
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
+ return 0;
+}
+
+static int mtk8250_remove(struct platform_device *pdev)
+{
+ struct mtk8250_data *data = platform_get_drvdata(pdev);
+
+ pm_runtime_get_sync(&pdev->dev);
+
+ serial8250_unregister_port(data->line);
+ if (!IS_ERR(data->uart_clk)) {
+ clk_disable_unprepare(data->uart_clk);
+ clk_put(data->uart_clk);
+ }
+
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mtk8250_suspend(struct device *dev)
+{
+ struct mtk8250_data *data = dev_get_drvdata(dev);
+
+ serial8250_suspend_port(data->line);
+
+ return 0;
+}
+
+static int mtk8250_resume(struct device *dev)
+{
+ struct mtk8250_data *data = dev_get_drvdata(dev);
+
+ serial8250_resume_port(data->line);
+
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PM_RUNTIME
+static int mtk8250_runtime_suspend(struct device *dev)
+{
+ struct mtk8250_data *data = dev_get_drvdata(dev);
+
+ if (!IS_ERR(data->uart_clk))
+ clk_disable_unprepare(data->uart_clk);
+
+ return 0;
+}
+
+static int mtk8250_runtime_resume(struct device *dev)
+{
+ struct mtk8250_data *data = dev_get_drvdata(dev);
+
+ if (!IS_ERR(data->uart_clk))
+ clk_prepare_enable(data->uart_clk);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops mtk8250_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(mtk8250_suspend, mtk8250_resume)
+ SET_RUNTIME_PM_OPS(mtk8250_runtime_suspend, mtk8250_runtime_resume,
+ NULL)
+};
+
+static const struct of_device_id mtk8250_of_match[] = {
+ { .compatible = "mediatek,mt6577-uart" },
+ { /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mtk8250_of_match);
+
+static struct platform_driver mtk8250_platform_driver = {
+ .driver = {
+ .name = "mt6577-uart",
+ .pm = &mtk8250_pm_ops,
+ .of_match_table = mtk8250_of_match,
+ },
+ .probe = mtk8250_probe,
+ .remove = mtk8250_remove,
+};
+module_platform_driver(mtk8250_platform_driver);
+
+MODULE_AUTHOR("Matthias Brugger");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Mediatek 8250 serial port driver");
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 61830b1792eb..4f1cd296f1b1 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -1355,9 +1355,6 @@ ce4100_serial_setup(struct serial_private *priv,
#define BYT_PRV_CLK_N_VAL_SHIFT 16
#define BYT_PRV_CLK_UPDATE (1 << 31)
-#define BYT_GENERAL_REG 0x808
-#define BYT_GENERAL_DIS_RTS_N_OVERRIDE (1 << 3)
-
#define BYT_TX_OVF_INT 0x820
#define BYT_TX_OVF_INT_MASK (1 << 1)
@@ -1412,16 +1409,6 @@ byt_set_termios(struct uart_port *p, struct ktermios *termios,
reg |= BYT_PRV_CLK_EN | BYT_PRV_CLK_UPDATE;
writel(reg, p->membase + BYT_PRV_CLK);
- /*
- * If auto-handshake mechanism is not enabled,
- * disable rts_n override
- */
- reg = readl(p->membase + BYT_GENERAL_REG);
- reg &= ~BYT_GENERAL_DIS_RTS_N_OVERRIDE;
- if (termios->c_cflag & CRTSCTS)
- reg |= BYT_GENERAL_DIS_RTS_N_OVERRIDE;
- writel(reg, p->membase + BYT_GENERAL_REG);
-
serial8250_do_set_termios(p, termios, old);
}
@@ -1788,6 +1775,7 @@ pci_wch_ch353_setup(struct serial_private *priv,
#define PCI_DEVICE_ID_COMMTECH_4222PCIE 0x0022
#define PCI_DEVICE_ID_BROADCOM_TRUMANAGE 0x160a
#define PCI_DEVICE_ID_AMCC_ADDIDATA_APCI7800 0x818e
+#define PCI_DEVICE_ID_INTEL_QRK_UART 0x0936
#define PCI_VENDOR_ID_SUNIX 0x1fd4
#define PCI_DEVICE_ID_SUNIX_1999 0x1999
@@ -1898,6 +1886,13 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID,
.setup = byt_serial_setup,
},
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_QRK_UART,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_default_setup,
+ },
/*
* ITE
*/
@@ -2740,6 +2735,7 @@ enum pci_board_num_t {
pbn_ADDIDATA_PCIe_8_3906250,
pbn_ce4100_1_115200,
pbn_byt,
+ pbn_qrk,
pbn_omegapci,
pbn_NETMOS9900_2s_115200,
pbn_brcm_trumanage,
@@ -3490,6 +3486,12 @@ static struct pciserial_board pci_boards[] = {
.uart_offset = 0x80,
.reg_shift = 2,
},
+ [pbn_qrk] = {
+ .flags = FL_BASE0,
+ .num_ports = 1,
+ .base_baud = 2764800,
+ .reg_shift = 2,
+ },
[pbn_omegapci] = {
.flags = FL_BASE0,
.num_ports = 8,
@@ -5192,6 +5194,12 @@ static struct pci_device_id serial_pci_tbl[] = {
pbn_byt },
/*
+ * Intel Quark x1000
+ */
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_QRK_UART,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_qrk },
+ /*
* Cronyx Omega PCI
*/
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_CRONYX_OMEGA,
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 349ee598b34c..21eca79224e4 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -298,3 +298,18 @@ config SERIAL_8250_RT288X
If you have a Ralink RT288x/RT305x SoC based board and want to use the
serial port, say Y to this option. The driver can handle up to 2 serial
ports. If unsure, say N.
+
+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_MT6577
+ bool "Mediatek serial port support"
+ depends on SERIAL_8250 && ARCH_MEDIATEK
+ help
+ If you have a Mediatek based board and want to use the
+ serial port, say Y to this option. If unsure, say N.
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index 36d68d054307..5256b894e46a 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -20,3 +20,5 @@ obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o
obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o
obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o
+obj-$(CONFIG_SERIAL_8250_FINTEK) += 8250_fintek.o
+obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 26cec64dadd7..649b784081c7 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -200,10 +200,29 @@ config SERIAL_KS8695_CONSOLE
receives all kernel messages and warnings and which allows
logins in single user mode).
+config SERIAL_MESON
+ tristate "Meson serial port support"
+ depends on ARCH_MESON
+ select SERIAL_CORE
+ help
+ This enables the driver for the on-chip UARTs of the Amlogic
+ MesonX processors.
+
+config SERIAL_MESON_CONSOLE
+ bool "Support for console on meson"
+ depends on SERIAL_MESON=y
+ select SERIAL_CORE_CONSOLE
+ help
+ Say Y here if you wish to use a Amlogic MesonX UART as the
+ system console (the system console is the device which
+ receives all kernel messages and warnings and which allows
+ logins in single user mode) as /dev/ttyAMLx.
+
config SERIAL_CLPS711X
tristate "CLPS711X serial port support"
depends on ARCH_CLPS711X || COMPILE_TEST
select SERIAL_CORE
+ select SERIAL_MCTRL_GPIO if GPIOLIB
help
This enables the driver for the on-chip UARTs of the Cirrus
Logic EP711x/EP721x/EP731x processors.
@@ -220,7 +239,7 @@ config SERIAL_CLPS711X_CONSOLE
config SERIAL_SAMSUNG
tristate "Samsung SoC serial support"
- depends on PLAT_SAMSUNG
+ depends on PLAT_SAMSUNG || ARCH_EXYNOS
select SERIAL_CORE
help
Support for the on-chip UARTs on the Samsung S3C24XX series CPUs,
@@ -1051,6 +1070,7 @@ config SERIAL_MSM_CONSOLE
bool "MSM serial console support"
depends on SERIAL_MSM=y
select SERIAL_CORE_CONSOLE
+ select SERIAL_EARLYCON
config SERIAL_MSM_HS
tristate "MSM UART High Speed: Serial Driver"
@@ -1410,6 +1430,7 @@ config SERIAL_XILINX_PS_UART_CONSOLE
bool "Cadence UART console support"
depends on SERIAL_XILINX_PS_UART=y
select SERIAL_CORE_CONSOLE
+ select SERIAL_EARLYCON
help
Enable a Cadence UART port to be the system console.
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 0080cc362e09..9a548acf5fdc 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -48,6 +48,7 @@ obj-$(CONFIG_SERIAL_MPC52xx) += mpc52xx_uart.o
obj-$(CONFIG_SERIAL_ICOM) += icom.o
obj-$(CONFIG_SERIAL_M32R_SIO) += m32r_sio.o
obj-$(CONFIG_SERIAL_MPSC) += mpsc.o
+obj-$(CONFIG_SERIAL_MESON) += meson_uart.o
obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o
obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o
diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c
index d22e3d98ae23..932e01995c0a 100644
--- a/drivers/tty/serial/altera_jtaguart.c
+++ b/drivers/tty/serial/altera_jtaguart.c
@@ -462,7 +462,7 @@ static int altera_jtaguart_remove(struct platform_device *pdev)
}
#ifdef CONFIG_OF
-static struct of_device_id altera_jtaguart_match[] = {
+static const struct of_device_id altera_jtaguart_match[] = {
{ .compatible = "ALTR,juart-1.0", },
{ .compatible = "altr,juart-1.0", },
{},
diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c
index 6a243239dbef..1cb2cdb1bc42 100644
--- a/drivers/tty/serial/altera_uart.c
+++ b/drivers/tty/serial/altera_uart.c
@@ -610,7 +610,7 @@ static int altera_uart_remove(struct platform_device *pdev)
}
#ifdef CONFIG_OF
-static struct of_device_id altera_uart_match[] = {
+static const struct of_device_id altera_uart_match[] = {
{ .compatible = "ALTR,uart-1.0", },
{ .compatible = "altr,uart-1.0", },
{},
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 8572f2a57fc8..02016fcd91b8 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -678,7 +678,8 @@ static void pl011_dma_flush_buffer(struct uart_port *port)
__releases(&uap->port.lock)
__acquires(&uap->port.lock)
{
- struct uart_amba_port *uap = (struct uart_amba_port *)port;
+ struct uart_amba_port *uap =
+ container_of(port, struct uart_amba_port, port);
if (!uap->using_tx_dma)
return;
@@ -1163,7 +1164,8 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
static void pl011_stop_tx(struct uart_port *port)
{
- struct uart_amba_port *uap = (struct uart_amba_port *)port;
+ struct uart_amba_port *uap =
+ container_of(port, struct uart_amba_port, port);
uap->im &= ~UART011_TXIM;
writew(uap->im, uap->port.membase + UART011_IMSC);
@@ -1172,7 +1174,8 @@ static void pl011_stop_tx(struct uart_port *port)
static void pl011_start_tx(struct uart_port *port)
{
- struct uart_amba_port *uap = (struct uart_amba_port *)port;
+ struct uart_amba_port *uap =
+ container_of(port, struct uart_amba_port, port);
if (!pl011_dma_tx_start(uap)) {
uap->im |= UART011_TXIM;
@@ -1182,7 +1185,8 @@ static void pl011_start_tx(struct uart_port *port)
static void pl011_stop_rx(struct uart_port *port)
{
- struct uart_amba_port *uap = (struct uart_amba_port *)port;
+ struct uart_amba_port *uap =
+ container_of(port, struct uart_amba_port, port);
uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM|
UART011_PEIM|UART011_BEIM|UART011_OEIM);
@@ -1193,7 +1197,8 @@ static void pl011_stop_rx(struct uart_port *port)
static void pl011_enable_ms(struct uart_port *port)
{
- struct uart_amba_port *uap = (struct uart_amba_port *)port;
+ struct uart_amba_port *uap =
+ container_of(port, struct uart_amba_port, port);
uap->im |= UART011_RIMIM|UART011_CTSMIM|UART011_DCDMIM|UART011_DSRMIM;
writew(uap->im, uap->port.membase + UART011_IMSC);
@@ -1349,14 +1354,16 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
static unsigned int pl011_tx_empty(struct uart_port *port)
{
- struct uart_amba_port *uap = (struct uart_amba_port *)port;
+ struct uart_amba_port *uap =
+ container_of(port, struct uart_amba_port, port);
unsigned int status = readw(uap->port.membase + UART01x_FR);
return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT;
}
static unsigned int pl011_get_mctrl(struct uart_port *port)
{
- struct uart_amba_port *uap = (struct uart_amba_port *)port;
+ struct uart_amba_port *uap =
+ container_of(port, struct uart_amba_port, port);
unsigned int result = 0;
unsigned int status = readw(uap->port.membase + UART01x_FR);
@@ -1374,7 +1381,8 @@ static unsigned int pl011_get_mctrl(struct uart_port *port)
static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
- struct uart_amba_port *uap = (struct uart_amba_port *)port;
+ struct uart_amba_port *uap =
+ container_of(port, struct uart_amba_port, port);
unsigned int cr;
cr = readw(uap->port.membase + UART011_CR);
@@ -1402,7 +1410,8 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
static void pl011_break_ctl(struct uart_port *port, int break_state)
{
- struct uart_amba_port *uap = (struct uart_amba_port *)port;
+ struct uart_amba_port *uap =
+ container_of(port, struct uart_amba_port, port);
unsigned long flags;
unsigned int lcr_h;
@@ -1420,7 +1429,8 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
static void pl011_quiesce_irqs(struct uart_port *port)
{
- struct uart_amba_port *uap = (struct uart_amba_port *)port;
+ struct uart_amba_port *uap =
+ container_of(port, struct uart_amba_port, port);
unsigned char __iomem *regs = uap->port.membase;
writew(readw(regs + UART011_MIS), regs + UART011_ICR);
@@ -1442,7 +1452,8 @@ static void pl011_quiesce_irqs(struct uart_port *port)
static int pl011_get_poll_char(struct uart_port *port)
{
- struct uart_amba_port *uap = (struct uart_amba_port *)port;
+ struct uart_amba_port *uap =
+ container_of(port, struct uart_amba_port, port);
unsigned int status;
/*
@@ -1461,7 +1472,8 @@ static int pl011_get_poll_char(struct uart_port *port)
static void pl011_put_poll_char(struct uart_port *port,
unsigned char ch)
{
- struct uart_amba_port *uap = (struct uart_amba_port *)port;
+ struct uart_amba_port *uap =
+ container_of(port, struct uart_amba_port, port);
while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
barrier();
@@ -1473,7 +1485,8 @@ static void pl011_put_poll_char(struct uart_port *port,
static int pl011_hwinit(struct uart_port *port)
{
- struct uart_amba_port *uap = (struct uart_amba_port *)port;
+ struct uart_amba_port *uap =
+ container_of(port, struct uart_amba_port, port);
int retval;
/* Optionaly enable pins to be muxed in and configured */
@@ -1526,7 +1539,8 @@ static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
static int pl011_startup(struct uart_port *port)
{
- struct uart_amba_port *uap = (struct uart_amba_port *)port;
+ struct uart_amba_port *uap =
+ container_of(port, struct uart_amba_port, port);
unsigned int cr, lcr_h, fbrd, ibrd;
int retval;
@@ -1618,7 +1632,8 @@ static void pl011_shutdown_channel(struct uart_amba_port *uap,
static void pl011_shutdown(struct uart_port *port)
{
- struct uart_amba_port *uap = (struct uart_amba_port *)port;
+ struct uart_amba_port *uap =
+ container_of(port, struct uart_amba_port, port);
unsigned int cr;
/*
@@ -1680,7 +1695,8 @@ static void
pl011_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
- struct uart_amba_port *uap = (struct uart_amba_port *)port;
+ struct uart_amba_port *uap =
+ container_of(port, struct uart_amba_port, port);
unsigned int lcr_h, old_cr;
unsigned long flags;
unsigned int baud, quot, clkdiv;
@@ -1822,7 +1838,8 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
static const char *pl011_type(struct uart_port *port)
{
- struct uart_amba_port *uap = (struct uart_amba_port *)port;
+ struct uart_amba_port *uap =
+ container_of(port, struct uart_amba_port, port);
return uap->port.type == PORT_AMBA ? uap->type : NULL;
}
@@ -1900,7 +1917,8 @@ static struct uart_amba_port *amba_ports[UART_NR];
static void pl011_console_putchar(struct uart_port *port, int ch)
{
- struct uart_amba_port *uap = (struct uart_amba_port *)port;
+ struct uart_amba_port *uap =
+ container_of(port, struct uart_amba_port, port);
while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
barrier();
diff --git a/drivers/tty/serial/bfin_sport_uart.c b/drivers/tty/serial/bfin_sport_uart.c
index 7810aa290edf..d62d8daac8ab 100644
--- a/drivers/tty/serial/bfin_sport_uart.c
+++ b/drivers/tty/serial/bfin_sport_uart.c
@@ -33,6 +33,7 @@
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
+#include <linux/gpio.h>
#include <asm/bfin_sport.h>
#include <asm/delay.h>
diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c
index dec0fd725d80..7da9911e95f0 100644
--- a/drivers/tty/serial/bfin_uart.c
+++ b/drivers/tty/serial/bfin_uart.c
@@ -108,22 +108,23 @@ static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
static irqreturn_t bfin_serial_mctrl_cts_int(int irq, void *dev_id)
{
struct bfin_serial_port *uart = dev_id;
- unsigned int status = bfin_serial_get_mctrl(&uart->port);
+ struct uart_port *uport = &uart->port;
+ unsigned int status = bfin_serial_get_mctrl(uport);
#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
- struct tty_struct *tty = uart->port.state->port.tty;
UART_CLEAR_SCTS(uart);
- if (tty->hw_stopped) {
+ if (uport->hw_stopped) {
if (status) {
- tty->hw_stopped = 0;
- uart_write_wakeup(&uart->port);
+ uport->hw_stopped = 0;
+ uart_write_wakeup(uport);
}
} else {
if (!status)
- tty->hw_stopped = 1;
+ uport->hw_stopped = 1;
}
+#else
+ uart_handle_cts_change(uport, status & TIOCM_CTS);
#endif
- uart_handle_cts_change(&uart->port, status & TIOCM_CTS);
return IRQ_HANDLED;
}
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index f5b4c3d7e38f..acfe31773643 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -33,6 +33,8 @@
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/clps711x.h>
+#include "serial_mctrl_gpio.h"
+
#define UART_CLPS711X_DEVNAME "ttyCL"
#define UART_CLPS711X_NR 2
#define UART_CLPS711X_MAJOR 204
@@ -62,7 +64,7 @@ struct clps711x_port {
unsigned int tx_enabled;
int rx_irq;
struct regmap *syscon;
- bool use_ms;
+ struct mctrl_gpios *gpios;
};
static struct uart_driver clps711x_uart = {
@@ -198,28 +200,17 @@ static unsigned int uart_clps711x_tx_empty(struct uart_port *port)
static unsigned int uart_clps711x_get_mctrl(struct uart_port *port)
{
+ unsigned int result = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR;
struct clps711x_port *s = dev_get_drvdata(port->dev);
- unsigned int result = 0;
-
- if (s->use_ms) {
- u32 sysflg = 0;
-
- regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg);
- if (sysflg & SYSFLG1_DCD)
- result |= TIOCM_CAR;
- if (sysflg & SYSFLG1_DSR)
- result |= TIOCM_DSR;
- if (sysflg & SYSFLG1_CTS)
- result |= TIOCM_CTS;
- } else
- result = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR;
- return result;
+ return mctrl_gpio_get(s->gpios, &result);
}
static void uart_clps711x_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
- /* Do nothing */
+ struct clps711x_port *s = dev_get_drvdata(port->dev);
+
+ mctrl_gpio_set(s->gpios, mctrl);
}
static void uart_clps711x_break_ctl(struct uart_port *port, int break_state)
@@ -490,15 +481,10 @@ static int uart_clps711x_probe(struct platform_device *pdev)
s->syscon = syscon_regmap_lookup_by_pdevname(syscon_name);
if (IS_ERR(s->syscon))
return PTR_ERR(s->syscon);
-
- s->use_ms = !index;
} else {
s->syscon = syscon_regmap_lookup_by_phandle(np, "syscon");
if (IS_ERR(s->syscon))
return PTR_ERR(s->syscon);
-
- if (!index)
- s->use_ms = of_property_read_bool(np, "uart-use-ms");
}
s->port.line = index;
@@ -513,6 +499,8 @@ static int uart_clps711x_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, s);
+ s->gpios = mctrl_gpio_init(&pdev->dev, 0);
+
ret = uart_add_one_port(&clps711x_uart, &s->port);
if (ret)
return ret;
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 044e86d528ae..8f62a3cec23e 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -80,6 +80,7 @@
#define URXD_FRMERR (1<<12)
#define URXD_BRK (1<<11)
#define URXD_PRERR (1<<10)
+#define URXD_RX_DATA (0xFF<<0)
#define UCR1_ADEN (1<<15) /* Auto detect interrupt */
#define UCR1_ADBR (1<<14) /* Auto detect baud rate */
#define UCR1_TRDYEN (1<<13) /* Transmitter ready interrupt enable */
@@ -435,12 +436,14 @@ static void imx_stop_rx(struct uart_port *port)
struct imx_port *sport = (struct imx_port *)port;
unsigned long temp;
- /*
- * We are maybe in the SMP context, so if the DMA TX thread is running
- * on other cpu, we have to wait for it to finish.
- */
- if (sport->dma_is_enabled && sport->dma_is_rxing)
- return;
+ if (sport->dma_is_enabled && sport->dma_is_rxing) {
+ if (sport->port.suspended) {
+ dmaengine_terminate_all(sport->dma_chan_rx);
+ sport->dma_is_rxing = 0;
+ } else {
+ return;
+ }
+ }
temp = readl(sport->port.membase + UCR2);
writel(temp & ~UCR2_RXEN, sport->port.membase + UCR2);
@@ -464,9 +467,19 @@ static inline void imx_transmit_buffer(struct imx_port *sport)
{
struct circ_buf *xmit = &sport->port.state->xmit;
+ if (sport->port.x_char) {
+ /* Send next char */
+ writel(sport->port.x_char, sport->port.membase + URTX0);
+ return;
+ }
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
+ imx_stop_tx(&sport->port);
+ return;
+ }
+
while (!uart_circ_empty(xmit) &&
- !(readl(sport->port.membase + uts_reg(sport))
- & UTS_TXFULL)) {
+ !(readl(sport->port.membase + uts_reg(sport)) & UTS_TXFULL)) {
/* send xmit->buf[xmit->tail]
* out the port here */
writel(xmit->buf[xmit->tail], sport->port.membase + URTX0);
@@ -567,9 +580,6 @@ static void imx_start_tx(struct uart_port *port)
struct imx_port *sport = (struct imx_port *)port;
unsigned long temp;
- if (uart_circ_empty(&port->state->xmit))
- return;
-
if (USE_IRDA(sport)) {
/* half duplex in IrDA mode; have to disable receive mode */
temp = readl(sport->port.membase + UCR4);
@@ -604,7 +614,10 @@ static void imx_start_tx(struct uart_port *port)
}
if (sport->dma_is_enabled) {
- imx_dma_tx(sport);
+ /* FIXME: port->x_char must be transmitted if != 0 */
+ if (!uart_circ_empty(&port->state->xmit) &&
+ !uart_tx_stopped(port))
+ imx_dma_tx(sport);
return;
}
@@ -632,27 +645,10 @@ static irqreturn_t imx_rtsint(int irq, void *dev_id)
static irqreturn_t imx_txint(int irq, void *dev_id)
{
struct imx_port *sport = dev_id;
- struct circ_buf *xmit = &sport->port.state->xmit;
unsigned long flags;
spin_lock_irqsave(&sport->port.lock, flags);
- if (sport->port.x_char) {
- /* Send next char */
- writel(sport->port.x_char, sport->port.membase + URTX0);
- goto out;
- }
-
- if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
- imx_stop_tx(&sport->port);
- goto out;
- }
-
imx_transmit_buffer(sport);
-
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(&sport->port);
-
-out:
spin_unlock_irqrestore(&sport->port.lock, flags);
return IRQ_HANDLED;
}
@@ -823,11 +819,9 @@ static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
struct imx_port *sport = (struct imx_port *)port;
unsigned long temp;
- temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS;
-
+ temp = readl(sport->port.membase + UCR2) & ~(UCR2_CTS | UCR2_CTSC);
if (mctrl & TIOCM_RTS)
- if (!sport->dma_is_enabled)
- temp |= UCR2_CTS;
+ temp |= UCR2_CTS | UCR2_CTSC;
writel(temp, sport->port.membase + UCR2);
@@ -1225,9 +1219,18 @@ static void imx_shutdown(struct uart_port *port)
unsigned long flags;
if (sport->dma_is_enabled) {
+ int ret;
+
/* We have to wait for the DMA to finish. */
- wait_event(sport->dma_wait,
+ ret = wait_event_interruptible(sport->dma_wait,
!sport->dma_is_rxing && !sport->dma_is_txing);
+ if (ret != 0) {
+ sport->dma_is_rxing = 0;
+ sport->dma_is_txing = 0;
+ dmaengine_terminate_all(sport->dma_chan_tx);
+ dmaengine_terminate_all(sport->dma_chan_rx);
+ }
+ imx_stop_tx(port);
imx_stop_rx(port);
imx_disable_dma(sport);
imx_uart_dma_exit(sport);
@@ -1506,32 +1509,10 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser)
#if defined(CONFIG_CONSOLE_POLL)
static int imx_poll_get_char(struct uart_port *port)
{
- struct imx_port_ucrs old_ucr;
- unsigned int status;
- unsigned char c;
-
- /* save control registers */
- imx_port_ucrs_save(port, &old_ucr);
-
- /* disable interrupts */
- writel(UCR1_UARTEN, port->membase + UCR1);
- writel(old_ucr.ucr2 & ~(UCR2_ATEN | UCR2_RTSEN | UCR2_ESCI),
- port->membase + UCR2);
- writel(old_ucr.ucr3 & ~(UCR3_DCD | UCR3_RI | UCR3_DTREN),
- port->membase + UCR3);
-
- /* poll */
- do {
- status = readl(port->membase + USR2);
- } while (~status & USR2_RDR);
-
- /* read */
- c = readl(port->membase + URXD0);
-
- /* restore control registers */
- imx_port_ucrs_restore(port, &old_ucr);
+ if (!(readl(port->membase + USR2) & USR2_RDR))
+ return NO_POLL_CHAR;
- return c;
+ return readl(port->membase + URXD0) & URXD_RX_DATA;
}
static void imx_poll_put_char(struct uart_port *port, unsigned char c)
diff --git a/drivers/tty/serial/jsm/jsm.h b/drivers/tty/serial/jsm/jsm.h
index 844d5e4eb1aa..af7013488aeb 100644
--- a/drivers/tty/serial/jsm/jsm.h
+++ b/drivers/tty/serial/jsm/jsm.h
@@ -67,6 +67,16 @@ do { \
#define MAXPORTS 8
#define MAX_STOPS_SENT 5
+/* Board ids */
+#define PCI_DEVICE_ID_NEO_4 0x00B0
+#define PCI_DEVICE_ID_NEO_1_422 0x00CC
+#define PCI_DEVICE_ID_NEO_1_422_485 0x00CD
+#define PCI_DEVICE_ID_NEO_2_422_485 0x00CE
+#define PCIE_DEVICE_ID_NEO_8 0x00F0
+#define PCIE_DEVICE_ID_NEO_4 0x00F1
+#define PCIE_DEVICE_ID_NEO_4RJ45 0x00F2
+#define PCIE_DEVICE_ID_NEO_8RJ45 0x00F3
+
/* Board type definitions */
#define T_NEO 0000
diff --git a/drivers/tty/serial/jsm/jsm_driver.c b/drivers/tty/serial/jsm/jsm_driver.c
index a47d882d6743..d2885a7bb090 100644
--- a/drivers/tty/serial/jsm/jsm_driver.c
+++ b/drivers/tty/serial/jsm/jsm_driver.c
@@ -93,12 +93,34 @@ static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* store the info for the board we've found */
brd->boardnum = adapter_count++;
brd->pci_dev = pdev;
- if (pdev->device == PCIE_DEVICE_ID_NEO_4_IBM)
+
+ switch (pdev->device) {
+
+ case PCI_DEVICE_ID_NEO_2DB9:
+ case PCI_DEVICE_ID_NEO_2DB9PRI:
+ case PCI_DEVICE_ID_NEO_2RJ45:
+ case PCI_DEVICE_ID_NEO_2RJ45PRI:
+ case PCI_DEVICE_ID_NEO_2_422_485:
+ brd->maxports = 2;
+ break;
+
+ case PCI_DEVICE_ID_NEO_4:
+ case PCIE_DEVICE_ID_NEO_4:
+ case PCIE_DEVICE_ID_NEO_4RJ45:
+ case PCIE_DEVICE_ID_NEO_4_IBM:
brd->maxports = 4;
- else if (pdev->device == PCI_DEVICE_ID_DIGI_NEO_8)
+ break;
+
+ case PCI_DEVICE_ID_DIGI_NEO_8:
+ case PCIE_DEVICE_ID_NEO_8:
+ case PCIE_DEVICE_ID_NEO_8RJ45:
brd->maxports = 8;
- else
- brd->maxports = 2;
+ break;
+
+ default:
+ brd->maxports = 1;
+ break;
+ }
spin_lock_init(&brd->bd_intr_lock);
@@ -209,6 +231,14 @@ static struct pci_device_id jsm_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45PRI), 0, 0, 3 },
{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_4_IBM), 0, 0, 4 },
{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_NEO_8), 0, 0, 5 },
+ { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_4), 0, 0, 6 },
+ { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_1_422), 0, 0, 7 },
+ { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_1_422_485), 0, 0, 8 },
+ { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2_422_485), 0, 0, 9 },
+ { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_8), 0, 0, 10 },
+ { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_4), 0, 0, 11 },
+ { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_4RJ45), 0, 0, 12 },
+ { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_8RJ45), 0, 0, 13 },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, jsm_pci_tbl);
diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c
index 6ec7501b464d..129dc5be6028 100644
--- a/drivers/tty/serial/kgdb_nmi.c
+++ b/drivers/tty/serial/kgdb_nmi.c
@@ -46,6 +46,8 @@ static atomic_t kgdb_nmi_num_readers = ATOMIC_INIT(0);
static int kgdb_nmi_console_setup(struct console *co, char *options)
{
+ arch_kgdb_ops.enable_nmi(1);
+
/* The NMI console uses the dbg_io_ops to issue console messages. To
* avoid duplicate messages during kdb sessions we must inform kdb's
* I/O utilities that messages sent to the console will automatically
@@ -77,7 +79,7 @@ static struct console kgdb_nmi_console = {
.setup = kgdb_nmi_console_setup,
.write = kgdb_nmi_console_write,
.device = kgdb_nmi_console_device,
- .flags = CON_PRINTBUFFER | CON_ANYTIME | CON_ENABLED,
+ .flags = CON_PRINTBUFFER | CON_ANYTIME,
.index = -1,
};
@@ -354,7 +356,6 @@ int kgdb_register_nmi_console(void)
}
register_console(&kgdb_nmi_console);
- arch_kgdb_ops.enable_nmi(1);
return 0;
err_drv_reg:
diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c
new file mode 100644
index 000000000000..15c749753317
--- /dev/null
+++ b/drivers/tty/serial/meson_uart.c
@@ -0,0 +1,634 @@
+/*
+ * Based on meson_uart.c, by AMLOGIC, INC.
+ *
+ * Copyright (C) 2014 Carlo Caione <carlo@caione.org>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+
+/* Register offsets */
+#define AML_UART_WFIFO 0x00
+#define AML_UART_RFIFO 0x04
+#define AML_UART_CONTROL 0x08
+#define AML_UART_STATUS 0x0c
+#define AML_UART_MISC 0x10
+#define AML_UART_REG5 0x14
+
+/* AML_UART_CONTROL bits */
+#define AML_UART_TX_EN BIT(12)
+#define AML_UART_RX_EN BIT(13)
+#define AML_UART_TX_RST BIT(22)
+#define AML_UART_RX_RST BIT(23)
+#define AML_UART_CLR_ERR BIT(24)
+#define AML_UART_RX_INT_EN BIT(27)
+#define AML_UART_TX_INT_EN BIT(28)
+#define AML_UART_DATA_LEN_MASK (0x03 << 20)
+#define AML_UART_DATA_LEN_8BIT (0x00 << 20)
+#define AML_UART_DATA_LEN_7BIT (0x01 << 20)
+#define AML_UART_DATA_LEN_6BIT (0x02 << 20)
+#define AML_UART_DATA_LEN_5BIT (0x03 << 20)
+
+/* AML_UART_STATUS bits */
+#define AML_UART_PARITY_ERR BIT(16)
+#define AML_UART_FRAME_ERR BIT(17)
+#define AML_UART_TX_FIFO_WERR BIT(18)
+#define AML_UART_RX_EMPTY BIT(20)
+#define AML_UART_TX_FULL BIT(21)
+#define AML_UART_TX_EMPTY BIT(22)
+#define AML_UART_ERR (AML_UART_PARITY_ERR | \
+ AML_UART_FRAME_ERR | \
+ AML_UART_TX_FIFO_WERR)
+
+/* AML_UART_CONTROL bits */
+#define AML_UART_TWO_WIRE_EN BIT(15)
+#define AML_UART_PARITY_TYPE BIT(18)
+#define AML_UART_PARITY_EN BIT(19)
+#define AML_UART_CLEAR_ERR BIT(24)
+#define AML_UART_STOP_BIN_LEN_MASK (0x03 << 16)
+#define AML_UART_STOP_BIN_1SB (0x00 << 16)
+#define AML_UART_STOP_BIN_2SB (0x01 << 16)
+
+/* AML_UART_MISC bits */
+#define AML_UART_XMIT_IRQ(c) (((c) & 0xff) << 8)
+#define AML_UART_RECV_IRQ(c) ((c) & 0xff)
+
+/* AML_UART_REG5 bits */
+#define AML_UART_BAUD_MASK 0x7fffff
+#define AML_UART_BAUD_USE BIT(23)
+
+#define AML_UART_PORT_NUM 6
+#define AML_UART_DEV_NAME "ttyAML"
+
+
+static struct uart_driver meson_uart_driver;
+
+static struct uart_port *meson_ports[AML_UART_PORT_NUM];
+
+static void meson_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static unsigned int meson_uart_get_mctrl(struct uart_port *port)
+{
+ return TIOCM_CTS;
+}
+
+static unsigned int meson_uart_tx_empty(struct uart_port *port)
+{
+ u32 val;
+
+ val = readl(port->membase + AML_UART_STATUS);
+ return (val & AML_UART_TX_EMPTY) ? TIOCSER_TEMT : 0;
+}
+
+static void meson_uart_stop_tx(struct uart_port *port)
+{
+ u32 val;
+
+ val = readl(port->membase + AML_UART_CONTROL);
+ val &= ~AML_UART_TX_EN;
+ writel(val, port->membase + AML_UART_CONTROL);
+}
+
+static void meson_uart_stop_rx(struct uart_port *port)
+{
+ u32 val;
+
+ val = readl(port->membase + AML_UART_CONTROL);
+ val &= ~AML_UART_RX_EN;
+ writel(val, port->membase + AML_UART_CONTROL);
+}
+
+static void meson_uart_shutdown(struct uart_port *port)
+{
+ unsigned long flags;
+ u32 val;
+
+ free_irq(port->irq, port);
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ val = readl(port->membase + AML_UART_CONTROL);
+ val &= ~(AML_UART_RX_EN | AML_UART_TX_EN);
+ val &= ~(AML_UART_RX_INT_EN | AML_UART_TX_INT_EN);
+ writel(val, port->membase + AML_UART_CONTROL);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void meson_uart_start_tx(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->state->xmit;
+ unsigned int ch;
+
+ if (uart_tx_stopped(port)) {
+ meson_uart_stop_tx(port);
+ return;
+ }
+
+ while (!(readl(port->membase + AML_UART_STATUS) & AML_UART_TX_FULL)) {
+ if (port->x_char) {
+ writel(port->x_char, port->membase + AML_UART_WFIFO);
+ port->icount.tx++;
+ port->x_char = 0;
+ continue;
+ }
+
+ if (uart_circ_empty(xmit))
+ break;
+
+ ch = xmit->buf[xmit->tail];
+ writel(ch, port->membase + AML_UART_WFIFO);
+ xmit->tail = (xmit->tail+1) & (SERIAL_XMIT_SIZE - 1);
+ port->icount.tx++;
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+}
+
+static void meson_receive_chars(struct uart_port *port)
+{
+ struct tty_port *tport = &port->state->port;
+ char flag;
+ u32 status, ch, mode;
+
+ do {
+ flag = TTY_NORMAL;
+ port->icount.rx++;
+ status = readl(port->membase + AML_UART_STATUS);
+
+ if (status & AML_UART_ERR) {
+ if (status & AML_UART_TX_FIFO_WERR)
+ port->icount.overrun++;
+ else if (status & AML_UART_FRAME_ERR)
+ port->icount.frame++;
+ else if (status & AML_UART_PARITY_ERR)
+ port->icount.frame++;
+
+ mode = readl(port->membase + AML_UART_CONTROL);
+ mode |= AML_UART_CLEAR_ERR;
+ writel(mode, port->membase + AML_UART_CONTROL);
+
+ /* It doesn't clear to 0 automatically */
+ mode &= ~AML_UART_CLEAR_ERR;
+ writel(mode, port->membase + AML_UART_CONTROL);
+
+ status &= port->read_status_mask;
+ if (status & AML_UART_FRAME_ERR)
+ flag = TTY_FRAME;
+ else if (status & AML_UART_PARITY_ERR)
+ flag = TTY_PARITY;
+ }
+
+ ch = readl(port->membase + AML_UART_RFIFO);
+ ch &= 0xff;
+
+ if ((status & port->ignore_status_mask) == 0)
+ tty_insert_flip_char(tport, ch, flag);
+
+ if (status & AML_UART_TX_FIFO_WERR)
+ tty_insert_flip_char(tport, 0, TTY_OVERRUN);
+
+ } while (!(readl(port->membase + AML_UART_STATUS) & AML_UART_RX_EMPTY));
+
+ spin_unlock(&port->lock);
+ tty_flip_buffer_push(tport);
+ spin_lock(&port->lock);
+}
+
+static irqreturn_t meson_uart_interrupt(int irq, void *dev_id)
+{
+ struct uart_port *port = (struct uart_port *)dev_id;
+
+ spin_lock(&port->lock);
+
+ if (!(readl(port->membase + AML_UART_STATUS) & AML_UART_RX_EMPTY))
+ meson_receive_chars(port);
+
+ if (!(readl(port->membase + AML_UART_STATUS) & AML_UART_TX_FULL))
+ meson_uart_start_tx(port);
+
+ spin_unlock(&port->lock);
+
+ return IRQ_HANDLED;
+}
+
+static const char *meson_uart_type(struct uart_port *port)
+{
+ return (port->type == PORT_MESON) ? "meson_uart" : NULL;
+}
+
+static int meson_uart_startup(struct uart_port *port)
+{
+ u32 val;
+ int ret = 0;
+
+ val = readl(port->membase + AML_UART_CONTROL);
+ val |= (AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLR_ERR);
+ writel(val, port->membase + AML_UART_CONTROL);
+
+ val &= ~(AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLR_ERR);
+ writel(val, port->membase + AML_UART_CONTROL);
+
+ val |= (AML_UART_RX_EN | AML_UART_TX_EN);
+ writel(val, port->membase + AML_UART_CONTROL);
+
+ val |= (AML_UART_RX_INT_EN | AML_UART_TX_INT_EN);
+ writel(val, port->membase + AML_UART_CONTROL);
+
+ val = (AML_UART_RECV_IRQ(1) | AML_UART_XMIT_IRQ(port->fifosize / 2));
+ writel(val, port->membase + AML_UART_MISC);
+
+ ret = request_irq(port->irq, meson_uart_interrupt, 0,
+ meson_uart_type(port), port);
+
+ return ret;
+}
+
+static void meson_uart_change_speed(struct uart_port *port, unsigned long baud)
+{
+ u32 val;
+
+ while (!(readl(port->membase + AML_UART_STATUS) & AML_UART_TX_EMPTY))
+ cpu_relax();
+
+ val = readl(port->membase + AML_UART_REG5);
+ val &= ~AML_UART_BAUD_MASK;
+ val = ((port->uartclk * 10 / (baud * 4) + 5) / 10) - 1;
+ val |= AML_UART_BAUD_USE;
+ writel(val, port->membase + AML_UART_REG5);
+}
+
+static void meson_uart_set_termios(struct uart_port *port,
+ struct ktermios *termios,
+ struct ktermios *old)
+{
+ unsigned int cflags, iflags, baud;
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ cflags = termios->c_cflag;
+ iflags = termios->c_iflag;
+
+ val = readl(port->membase + AML_UART_CONTROL);
+
+ val &= ~AML_UART_DATA_LEN_MASK;
+ switch (cflags & CSIZE) {
+ case CS8:
+ val |= AML_UART_DATA_LEN_8BIT;
+ break;
+ case CS7:
+ val |= AML_UART_DATA_LEN_7BIT;
+ break;
+ case CS6:
+ val |= AML_UART_DATA_LEN_6BIT;
+ break;
+ case CS5:
+ val |= AML_UART_DATA_LEN_5BIT;
+ break;
+ }
+
+ if (cflags & PARENB)
+ val |= AML_UART_PARITY_EN;
+ else
+ val &= ~AML_UART_PARITY_EN;
+
+ if (cflags & PARODD)
+ val |= AML_UART_PARITY_TYPE;
+ else
+ val &= ~AML_UART_PARITY_TYPE;
+
+ val &= ~AML_UART_STOP_BIN_LEN_MASK;
+ if (cflags & CSTOPB)
+ val |= AML_UART_STOP_BIN_2SB;
+ else
+ val &= ~AML_UART_STOP_BIN_1SB;
+
+ if (cflags & CRTSCTS)
+ val &= ~AML_UART_TWO_WIRE_EN;
+ else
+ val |= AML_UART_TWO_WIRE_EN;
+
+ writel(val, port->membase + AML_UART_CONTROL);
+
+ baud = uart_get_baud_rate(port, termios, old, 9600, 115200);
+ meson_uart_change_speed(port, baud);
+
+ port->read_status_mask = AML_UART_TX_FIFO_WERR;
+ if (iflags & INPCK)
+ port->read_status_mask |= AML_UART_PARITY_ERR |
+ AML_UART_FRAME_ERR;
+
+ port->ignore_status_mask = 0;
+ if (iflags & IGNPAR)
+ port->ignore_status_mask |= AML_UART_PARITY_ERR |
+ AML_UART_FRAME_ERR;
+
+ uart_update_timeout(port, termios->c_cflag, baud);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int meson_uart_verify_port(struct uart_port *port,
+ struct serial_struct *ser)
+{
+ int ret = 0;
+
+ if (port->type != PORT_MESON)
+ ret = -EINVAL;
+ if (port->irq != ser->irq)
+ ret = -EINVAL;
+ if (ser->baud_base < 9600)
+ ret = -EINVAL;
+ return ret;
+}
+
+static void meson_uart_release_port(struct uart_port *port)
+{
+ if (port->flags & UPF_IOREMAP) {
+ iounmap(port->membase);
+ port->membase = NULL;
+ }
+}
+
+static int meson_uart_request_port(struct uart_port *port)
+{
+ struct platform_device *pdev = to_platform_device(port->dev);
+ struct resource *res;
+ int size;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "cannot obtain I/O memory region");
+ return -ENODEV;
+ }
+ size = resource_size(res);
+
+ if (!devm_request_mem_region(port->dev, port->mapbase, size,
+ dev_name(port->dev))) {
+ dev_err(port->dev, "Memory region busy\n");
+ return -EBUSY;
+ }
+
+ if (port->flags & UPF_IOREMAP) {
+ port->membase = devm_ioremap_nocache(port->dev,
+ port->mapbase,
+ size);
+ if (port->membase == NULL)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void meson_uart_config_port(struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE) {
+ port->type = PORT_MESON;
+ meson_uart_request_port(port);
+ }
+}
+
+static struct uart_ops meson_uart_ops = {
+ .set_mctrl = meson_uart_set_mctrl,
+ .get_mctrl = meson_uart_get_mctrl,
+ .tx_empty = meson_uart_tx_empty,
+ .start_tx = meson_uart_start_tx,
+ .stop_tx = meson_uart_stop_tx,
+ .stop_rx = meson_uart_stop_rx,
+ .startup = meson_uart_startup,
+ .shutdown = meson_uart_shutdown,
+ .set_termios = meson_uart_set_termios,
+ .type = meson_uart_type,
+ .config_port = meson_uart_config_port,
+ .request_port = meson_uart_request_port,
+ .release_port = meson_uart_release_port,
+ .verify_port = meson_uart_verify_port,
+};
+
+#ifdef CONFIG_SERIAL_MESON_CONSOLE
+
+static void meson_console_putchar(struct uart_port *port, int ch)
+{
+ if (!port->membase)
+ return;
+
+ while (readl(port->membase + AML_UART_STATUS) & AML_UART_TX_FULL)
+ cpu_relax();
+ writel(ch, port->membase + AML_UART_WFIFO);
+}
+
+static void meson_serial_console_write(struct console *co, const char *s,
+ u_int count)
+{
+ struct uart_port *port;
+ unsigned long flags;
+ int locked;
+
+ port = meson_ports[co->index];
+ if (!port)
+ return;
+
+ local_irq_save(flags);
+ if (port->sysrq) {
+ locked = 0;
+ } else if (oops_in_progress) {
+ locked = spin_trylock(&port->lock);
+ } else {
+ spin_lock(&port->lock);
+ locked = 1;
+ }
+
+ uart_console_write(port, s, count, meson_console_putchar);
+
+ if (locked)
+ spin_unlock(&port->lock);
+ local_irq_restore(flags);
+}
+
+static int meson_serial_console_setup(struct console *co, char *options)
+{
+ struct uart_port *port;
+ int baud = 115200;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ if (co->index < 0 || co->index >= AML_UART_PORT_NUM)
+ return -EINVAL;
+
+ port = meson_ports[co->index];
+ if (!port || !port->membase)
+ return -ENODEV;
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct console meson_serial_console = {
+ .name = AML_UART_DEV_NAME,
+ .write = meson_serial_console_write,
+ .device = uart_console_device,
+ .setup = meson_serial_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &meson_uart_driver,
+};
+
+static int __init meson_serial_console_init(void)
+{
+ register_console(&meson_serial_console);
+ return 0;
+}
+console_initcall(meson_serial_console_init);
+
+#define MESON_SERIAL_CONSOLE (&meson_serial_console)
+#else
+#define MESON_SERIAL_CONSOLE NULL
+#endif
+
+static struct uart_driver meson_uart_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = "meson_uart",
+ .dev_name = AML_UART_DEV_NAME,
+ .nr = AML_UART_PORT_NUM,
+ .cons = MESON_SERIAL_CONSOLE,
+};
+
+static int meson_uart_probe(struct platform_device *pdev)
+{
+ struct resource *res_mem, *res_irq;
+ struct uart_port *port;
+ struct clk *clk;
+ int ret = 0;
+
+ if (pdev->dev.of_node)
+ pdev->id = of_alias_get_id(pdev->dev.of_node, "serial");
+
+ if (pdev->id < 0 || pdev->id >= AML_UART_PORT_NUM)
+ return -EINVAL;
+
+ res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res_mem)
+ return -ENODEV;
+
+ res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res_irq)
+ return -ENODEV;
+
+ if (meson_ports[pdev->id]) {
+ dev_err(&pdev->dev, "port %d already allocated\n", pdev->id);
+ return -EBUSY;
+ }
+
+ port = devm_kzalloc(&pdev->dev, sizeof(struct uart_port), GFP_KERNEL);
+ if (!port)
+ return -ENOMEM;
+
+ clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ port->uartclk = clk_get_rate(clk);
+ port->iotype = UPIO_MEM;
+ port->mapbase = res_mem->start;
+ port->irq = res_irq->start;
+ port->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_LOW_LATENCY;
+ port->dev = &pdev->dev;
+ port->line = pdev->id;
+ port->type = PORT_MESON;
+ port->x_char = 0;
+ port->ops = &meson_uart_ops;
+ port->fifosize = 64;
+
+ meson_ports[pdev->id] = port;
+ platform_set_drvdata(pdev, port);
+
+ ret = uart_add_one_port(&meson_uart_driver, port);
+ if (ret)
+ meson_ports[pdev->id] = NULL;
+
+ return ret;
+}
+
+static int meson_uart_remove(struct platform_device *pdev)
+{
+ struct uart_port *port;
+
+ port = platform_get_drvdata(pdev);
+ uart_remove_one_port(&meson_uart_driver, port);
+ meson_ports[pdev->id] = NULL;
+
+ return 0;
+}
+
+
+static const struct of_device_id meson_uart_dt_match[] = {
+ { .compatible = "amlogic,meson-uart" },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, meson_uart_dt_match);
+
+static struct platform_driver meson_uart_platform_driver = {
+ .probe = meson_uart_probe,
+ .remove = meson_uart_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "meson_uart",
+ .of_match_table = meson_uart_dt_match,
+ },
+};
+
+static int __init meson_uart_init(void)
+{
+ int ret;
+
+ ret = uart_register_driver(&meson_uart_driver);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&meson_uart_platform_driver);
+ if (ret)
+ uart_unregister_driver(&meson_uart_driver);
+
+ return ret;
+}
+
+static void __exit meson_uart_exit(void)
+{
+ platform_driver_unregister(&meson_uart_platform_driver);
+ uart_unregister_driver(&meson_uart_driver);
+}
+
+module_init(meson_uart_init);
+module_exit(meson_uart_exit);
+
+MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
+MODULE_DESCRIPTION("Amlogic Meson serial port driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c
index 97888f4900ec..a5f4e3648b15 100644
--- a/drivers/tty/serial/mpc52xx_uart.c
+++ b/drivers/tty/serial/mpc52xx_uart.c
@@ -1087,22 +1087,6 @@ mpc52xx_uart_start_tx(struct uart_port *port)
}
static void
-mpc52xx_uart_send_xchar(struct uart_port *port, char ch)
-{
- unsigned long flags;
- spin_lock_irqsave(&port->lock, flags);
-
- port->x_char = ch;
- if (ch) {
- /* Make sure tx interrupts are on */
- /* Truly necessary ??? They should be anyway */
- psc_ops->start_tx(port);
- }
-
- spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void
mpc52xx_uart_stop_rx(struct uart_port *port)
{
/* port->lock taken by caller */
@@ -1361,7 +1345,6 @@ static struct uart_ops mpc52xx_uart_ops = {
.get_mctrl = mpc52xx_uart_get_mctrl,
.stop_tx = mpc52xx_uart_stop_tx,
.start_tx = mpc52xx_uart_start_tx,
- .send_xchar = mpc52xx_uart_send_xchar,
.stop_rx = mpc52xx_uart_stop_rx,
.enable_ms = mpc52xx_uart_enable_ms,
.break_ctl = mpc52xx_uart_break_ctl,
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index 0da0b5474e98..4b6c78331a64 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -190,11 +190,10 @@ static void handle_rx(struct uart_port *port)
/* Mask conditions we're ignorning. */
sr &= port->read_status_mask;
- if (sr & UART_SR_RX_BREAK) {
+ if (sr & UART_SR_RX_BREAK)
flag = TTY_BREAK;
- } else if (sr & UART_SR_PAR_FRAME_ERR) {
+ else if (sr & UART_SR_PAR_FRAME_ERR)
flag = TTY_FRAME;
- }
if (!uart_handle_sysrq_char(port, c))
tty_insert_flip_char(tport, c, flag);
@@ -315,7 +314,6 @@ static unsigned int msm_get_mctrl(struct uart_port *port)
return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR | TIOCM_RTS;
}
-
static void msm_reset(struct uart_port *port)
{
struct msm_port *msm_port = UART_TO_MSM(port);
@@ -336,6 +334,7 @@ static void msm_reset(struct uart_port *port)
static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
unsigned int mr;
+
mr = msm_read(port, UART_MR1);
if (!(mctrl & TIOCM_RTS)) {
@@ -431,7 +430,6 @@ static int msm_set_baud_rate(struct uart_port *port, unsigned int baud)
return baud;
}
-
static void msm_init_clock(struct uart_port *port)
{
struct msm_port *msm_port = UART_TO_MSM(port);
@@ -646,6 +644,7 @@ fail_release_port:
static void msm_config_port(struct uart_port *port, int flags)
{
int ret;
+
if (flags & UART_CONFIG_TYPE) {
port->type = PORT_MSM;
ret = msm_request_port(port);
@@ -678,22 +677,11 @@ static void msm_power(struct uart_port *port, unsigned int state,
clk_disable_unprepare(msm_port->pclk);
break;
default:
- printk(KERN_ERR "msm_serial: Unknown PM state %d\n", state);
+ pr_err("msm_serial: Unknown PM state %d\n", state);
}
}
#ifdef CONFIG_CONSOLE_POLL
-static int msm_poll_init(struct uart_port *port)
-{
- struct msm_port *msm_port = UART_TO_MSM(port);
-
- /* Enable single character mode on RX FIFO */
- if (msm_port->is_uartdm >= UARTDM_1P4)
- msm_write(port, UARTDM_DMEN_RX_SC_ENABLE, UARTDM_DMEN);
-
- return 0;
-}
-
static int msm_poll_get_char_single(struct uart_port *port)
{
struct msm_port *msm_port = UART_TO_MSM(port);
@@ -701,11 +689,11 @@ static int msm_poll_get_char_single(struct uart_port *port)
if (!(msm_read(port, UART_SR) & UART_SR_RX_READY))
return NO_POLL_CHAR;
- else
- return msm_read(port, rf_reg) & 0xff;
+
+ return msm_read(port, rf_reg) & 0xff;
}
-static int msm_poll_get_char_dm_1p3(struct uart_port *port)
+static int msm_poll_get_char_dm(struct uart_port *port)
{
int c;
static u32 slop;
@@ -729,6 +717,10 @@ static int msm_poll_get_char_dm_1p3(struct uart_port *port)
slop = msm_read(port, UARTDM_RF);
c = sp[0];
count--;
+ msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR);
+ msm_write(port, 0xFFFFFF, UARTDM_DMRX);
+ msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE,
+ UART_CR);
} else {
c = NO_POLL_CHAR;
}
@@ -752,8 +744,8 @@ static int msm_poll_get_char(struct uart_port *port)
imr = msm_read(port, UART_IMR);
msm_write(port, 0, UART_IMR);
- if (msm_port->is_uartdm == UARTDM_1P3)
- c = msm_poll_get_char_dm_1p3(port);
+ if (msm_port->is_uartdm)
+ c = msm_poll_get_char_dm(port);
else
c = msm_poll_get_char_single(port);
@@ -788,8 +780,6 @@ static void msm_poll_put_char(struct uart_port *port, unsigned char c)
/* Enable interrupts */
msm_write(port, imr, UART_IMR);
-
- return;
}
#endif
@@ -812,7 +802,6 @@ static struct uart_ops msm_uart_pops = {
.verify_port = msm_verify_port,
.pm = msm_power,
#ifdef CONFIG_CONSOLE_POLL
- .poll_init = msm_poll_init,
.poll_get_char = msm_poll_get_char,
.poll_put_char = msm_poll_put_char,
#endif
@@ -856,22 +845,15 @@ static inline struct uart_port *get_port_from_line(unsigned int line)
}
#ifdef CONFIG_SERIAL_MSM_CONSOLE
-static void msm_console_write(struct console *co, const char *s,
- unsigned int count)
+static void __msm_console_write(struct uart_port *port, const char *s,
+ unsigned int count, bool is_uartdm)
{
int i;
- struct uart_port *port;
- struct msm_port *msm_port;
int num_newlines = 0;
bool replaced = false;
void __iomem *tf;
- BUG_ON(co->index < 0 || co->index >= UART_NR);
-
- port = get_port_from_line(co->index);
- msm_port = UART_TO_MSM(port);
-
- if (msm_port->is_uartdm)
+ if (is_uartdm)
tf = port->membase + UARTDM_TF;
else
tf = port->membase + UART_TF;
@@ -883,7 +865,7 @@ static void msm_console_write(struct console *co, const char *s,
count += num_newlines;
spin_lock(&port->lock);
- if (msm_port->is_uartdm)
+ if (is_uartdm)
reset_dm_count(port, count);
i = 0;
@@ -892,7 +874,7 @@ static void msm_console_write(struct console *co, const char *s,
unsigned int num_chars;
char buf[4] = { 0 };
- if (msm_port->is_uartdm)
+ if (is_uartdm)
num_chars = min(count - i, (unsigned int)sizeof(buf));
else
num_chars = 1;
@@ -921,6 +903,20 @@ static void msm_console_write(struct console *co, const char *s,
spin_unlock(&port->lock);
}
+static void msm_console_write(struct console *co, const char *s,
+ unsigned int count)
+{
+ struct uart_port *port;
+ struct msm_port *msm_port;
+
+ BUG_ON(co->index < 0 || co->index >= UART_NR);
+
+ port = get_port_from_line(co->index);
+ msm_port = UART_TO_MSM(port);
+
+ __msm_console_write(port, s, count, msm_port->is_uartdm);
+}
+
static int __init msm_console_setup(struct console *co, char *options)
{
struct uart_port *port;
@@ -958,11 +954,54 @@ static int __init msm_console_setup(struct console *co, char *options)
msm_write(port, UART_CR_TX_ENABLE, UART_CR);
}
- printk(KERN_INFO "msm_serial: console setup on port #%d\n", port->line);
+ pr_info("msm_serial: console setup on port #%d\n", port->line);
return uart_set_options(port, co, baud, parity, bits, flow);
}
+static void
+msm_serial_early_write(struct console *con, const char *s, unsigned n)
+{
+ struct earlycon_device *dev = con->data;
+
+ __msm_console_write(&dev->port, s, n, false);
+}
+
+static int __init
+msm_serial_early_console_setup(struct earlycon_device *device, const char *opt)
+{
+ if (!device->port.membase)
+ return -ENODEV;
+
+ device->con->write = msm_serial_early_write;
+ return 0;
+}
+EARLYCON_DECLARE(msm_serial, msm_serial_early_console_setup);
+OF_EARLYCON_DECLARE(msm_serial, "qcom,msm-uart",
+ msm_serial_early_console_setup);
+
+static void
+msm_serial_early_write_dm(struct console *con, const char *s, unsigned n)
+{
+ struct earlycon_device *dev = con->data;
+
+ __msm_console_write(&dev->port, s, n, true);
+}
+
+static int __init
+msm_serial_early_console_setup_dm(struct earlycon_device *device,
+ const char *opt)
+{
+ if (!device->port.membase)
+ return -ENODEV;
+
+ device->con->write = msm_serial_early_write_dm;
+ return 0;
+}
+EARLYCON_DECLARE(msm_serial_dm, msm_serial_early_console_setup_dm);
+OF_EARLYCON_DECLARE(msm_serial_dm, "qcom,msm-uartdm",
+ msm_serial_early_console_setup_dm);
+
static struct uart_driver msm_uart_driver;
static struct console msm_console = {
@@ -1013,7 +1052,7 @@ static int msm_serial_probe(struct platform_device *pdev)
if (unlikely(pdev->id < 0 || pdev->id >= UART_NR))
return -ENXIO;
- printk(KERN_INFO "msm_serial: detected port #%d\n", pdev->id);
+ dev_info(&pdev->dev, "msm_serial: detected port #%d\n", pdev->id);
port = get_port_from_line(pdev->id);
port->dev = &pdev->dev;
@@ -1038,8 +1077,7 @@ static int msm_serial_probe(struct platform_device *pdev)
}
port->uartclk = clk_get_rate(msm_port->clk);
- printk(KERN_INFO "uartclk = %d\n", port->uartclk);
-
+ dev_info(&pdev->dev, "uartclk = %d\n", port->uartclk);
resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (unlikely(!resource))
@@ -1093,7 +1131,7 @@ static int __init msm_serial_init(void)
if (unlikely(ret))
uart_unregister_driver(&msm_uart_driver);
- printk(KERN_INFO "msm_serial: driver initialized\n");
+ pr_info("msm_serial: driver initialized\n");
return ret;
}
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index b5c329248c81..10c29334fe2f 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -408,7 +408,7 @@ static void mxs_auart_set_mctrl(struct uart_port *u, unsigned mctrl)
ctrl &= ~(AUART_CTRL2_RTSEN | AUART_CTRL2_RTS);
if (mctrl & TIOCM_RTS) {
- if (tty_port_cts_enabled(&u->state->port))
+ if (uart_cts_enabled(u))
ctrl |= AUART_CTRL2_RTSEN;
else
ctrl |= AUART_CTRL2_RTS;
diff --git a/drivers/tty/serial/nwpserial.c b/drivers/tty/serial/nwpserial.c
index c06366b6bc29..5da7622e88c3 100644
--- a/drivers/tty/serial/nwpserial.c
+++ b/drivers/tty/serial/nwpserial.c
@@ -22,6 +22,7 @@
#include <linux/of_platform.h>
#include <linux/of_device.h>
#include <linux/nwpserial.h>
+#include <linux/delay.h>
#include <asm/prom.h>
#include <asm/dcr.h>
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c
index 68d4455f3cf9..8bc2563335ae 100644
--- a/drivers/tty/serial/of_serial.c
+++ b/drivers/tty/serial/of_serial.c
@@ -183,10 +183,6 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
"auto-flow-control"))
port8250.capabilities |= UART_CAP_AFE;
- if (of_property_read_bool(ofdev->dev.of_node,
- "has-hw-flow-control"))
- port8250.port.flags |= UPF_HARD_FLOW;
-
ret = serial8250_register_8250_port(&port8250);
break;
}
@@ -244,6 +240,32 @@ static int of_platform_serial_remove(struct platform_device *ofdev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int of_serial_suspend(struct device *dev)
+{
+ struct of_serial_info *info = dev_get_drvdata(dev);
+
+ serial8250_suspend_port(info->line);
+ if (info->clk)
+ clk_disable_unprepare(info->clk);
+
+ return 0;
+}
+
+static int of_serial_resume(struct device *dev)
+{
+ struct of_serial_info *info = dev_get_drvdata(dev);
+
+ if (info->clk)
+ clk_prepare_enable(info->clk);
+
+ serial8250_resume_port(info->line);
+
+ return 0;
+}
+#endif
+static SIMPLE_DEV_PM_OPS(of_serial_pm_ops, of_serial_suspend, of_serial_resume);
+
/*
* A few common types, add more as needed.
*/
@@ -275,6 +297,7 @@ static struct platform_driver of_platform_serial_driver = {
.name = "of_serial",
.owner = THIS_MODULE,
.of_match_table = of_platform_serial_table,
+ .pm = &of_serial_pm_ops,
},
.probe = of_platform_serial_probe,
.remove = of_platform_serial_remove,
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index d017cec8a34a..18c30cabe27f 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -239,6 +239,26 @@ static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable)
}
/*
+ * Calculate the absolute difference between the desired and actual baud
+ * rate for the given mode.
+ */
+static inline int calculate_baud_abs_diff(struct uart_port *port,
+ unsigned int baud, unsigned int mode)
+{
+ unsigned int n = port->uartclk / (mode * baud);
+ int abs_diff;
+
+ if (n == 0)
+ n = 1;
+
+ abs_diff = baud - (port->uartclk / (mode * n));
+ if (abs_diff < 0)
+ abs_diff = -abs_diff;
+
+ return abs_diff;
+}
+
+/*
* serial_omap_baud_is_mode16 - check if baud rate is MODE16X
* @port: uart port info
* @baud: baudrate for which mode needs to be determined
@@ -252,16 +272,10 @@ static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable)
static bool
serial_omap_baud_is_mode16(struct uart_port *port, unsigned int baud)
{
- unsigned int n13 = port->uartclk / (13 * baud);
- unsigned int n16 = port->uartclk / (16 * baud);
- int baudAbsDiff13 = baud - (port->uartclk / (13 * n13));
- int baudAbsDiff16 = baud - (port->uartclk / (16 * n16));
- if (baudAbsDiff13 < 0)
- baudAbsDiff13 = -baudAbsDiff13;
- if (baudAbsDiff16 < 0)
- baudAbsDiff16 = -baudAbsDiff16;
-
- return (baudAbsDiff13 >= baudAbsDiff16);
+ int abs_diff_13 = calculate_baud_abs_diff(port, baud, 13);
+ int abs_diff_16 = calculate_baud_abs_diff(port, baud, 16);
+
+ return (abs_diff_13 >= abs_diff_16);
}
/*
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 29a7be47389a..df3a8c74358e 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -59,6 +59,11 @@ static void uart_change_pm(struct uart_state *state,
static void uart_port_shutdown(struct tty_port *port);
+static int uart_dcd_enabled(struct uart_port *uport)
+{
+ return uport->status & UPSTAT_DCD_ENABLE;
+}
+
/*
* This routine is used by the interrupt handler to schedule processing in
* the software interrupt portion of the driver.
@@ -90,7 +95,7 @@ static void __uart_start(struct tty_struct *tty)
struct uart_state *state = tty->driver_data;
struct uart_port *port = state->uart_port;
- if (!tty->stopped && !tty->hw_stopped)
+ if (!uart_tx_stopped(port))
port->ops->start_tx(port);
}
@@ -130,7 +135,6 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
int init_hw)
{
struct uart_port *uport = state->uart_port;
- struct tty_port *port = &state->port;
unsigned long page;
int retval = 0;
@@ -175,17 +179,14 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
if (tty->termios.c_cflag & CBAUD)
uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
}
- /*
- * if hw support flow control without software intervention,
- * then skip the below check
- */
- if (tty_port_cts_enabled(port) &&
- !(uport->flags & UPF_HARD_FLOW)) {
- spin_lock_irq(&uport->lock);
- if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS))
- tty->hw_stopped = 1;
- spin_unlock_irq(&uport->lock);
- }
+
+ spin_lock_irq(&uport->lock);
+ if (uart_cts_enabled(uport) &&
+ !(uport->ops->get_mctrl(uport) & TIOCM_CTS))
+ uport->hw_stopped = 1;
+ else
+ uport->hw_stopped = 0;
+ spin_unlock_irq(&uport->lock);
}
/*
@@ -439,7 +440,6 @@ EXPORT_SYMBOL(uart_get_divisor);
static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
struct ktermios *old_termios)
{
- struct tty_port *port = &state->port;
struct uart_port *uport = state->uart_port;
struct ktermios *termios;
@@ -454,17 +454,19 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
uport->ops->set_termios(uport, termios, old_termios);
/*
- * Set flags based on termios cflag
+ * Set modem status enables based on termios cflag
*/
+ spin_lock_irq(&uport->lock);
if (termios->c_cflag & CRTSCTS)
- set_bit(ASYNCB_CTS_FLOW, &port->flags);
+ uport->status |= UPSTAT_CTS_ENABLE;
else
- clear_bit(ASYNCB_CTS_FLOW, &port->flags);
+ uport->status &= ~UPSTAT_CTS_ENABLE;
if (termios->c_cflag & CLOCAL)
- clear_bit(ASYNCB_CHECK_CD, &port->flags);
+ uport->status &= ~UPSTAT_DCD_ENABLE;
else
- set_bit(ASYNCB_CHECK_CD, &port->flags);
+ uport->status |= UPSTAT_DCD_ENABLE;
+ spin_unlock_irq(&uport->lock);
}
static inline int __uart_put_char(struct uart_port *port,
@@ -604,12 +606,11 @@ static void uart_send_xchar(struct tty_struct *tty, char ch)
if (port->ops->send_xchar)
port->ops->send_xchar(port, ch);
else {
+ spin_lock_irqsave(&port->lock, flags);
port->x_char = ch;
- if (ch) {
- spin_lock_irqsave(&port->lock, flags);
+ if (ch)
port->ops->start_tx(port);
- spin_unlock_irqrestore(&port->lock, flags);
- }
+ spin_unlock_irqrestore(&port->lock, flags);
}
}
@@ -652,12 +653,8 @@ static void uart_unthrottle(struct tty_struct *tty)
mask &= ~port->flags;
}
- if (mask & UPF_SOFT_FLOW) {
- if (port->x_char)
- port->x_char = 0;
- else
- uart_send_xchar(tty, START_CHAR(tty));
- }
+ if (mask & UPF_SOFT_FLOW)
+ uart_send_xchar(tty, START_CHAR(tty));
if (mask & UPF_HARD_FLOW)
uart_set_mctrl(port, TIOCM_RTS);
@@ -892,10 +889,11 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
*/
if (uport->flags & UPF_SPD_MASK) {
char buf[64];
- printk(KERN_NOTICE
- "%s sets custom speed on %s. This "
- "is deprecated.\n", current->comm,
- tty_name(port->tty, buf));
+
+ dev_notice(uport->dev,
+ "%s sets custom speed on %s. This is deprecated.\n",
+ current->comm,
+ tty_name(port->tty, buf));
}
uart_change_speed(tty, state, NULL);
}
@@ -952,7 +950,7 @@ static int uart_get_lsr_info(struct tty_struct *tty,
*/
if (uport->x_char ||
((uart_circ_chars_pending(&state->xmit) > 0) &&
- !tty->stopped && !tty->hw_stopped))
+ !uart_tx_stopped(uport)))
result &= ~TIOCSER_TEMT;
return put_user(result, value);
@@ -1251,7 +1249,6 @@ static void uart_set_termios(struct tty_struct *tty,
{
struct uart_state *state = tty->driver_data;
struct uart_port *uport = state->uart_port;
- unsigned long flags;
unsigned int cflag = tty->termios.c_cflag;
unsigned int iflag_mask = IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK;
bool sw_changed = false;
@@ -1291,34 +1288,33 @@ static void uart_set_termios(struct tty_struct *tty,
/* Handle transition away from B0 status */
else if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
unsigned int mask = TIOCM_DTR;
- if (!(cflag & CRTSCTS) ||
- !test_bit(TTY_THROTTLED, &tty->flags))
+ if (!(cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags))
mask |= TIOCM_RTS;
uart_set_mctrl(uport, mask);
}
/*
* If the port is doing h/w assisted flow control, do nothing.
- * We assume that tty->hw_stopped has never been set.
+ * We assume that port->hw_stopped has never been set.
*/
if (uport->flags & UPF_HARD_FLOW)
return;
/* Handle turning off CRTSCTS */
if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) {
- spin_lock_irqsave(&uport->lock, flags);
- tty->hw_stopped = 0;
+ spin_lock_irq(&uport->lock);
+ uport->hw_stopped = 0;
__uart_start(tty);
- spin_unlock_irqrestore(&uport->lock, flags);
+ spin_unlock_irq(&uport->lock);
}
/* Handle turning on CRTSCTS */
else if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
- spin_lock_irqsave(&uport->lock, flags);
+ spin_lock_irq(&uport->lock);
if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) {
- tty->hw_stopped = 1;
+ uport->hw_stopped = 1;
uport->ops->stop_tx(uport);
}
- spin_unlock_irqrestore(&uport->lock, flags);
+ spin_unlock_irq(&uport->lock);
}
}
@@ -1975,12 +1971,9 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
for (tries = 3; !ops->tx_empty(uport) && tries; tries--)
msleep(10);
if (!tries)
- printk(KERN_ERR "%s%s%s%d: Unable to drain "
- "transmitter\n",
- uport->dev ? dev_name(uport->dev) : "",
- uport->dev ? ": " : "",
- drv->dev_name,
- drv->tty_driver->name_base + uport->line);
+ dev_err(uport->dev, "%s%d: Unable to drain transmitter\n",
+ drv->dev_name,
+ drv->tty_driver->name_base + uport->line);
if (console_suspend_enabled || !uart_console(uport))
ops->shutdown(uport);
@@ -2109,9 +2102,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
break;
}
- printk(KERN_INFO "%s%s%s%d at %s (irq = %d, base_baud = %d) is a %s\n",
- port->dev ? dev_name(port->dev) : "",
- port->dev ? ": " : "",
+ dev_info(port->dev, "%s%d at %s (irq = %d, base_baud = %d) is a %s\n",
drv->dev_name,
drv->tty_driver->name_base + port->line,
address, port->irq, port->uartclk / 16, uart_type(port));
@@ -2640,7 +2631,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
if (likely(!IS_ERR(tty_dev))) {
device_set_wakeup_capable(tty_dev, 1);
} else {
- printk(KERN_ERR "Cannot register tty device on line %d\n",
+ dev_err(uport->dev, "Cannot register tty device on line %d\n",
uport->line);
}
@@ -2675,7 +2666,7 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
BUG_ON(in_interrupt());
if (state->uart_port != uport)
- printk(KERN_ALERT "Removing wrong port: %p != %p\n",
+ dev_alert(uport->dev, "Removing wrong port: %p != %p\n",
state->uart_port, uport);
mutex_lock(&port_mutex);
@@ -2757,22 +2748,29 @@ EXPORT_SYMBOL(uart_match_port);
* uart_handle_dcd_change - handle a change of carrier detect state
* @uport: uart_port structure for the open port
* @status: new carrier detect status, nonzero if active
+ *
+ * Caller must hold uport->lock
*/
void uart_handle_dcd_change(struct uart_port *uport, unsigned int status)
{
struct tty_port *port = &uport->state->port;
struct tty_struct *tty = port->tty;
- struct tty_ldisc *ld = tty ? tty_ldisc_ref(tty) : NULL;
+ struct tty_ldisc *ld;
- if (ld) {
- if (ld->ops->dcd_change)
- ld->ops->dcd_change(tty, status);
- tty_ldisc_deref(ld);
+ lockdep_assert_held_once(&uport->lock);
+
+ if (tty) {
+ ld = tty_ldisc_ref(tty);
+ if (ld) {
+ if (ld->ops->dcd_change)
+ ld->ops->dcd_change(tty, status);
+ tty_ldisc_deref(ld);
+ }
}
uport->icount.dcd++;
- if (port->flags & ASYNC_CHECK_CD) {
+ if (uart_dcd_enabled(uport)) {
if (status)
wake_up_interruptible(&port->open_wait);
else if (tty)
@@ -2785,26 +2783,25 @@ EXPORT_SYMBOL_GPL(uart_handle_dcd_change);
* uart_handle_cts_change - handle a change of clear-to-send state
* @uport: uart_port structure for the open port
* @status: new clear to send status, nonzero if active
+ *
+ * Caller must hold uport->lock
*/
void uart_handle_cts_change(struct uart_port *uport, unsigned int status)
{
- struct tty_port *port = &uport->state->port;
- struct tty_struct *tty = port->tty;
+ lockdep_assert_held_once(&uport->lock);
uport->icount.cts++;
- /* skip below code if the hw flow control is supported */
- if (tty_port_cts_enabled(port) &&
- !(uport->flags & UPF_HARD_FLOW)) {
- if (tty->hw_stopped) {
+ if (uart_cts_enabled(uport)) {
+ if (uport->hw_stopped) {
if (status) {
- tty->hw_stopped = 0;
+ uport->hw_stopped = 0;
uport->ops->start_tx(uport);
uart_write_wakeup(uport);
}
} else {
if (!status) {
- tty->hw_stopped = 1;
+ uport->hw_stopped = 1;
uport->ops->stop_tx(uport);
}
}
diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c
index bf9560ffe3f4..a3035f997b98 100644
--- a/drivers/tty/serial/serial_mctrl_gpio.c
+++ b/drivers/tty/serial/serial_mctrl_gpio.c
@@ -18,7 +18,7 @@
#include <linux/err.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
-#include <uapi/asm-generic/termios.h>
+#include <linux/termios.h>
#include "serial_mctrl_gpio.h"
diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index 8b2d7356611d..a3165842ca29 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -151,12 +151,20 @@ static inline struct asc_port *to_asc_port(struct uart_port *port)
static inline u32 asc_in(struct uart_port *port, u32 offset)
{
+#ifdef readl_relaxed
+ return readl_relaxed(port->membase + offset);
+#else
return readl(port->membase + offset);
+#endif
}
static inline void asc_out(struct uart_port *port, u32 offset, u32 value)
{
+#ifdef writel_relaxed
+ writel_relaxed(value, port->membase + offset);
+#else
writel(value, port->membase + offset);
+#endif
}
/*
diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c
index 20521db2189f..25d43ce8b318 100644
--- a/drivers/tty/serial/sunhv.c
+++ b/drivers/tty/serial/sunhv.c
@@ -268,6 +268,9 @@ static void sunhv_send_xchar(struct uart_port *port, char ch)
unsigned long flags;
int limit = 10000;
+ if (ch == __DISABLED_CHAR)
+ return;
+
spin_lock_irqsave(&port->lock, flags);
while (limit-- > 0) {
diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c
index b9598b227a45..b339fe4811cd 100644
--- a/drivers/tty/serial/sunsab.c
+++ b/drivers/tty/serial/sunsab.c
@@ -436,7 +436,7 @@ static void sunsab_start_tx(struct uart_port *port)
struct circ_buf *xmit = &up->port.state->xmit;
int i;
- if (uart_circ_empty(xmit))
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port))
return;
up->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS|SAB82532_IMR1_XPR);
@@ -468,6 +468,9 @@ static void sunsab_send_xchar(struct uart_port *port, char ch)
struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
unsigned long flags;
+ if (ch == __DISABLED_CHAR)
+ return;
+
spin_lock_irqsave(&up->port.lock, flags);
sunsab_tec_wait(up);
diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c
index 9fc22f40796e..189f52e3111f 100644
--- a/drivers/tty/serial/uartlite.c
+++ b/drivers/tty/serial/uartlite.c
@@ -665,7 +665,6 @@ static struct platform_driver ulite_platform_driver = {
.probe = ulite_probe,
.remove = ulite_remove,
.driver = {
- .owner = THIS_MODULE,
.name = "uartlite",
.of_match_table = of_match_ptr(ulite_of_match),
},
diff --git a/drivers/tty/serial/vr41xx_siu.c b/drivers/tty/serial/vr41xx_siu.c
index db0c8a4ab03e..d7f9d622cdcb 100644
--- a/drivers/tty/serial/vr41xx_siu.c
+++ b/drivers/tty/serial/vr41xx_siu.c
@@ -847,7 +847,6 @@ void __init vr41xx_siu_early_setup(struct uart_port *port)
siu_uart_ports[port->line].type = port->type;
siu_uart_ports[port->line].uartclk = SIU_BAUD_BASE * 16;
siu_uart_ports[port->line].mapbase = port->mapbase;
- siu_uart_ports[port->line].mapbase = port->mapbase;
siu_uart_ports[port->line].ops = &siu_uart_ops;
}
diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c
index 15ad6fcda88b..b2bc9e8ba048 100644
--- a/drivers/tty/serial/vt8500_serial.c
+++ b/drivers/tty/serial/vt8500_serial.c
@@ -33,8 +33,8 @@
#include <linux/serial.h>
#include <linux/slab.h>
#include <linux/clk.h>
-#include <linux/platform_device.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/err.h>
/*
@@ -78,13 +78,40 @@
#define RX_FIFO_INTS (RXFAF | RXFF | RXOVER | PER | FER | RXTOUT)
#define TX_FIFO_INTS (TXFAE | TXFE | TXUDR)
+/*
+ * Line control bits
+ */
+
+#define VT8500_TXEN (1 << 0) /* Enable transmit logic */
+#define VT8500_RXEN (1 << 1) /* Enable receive logic */
+#define VT8500_CS8 (1 << 2) /* 8-bit data length (vs. 7-bit) */
+#define VT8500_CSTOPB (1 << 3) /* 2 stop bits (vs. 1) */
+#define VT8500_PARENB (1 << 4) /* Enable parity */
+#define VT8500_PARODD (1 << 5) /* Odd parity (vs. even) */
+#define VT8500_RTS (1 << 6) /* Ready to send */
+#define VT8500_LOOPBK (1 << 7) /* Enable internal loopback */
+#define VT8500_DMA (1 << 8) /* Enable DMA mode (needs FIFO) */
+#define VT8500_BREAK (1 << 9) /* Initiate break signal */
+#define VT8500_PSLVERR (1 << 10) /* APB error upon empty RX FIFO read */
+#define VT8500_SWRTSCTS (1 << 11) /* Software-controlled RTS/CTS */
+
+/*
+ * Capability flags (driver-internal)
+ */
+
+#define VT8500_HAS_SWRTSCTS_SWITCH (1 << 1)
+
+#define VT8500_RECOMMENDED_CLK 12000000
+#define VT8500_OVERSAMPLING_DIVISOR 13
#define VT8500_MAX_PORTS 6
struct vt8500_port {
struct uart_port uart;
char name[16];
struct clk *clk;
+ unsigned int clk_predivisor;
unsigned int ier;
+ unsigned int vt8500_uart_flags;
};
/*
@@ -267,31 +294,45 @@ static unsigned int vt8500_get_mctrl(struct uart_port *port)
static void vt8500_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
+ unsigned int lcr = vt8500_read(port, VT8500_URLCR);
+
+ if (mctrl & TIOCM_RTS)
+ lcr |= VT8500_RTS;
+ else
+ lcr &= ~VT8500_RTS;
+
+ vt8500_write(port, lcr, VT8500_URLCR);
}
static void vt8500_break_ctl(struct uart_port *port, int break_ctl)
{
if (break_ctl)
- vt8500_write(port, vt8500_read(port, VT8500_URLCR) | (1 << 9),
+ vt8500_write(port,
+ vt8500_read(port, VT8500_URLCR) | VT8500_BREAK,
VT8500_URLCR);
}
static int vt8500_set_baud_rate(struct uart_port *port, unsigned int baud)
{
+ struct vt8500_port *vt8500_port =
+ container_of(port, struct vt8500_port, uart);
unsigned long div;
unsigned int loops = 1000;
- div = vt8500_read(port, VT8500_URDIV) & ~(0x3ff);
+ div = ((vt8500_port->clk_predivisor - 1) & 0xf) << 16;
+ div |= (uart_get_divisor(port, baud) - 1) & 0x3ff;
- if (unlikely((baud < 900) || (baud > 921600)))
- div |= 7;
- else
- div |= (921600 / baud) - 1;
+ /* Effective baud rate */
+ baud = port->uartclk / 16 / ((div & 0x3ff) + 1);
while ((vt8500_read(port, VT8500_URUSR) & (1 << 5)) && --loops)
cpu_relax();
+
vt8500_write(port, div, VT8500_URDIV);
+ /* Break signal timing depends on baud rate, update accordingly */
+ vt8500_write(port, mult_frac(baud, 4096, 1000000), VT8500_URBKR);
+
return baud;
}
@@ -347,31 +388,35 @@ static void vt8500_set_termios(struct uart_port *port,
/* calculate parity */
lcr = vt8500_read(&vt8500_port->uart, VT8500_URLCR);
- lcr &= ~((1 << 5) | (1 << 4));
+ lcr &= ~(VT8500_PARENB | VT8500_PARODD);
if (termios->c_cflag & PARENB) {
- lcr |= (1 << 4);
+ lcr |= VT8500_PARENB;
termios->c_cflag &= ~CMSPAR;
if (termios->c_cflag & PARODD)
- lcr |= (1 << 5);
+ lcr |= VT8500_PARODD;
}
/* calculate bits per char */
- lcr &= ~(1 << 2);
+ lcr &= ~VT8500_CS8;
switch (termios->c_cflag & CSIZE) {
case CS7:
break;
case CS8:
default:
- lcr |= (1 << 2);
+ lcr |= VT8500_CS8;
termios->c_cflag &= ~CSIZE;
termios->c_cflag |= CS8;
break;
}
/* calculate stop bits */
- lcr &= ~(1 << 3);
+ lcr &= ~VT8500_CSTOPB;
if (termios->c_cflag & CSTOPB)
- lcr |= (1 << 3);
+ lcr |= VT8500_CSTOPB;
+
+ lcr &= ~VT8500_SWRTSCTS;
+ if (vt8500_port->vt8500_uart_flags & VT8500_HAS_SWRTSCTS_SWITCH)
+ lcr |= VT8500_SWRTSCTS;
/* set parity, bits per char, and stop bit */
vt8500_write(&vt8500_port->uart, lcr, VT8500_URLCR);
@@ -521,6 +566,33 @@ static struct console vt8500_console = {
#define VT8500_CONSOLE NULL
#endif
+#ifdef CONFIG_CONSOLE_POLL
+static int vt8500_get_poll_char(struct uart_port *port)
+{
+ unsigned int status = vt8500_read(port, VT8500_URFIDX);
+
+ if (!(status & 0x1f00))
+ return NO_POLL_CHAR;
+
+ return vt8500_read(port, VT8500_RXFIFO) & 0xff;
+}
+
+static void vt8500_put_poll_char(struct uart_port *port, unsigned char c)
+{
+ unsigned int status, tmout = 10000;
+
+ do {
+ status = vt8500_read(port, VT8500_URFIDX);
+
+ if (--tmout == 0)
+ break;
+ udelay(1);
+ } while (status & 0x10);
+
+ vt8500_write(port, c, VT8500_TXFIFO);
+}
+#endif
+
static struct uart_ops vt8500_uart_pops = {
.tx_empty = vt8500_tx_empty,
.set_mctrl = vt8500_set_mctrl,
@@ -538,6 +610,10 @@ static struct uart_ops vt8500_uart_pops = {
.request_port = vt8500_request_port,
.config_port = vt8500_config_port,
.verify_port = vt8500_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_get_char = vt8500_get_poll_char,
+ .poll_put_char = vt8500_put_poll_char,
+#endif
};
static struct uart_driver vt8500_uart_driver = {
@@ -548,14 +624,31 @@ static struct uart_driver vt8500_uart_driver = {
.cons = VT8500_CONSOLE,
};
+static unsigned int vt8500_flags; /* none required so far */
+static unsigned int wm8880_flags = VT8500_HAS_SWRTSCTS_SWITCH;
+
+static const struct of_device_id wmt_dt_ids[] = {
+ { .compatible = "via,vt8500-uart", .data = &vt8500_flags},
+ { .compatible = "wm,wm8880-uart", .data = &wm8880_flags},
+ {}
+};
+
static int vt8500_serial_probe(struct platform_device *pdev)
{
struct vt8500_port *vt8500_port;
struct resource *mmres, *irqres;
struct device_node *np = pdev->dev.of_node;
+ const struct of_device_id *match;
+ const unsigned int *flags;
int ret;
int port;
+ match = of_match_device(wmt_dt_ids, &pdev->dev);
+ if (!match)
+ return -EINVAL;
+
+ flags = match->data;
+
mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!mmres || !irqres)
@@ -605,6 +698,11 @@ static int vt8500_serial_probe(struct platform_device *pdev)
return ret;
}
+ vt8500_port->vt8500_uart_flags = *flags;
+ vt8500_port->clk_predivisor = DIV_ROUND_CLOSEST(
+ clk_get_rate(vt8500_port->clk),
+ VT8500_RECOMMENDED_CLK
+ );
vt8500_port->uart.type = PORT_VT8500;
vt8500_port->uart.iotype = UPIO_MEM;
vt8500_port->uart.mapbase = mmres->start;
@@ -615,7 +713,10 @@ static int vt8500_serial_probe(struct platform_device *pdev)
vt8500_port->uart.dev = &pdev->dev;
vt8500_port->uart.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
- vt8500_port->uart.uartclk = clk_get_rate(vt8500_port->clk);
+ /* Serial core uses the magic "16" everywhere - adjust for it */
+ vt8500_port->uart.uartclk = 16 * clk_get_rate(vt8500_port->clk) /
+ vt8500_port->clk_predivisor /
+ VT8500_OVERSAMPLING_DIVISOR;
snprintf(vt8500_port->name, sizeof(vt8500_port->name),
"VT8500 UART%d", pdev->id);
@@ -639,11 +740,6 @@ static int vt8500_serial_remove(struct platform_device *pdev)
return 0;
}
-static const struct of_device_id wmt_dt_ids[] = {
- { .compatible = "via,vt8500-uart", },
- {}
-};
-
static struct platform_driver vt8500_platform_driver = {
.probe = vt8500_serial_probe,
.remove = vt8500_serial_remove,
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index 806e4bcadbd7..200c1af2141b 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -1051,6 +1051,25 @@ static void cdns_uart_console_putchar(struct uart_port *port, int ch)
cdns_uart_writel(ch, CDNS_UART_FIFO_OFFSET);
}
+static void cdns_early_write(struct console *con, const char *s, unsigned n)
+{
+ struct earlycon_device *dev = con->data;
+
+ uart_console_write(&dev->port, s, n, cdns_uart_console_putchar);
+}
+
+static int __init cdns_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ if (!device->port.membase)
+ return -ENODEV;
+
+ device->con->write = cdns_early_write;
+
+ return 0;
+}
+EARLYCON_DECLARE(cdns, cdns_early_console_setup);
+
/**
* cdns_uart_console_write - perform write operation
* @co: Console handle
@@ -1428,7 +1447,6 @@ static struct platform_driver cdns_uart_platform_driver = {
.probe = cdns_uart_probe,
.remove = cdns_uart_remove,
.driver = {
- .owner = THIS_MODULE,
.name = CDNS_UART_NAME,
.of_match_table = cdns_uart_of_match,
.pm = &cdns_uart_dev_pm_ops,
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 8fbad3410c75..2f6f9b5e4891 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -908,8 +908,7 @@ void no_tty(void)
* stop_tty - propagate flow control
* @tty: tty to stop
*
- * Perform flow control to the driver. For PTY/TTY pairs we
- * must also propagate the TIOCKPKT status. May be called
+ * Perform flow control to the driver. May be called
* on an already stopped device and will not re-call the driver
* method.
*
@@ -919,64 +918,58 @@ void no_tty(void)
* but not always.
*
* Locking:
- * Uses the tty control lock internally
+ * flow_lock
*/
-void stop_tty(struct tty_struct *tty)
+void __stop_tty(struct tty_struct *tty)
{
- unsigned long flags;
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- if (tty->stopped) {
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ if (tty->stopped)
return;
- }
tty->stopped = 1;
- if (tty->link && tty->link->packet) {
- tty->ctrl_status &= ~TIOCPKT_START;
- tty->ctrl_status |= TIOCPKT_STOP;
- wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
- }
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
if (tty->ops->stop)
(tty->ops->stop)(tty);
}
+void stop_tty(struct tty_struct *tty)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&tty->flow_lock, flags);
+ __stop_tty(tty);
+ spin_unlock_irqrestore(&tty->flow_lock, flags);
+}
EXPORT_SYMBOL(stop_tty);
/**
* start_tty - propagate flow control
* @tty: tty to start
*
- * Start a tty that has been stopped if at all possible. Perform
- * any necessary wakeups and propagate the TIOCPKT status. If this
- * is the tty was previous stopped and is being started then the
- * driver start method is invoked and the line discipline woken.
+ * Start a tty that has been stopped if at all possible. If this
+ * tty was previous stopped and is now being started, the driver
+ * start method is invoked and the line discipline woken.
*
* Locking:
- * ctrl_lock
+ * flow_lock
*/
-void start_tty(struct tty_struct *tty)
+void __start_tty(struct tty_struct *tty)
{
- unsigned long flags;
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- if (!tty->stopped || tty->flow_stopped) {
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ if (!tty->stopped || tty->flow_stopped)
return;
- }
tty->stopped = 0;
- if (tty->link && tty->link->packet) {
- tty->ctrl_status &= ~TIOCPKT_STOP;
- tty->ctrl_status |= TIOCPKT_START;
- wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
- }
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
if (tty->ops->start)
(tty->ops->start)(tty);
- /* If we have a running line discipline it may need kicking */
tty_wakeup(tty);
}
+void start_tty(struct tty_struct *tty)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&tty->flow_lock, flags);
+ __start_tty(tty);
+ spin_unlock_irqrestore(&tty->flow_lock, flags);
+}
EXPORT_SYMBOL(start_tty);
/* We limit tty time update visibility to every 8 seconds or so. */
@@ -1030,14 +1023,14 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
return i;
}
-void tty_write_unlock(struct tty_struct *tty)
+static void tty_write_unlock(struct tty_struct *tty)
__releases(&tty->atomic_write_lock)
{
mutex_unlock(&tty->atomic_write_lock);
wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
}
-int tty_write_lock(struct tty_struct *tty, int ndelay)
+static int tty_write_lock(struct tty_struct *tty, int ndelay)
__acquires(&tty->atomic_write_lock)
{
if (!mutex_trylock(&tty->atomic_write_lock)) {
@@ -1224,6 +1217,35 @@ ssize_t redirected_tty_write(struct file *file, const char __user *buf,
return tty_write(file, buf, count, ppos);
}
+/**
+ * tty_send_xchar - send priority character
+ *
+ * Send a high priority character to the tty even if stopped
+ *
+ * Locking: none for xchar method, write ordering for write method.
+ */
+
+int tty_send_xchar(struct tty_struct *tty, char ch)
+{
+ int was_stopped = tty->stopped;
+
+ if (tty->ops->send_xchar) {
+ tty->ops->send_xchar(tty, ch);
+ return 0;
+ }
+
+ if (tty_write_lock(tty, 0) < 0)
+ return -ERESTARTSYS;
+
+ if (was_stopped)
+ start_tty(tty);
+ tty->ops->write(tty, &ch, 1);
+ if (was_stopped)
+ stop_tty(tty);
+ tty_write_unlock(tty);
+ return 0;
+}
+
static char ptychar[] = "pqrstuvwxyzabcde";
/**
@@ -1544,13 +1566,14 @@ static void release_one_tty(struct work_struct *work)
struct tty_struct *tty =
container_of(work, struct tty_struct, hangup_work);
struct tty_driver *driver = tty->driver;
+ struct module *owner = driver->owner;
if (tty->ops->cleanup)
tty->ops->cleanup(tty);
tty->magic = 0;
tty_driver_kref_put(driver);
- module_put(driver->owner);
+ module_put(owner);
spin_lock(&tty_files_lock);
list_del_init(&tty->tty_files);
@@ -3018,6 +3041,7 @@ struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx)
INIT_WORK(&tty->hangup_work, do_tty_hangup);
mutex_init(&tty->atomic_write_lock);
spin_lock_init(&tty->ctrl_lock);
+ spin_lock_init(&tty->flow_lock);
INIT_LIST_HEAD(&tty->tty_files);
INIT_WORK(&tty->SAK_work, do_SAK_work);
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
index 6fd60fece6b4..62380ccf70fb 100644
--- a/drivers/tty/tty_ioctl.c
+++ b/drivers/tty/tty_ioctl.c
@@ -402,7 +402,7 @@ void tty_termios_encode_baud_rate(struct ktermios *termios,
#ifdef BOTHER
/* If the user asked for a precise weird speed give a precise weird
- answer. If they asked for a Bfoo speed they many have problems
+ answer. If they asked for a Bfoo speed they may have problems
digesting non-exact replies so fuzz a bit */
if ((termios->c_cflag & CBAUD) == BOTHER)
@@ -912,35 +912,6 @@ static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
#endif
/**
- * send_prio_char - send priority character
- *
- * Send a high priority character to the tty even if stopped
- *
- * Locking: none for xchar method, write ordering for write method.
- */
-
-static int send_prio_char(struct tty_struct *tty, char ch)
-{
- int was_stopped = tty->stopped;
-
- if (tty->ops->send_xchar) {
- tty->ops->send_xchar(tty, ch);
- return 0;
- }
-
- if (tty_write_lock(tty, 0) < 0)
- return -ERESTARTSYS;
-
- if (was_stopped)
- start_tty(tty);
- tty->ops->write(tty, &ch, 1);
- if (was_stopped)
- stop_tty(tty);
- tty_write_unlock(tty);
- return 0;
-}
-
-/**
* tty_change_softcar - carrier change ioctl helper
* @tty: tty to update
* @arg: enable/disable CLOCAL
@@ -1177,29 +1148,37 @@ int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
return retval;
switch (arg) {
case TCOOFF:
+ spin_lock_irq(&tty->flow_lock);
if (!tty->flow_stopped) {
tty->flow_stopped = 1;
- stop_tty(tty);
+ __stop_tty(tty);
}
+ spin_unlock_irq(&tty->flow_lock);
break;
case TCOON:
+ spin_lock_irq(&tty->flow_lock);
if (tty->flow_stopped) {
tty->flow_stopped = 0;
- start_tty(tty);
+ __start_tty(tty);
}
+ spin_unlock_irq(&tty->flow_lock);
break;
case TCIOFF:
+ down_read(&tty->termios_rwsem);
if (STOP_CHAR(tty) != __DISABLED_CHAR)
- return send_prio_char(tty, STOP_CHAR(tty));
+ retval = tty_send_xchar(tty, STOP_CHAR(tty));
+ up_read(&tty->termios_rwsem);
break;
case TCION:
+ down_read(&tty->termios_rwsem);
if (START_CHAR(tty) != __DISABLED_CHAR)
- return send_prio_char(tty, START_CHAR(tty));
+ retval = tty_send_xchar(tty, START_CHAR(tty));
+ up_read(&tty->termios_rwsem);
break;
default:
return -EINVAL;
}
- return 0;
+ return retval;
case TCFLSH:
retval = tty_check_change(tty);
if (retval)
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index d0e3a4497707..c039cfea5b11 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -268,30 +268,30 @@ EXPORT_SYMBOL(kd_mksound);
static int kbd_rate_helper(struct input_handle *handle, void *data)
{
struct input_dev *dev = handle->dev;
- struct kbd_repeat *rep = data;
+ struct kbd_repeat *rpt = data;
if (test_bit(EV_REP, dev->evbit)) {
- if (rep[0].delay > 0)
+ if (rpt[0].delay > 0)
input_inject_event(handle,
- EV_REP, REP_DELAY, rep[0].delay);
- if (rep[0].period > 0)
+ EV_REP, REP_DELAY, rpt[0].delay);
+ if (rpt[0].period > 0)
input_inject_event(handle,
- EV_REP, REP_PERIOD, rep[0].period);
+ EV_REP, REP_PERIOD, rpt[0].period);
- rep[1].delay = dev->rep[REP_DELAY];
- rep[1].period = dev->rep[REP_PERIOD];
+ rpt[1].delay = dev->rep[REP_DELAY];
+ rpt[1].period = dev->rep[REP_PERIOD];
}
return 0;
}
-int kbd_rate(struct kbd_repeat *rep)
+int kbd_rate(struct kbd_repeat *rpt)
{
- struct kbd_repeat data[2] = { *rep };
+ struct kbd_repeat data[2] = { *rpt };
input_handler_for_each_handle(&kbd_handler, data, kbd_rate_helper);
- *rep = data[1]; /* Copy currently used settings */
+ *rpt = data[1]; /* Copy currently used settings */
return 0;
}
@@ -971,15 +971,15 @@ static unsigned char getledstate(void)
return ledstate;
}
-void setledstate(struct kbd_struct *kbd, unsigned int led)
+void setledstate(struct kbd_struct *kb, unsigned int led)
{
unsigned long flags;
spin_lock_irqsave(&led_lock, flags);
if (!(led & ~7)) {
ledioctl = led;
- kbd->ledmode = LED_SHOW_IOCTL;
+ kb->ledmode = LED_SHOW_IOCTL;
} else
- kbd->ledmode = LED_SHOW_FLAGS;
+ kb->ledmode = LED_SHOW_FLAGS;
set_leds();
spin_unlock_irqrestore(&led_lock, flags);
@@ -987,12 +987,12 @@ void setledstate(struct kbd_struct *kbd, unsigned int led)
static inline unsigned char getleds(void)
{
- struct kbd_struct *kbd = kbd_table + fg_console;
+ struct kbd_struct *kb = kbd_table + fg_console;
- if (kbd->ledmode == LED_SHOW_IOCTL)
+ if (kb->ledmode == LED_SHOW_IOCTL)
return ledioctl;
- return kbd->ledflagstate;
+ return kb->ledflagstate;
}
static int kbd_update_leds_helper(struct input_handle *handle, void *data)
@@ -1018,12 +1018,12 @@ static int kbd_update_leds_helper(struct input_handle *handle, void *data)
*/
int vt_get_leds(int console, int flag)
{
- struct kbd_struct * kbd = kbd_table + console;
+ struct kbd_struct *kb = kbd_table + console;
int ret;
unsigned long flags;
spin_lock_irqsave(&led_lock, flags);
- ret = vc_kbd_led(kbd, flag);
+ ret = vc_kbd_led(kb, flag);
spin_unlock_irqrestore(&led_lock, flags);
return ret;
@@ -1040,8 +1040,8 @@ EXPORT_SYMBOL_GPL(vt_get_leds);
*/
void vt_set_led_state(int console, int leds)
{
- struct kbd_struct * kbd = kbd_table + console;
- setledstate(kbd, leds);
+ struct kbd_struct *kb = kbd_table + console;
+ setledstate(kb, leds);
}
/**
@@ -1059,10 +1059,10 @@ void vt_set_led_state(int console, int leds)
*/
void vt_kbd_con_start(int console)
{
- struct kbd_struct * kbd = kbd_table + console;
+ struct kbd_struct *kb = kbd_table + console;
unsigned long flags;
spin_lock_irqsave(&led_lock, flags);
- clr_vc_kbd_led(kbd, VC_SCROLLOCK);
+ clr_vc_kbd_led(kb, VC_SCROLLOCK);
set_leds();
spin_unlock_irqrestore(&led_lock, flags);
}
@@ -1076,10 +1076,10 @@ void vt_kbd_con_start(int console)
*/
void vt_kbd_con_stop(int console)
{
- struct kbd_struct * kbd = kbd_table + console;
+ struct kbd_struct *kb = kbd_table + console;
unsigned long flags;
spin_lock_irqsave(&led_lock, flags);
- set_vc_kbd_led(kbd, VC_SCROLLOCK);
+ set_vc_kbd_led(kb, VC_SCROLLOCK);
set_leds();
spin_unlock_irqrestore(&led_lock, flags);
}
@@ -1512,15 +1512,14 @@ int __init kbd_init(void)
/**
* vt_do_diacrit - diacritical table updates
* @cmd: ioctl request
- * @up: pointer to user data for ioctl
+ * @udp: pointer to user data for ioctl
* @perm: permissions check computed by caller
*
* Update the diacritical tables atomically and safely. Lock them
* against simultaneous keypresses
*/
-int vt_do_diacrit(unsigned int cmd, void __user *up, int perm)
+int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm)
{
- struct kbdiacrs __user *a = up;
unsigned long flags;
int asize;
int ret = 0;
@@ -1528,12 +1527,13 @@ int vt_do_diacrit(unsigned int cmd, void __user *up, int perm)
switch (cmd) {
case KDGKBDIACR:
{
- struct kbdiacr *diacr;
+ struct kbdiacrs __user *a = udp;
+ struct kbdiacr *dia;
int i;
- diacr = kmalloc(MAX_DIACR * sizeof(struct kbdiacr),
+ dia = kmalloc(MAX_DIACR * sizeof(struct kbdiacr),
GFP_KERNEL);
- if (diacr == NULL)
+ if (!dia)
return -ENOMEM;
/* Lock the diacriticals table, make a copy and then
@@ -1542,26 +1542,26 @@ int vt_do_diacrit(unsigned int cmd, void __user *up, int perm)
asize = accent_table_size;
for (i = 0; i < asize; i++) {
- diacr[i].diacr = conv_uni_to_8bit(
+ dia[i].diacr = conv_uni_to_8bit(
accent_table[i].diacr);
- diacr[i].base = conv_uni_to_8bit(
+ dia[i].base = conv_uni_to_8bit(
accent_table[i].base);
- diacr[i].result = conv_uni_to_8bit(
+ dia[i].result = conv_uni_to_8bit(
accent_table[i].result);
}
spin_unlock_irqrestore(&kbd_event_lock, flags);
if (put_user(asize, &a->kb_cnt))
ret = -EFAULT;
- else if (copy_to_user(a->kbdiacr, diacr,
+ else if (copy_to_user(a->kbdiacr, dia,
asize * sizeof(struct kbdiacr)))
ret = -EFAULT;
- kfree(diacr);
+ kfree(dia);
return ret;
}
case KDGKBDIACRUC:
{
- struct kbdiacrsuc __user *a = up;
+ struct kbdiacrsuc __user *a = udp;
void *buf;
buf = kmalloc(MAX_DIACR * sizeof(struct kbdiacruc),
@@ -1589,8 +1589,8 @@ int vt_do_diacrit(unsigned int cmd, void __user *up, int perm)
case KDSKBDIACR:
{
- struct kbdiacrs __user *a = up;
- struct kbdiacr *diacr = NULL;
+ struct kbdiacrs __user *a = udp;
+ struct kbdiacr *dia = NULL;
unsigned int ct;
int i;
@@ -1602,14 +1602,14 @@ int vt_do_diacrit(unsigned int cmd, void __user *up, int perm)
return -EINVAL;
if (ct) {
- diacr = kmalloc(sizeof(struct kbdiacr) * ct,
+ dia = kmalloc(sizeof(struct kbdiacr) * ct,
GFP_KERNEL);
- if (diacr == NULL)
+ if (!dia)
return -ENOMEM;
- if (copy_from_user(diacr, a->kbdiacr,
+ if (copy_from_user(dia, a->kbdiacr,
sizeof(struct kbdiacr) * ct)) {
- kfree(diacr);
+ kfree(dia);
return -EFAULT;
}
}
@@ -1618,20 +1618,20 @@ int vt_do_diacrit(unsigned int cmd, void __user *up, int perm)
accent_table_size = ct;
for (i = 0; i < ct; i++) {
accent_table[i].diacr =
- conv_8bit_to_uni(diacr[i].diacr);
+ conv_8bit_to_uni(dia[i].diacr);
accent_table[i].base =
- conv_8bit_to_uni(diacr[i].base);
+ conv_8bit_to_uni(dia[i].base);
accent_table[i].result =
- conv_8bit_to_uni(diacr[i].result);
+ conv_8bit_to_uni(dia[i].result);
}
spin_unlock_irqrestore(&kbd_event_lock, flags);
- kfree(diacr);
+ kfree(dia);
return 0;
}
case KDSKBDIACRUC:
{
- struct kbdiacrsuc __user *a = up;
+ struct kbdiacrsuc __user *a = udp;
unsigned int ct;
void *buf = NULL;
@@ -1679,28 +1679,28 @@ int vt_do_diacrit(unsigned int cmd, void __user *up, int perm)
*/
int vt_do_kdskbmode(int console, unsigned int arg)
{
- struct kbd_struct * kbd = kbd_table + console;
+ struct kbd_struct *kb = kbd_table + console;
int ret = 0;
unsigned long flags;
spin_lock_irqsave(&kbd_event_lock, flags);
switch(arg) {
case K_RAW:
- kbd->kbdmode = VC_RAW;
+ kb->kbdmode = VC_RAW;
break;
case K_MEDIUMRAW:
- kbd->kbdmode = VC_MEDIUMRAW;
+ kb->kbdmode = VC_MEDIUMRAW;
break;
case K_XLATE:
- kbd->kbdmode = VC_XLATE;
+ kb->kbdmode = VC_XLATE;
do_compute_shiftstate();
break;
case K_UNICODE:
- kbd->kbdmode = VC_UNICODE;
+ kb->kbdmode = VC_UNICODE;
do_compute_shiftstate();
break;
case K_OFF:
- kbd->kbdmode = VC_OFF;
+ kb->kbdmode = VC_OFF;
break;
default:
ret = -EINVAL;
@@ -1719,17 +1719,17 @@ int vt_do_kdskbmode(int console, unsigned int arg)
*/
int vt_do_kdskbmeta(int console, unsigned int arg)
{
- struct kbd_struct * kbd = kbd_table + console;
+ struct kbd_struct *kb = kbd_table + console;
int ret = 0;
unsigned long flags;
spin_lock_irqsave(&kbd_event_lock, flags);
switch(arg) {
case K_METABIT:
- clr_vc_kbd_mode(kbd, VC_META);
+ clr_vc_kbd_mode(kb, VC_META);
break;
case K_ESCPREFIX:
- set_vc_kbd_mode(kbd, VC_META);
+ set_vc_kbd_mode(kb, VC_META);
break;
default:
ret = -EINVAL;
@@ -1768,7 +1768,7 @@ int vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc,
int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm,
int console)
{
- struct kbd_struct * kbd = kbd_table + console;
+ struct kbd_struct *kb = kbd_table + console;
struct kbentry tmp;
ushort *key_map, *new_map, val, ov;
unsigned long flags;
@@ -1786,7 +1786,7 @@ int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm,
key_map = key_maps[s];
if (key_map) {
val = U(key_map[i]);
- if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
+ if (kb->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
val = K_HOLE;
} else
val = (i ? K_HOLE : K_NOSUCHMAP);
@@ -1814,7 +1814,7 @@ int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm,
if (KVAL(v) > max_vals[KTYP(v)])
return -EINVAL;
} else
- if (kbd->kbdmode != VC_UNICODE)
+ if (kb->kbdmode != VC_UNICODE)
return -EINVAL;
/* ++Geert: non-PC keyboards may generate keycode zero */
@@ -1985,7 +1985,7 @@ reterr:
int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm)
{
- struct kbd_struct * kbd = kbd_table + console;
+ struct kbd_struct *kb = kbd_table + console;
unsigned long flags;
unsigned char ucval;
@@ -1994,7 +1994,7 @@ int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm)
/* don't use them - they will go away without warning */
case KDGKBLED:
spin_lock_irqsave(&kbd_event_lock, flags);
- ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4);
+ ucval = kb->ledflagstate | (kb->default_ledflagstate << 4);
spin_unlock_irqrestore(&kbd_event_lock, flags);
return put_user(ucval, (char __user *)arg);
@@ -2004,8 +2004,8 @@ int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm)
if (arg & ~0x77)
return -EINVAL;
spin_lock_irqsave(&led_lock, flags);
- kbd->ledflagstate = (arg & 7);
- kbd->default_ledflagstate = ((arg >> 4) & 7);
+ kb->ledflagstate = (arg & 7);
+ kb->default_ledflagstate = ((arg >> 4) & 7);
set_leds();
spin_unlock_irqrestore(&led_lock, flags);
return 0;
@@ -2019,7 +2019,7 @@ int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm)
case KDSETLED:
if (!perm)
return -EPERM;
- setledstate(kbd, arg);
+ setledstate(kb, arg);
return 0;
}
return -ENOIOCTLCMD;
@@ -2027,9 +2027,9 @@ int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm)
int vt_do_kdgkbmode(int console)
{
- struct kbd_struct * kbd = kbd_table + console;
+ struct kbd_struct *kb = kbd_table + console;
/* This is a spot read so needs no locking */
- switch (kbd->kbdmode) {
+ switch (kb->kbdmode) {
case VC_RAW:
return K_RAW;
case VC_MEDIUMRAW:
@@ -2051,9 +2051,9 @@ int vt_do_kdgkbmode(int console)
*/
int vt_do_kdgkbmeta(int console)
{
- struct kbd_struct * kbd = kbd_table + console;
+ struct kbd_struct *kb = kbd_table + console;
/* Again a spot read so no locking */
- return vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT;
+ return vc_kbd_mode(kb, VC_META) ? K_ESCPREFIX : K_METABIT;
}
/**
@@ -2092,19 +2092,19 @@ int vt_get_shift_state(void)
*/
void vt_reset_keyboard(int console)
{
- struct kbd_struct * kbd = kbd_table + console;
+ struct kbd_struct *kb = kbd_table + console;
unsigned long flags;
spin_lock_irqsave(&kbd_event_lock, flags);
- set_vc_kbd_mode(kbd, VC_REPEAT);
- clr_vc_kbd_mode(kbd, VC_CKMODE);
- clr_vc_kbd_mode(kbd, VC_APPLIC);
- clr_vc_kbd_mode(kbd, VC_CRLF);
- kbd->lockstate = 0;
- kbd->slockstate = 0;
+ set_vc_kbd_mode(kb, VC_REPEAT);
+ clr_vc_kbd_mode(kb, VC_CKMODE);
+ clr_vc_kbd_mode(kb, VC_APPLIC);
+ clr_vc_kbd_mode(kb, VC_CRLF);
+ kb->lockstate = 0;
+ kb->slockstate = 0;
spin_lock(&led_lock);
- kbd->ledmode = LED_SHOW_FLAGS;
- kbd->ledflagstate = kbd->default_ledflagstate;
+ kb->ledmode = LED_SHOW_FLAGS;
+ kb->ledflagstate = kb->default_ledflagstate;
spin_unlock(&led_lock);
/* do not do set_leds here because this causes an endless tasklet loop
when the keyboard hasn't been initialized yet */
@@ -2122,8 +2122,8 @@ void vt_reset_keyboard(int console)
int vt_get_kbd_mode_bit(int console, int bit)
{
- struct kbd_struct * kbd = kbd_table + console;
- return vc_kbd_mode(kbd, bit);
+ struct kbd_struct *kb = kbd_table + console;
+ return vc_kbd_mode(kb, bit);
}
/**
@@ -2137,11 +2137,11 @@ int vt_get_kbd_mode_bit(int console, int bit)
void vt_set_kbd_mode_bit(int console, int bit)
{
- struct kbd_struct * kbd = kbd_table + console;
+ struct kbd_struct *kb = kbd_table + console;
unsigned long flags;
spin_lock_irqsave(&kbd_event_lock, flags);
- set_vc_kbd_mode(kbd, bit);
+ set_vc_kbd_mode(kb, bit);
spin_unlock_irqrestore(&kbd_event_lock, flags);
}
@@ -2156,10 +2156,10 @@ void vt_set_kbd_mode_bit(int console, int bit)
void vt_clr_kbd_mode_bit(int console, int bit)
{
- struct kbd_struct * kbd = kbd_table + console;
+ struct kbd_struct *kb = kbd_table + console;
unsigned long flags;
spin_lock_irqsave(&kbd_event_lock, flags);
- clr_vc_kbd_mode(kbd, bit);
+ clr_vc_kbd_mode(kb, bit);
spin_unlock_irqrestore(&kbd_event_lock, flags);
}
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index 8a23c53b946e..12b0e67473ba 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -834,7 +834,6 @@ static void digi_set_termios(struct tty_struct *tty,
arg |= DIGI_OUTPUT_FLOW_CONTROL_CTS;
} else {
arg &= ~DIGI_OUTPUT_FLOW_CONTROL_CTS;
- tty->hw_stopped = 0;
}
buf[i++] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL;
@@ -1500,15 +1499,11 @@ static int digi_read_oob_callback(struct urb *urb)
if (val & DIGI_READ_INPUT_SIGNALS_CTS) {
priv->dp_modem_signals |= TIOCM_CTS;
/* port must be open to use tty struct */
- if (rts) {
- tty->hw_stopped = 0;
+ if (rts)
tty_port_tty_wakeup(&port->port);
- }
} else {
priv->dp_modem_signals &= ~TIOCM_CTS;
/* port must be open to use tty struct */
- if (rts)
- tty->hw_stopped = 1;
}
if (val & DIGI_READ_INPUT_SIGNALS_DSR)
priv->dp_modem_signals |= TIOCM_DSR;
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index c0a42e9e6777..ddbb8fe1046d 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -1456,12 +1456,8 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr)
tty = tty_port_tty_get(&edge_port->port->port);
/* handle CTS flow control */
if (tty && C_CRTSCTS(tty)) {
- if (msr & EDGEPORT_MSR_CTS) {
- tty->hw_stopped = 0;
+ if (msr & EDGEPORT_MSR_CTS)
tty_wakeup(tty);
- } else {
- tty->hw_stopped = 1;
- }
}
tty_kref_put(tty);
}
@@ -2177,7 +2173,6 @@ static void change_port_settings(struct tty_struct *tty,
dev_dbg(dev, "%s - RTS/CTS is enabled\n", __func__);
} else {
dev_dbg(dev, "%s - RTS/CTS is disabled\n", __func__);
- tty->hw_stopped = 0;
restart_read(edge_port);
}
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index 3dd3ff8c50d3..e9da41d9fe7f 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -773,7 +773,6 @@ static void ti_set_termios(struct tty_struct *tty,
config->wFlags |= TI_UART_ENABLE_RTS_IN;
config->wFlags |= TI_UART_ENABLE_CTS_OUT;
} else {
- tty->hw_stopped = 0;
ti_restart_read(tport, tty);
}
@@ -1291,12 +1290,8 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr)
/* handle CTS flow control */
tty = tty_port_tty_get(&tport->tp_port->port);
if (tty && C_CRTSCTS(tty)) {
- if (msr & TI_MSR_CTS) {
- tty->hw_stopped = 0;
+ if (msr & TI_MSR_CTS)
tty_wakeup(tty);
- } else {
- tty->hw_stopped = 1;
- }
}
tty_kref_put(tty);
}
diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
index 008388f920d7..64c7425afbce 100644
--- a/include/linux/lockdep.h
+++ b/include/linux/lockdep.h
@@ -362,6 +362,10 @@ extern void lockdep_trace_alloc(gfp_t mask);
WARN_ON(debug_locks && !lockdep_is_held(l)); \
} while (0)
+#define lockdep_assert_held_once(l) do { \
+ WARN_ON_ONCE(debug_locks && !lockdep_is_held(l)); \
+ } while (0)
+
#define lockdep_recursing(tsk) ((tsk)->lockdep_recursion)
#else /* !CONFIG_LOCKDEP */
@@ -412,6 +416,7 @@ struct lock_class_key { };
#define lockdep_depth(tsk) (0)
#define lockdep_assert_held(l) do { (void)(l); } while (0)
+#define lockdep_assert_held_once(l) do { (void)(l); } while (0)
#define lockdep_recursing(tsk) (0)
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
index f93649e22c43..3df10d5f154b 100644
--- a/include/linux/serial_8250.h
+++ b/include/linux/serial_8250.h
@@ -84,6 +84,7 @@ struct uart_8250_port {
unsigned char mcr_mask; /* mask of user bits */
unsigned char mcr_force; /* mask of forced bits */
unsigned char cur_iotype; /* Running I/O type */
+ unsigned int rpm_tx_active;
/*
* Some bits in registers are cleared on a read, so they must
@@ -96,10 +97,13 @@ struct uart_8250_port {
unsigned char msr_saved_flags;
struct uart_8250_dma *dma;
+ struct serial_rs485 rs485;
/* 8250 specific callbacks */
int (*dl_read)(struct uart_8250_port *);
void (*dl_write)(struct uart_8250_port *, int);
+ int (*rs485_config)(struct uart_8250_port *,
+ struct serial_rs485 *rs485);
};
static inline struct uart_8250_port *up_to_u8250p(struct uart_port *up)
@@ -121,6 +125,8 @@ extern void serial8250_early_out(struct uart_port *port, int offset, int value);
extern int setup_early_serial8250_console(char *cmdline);
extern void serial8250_do_set_termios(struct uart_port *port,
struct ktermios *termios, struct ktermios *old);
+extern int serial8250_do_startup(struct uart_port *port);
+extern void serial8250_do_shutdown(struct uart_port *port);
extern void serial8250_do_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate);
extern int fsl8250_handle_irq(struct uart_port *port);
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index cf3a1e789bf5..21c2e05c1bc3 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -112,6 +112,7 @@ struct uart_icount {
};
typedef unsigned int __bitwise__ upf_t;
+typedef unsigned int __bitwise__ upstat_t;
struct uart_port {
spinlock_t lock; /* port lock */
@@ -122,6 +123,10 @@ struct uart_port {
void (*set_termios)(struct uart_port *,
struct ktermios *new,
struct ktermios *old);
+ int (*startup)(struct uart_port *port);
+ void (*shutdown)(struct uart_port *port);
+ void (*throttle)(struct uart_port *port);
+ void (*unthrottle)(struct uart_port *port);
int (*handle_irq)(struct uart_port *);
void (*pm)(struct uart_port *, unsigned int state,
unsigned int old);
@@ -152,6 +157,7 @@ struct uart_port {
unsigned long sysrq; /* sysrq timeout */
#endif
+ /* flags must be updated while holding port mutex */
upf_t flags;
#define UPF_FOURPORT ((__force upf_t) (1 << 1))
@@ -187,6 +193,13 @@ struct uart_port {
#define UPF_CHANGE_MASK ((__force upf_t) (0x17fff))
#define UPF_USR_MASK ((__force upf_t) (UPF_SPD_MASK|UPF_LOW_LATENCY))
+ /* status must be updated while holding port lock */
+ upstat_t status;
+
+#define UPSTAT_CTS_ENABLE ((__force upstat_t) (1 << 0))
+#define UPSTAT_DCD_ENABLE ((__force upstat_t) (1 << 1))
+
+ int hw_stopped; /* sw-assisted CTS flow state */
unsigned int mctrl; /* current modem ctrl settings */
unsigned int timeout; /* character-based timeout */
unsigned int type; /* port type */
@@ -347,11 +360,16 @@ int uart_resume_port(struct uart_driver *reg, struct uart_port *port);
static inline int uart_tx_stopped(struct uart_port *port)
{
struct tty_struct *tty = port->state->port.tty;
- if(tty->stopped || tty->hw_stopped)
+ if (tty->stopped || port->hw_stopped)
return 1;
return 0;
}
+static inline bool uart_cts_enabled(struct uart_port *uport)
+{
+ return uport->status & UPSTAT_CTS_ENABLE;
+}
+
/*
* The following are helper functions for the low level drivers.
*/
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 84132942902a..5171ef8f7b85 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -252,6 +252,7 @@ struct tty_struct {
struct rw_semaphore termios_rwsem;
struct mutex winsize_mutex;
spinlock_t ctrl_lock;
+ spinlock_t flow_lock;
/* Termios values are protected by the termios rwsem */
struct ktermios termios, termios_locked;
struct termiox *termiox; /* May be NULL for unsupported */
@@ -261,8 +262,13 @@ struct tty_struct {
unsigned long flags;
int count;
struct winsize winsize; /* winsize_mutex */
- unsigned char stopped:1, hw_stopped:1, flow_stopped:1, packet:1;
- unsigned char ctrl_status; /* ctrl_lock */
+ unsigned long stopped:1, /* flow_lock */
+ flow_stopped:1,
+ unused:BITS_PER_LONG - 2;
+ int hw_stopped;
+ unsigned long ctrl_status:8, /* ctrl_lock */
+ packet:1,
+ unused_ctrl:BITS_PER_LONG - 9;
unsigned int receive_room; /* Bytes free for queue */
int flow_change;
@@ -397,7 +403,9 @@ extern int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
extern char *tty_name(struct tty_struct *tty, char *buf);
extern void tty_wait_until_sent(struct tty_struct *tty, long timeout);
extern int tty_check_change(struct tty_struct *tty);
+extern void __stop_tty(struct tty_struct *tty);
extern void stop_tty(struct tty_struct *tty);
+extern void __start_tty(struct tty_struct *tty);
extern void start_tty(struct tty_struct *tty);
extern int tty_register_driver(struct tty_driver *driver);
extern int tty_unregister_driver(struct tty_driver *driver);
@@ -411,6 +419,7 @@ extern void tty_unregister_device(struct tty_driver *driver, unsigned index);
extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp,
int buflen);
extern void tty_write_message(struct tty_struct *tty, char *msg);
+extern int tty_send_xchar(struct tty_struct *tty, char ch);
extern int tty_put_char(struct tty_struct *tty, unsigned char c);
extern int tty_chars_in_buffer(struct tty_struct *tty);
extern int tty_write_room(struct tty_struct *tty);
@@ -495,8 +504,6 @@ extern struct tty_struct *tty_pair_get_pty(struct tty_struct *tty);
extern struct mutex tty_mutex;
extern spinlock_t tty_files_lock;
-extern void tty_write_unlock(struct tty_struct *tty);
-extern int tty_write_lock(struct tty_struct *tty, int ndelay);
#define tty_is_writelocked(tty) (mutex_is_locked(&tty->atomic_write_lock))
extern void tty_port_init(struct tty_port *port);
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index e48c608a8fa8..92e337c18839 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -152,6 +152,8 @@
* This routine notifies the tty driver that it should stop
* outputting characters to the tty device.
*
+ * Called with ->flow_lock held. Serialized with start() method.
+ *
* Optional:
*
* Note: Call stop_tty not this method.
@@ -161,6 +163,8 @@
* This routine notifies the tty driver that it resume sending
* characters to the tty device.
*
+ * Called with ->flow_lock held. Serialized with stop() method.
+ *
* Optional:
*
* Note: Call start_tty not this method.
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
index 5820269aa132..16ad8521af6a 100644
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -244,4 +244,7 @@
/* SC16IS74xx */
#define PORT_SC16IS7XX 108
+/* MESON */
+#define PORT_MESON 109
+
#endif /* _UAPILINUX_SERIAL_CORE_H */