summaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2021-09-01 09:51:16 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2021-09-01 09:51:16 -0700
commit7c314bdfb64e4bb8d2f829376ed56ce663483752 (patch)
treece846e0c4e8c8138258dd00c1f15aad7368fafbb /drivers/tty
parentebf435d3b51b22340ef047aad0c2936ec4833ab2 (diff)
parent2e5f3a69b6fcd52a64ce3d746c6ee8390b6cabe8 (diff)
downloadlinux-stable-7c314bdfb64e4bb8d2f829376ed56ce663483752.tar.gz
linux-stable-7c314bdfb64e4bb8d2f829376ed56ce663483752.tar.bz2
linux-stable-7c314bdfb64e4bb8d2f829376ed56ce663483752.zip
Merge tag 'tty-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty / serial updates from Greg KH: "Here is the "big" set of tty/serial driver patches for 5.15-rc1 Nothing major in here at all, just some driver updates and more cleanups on old tty apis and code that needed it that includes: - tty.h cleanup of things that didn't belong in it - other tty cleanups by Jiri - driver cleanups - rs485 support added to amba-pl011 driver - dts updates - stm32 serial driver updates - other minor fixes and driver updates All have been in linux-next for a while with no reported problems" * tag 'tty-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (83 commits) tty: serial: uartlite: Use read_poll_timeout for a polling loop tty: serial: uartlite: Use constants in early_uartlite_putc tty: Fix data race between tiocsti() and flush_to_ldisc() serial: vt8500: Use of_device_get_match_data serial: tegra: Use of_device_get_match_data serial: 8250_ingenic: Use of_device_get_match_data tty: serial: linflexuart: Remove redundant check to simplify the code tty: serial: fsl_lpuart: do software reset for imx7ulp and imx8qxp tty: serial: fsl_lpuart: enable two stop bits for lpuart32 tty: serial: fsl_lpuart: fix the wrong mapbase value mxser: use semi-colons instead of commas tty: moxa: use semi-colons instead of commas tty: serial: fsl_lpuart: check dma_tx_in_progress in tx dma callback tty: replace in_irq() with in_hardirq() serial: sh-sci: fix break handling for sysrq serial: stm32: use devm_platform_get_and_ioremap_resource() serial: stm32: use the defined variable to simplify code Revert "arm pl011 serial: support multi-irq request" tty: serial: samsung: Add Exynos850 SoC data tty: serial: samsung: Fix driver data macros style ...
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/amiserial.c278
-rw-r--r--drivers/tty/ehv_bytechan.c34
-rw-r--r--drivers/tty/goldfish.c18
-rw-r--r--drivers/tty/hvc/hvc_console.c10
-rw-r--r--drivers/tty/hvc/hvc_xen.c17
-rw-r--r--drivers/tty/hvc/hvcs.c12
-rw-r--r--drivers/tty/hvc/hvsi.c55
-rw-r--r--drivers/tty/ipwireless/tty.c12
-rw-r--r--drivers/tty/mips_ejtag_fdc.c2
-rw-r--r--drivers/tty/moxa.c12
-rw-r--r--drivers/tty/mxser.c24
-rw-r--r--drivers/tty/n_gsm.c13
-rw-r--r--drivers/tty/nozomi.c12
-rw-r--r--drivers/tty/serdev/core.c36
-rw-r--r--drivers/tty/serial/8250/8250_bcm7271.c2
-rw-r--r--drivers/tty/serial/8250/8250_exar.c36
-rw-r--r--drivers/tty/serial/8250/8250_ingenic.c6
-rw-r--r--drivers/tty/serial/8250/8250_lpss.c10
-rw-r--r--drivers/tty/serial/8250/8250_omap.c27
-rw-r--r--drivers/tty/serial/8250/8250_pci.c2
-rw-r--r--drivers/tty/serial/8250/8250_pnp.c2
-rw-r--r--drivers/tty/serial/8250/8250_port.c3
-rw-r--r--drivers/tty/serial/8250/Kconfig10
-rw-r--r--drivers/tty/serial/Kconfig4
-rw-r--r--drivers/tty/serial/amba-pl011.c163
-rw-r--r--drivers/tty/serial/fsl_linflexuart.c6
-rw-r--r--drivers/tty/serial/fsl_lpuart.c62
-rw-r--r--drivers/tty/serial/jsm/jsm_neo.c2
-rw-r--r--drivers/tty/serial/jsm/jsm_tty.c3
-rw-r--r--drivers/tty/serial/kgdb_nmi.c11
-rw-r--r--drivers/tty/serial/max310x.c15
-rw-r--r--drivers/tty/serial/omap-serial.c75
-rw-r--r--drivers/tty/serial/samsung_tty.c95
-rw-r--r--drivers/tty/serial/serial-tegra.c6
-rw-r--r--drivers/tty/serial/serial_core.c20
-rw-r--r--drivers/tty/serial/sh-sci.c7
-rw-r--r--drivers/tty/serial/stm32-usart.c11
-rw-r--r--drivers/tty/serial/uartlite.c88
-rw-r--r--drivers/tty/serial/vt8500_serial.c7
-rw-r--r--drivers/tty/synclink_gt.c12
-rw-r--r--drivers/tty/sysrq.c4
-rw-r--r--drivers/tty/tty_io.c17
-rw-r--r--drivers/tty/ttynull.c4
-rw-r--r--drivers/tty/vcc.c4
-rw-r--r--drivers/tty/vt/keyboard.c62
-rw-r--r--drivers/tty/vt/vt.c27
46 files changed, 804 insertions, 534 deletions
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index 5ec19c48fb7a..1e60dbef676c 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -22,8 +22,6 @@
*
*/
-#include <linux/delay.h>
-
/* Set of debugging defines */
#undef SERIAL_DEBUG_INTR
@@ -31,55 +29,42 @@
#undef SERIAL_DEBUG_FLOW
#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-/* Sanity checks */
-
-#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
-#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
- tty->name, (info->tport.flags), serial_driver->refcount,info->count,tty->count,s)
-#else
-#define DBG_CNT(s)
-#endif
-
/*
* End of serial driver configuration section.
*/
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/serial.h>
-#include <linux/serial_reg.h>
-static char *serial_version = "4.30";
-
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
+#include <linux/bitops.h>
#include <linux/circ_buf.h>
#include <linux/console.h>
-#include <linux/major.h>
-#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
#include <linux/fcntl.h>
-#include <linux/ptrace.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/ptrace.h>
#include <linux/seq_file.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <linux/platform_device.h>
-
-#include <asm/setup.h>
-
-
-#include <asm/irq.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
#include <asm/amigahw.h>
#include <asm/amigaints.h>
+#include <asm/irq.h>
+#include <asm/setup.h>
struct serial_state {
struct tty_port tport;
@@ -88,7 +73,6 @@ struct serial_state {
unsigned long port;
int baud_base;
- int xmit_fifo_size;
int custom_divisor;
int read_status_mask;
int ignore_status_mask;
@@ -99,14 +83,13 @@ struct serial_state {
int x_char; /* xon/xoff character */
};
-#define custom amiga_custom
-static char *serial_name = "Amiga-builtin serial driver";
-
static struct tty_driver *serial_driver;
/* number of characters left in xmit buffer before we ask for more */
#define WAKEUP_CHARS 256
+#define XMIT_FIFO_SIZE 1
+
static unsigned char current_ctl_bits;
static void change_speed(struct tty_struct *tty, struct serial_state *info,
@@ -114,13 +97,7 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info,
static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
-static struct serial_state rs_table[1];
-
-#define NR_PORTS ARRAY_SIZE(rs_table)
-
-#include <linux/uaccess.h>
-
-#define serial_isroot() (capable(CAP_SYS_ADMIN))
+static struct serial_state serial_state;
/* some serial hardware definitions */
#define SDR_OVRUN (1<<15)
@@ -161,9 +138,9 @@ static void rs_stop(struct tty_struct *tty)
if (info->IER & UART_IER_THRI) {
info->IER &= ~UART_IER_THRI;
/* disable Tx interrupt and remove any pending interrupts */
- custom.intena = IF_TBE;
+ amiga_custom.intena = IF_TBE;
mb();
- custom.intreq = IF_TBE;
+ amiga_custom.intreq = IF_TBE;
mb();
}
local_irq_restore(flags);
@@ -179,10 +156,10 @@ static void rs_start(struct tty_struct *tty)
&& info->xmit.buf
&& !(info->IER & UART_IER_THRI)) {
info->IER |= UART_IER_THRI;
- custom.intena = IF_SETCLR | IF_TBE;
+ amiga_custom.intena = IF_SETCLR | IF_TBE;
mb();
/* set a pending Tx Interrupt, transmitter should restart now */
- custom.intreq = IF_SETCLR | IF_TBE;
+ amiga_custom.intreq = IF_SETCLR | IF_TBE;
mb();
}
local_irq_restore(flags);
@@ -191,21 +168,8 @@ static void rs_start(struct tty_struct *tty)
/*
* ----------------------------------------------------------------------
*
- * Here starts the interrupt handling routines. All of the following
- * subroutines are declared as inline and are folded into
- * rs_interrupt(). They were separated out for readability's sake.
- *
- * Note: rs_interrupt() is a "fast" interrupt, which means that it
- * runs with interrupts turned off. People who may want to modify
- * rs_interrupt() should try to keep the interrupt handler as fast as
- * possible. After you are done making modifications, it is not a bad
- * idea to do:
- *
- * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
- *
- * and look at the resulting assemble code in serial.s.
+ * Here start the interrupt handling routines.
*
- * - Ted Ts'o (tytso@mit.edu), 7-Mar-93
* -----------------------------------------------------------------------
*/
@@ -220,9 +184,9 @@ static void receive_chars(struct serial_state *info)
icount = &info->icount;
status = UART_LSR_DR; /* We obviously have a character! */
- serdatr = custom.serdatr;
+ serdatr = amiga_custom.serdatr;
mb();
- custom.intreq = IF_RBF;
+ amiga_custom.intreq = IF_RBF;
mb();
if((serdatr & 0x1ff) == 0)
@@ -299,10 +263,10 @@ out:
static void transmit_chars(struct serial_state *info)
{
- custom.intreq = IF_TBE;
+ amiga_custom.intreq = IF_TBE;
mb();
if (info->x_char) {
- custom.serdat = info->x_char | 0x100;
+ amiga_custom.serdat = info->x_char | 0x100;
mb();
info->icount.tx++;
info->x_char = 0;
@@ -312,12 +276,12 @@ static void transmit_chars(struct serial_state *info)
|| info->tport.tty->flow.stopped
|| info->tport.tty->hw_stopped) {
info->IER &= ~UART_IER_THRI;
- custom.intena = IF_TBE;
+ amiga_custom.intena = IF_TBE;
mb();
return;
}
- custom.serdat = info->xmit.buf[info->xmit.tail++] | 0x100;
+ amiga_custom.serdat = info->xmit.buf[info->xmit.tail++] | 0x100;
mb();
info->xmit.tail = info->xmit.tail & (SERIAL_XMIT_SIZE-1);
info->icount.tx++;
@@ -331,7 +295,7 @@ static void transmit_chars(struct serial_state *info)
printk("THRE...");
#endif
if (info->xmit.head == info->xmit.tail) {
- custom.intena = IF_TBE;
+ amiga_custom.intena = IF_TBE;
mb();
info->IER &= ~UART_IER_THRI;
}
@@ -384,10 +348,10 @@ static void check_modem_status(struct serial_state *info)
#endif
port->tty->hw_stopped = 0;
info->IER |= UART_IER_THRI;
- custom.intena = IF_SETCLR | IF_TBE;
+ amiga_custom.intena = IF_SETCLR | IF_TBE;
mb();
/* set a pending Tx Interrupt, transmitter should restart now */
- custom.intreq = IF_SETCLR | IF_TBE;
+ amiga_custom.intreq = IF_SETCLR | IF_TBE;
mb();
tty_wakeup(port->tty);
return;
@@ -400,9 +364,9 @@ static void check_modem_status(struct serial_state *info)
port->tty->hw_stopped = 1;
info->IER &= ~UART_IER_THRI;
/* disable Tx interrupt and remove any pending interrupts */
- custom.intena = IF_TBE;
+ amiga_custom.intena = IF_TBE;
mb();
- custom.intreq = IF_TBE;
+ amiga_custom.intreq = IF_TBE;
mb();
}
}
@@ -444,7 +408,7 @@ static irqreturn_t ser_tx_int(int irq, void *dev_id)
{
struct serial_state *info = dev_id;
- if (custom.serdatr & SDR_TBE) {
+ if (amiga_custom.serdatr & SDR_TBE) {
#ifdef SERIAL_DEBUG_INTR
printk("ser_tx_int...");
#endif
@@ -504,20 +468,20 @@ static int startup(struct tty_struct *tty, struct serial_state *info)
/* Clear anything in the input buffer */
- custom.intreq = IF_RBF;
+ amiga_custom.intreq = IF_RBF;
mb();
retval = request_irq(IRQ_AMIGA_VERTB, ser_vbl_int, 0, "serial status", info);
if (retval) {
- if (serial_isroot()) {
- set_bit(TTY_IO_ERROR, &tty->flags);
- retval = 0;
- }
- goto errout;
+ if (capable(CAP_SYS_ADMIN)) {
+ set_bit(TTY_IO_ERROR, &tty->flags);
+ retval = 0;
+ }
+ goto errout;
}
/* enable both Rx and Tx interrupts */
- custom.intena = IF_SETCLR | IF_RBF | IF_TBE;
+ amiga_custom.intena = IF_SETCLR | IF_RBF | IF_TBE;
mb();
info->IER = UART_IER_MSI;
@@ -553,13 +517,10 @@ errout:
static void shutdown(struct tty_struct *tty, struct serial_state *info)
{
unsigned long flags;
- struct serial_state *state;
if (!tty_port_initialized(&info->tport))
return;
- state = info;
-
#ifdef SERIAL_DEBUG_OPEN
printk("Shutting down serial port %d ....\n", info->line);
#endif
@@ -583,11 +544,11 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info)
}
info->IER = 0;
- custom.intena = IF_RBF | IF_TBE;
+ amiga_custom.intena = IF_RBF | IF_TBE;
mb();
/* disable break condition */
- custom.adkcon = AC_UARTBRK;
+ amiga_custom.adkcon = AC_UARTBRK;
mb();
if (C_HUPCL(tty))
@@ -671,7 +632,7 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info,
if (!quot)
quot = baud_base / 9600;
info->quot = quot;
- info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base);
+ info->timeout = (XMIT_FIFO_SIZE*HZ*bits*quot) / baud_base;
info->timeout += HZ/50; /* Add .02 seconds of slop */
/* CTS flow control flag and modem status interrupts */
@@ -731,7 +692,7 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info,
if(cval & UART_LCR_PARITY)
serper |= (SERPER_PARENB);
- custom.serper = serper;
+ amiga_custom.serper = serper;
mb();
}
@@ -775,10 +736,10 @@ static void rs_flush_chars(struct tty_struct *tty)
local_irq_save(flags);
info->IER |= UART_IER_THRI;
- custom.intena = IF_SETCLR | IF_TBE;
+ amiga_custom.intena = IF_SETCLR | IF_TBE;
mb();
/* set a pending Tx Interrupt, transmitter should restart now */
- custom.intreq = IF_SETCLR | IF_TBE;
+ amiga_custom.intreq = IF_SETCLR | IF_TBE;
mb();
local_irq_restore(flags);
}
@@ -817,10 +778,10 @@ static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count
&& !(info->IER & UART_IER_THRI)) {
info->IER |= UART_IER_THRI;
local_irq_disable();
- custom.intena = IF_SETCLR | IF_TBE;
+ amiga_custom.intena = IF_SETCLR | IF_TBE;
mb();
/* set a pending Tx Interrupt, transmitter should restart now */
- custom.intreq = IF_SETCLR | IF_TBE;
+ amiga_custom.intreq = IF_SETCLR | IF_TBE;
mb();
local_irq_restore(flags);
}
@@ -867,11 +828,11 @@ static void rs_send_xchar(struct tty_struct *tty, char ch)
/* Check this ! */
local_irq_save(flags);
- if(!(custom.intenar & IF_TBE)) {
- custom.intena = IF_SETCLR | IF_TBE;
+ if(!(amiga_custom.intenar & IF_TBE)) {
+ amiga_custom.intena = IF_SETCLR | IF_TBE;
mb();
/* set a pending Tx Interrupt, transmitter should restart now */
- custom.intreq = IF_SETCLR | IF_TBE;
+ amiga_custom.intreq = IF_SETCLR | IF_TBE;
mb();
}
local_irq_restore(flags);
@@ -948,7 +909,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_struct *ss)
ss->line = tty->index;
ss->port = state->port;
ss->flags = state->tport.flags;
- ss->xmit_fifo_size = state->xmit_fifo_size;
+ ss->xmit_fifo_size = XMIT_FIFO_SIZE;
ss->baud_base = state->baud_base;
ss->close_delay = close_delay;
ss->closing_wait = closing_wait;
@@ -969,7 +930,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss)
change_spd = ((ss->flags ^ port->flags) & ASYNC_SPD_MASK) ||
ss->custom_divisor != state->custom_divisor;
if (ss->irq || ss->port != state->port ||
- ss->xmit_fifo_size != state->xmit_fifo_size) {
+ ss->xmit_fifo_size != XMIT_FIFO_SIZE) {
tty_unlock(tty);
return -EINVAL;
}
@@ -979,11 +940,10 @@ static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss)
if (closing_wait != ASYNC_CLOSING_WAIT_NONE)
closing_wait = msecs_to_jiffies(closing_wait * 10);
- if (!serial_isroot()) {
+ if (!capable(CAP_SYS_ADMIN)) {
if ((ss->baud_base != state->baud_base) ||
(close_delay != port->close_delay) ||
(closing_wait != port->closing_wait) ||
- (ss->xmit_fifo_size != state->xmit_fifo_size) ||
((ss->flags & ~ASYNC_USR_MASK) !=
(port->flags & ~ASYNC_USR_MASK))) {
tty_unlock(tty);
@@ -1043,7 +1003,7 @@ static int get_lsr_info(struct serial_state *info, unsigned int __user *value)
unsigned long flags;
local_irq_save(flags);
- status = custom.serdatr;
+ status = amiga_custom.serdatr;
mb();
local_irq_restore(flags);
result = ((status & SDR_TSRE) ? TIOCSER_TEMT : 0);
@@ -1105,9 +1065,9 @@ static int rs_break(struct tty_struct *tty, int break_state)
local_irq_save(flags);
if (break_state == -1)
- custom.adkcon = AC_SETCLR | AC_UARTBRK;
+ amiga_custom.adkcon = AC_SETCLR | AC_UARTBRK;
else
- custom.adkcon = AC_UARTBRK;
+ amiga_custom.adkcon = AC_UARTBRK;
mb();
local_irq_restore(flags);
return 0;
@@ -1284,10 +1244,10 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
state->read_status_mask &= ~UART_LSR_DR;
if (tty_port_initialized(port)) {
/* disable receive interrupts */
- custom.intena = IF_RBF;
+ amiga_custom.intena = IF_RBF;
mb();
/* clear any pending receive interrupt */
- custom.intreq = IF_RBF;
+ amiga_custom.intreq = IF_RBF;
mb();
/*
@@ -1315,9 +1275,6 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
unsigned long orig_jiffies, char_time;
int lsr;
- if (info->xmit_fifo_size == 0)
- return; /* Just in case.... */
-
orig_jiffies = jiffies;
/*
@@ -1328,7 +1285,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
* Note: we have to use pretty tight timings here to satisfy
* the NIST-PCTS.
*/
- char_time = (info->timeout - HZ/50) / info->xmit_fifo_size;
+ char_time = (info->timeout - HZ/50) / XMIT_FIFO_SIZE;
char_time = char_time / 5;
if (char_time == 0)
char_time = 1;
@@ -1349,7 +1306,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
printk("jiff=%lu...", jiffies);
#endif
- while(!((lsr = custom.serdatr) & SDR_TSRE)) {
+ while(!((lsr = amiga_custom.serdatr) & SDR_TSRE)) {
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
printk("serdatr = %d (jiff=%lu)...", lsr, jiffies);
#endif
@@ -1389,14 +1346,14 @@ static void rs_hangup(struct tty_struct *tty)
*/
static int rs_open(struct tty_struct *tty, struct file * filp)
{
- struct serial_state *info = rs_table + tty->index;
- struct tty_port *port = &info->tport;
+ struct tty_port *port = tty->port;
+ struct serial_state *info = container_of(port, struct serial_state,
+ tport);
int retval;
port->count++;
port->tty = tty;
tty->driver_data = info;
- tty->port = port;
retval = startup(tty, info);
if (retval) {
@@ -1461,8 +1418,8 @@ static inline void line_info(struct seq_file *m, int line,
static int rs_proc_show(struct seq_file *m, void *v)
{
- seq_printf(m, "serinfo:1.0 driver:%s\n", serial_version);
- line_info(m, 0, &rs_table[0]);
+ seq_printf(m, "serinfo:1.0 driver:4.30\n");
+ line_info(m, 0, &serial_state);
return 0;
}
@@ -1474,17 +1431,6 @@ static int rs_proc_show(struct seq_file *m, void *v)
* ---------------------------------------------------------------------
*/
-/*
- * This routine prints out the appropriate serial driver version
- * number, and identifies which options were configured into this
- * driver.
- */
-static void show_serial_version(void)
-{
- printk(KERN_INFO "%s version %s\n", serial_name, serial_version);
-}
-
-
static const struct tty_operations serial_ops = {
.open = rs_open,
.close = rs_close,
@@ -1543,52 +1489,43 @@ static const struct tty_port_operations amiga_port_ops = {
*/
static int __init amiga_serial_probe(struct platform_device *pdev)
{
+ struct serial_state *state = &serial_state;
+ struct tty_driver *driver;
unsigned long flags;
- struct serial_state * state;
int error;
- serial_driver = alloc_tty_driver(NR_PORTS);
- if (!serial_driver)
- return -ENOMEM;
-
- show_serial_version();
+ driver = tty_alloc_driver(1, TTY_DRIVER_REAL_RAW);
+ if (IS_ERR(driver))
+ return PTR_ERR(driver);
/* Initialize the tty_driver structure */
- serial_driver->driver_name = "amiserial";
- serial_driver->name = "ttyS";
- serial_driver->major = TTY_MAJOR;
- serial_driver->minor_start = 64;
- serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
- serial_driver->subtype = SERIAL_TYPE_NORMAL;
- serial_driver->init_termios = tty_std_termios;
- serial_driver->init_termios.c_cflag =
+ driver->driver_name = "amiserial";
+ driver->name = "ttyS";
+ driver->major = TTY_MAJOR;
+ driver->minor_start = 64;
+ driver->type = TTY_DRIVER_TYPE_SERIAL;
+ driver->subtype = SERIAL_TYPE_NORMAL;
+ driver->init_termios = tty_std_termios;
+ driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- serial_driver->flags = TTY_DRIVER_REAL_RAW;
- tty_set_operations(serial_driver, &serial_ops);
-
- state = rs_table;
- state->port = (int)&custom.serdatr; /* Just to give it a value */
- state->custom_divisor = 0;
- state->icount.cts = state->icount.dsr =
- state->icount.rng = state->icount.dcd = 0;
- state->icount.rx = state->icount.tx = 0;
- state->icount.frame = state->icount.parity = 0;
- state->icount.overrun = state->icount.brk = 0;
+ tty_set_operations(driver, &serial_ops);
+
+ memset(state, 0, sizeof(*state));
+ state->port = (int)&amiga_custom.serdatr; /* Just to give it a value */
tty_port_init(&state->tport);
state->tport.ops = &amiga_port_ops;
- tty_port_link_device(&state->tport, serial_driver, 0);
+ tty_port_link_device(&state->tport, driver, 0);
- error = tty_register_driver(serial_driver);
+ error = tty_register_driver(driver);
if (error)
- goto fail_put_tty_driver;
+ goto fail_tty_driver_kref_put;
printk(KERN_INFO "ttyS0 is the amiga builtin serial port\n");
/* Hardware set up */
state->baud_base = amiga_colorclock;
- state->xmit_fifo_size = 1;
/* set ISRs, and then disable the rx interrupts */
error = request_irq(IRQ_AMIGA_TBE, ser_tx_int, 0, "serial TX", state);
@@ -1603,11 +1540,11 @@ static int __init amiga_serial_probe(struct platform_device *pdev)
local_irq_save(flags);
/* turn off Rx and Tx interrupts */
- custom.intena = IF_RBF | IF_TBE;
+ amiga_custom.intena = IF_RBF | IF_TBE;
mb();
/* clear any pending interrupt */
- custom.intreq = IF_RBF | IF_TBE;
+ amiga_custom.intreq = IF_RBF | IF_TBE;
mb();
local_irq_restore(flags);
@@ -1621,15 +1558,17 @@ static int __init amiga_serial_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, state);
+ serial_driver = driver;
+
return 0;
fail_free_irq:
free_irq(IRQ_AMIGA_TBE, state);
fail_unregister:
- tty_unregister_driver(serial_driver);
-fail_put_tty_driver:
+ tty_unregister_driver(driver);
+fail_tty_driver_kref_put:
tty_port_destroy(&state->tport);
- put_tty_driver(serial_driver);
+ tty_driver_kref_put(driver);
return error;
}
@@ -1637,9 +1576,8 @@ static int __exit amiga_serial_remove(struct platform_device *pdev)
{
struct serial_state *state = platform_get_drvdata(pdev);
- /* printk("Unloading %s: version %s\n", serial_name, serial_version); */
tty_unregister_driver(serial_driver);
- put_tty_driver(serial_driver);
+ tty_driver_kref_put(serial_driver);
tty_port_destroy(&state->tport);
free_irq(IRQ_AMIGA_TBE, state);
@@ -1668,8 +1606,8 @@ module_platform_driver_probe(amiga_serial_driver, amiga_serial_probe);
static void amiga_serial_putc(char c)
{
- custom.serdat = (unsigned char)c | 0x100;
- while (!(custom.serdatr & 0x2000))
+ amiga_custom.serdat = (unsigned char)c | 0x100;
+ while (!(amiga_custom.serdatr & 0x2000))
barrier();
}
@@ -1682,9 +1620,9 @@ static void amiga_serial_putc(char c)
static void serial_console_write(struct console *co, const char *s,
unsigned count)
{
- unsigned short intena = custom.intenar;
+ unsigned short intena = amiga_custom.intenar;
- custom.intena = IF_TBE;
+ amiga_custom.intena = IF_TBE;
while (count--) {
if (*s == '\n')
@@ -1692,7 +1630,7 @@ static void serial_console_write(struct console *co, const char *s,
amiga_serial_putc(*s++);
}
- custom.intena = IF_SETCLR | (intena & IF_TBE);
+ amiga_custom.intena = IF_SETCLR | (intena & IF_TBE);
}
static struct tty_driver *serial_console_device(struct console *c, int *index)
diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c
index 445e5ff9b36d..19d32cb6af84 100644
--- a/drivers/tty/ehv_bytechan.c
+++ b/drivers/tty/ehv_bytechan.c
@@ -751,6 +751,7 @@ static struct platform_driver ehv_bc_tty_driver = {
*/
static int __init ehv_bc_init(void)
{
+ struct tty_driver *driver;
struct device_node *np;
unsigned int count = 0; /* Number of elements in bcs[] */
int ret;
@@ -773,26 +774,28 @@ static int __init ehv_bc_init(void)
if (!bcs)
return -ENOMEM;
- ehv_bc_driver = alloc_tty_driver(count);
- if (!ehv_bc_driver) {
- ret = -ENOMEM;
+ driver = tty_alloc_driver(count, TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV);
+ if (IS_ERR(driver)) {
+ ret = PTR_ERR(driver);
goto err_free_bcs;
}
- ehv_bc_driver->driver_name = "ehv-bc";
- ehv_bc_driver->name = ehv_bc_console.name;
- ehv_bc_driver->type = TTY_DRIVER_TYPE_CONSOLE;
- ehv_bc_driver->subtype = SYSTEM_TYPE_CONSOLE;
- ehv_bc_driver->init_termios = tty_std_termios;
- ehv_bc_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
- tty_set_operations(ehv_bc_driver, &ehv_bc_ops);
+ driver->driver_name = "ehv-bc";
+ driver->name = ehv_bc_console.name;
+ driver->type = TTY_DRIVER_TYPE_CONSOLE;
+ driver->subtype = SYSTEM_TYPE_CONSOLE;
+ driver->init_termios = tty_std_termios;
+ tty_set_operations(driver, &ehv_bc_ops);
- ret = tty_register_driver(ehv_bc_driver);
+ ret = tty_register_driver(driver);
if (ret) {
pr_err("ehv-bc: could not register tty driver (ret=%i)\n", ret);
- goto err_put_tty_driver;
+ goto err_tty_driver_kref_put;
}
+ ehv_bc_driver = driver;
+
ret = platform_driver_register(&ehv_bc_tty_driver);
if (ret) {
pr_err("ehv-bc: could not register platform driver (ret=%i)\n",
@@ -803,9 +806,10 @@ static int __init ehv_bc_init(void)
return 0;
err_deregister_tty_driver:
- tty_unregister_driver(ehv_bc_driver);
-err_put_tty_driver:
- put_tty_driver(ehv_bc_driver);
+ ehv_bc_driver = NULL;
+ tty_unregister_driver(driver);
+err_tty_driver_kref_put:
+ tty_driver_kref_put(driver);
err_free_bcs:
kfree(bcs);
diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c
index ccb683a6e6f5..d24af649a8bb 100644
--- a/drivers/tty/goldfish.c
+++ b/drivers/tty/goldfish.c
@@ -253,18 +253,18 @@ static int goldfish_tty_create_driver(void)
ret = -ENOMEM;
goto err_alloc_goldfish_ttys_failed;
}
- tty = alloc_tty_driver(goldfish_tty_line_count);
- if (tty == NULL) {
- ret = -ENOMEM;
- goto err_alloc_tty_driver_failed;
+ tty = tty_alloc_driver(goldfish_tty_line_count,
+ TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV);
+ if (IS_ERR(tty)) {
+ ret = PTR_ERR(tty);
+ goto err_tty_alloc_driver_failed;
}
tty->driver_name = "goldfish";
tty->name = "ttyGF";
tty->type = TTY_DRIVER_TYPE_SERIAL;
tty->subtype = SERIAL_TYPE_NORMAL;
tty->init_termios = tty_std_termios;
- tty->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
- TTY_DRIVER_DYNAMIC_DEV;
tty_set_operations(tty, &goldfish_tty_ops);
ret = tty_register_driver(tty);
if (ret)
@@ -274,8 +274,8 @@ static int goldfish_tty_create_driver(void)
return 0;
err_tty_register_driver_failed:
- put_tty_driver(tty);
-err_alloc_tty_driver_failed:
+ tty_driver_kref_put(tty);
+err_tty_alloc_driver_failed:
kfree(goldfish_ttys);
goldfish_ttys = NULL;
err_alloc_goldfish_ttys_failed:
@@ -285,7 +285,7 @@ err_alloc_goldfish_ttys_failed:
static void goldfish_tty_delete_driver(void)
{
tty_unregister_driver(goldfish_tty_driver);
- put_tty_driver(goldfish_tty_driver);
+ tty_driver_kref_put(goldfish_tty_driver);
goldfish_tty_driver = NULL;
kfree(goldfish_ttys);
goldfish_ttys = NULL;
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c
index 5bb8c4e44961..7b30d5a05e2f 100644
--- a/drivers/tty/hvc/hvc_console.c
+++ b/drivers/tty/hvc/hvc_console.c
@@ -1021,9 +1021,10 @@ static int hvc_init(void)
int err;
/* We need more than hvc_count adapters due to hotplug additions. */
- drv = alloc_tty_driver(HVC_ALLOC_TTY_ADAPTERS);
- if (!drv) {
- err = -ENOMEM;
+ drv = tty_alloc_driver(HVC_ALLOC_TTY_ADAPTERS, TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_RESET_TERMIOS);
+ if (IS_ERR(drv)) {
+ err = PTR_ERR(drv);
goto out;
}
@@ -1033,7 +1034,6 @@ static int hvc_init(void)
drv->minor_start = HVC_MINOR;
drv->type = TTY_DRIVER_TYPE_SYSTEM;
drv->init_termios = tty_std_termios;
- drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
tty_set_operations(drv, &hvc_ops);
/* Always start the kthread because there can be hotplug vty adapters
@@ -1063,7 +1063,7 @@ stop_thread:
kthread_stop(hvc_task);
hvc_task = NULL;
put_tty:
- put_tty_driver(drv);
+ tty_driver_kref_put(drv);
out:
return err;
}
diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c
index 92c9a476defc..8f143c09a169 100644
--- a/drivers/tty/hvc/hvc_xen.c
+++ b/drivers/tty/hvc/hvc_xen.c
@@ -86,7 +86,11 @@ static int __write_console(struct xencons_info *xencons,
cons = intf->out_cons;
prod = intf->out_prod;
mb(); /* update queue values before going on */
- BUG_ON((prod - cons) > sizeof(intf->out));
+
+ if ((prod - cons) > sizeof(intf->out)) {
+ pr_err_once("xencons: Illegal ring page indices");
+ return -EINVAL;
+ }
while ((sent < len) && ((prod - cons) < sizeof(intf->out)))
intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++];
@@ -114,7 +118,10 @@ static int domU_write_console(uint32_t vtermno, const char *data, int len)
*/
while (len) {
int sent = __write_console(cons, data, len);
-
+
+ if (sent < 0)
+ return sent;
+
data += sent;
len -= sent;
@@ -138,7 +145,11 @@ static int domU_read_console(uint32_t vtermno, char *buf, int len)
cons = intf->in_cons;
prod = intf->in_prod;
mb(); /* get pointers before reading ring */
- BUG_ON((prod - cons) > sizeof(intf->in));
+
+ if ((prod - cons) > sizeof(intf->in)) {
+ pr_err_once("xencons: Illegal ring page indices");
+ return -EINVAL;
+ }
while (cons != prod && recv < len)
buf[recv++] = intf->in[MASK_XENCONS_IDX(cons++, intf->in)];
diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c
index fe5e6b4f43de..245da1dfd818 100644
--- a/drivers/tty/hvc/hvcs.c
+++ b/drivers/tty/hvc/hvcs.c
@@ -1445,10 +1445,11 @@ static int hvcs_initialize(void)
} else
num_ttys_to_alloc = hvcs_parm_num_devs;
- hvcs_tty_driver = alloc_tty_driver(num_ttys_to_alloc);
- if (!hvcs_tty_driver) {
+ hvcs_tty_driver = tty_alloc_driver(num_ttys_to_alloc,
+ TTY_DRIVER_REAL_RAW);
+ if (IS_ERR(hvcs_tty_driver)) {
mutex_unlock(&hvcs_init_mutex);
- return -ENOMEM;
+ return PTR_ERR(hvcs_tty_driver);
}
if (hvcs_alloc_index_list(num_ttys_to_alloc)) {
@@ -1473,7 +1474,6 @@ static int hvcs_initialize(void)
* throw us into a horrible recursive echo-echo-echo loop.
*/
hvcs_tty_driver->init_termios = hvcs_tty_termios;
- hvcs_tty_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(hvcs_tty_driver, &hvcs_ops);
@@ -1509,7 +1509,7 @@ buff_alloc_fail:
register_fail:
hvcs_free_index_list();
index_fail:
- put_tty_driver(hvcs_tty_driver);
+ tty_driver_kref_put(hvcs_tty_driver);
hvcs_tty_driver = NULL;
mutex_unlock(&hvcs_init_mutex);
return rc;
@@ -1562,7 +1562,7 @@ static void __exit hvcs_module_exit(void)
hvcs_free_index_list();
- put_tty_driver(hvcs_tty_driver);
+ tty_driver_kref_put(hvcs_tty_driver);
printk(KERN_INFO "HVCS: driver module removed.\n");
}
diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c
index bfc15279d5bc..aa81f4835fef 100644
--- a/drivers/tty/hvc/hvsi.c
+++ b/drivers/tty/hvc/hvsi.c
@@ -1038,29 +1038,29 @@ static const struct tty_operations hvsi_ops = {
static int __init hvsi_init(void)
{
- int i;
-
- hvsi_driver = alloc_tty_driver(hvsi_count);
- if (!hvsi_driver)
- return -ENOMEM;
-
- hvsi_driver->driver_name = "hvsi";
- hvsi_driver->name = "hvsi";
- hvsi_driver->major = HVSI_MAJOR;
- hvsi_driver->minor_start = HVSI_MINOR;
- hvsi_driver->type = TTY_DRIVER_TYPE_SYSTEM;
- hvsi_driver->init_termios = tty_std_termios;
- hvsi_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
- hvsi_driver->init_termios.c_ispeed = 9600;
- hvsi_driver->init_termios.c_ospeed = 9600;
- hvsi_driver->flags = TTY_DRIVER_REAL_RAW;
- tty_set_operations(hvsi_driver, &hvsi_ops);
+ struct tty_driver *driver;
+ int i, ret;
+
+ driver = tty_alloc_driver(hvsi_count, TTY_DRIVER_REAL_RAW);
+ if (IS_ERR(driver))
+ return PTR_ERR(driver);
+
+ driver->driver_name = "hvsi";
+ driver->name = "hvsi";
+ driver->major = HVSI_MAJOR;
+ driver->minor_start = HVSI_MINOR;
+ driver->type = TTY_DRIVER_TYPE_SYSTEM;
+ driver->init_termios = tty_std_termios;
+ driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
+ driver->init_termios.c_ispeed = 9600;
+ driver->init_termios.c_ospeed = 9600;
+ tty_set_operations(driver, &hvsi_ops);
for (i=0; i < hvsi_count; i++) {
struct hvsi_struct *hp = &hvsi_ports[i];
int ret = 1;
- tty_port_link_device(&hp->port, hvsi_driver, i);
+ tty_port_link_device(&hp->port, driver, i);
ret = request_irq(hp->virq, hvsi_interrupt, 0, "hvsi", hp);
if (ret)
@@ -1069,12 +1069,27 @@ static int __init hvsi_init(void)
}
hvsi_wait = wait_for_state; /* irqs active now */
- if (tty_register_driver(hvsi_driver))
- panic("Couldn't register hvsi console driver\n");
+ ret = tty_register_driver(driver);
+ if (ret) {
+ pr_err("Couldn't register hvsi console driver\n");
+ goto err_free_irq;
+ }
+
+ hvsi_driver = driver;
printk(KERN_DEBUG "HVSI: registered %i devices\n", hvsi_count);
return 0;
+err_free_irq:
+ hvsi_wait = poll_for_state;
+ for (i = 0; i < hvsi_count; i++) {
+ struct hvsi_struct *hp = &hvsi_ports[i];
+
+ free_irq(hp->virq, hp);
+ }
+ tty_driver_kref_put(driver);
+
+ return ret;
}
device_initcall(hvsi_init);
diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c
index e3a5a5ba752c..9edd5ae17580 100644
--- a/drivers/tty/ipwireless/tty.c
+++ b/drivers/tty/ipwireless/tty.c
@@ -564,9 +564,10 @@ int ipwireless_tty_init(void)
{
int result;
- ipw_tty_driver = alloc_tty_driver(IPWIRELESS_PCMCIA_MINORS);
- if (!ipw_tty_driver)
- return -ENOMEM;
+ ipw_tty_driver = tty_alloc_driver(IPWIRELESS_PCMCIA_MINORS,
+ TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV);
+ if (IS_ERR(ipw_tty_driver))
+ return PTR_ERR(ipw_tty_driver);
ipw_tty_driver->driver_name = IPWIRELESS_PCCARD_NAME;
ipw_tty_driver->name = "ttyIPWp";
@@ -574,7 +575,6 @@ int ipwireless_tty_init(void)
ipw_tty_driver->minor_start = IPWIRELESS_PCMCIA_START;
ipw_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
ipw_tty_driver->subtype = SERIAL_TYPE_NORMAL;
- ipw_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
ipw_tty_driver->init_termios = tty_std_termios;
ipw_tty_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
@@ -585,7 +585,7 @@ int ipwireless_tty_init(void)
if (result) {
printk(KERN_ERR IPWIRELESS_PCCARD_NAME
": failed to register tty driver\n");
- put_tty_driver(ipw_tty_driver);
+ tty_driver_kref_put(ipw_tty_driver);
return result;
}
@@ -595,7 +595,7 @@ int ipwireless_tty_init(void)
void ipwireless_tty_release(void)
{
tty_unregister_driver(ipw_tty_driver);
- put_tty_driver(ipw_tty_driver);
+ tty_driver_kref_put(ipw_tty_driver);
}
int ipwireless_tty_is_modem(struct ipw_tty *tty)
diff --git a/drivers/tty/mips_ejtag_fdc.c b/drivers/tty/mips_ejtag_fdc.c
index 3b5915b94fac..02c10a968de1 100644
--- a/drivers/tty/mips_ejtag_fdc.c
+++ b/drivers/tty/mips_ejtag_fdc.c
@@ -1042,7 +1042,7 @@ err_destroy_ports:
dport = &priv->ports[nport];
tty_port_destroy(&dport->port);
}
- put_tty_driver(priv->driver);
+ tty_driver_kref_put(priv->driver);
return ret;
}
diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c
index 64b18177c790..bf17e90858b8 100644
--- a/drivers/tty/moxa.c
+++ b/drivers/tty/moxa.c
@@ -1053,7 +1053,7 @@ static int __init moxa_init(void)
if (tty_register_driver(moxaDriver)) {
printk(KERN_ERR "can't register MOXA Smartio tty driver!\n");
- put_tty_driver(moxaDriver);
+ tty_driver_kref_put(moxaDriver);
return -1;
}
@@ -1119,7 +1119,7 @@ static void __exit moxa_exit(void)
del_timer_sync(&moxaTimer);
tty_unregister_driver(moxaDriver);
- put_tty_driver(moxaDriver);
+ tty_driver_kref_put(moxaDriver);
}
module_init(moxa_init);
@@ -2034,10 +2034,10 @@ static int moxa_get_serial_info(struct tty_struct *tty,
if (!info)
return -ENODEV;
mutex_lock(&info->port.mutex);
- ss->type = info->type,
- ss->line = info->port.tty->index,
- ss->flags = info->port.flags,
- ss->baud_base = 921600,
+ ss->type = info->type;
+ ss->line = info->port.tty->index;
+ ss->flags = info->port.flags;
+ ss->baud_base = 921600;
ss->close_delay = jiffies_to_msecs(info->port.close_delay) / 10;
mutex_unlock(&info->port.mutex);
return 0;
diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c
index 900ccb2ca166..1216f3985e18 100644
--- a/drivers/tty/mxser.c
+++ b/drivers/tty/mxser.c
@@ -1039,12 +1039,12 @@ static int mxser_get_serial_info(struct tty_struct *tty,
if (closing_wait != ASYNC_CLOSING_WAIT_NONE)
closing_wait = jiffies_to_msecs(closing_wait) / 10;
- ss->type = info->type,
- ss->line = tty->index,
- ss->port = info->ioaddr,
- ss->irq = info->board->irq,
- ss->flags = info->port.flags,
- ss->baud_base = MXSER_BAUD_BASE,
+ ss->type = info->type;
+ ss->line = tty->index;
+ ss->port = info->ioaddr;
+ ss->irq = info->board->irq;
+ ss->flags = info->port.flags;
+ ss->baud_base = MXSER_BAUD_BASE;
ss->close_delay = close_delay;
ss->closing_wait = closing_wait;
ss->custom_divisor = MXSER_CUSTOM_DIVISOR,
@@ -1976,9 +1976,10 @@ static int __init mxser_module_init(void)
{
int retval;
- mxvar_sdriver = alloc_tty_driver(MXSER_PORTS);
- if (!mxvar_sdriver)
- return -ENOMEM;
+ mxvar_sdriver = tty_alloc_driver(MXSER_PORTS, TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV);
+ if (IS_ERR(mxvar_sdriver))
+ return PTR_ERR(mxvar_sdriver);
/* Initialize the tty_driver structure */
mxvar_sdriver->name = "ttyMI";
@@ -1988,7 +1989,6 @@ static int __init mxser_module_init(void)
mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL;
mxvar_sdriver->init_termios = tty_std_termios;
mxvar_sdriver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
- mxvar_sdriver->flags = TTY_DRIVER_REAL_RAW|TTY_DRIVER_DYNAMIC_DEV;
tty_set_operations(mxvar_sdriver, &mxser_ops);
retval = tty_register_driver(mxvar_sdriver);
@@ -2008,7 +2008,7 @@ static int __init mxser_module_init(void)
err_unr:
tty_unregister_driver(mxvar_sdriver);
err_put:
- put_tty_driver(mxvar_sdriver);
+ tty_driver_kref_put(mxvar_sdriver);
return retval;
}
@@ -2016,7 +2016,7 @@ static void __exit mxser_module_exit(void)
{
pci_unregister_driver(&mxser_driver);
tty_unregister_driver(mxvar_sdriver);
- put_tty_driver(mxvar_sdriver);
+ tty_driver_kref_put(mxvar_sdriver);
}
module_init(mxser_module_init);
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index e907b7a5cab5..1d92d2a84889 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -3252,10 +3252,11 @@ static int __init gsm_init(void)
return status;
}
- gsm_tty_driver = alloc_tty_driver(256);
- if (!gsm_tty_driver) {
+ gsm_tty_driver = tty_alloc_driver(256, TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_HARDWARE_BREAK);
+ if (IS_ERR(gsm_tty_driver)) {
pr_err("gsm_init: tty allocation failed.\n");
- status = -ENOMEM;
+ status = PTR_ERR(gsm_tty_driver);
goto err_unreg_ldisc;
}
gsm_tty_driver->driver_name = "gsmtty";
@@ -3264,8 +3265,6 @@ static int __init gsm_init(void)
gsm_tty_driver->minor_start = 0;
gsm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
gsm_tty_driver->subtype = SERIAL_TYPE_NORMAL;
- gsm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV
- | TTY_DRIVER_HARDWARE_BREAK;
gsm_tty_driver->init_termios = tty_std_termios;
/* Fixme */
gsm_tty_driver->init_termios.c_lflag &= ~ECHO;
@@ -3280,7 +3279,7 @@ static int __init gsm_init(void)
gsm_tty_driver->major, gsm_tty_driver->minor_start);
return 0;
err_put_driver:
- put_tty_driver(gsm_tty_driver);
+ tty_driver_kref_put(gsm_tty_driver);
err_unreg_ldisc:
tty_unregister_ldisc(&tty_ldisc_packet);
return status;
@@ -3290,7 +3289,7 @@ static void __exit gsm_exit(void)
{
tty_unregister_ldisc(&tty_ldisc_packet);
tty_unregister_driver(gsm_tty_driver);
- put_tty_driver(gsm_tty_driver);
+ tty_driver_kref_put(gsm_tty_driver);
}
module_init(gsm_init);
diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c
index 0c80f25c8c3d..0454c78deee6 100644
--- a/drivers/tty/nozomi.c
+++ b/drivers/tty/nozomi.c
@@ -1824,16 +1824,16 @@ static __init int nozomi_init(void)
{
int ret;
- ntty_driver = alloc_tty_driver(NTTY_TTY_MAXMINORS);
- if (!ntty_driver)
- return -ENOMEM;
+ ntty_driver = tty_alloc_driver(NTTY_TTY_MAXMINORS, TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV);
+ if (IS_ERR(ntty_driver))
+ return PTR_ERR(ntty_driver);
ntty_driver->driver_name = NOZOMI_NAME_TTY;
ntty_driver->name = "noz";
ntty_driver->major = 0;
ntty_driver->type = TTY_DRIVER_TYPE_SERIAL;
ntty_driver->subtype = SERIAL_TYPE_NORMAL;
- ntty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
ntty_driver->init_termios = tty_std_termios;
ntty_driver->init_termios.c_cflag = B115200 | CS8 | CREAD | \
HUPCL | CLOCAL;
@@ -1857,7 +1857,7 @@ static __init int nozomi_init(void)
unr_tty:
tty_unregister_driver(ntty_driver);
free_tty:
- put_tty_driver(ntty_driver);
+ tty_driver_kref_put(ntty_driver);
return ret;
}
@@ -1865,7 +1865,7 @@ static __exit void nozomi_exit(void)
{
pci_unregister_driver(&nozomi_driver);
tty_unregister_driver(ntty_driver);
- put_tty_driver(ntty_driver);
+ tty_driver_kref_put(ntty_driver);
}
module_init(nozomi_init);
diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c
index 92498961fd92..f1324fe99378 100644
--- a/drivers/tty/serdev/core.c
+++ b/drivers/tty/serdev/core.c
@@ -562,23 +562,45 @@ struct acpi_serdev_lookup {
int index;
};
+/**
+ * serdev_acpi_get_uart_resource - Gets UARTSerialBus resource if type matches
+ * @ares: ACPI resource
+ * @uart: Pointer to UARTSerialBus resource will be returned here
+ *
+ * Checks if the given ACPI resource is of type UARTSerialBus.
+ * In this case, returns a pointer to it to the caller.
+ *
+ * Return: True if resource type is of UARTSerialBus, otherwise false.
+ */
+bool serdev_acpi_get_uart_resource(struct acpi_resource *ares,
+ struct acpi_resource_uart_serialbus **uart)
+{
+ struct acpi_resource_uart_serialbus *sb;
+
+ if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
+ return false;
+
+ sb = &ares->data.uart_serial_bus;
+ if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_UART)
+ return false;
+
+ *uart = sb;
+ return true;
+}
+EXPORT_SYMBOL_GPL(serdev_acpi_get_uart_resource);
+
static int acpi_serdev_parse_resource(struct acpi_resource *ares, void *data)
{
struct acpi_serdev_lookup *lookup = data;
struct acpi_resource_uart_serialbus *sb;
acpi_status status;
- if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
- return 1;
-
- if (ares->data.common_serial_bus.type != ACPI_RESOURCE_SERIAL_TYPE_UART)
+ if (!serdev_acpi_get_uart_resource(ares, &sb))
return 1;
if (lookup->index != -1 && lookup->n++ != lookup->index)
return 1;
- sb = &ares->data.uart_serial_bus;
-
status = acpi_get_handle(lookup->device_handle,
sb->resource_source.string_ptr,
&lookup->controller_handle);
@@ -586,7 +608,7 @@ static int acpi_serdev_parse_resource(struct acpi_resource *ares, void *data)
return 1;
/*
- * NOTE: Ideally, we would also want to retreive other properties here,
+ * NOTE: Ideally, we would also want to retrieve other properties here,
* once setting them before opening the device is supported by serdev.
*/
diff --git a/drivers/tty/serial/8250/8250_bcm7271.c b/drivers/tty/serial/8250/8250_bcm7271.c
index 725a450058f8..7f656fac503f 100644
--- a/drivers/tty/serial/8250/8250_bcm7271.c
+++ b/drivers/tty/serial/8250/8250_bcm7271.c
@@ -941,7 +941,7 @@ static int brcmuart_probe(struct platform_device *pdev)
struct clk *baud_mux_clk;
struct uart_8250_port up;
struct resource *irq;
- void __iomem *membase = 0;
+ void __iomem *membase = NULL;
resource_size_t mapbase = 0;
u32 clk_rate = 0;
int ret;
diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c
index 3ffeedc29c83..d502240bbcf2 100644
--- a/drivers/tty/serial/8250/8250_exar.c
+++ b/drivers/tty/serial/8250/8250_exar.c
@@ -114,6 +114,7 @@ struct exar8250;
struct exar8250_platform {
int (*rs485_config)(struct uart_port *, struct serial_rs485 *);
int (*register_gpio)(struct pci_dev *, struct uart_8250_port *);
+ void (*unregister_gpio)(struct uart_8250_port *);
};
/**
@@ -352,9 +353,8 @@ static void setup_gpio(struct pci_dev *pcidev, u8 __iomem *p)
writeb(0x00, p + UART_EXAR_MPIOOD_15_8);
}
-static void *
-__xr17v35x_register_gpio(struct pci_dev *pcidev,
- const struct software_node *node)
+static struct platform_device *__xr17v35x_register_gpio(struct pci_dev *pcidev,
+ const struct software_node *node)
{
struct platform_device *pdev;
@@ -374,6 +374,12 @@ __xr17v35x_register_gpio(struct pci_dev *pcidev,
return pdev;
}
+static void __xr17v35x_unregister_gpio(struct platform_device *pdev)
+{
+ device_remove_software_node(&pdev->dev);
+ platform_device_unregister(pdev);
+}
+
static const struct property_entry exar_gpio_properties[] = {
PROPERTY_ENTRY_U32("exar,first-pin", 0),
PROPERTY_ENTRY_U32("ngpios", 16),
@@ -384,8 +390,7 @@ static const struct software_node exar_gpio_node = {
.properties = exar_gpio_properties,
};
-static int xr17v35x_register_gpio(struct pci_dev *pcidev,
- struct uart_8250_port *port)
+static int xr17v35x_register_gpio(struct pci_dev *pcidev, struct uart_8250_port *port)
{
if (pcidev->vendor == PCI_VENDOR_ID_EXAR)
port->port.private_data =
@@ -394,6 +399,15 @@ static int xr17v35x_register_gpio(struct pci_dev *pcidev,
return 0;
}
+static void xr17v35x_unregister_gpio(struct uart_8250_port *port)
+{
+ if (!port->port.private_data)
+ return;
+
+ __xr17v35x_unregister_gpio(port->port.private_data);
+ port->port.private_data = NULL;
+}
+
static int generic_rs485_config(struct uart_port *port,
struct serial_rs485 *rs485)
{
@@ -419,6 +433,7 @@ static int generic_rs485_config(struct uart_port *port,
static const struct exar8250_platform exar8250_default_platform = {
.register_gpio = xr17v35x_register_gpio,
+ .unregister_gpio = xr17v35x_unregister_gpio,
.rs485_config = generic_rs485_config,
};
@@ -484,6 +499,7 @@ static int iot2040_register_gpio(struct pci_dev *pcidev,
static const struct exar8250_platform iot2040_platform = {
.rs485_config = iot2040_rs485_config,
.register_gpio = iot2040_register_gpio,
+ .unregister_gpio = xr17v35x_unregister_gpio,
};
/*
@@ -555,17 +571,11 @@ pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev,
static void pci_xr17v35x_exit(struct pci_dev *pcidev)
{
+ const struct exar8250_platform *platform = exar_get_platform();
struct exar8250 *priv = pci_get_drvdata(pcidev);
struct uart_8250_port *port = serial8250_get_port(priv->line[0]);
- struct platform_device *pdev;
- pdev = port->port.private_data;
- if (!pdev)
- return;
-
- device_remove_software_node(&pdev->dev);
- platform_device_unregister(pdev);
- port->port.private_data = NULL;
+ platform->unregister_gpio(port);
}
static inline void exar_misc_clear(struct exar8250 *priv)
diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c
index 988bf6bcce42..65402d05eff9 100644
--- a/drivers/tty/serial/8250/8250_ingenic.c
+++ b/drivers/tty/serial/8250/8250_ingenic.c
@@ -209,16 +209,14 @@ static int ingenic_uart_probe(struct platform_device *pdev)
struct uart_8250_port uart = {};
struct ingenic_uart_data *data;
const struct ingenic_uart_config *cdata;
- const struct of_device_id *match;
struct resource *regs;
int irq, err, line;
- match = of_match_device(of_match, &pdev->dev);
- if (!match) {
+ cdata = of_device_get_match_data(&pdev->dev);
+ if (!cdata) {
dev_err(&pdev->dev, "Error: No device match found\n");
return -ENODEV;
}
- cdata = match->data;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
diff --git a/drivers/tty/serial/8250/8250_lpss.c b/drivers/tty/serial/8250/8250_lpss.c
index 4dee8a9e0c95..848d81e3838c 100644
--- a/drivers/tty/serial/8250/8250_lpss.c
+++ b/drivers/tty/serial/8250/8250_lpss.c
@@ -158,6 +158,16 @@ static int byt_serial_setup(struct lpss8250 *lpss, struct uart_port *port)
static int ehl_serial_setup(struct lpss8250 *lpss, struct uart_port *port)
{
+ struct uart_8250_dma *dma = &lpss->data.dma;
+ struct uart_8250_port *up = up_to_u8250p(port);
+
+ /*
+ * This simply makes the checks in the 8250_port to try the DMA
+ * channel request which in turn uses the magic of ACPI tables
+ * parsing (see drivers/dma/acpi-dma.c for the details) and
+ * matching with the registered General Purpose DMA controllers.
+ */
+ up->dma = dma;
return 0;
}
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 79418d4beb48..891fd8345e25 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -538,7 +538,7 @@ static void omap_8250_pm(struct uart_port *port, unsigned int state,
static void omap_serial_fill_features_erratas(struct uart_8250_port *up,
struct omap8250_priv *priv)
{
- const struct soc_device_attribute k3_soc_devices[] = {
+ static const struct soc_device_attribute k3_soc_devices[] = {
{ .family = "AM65X", },
{ .family = "J721E", .revision = "SR1.0" },
{ /* sentinel */ }
@@ -617,7 +617,7 @@ static irqreturn_t omap8250_irq(int irq, void *dev_id)
struct uart_port *port = dev_id;
struct omap8250_priv *priv = port->private_data;
struct uart_8250_port *up = up_to_u8250p(port);
- unsigned int iir;
+ unsigned int iir, lsr;
int ret;
#ifdef CONFIG_SERIAL_8250_DMA
@@ -628,6 +628,7 @@ static irqreturn_t omap8250_irq(int irq, void *dev_id)
#endif
serial8250_rpm_get(up);
+ lsr = serial_port_in(port, UART_LSR);
iir = serial_port_in(port, UART_IIR);
ret = serial8250_handle_irq(port, iir);
@@ -642,6 +643,24 @@ static irqreturn_t omap8250_irq(int irq, void *dev_id)
serial_port_in(port, UART_RX);
}
+ /* Stop processing interrupts on input overrun */
+ if ((lsr & UART_LSR_OE) && up->overrun_backoff_time_ms > 0) {
+ unsigned long delay;
+
+ up->ier = port->serial_in(port, UART_IER);
+ if (up->ier & (UART_IER_RLSI | UART_IER_RDI)) {
+ port->ops->stop_rx(port);
+ } else {
+ /* Keep restarting the timer until
+ * the input overrun subsides.
+ */
+ cancel_delayed_work(&up->overrun_backoff);
+ }
+
+ delay = msecs_to_jiffies(up->overrun_backoff_time_ms);
+ schedule_delayed_work(&up->overrun_backoff, delay);
+ }
+
serial8250_rpm_put(up);
return IRQ_RETVAL(ret);
@@ -1353,6 +1372,10 @@ static int omap8250_probe(struct platform_device *pdev)
}
}
+ if (of_property_read_u32(np, "overrun-throttle-ms",
+ &up.overrun_backoff_time_ms) != 0)
+ up.overrun_backoff_time_ms = 0;
+
priv->wakeirq = irq_of_parse_and_map(np, 1);
pdata = of_device_get_match_data(&pdev->dev);
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index a808c283883e..726912b16a55 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -87,7 +87,7 @@ static void moan_device(const char *str, struct pci_dev *dev)
static int
setup_port(struct serial_private *priv, struct uart_8250_port *port,
- int bar, int offset, int regshift)
+ u8 bar, unsigned int offset, int regshift)
{
struct pci_dev *dev = priv->dev;
diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c
index de90d681b64c..98e5ee4d0d08 100644
--- a/drivers/tty/serial/8250/8250_pnp.c
+++ b/drivers/tty/serial/8250/8250_pnp.c
@@ -13,6 +13,7 @@
#include <linux/pnp.h>
#include <linux/string.h>
#include <linux/kernel.h>
+#include <linux/property.h>
#include <linux/serial_core.h>
#include <linux/bitops.h>
@@ -475,6 +476,7 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
if (pnp_irq_flags(dev, 0) & IORESOURCE_IRQ_SHAREABLE)
uart.port.flags |= UPF_SHARE_IRQ;
uart.port.uartclk = 1843200;
+ device_property_read_u32(&dev->dev, "clock-frequency", &uart.port.uartclk);
uart.port.dev = &dev->dev;
line = serial8250_register_8250_port(&uart);
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 1da29a219842..66374704747e 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -122,7 +122,8 @@ static const struct serial8250_config uart_config[] = {
.name = "16C950/954",
.fifo_size = 128,
.tx_loadsz = 128,
- .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+ .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01,
+ .rxtrig_bytes = {16, 32, 112, 120},
/* UART_CAP_EFR breaks billionon CF bluetooth card. */
.flags = UART_CAP_FIFO | UART_CAP_SLEEP,
},
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index d1b3c2373fa4..71ae16de0f90 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -363,7 +363,7 @@ config SERIAL_8250_BCM2835AUX
config SERIAL_8250_FSL
bool
depends on SERIAL_8250_CONSOLE
- default PPC || ARM || ARM64
+ default PPC || ARM || ARM64 || COMPILE_TEST
config SERIAL_8250_DW
tristate "Support for Synopsys DesignWare 8250 quirks"
@@ -375,7 +375,8 @@ config SERIAL_8250_DW
config SERIAL_8250_EM
tristate "Support for Emma Mobile integrated serial port"
- depends on SERIAL_8250 && ARM && HAVE_CLK
+ depends on SERIAL_8250 && HAVE_CLK
+ depends on ARM || COMPILE_TEST
help
Selecting this option will add support for the integrated serial
port hardware found on the Emma Mobile line of processors.
@@ -383,7 +384,8 @@ config SERIAL_8250_EM
config SERIAL_8250_IOC3
tristate "SGI IOC3 8250 UART support"
- depends on SGI_MFD_IOC3 && SERIAL_8250
+ depends on SERIAL_8250
+ depends on SGI_MFD_IOC3 || COMPILE_TEST
select SERIAL_8250_EXTENDED
select SERIAL_8250_SHARE_IRQ
help
@@ -495,7 +497,7 @@ config SERIAL_8250_MID
config SERIAL_8250_PXA
tristate "PXA serial port support"
depends on SERIAL_8250
- depends on ARCH_PXA || ARCH_MMP
+ depends on ARCH_PXA || ARCH_MMP || COMPILE_TEST
help
If you have a machine based on an Intel XScale PXA2xx CPU you can
enable its onboard serial ports by enabling this option. The option is
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 24282ad99d85..131a6a587acd 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -959,7 +959,7 @@ config SERIAL_VT8500_CONSOLE
config SERIAL_OMAP
tristate "OMAP serial port support"
- depends on ARCH_OMAP2PLUS || COMPILE_TEST
+ depends on (ARCH_OMAP2PLUS && !SERIAL_8250_OMAP) || COMPILE_TEST
select SERIAL_CORE
help
If you have a machine based on an Texas Instruments OMAP CPU you
@@ -1382,7 +1382,7 @@ config SERIAL_ST_ASC
select SERIAL_CORE
depends on ARM || COMPILE_TEST
help
- This driver is for the on-chip Asychronous Serial Controller on
+ This driver is for the on-chip Asynchronous Serial Controller on
STMicroelectronics STi SoCs.
ASC is embedded in ST COMMS IP block. It supports Rx & Tx functionality.
It support all industry standard baud rates.
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index e14f3378b8a0..d361cd84ff8c 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -265,6 +265,8 @@ struct uart_amba_port {
unsigned int old_cr; /* state during shutdown */
unsigned int fixed_baud; /* vendor-set fixed baud rate */
char type[12];
+ bool rs485_tx_started;
+ unsigned int rs485_tx_drain_interval; /* usecs */
#ifdef CONFIG_DMA_ENGINE
/* DMA stuff */
bool using_tx_dma;
@@ -275,6 +277,8 @@ struct uart_amba_port {
#endif
};
+static unsigned int pl011_tx_empty(struct uart_port *port);
+
static unsigned int pl011_reg_to_offset(const struct uart_amba_port *uap,
unsigned int reg)
{
@@ -1282,6 +1286,42 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
#define pl011_dma_flush_buffer NULL
#endif
+static void pl011_rs485_tx_stop(struct uart_amba_port *uap)
+{
+ struct uart_port *port = &uap->port;
+ int i = 0;
+ u32 cr;
+
+ /* Wait until hardware tx queue is empty */
+ while (!pl011_tx_empty(port)) {
+ if (i == port->fifosize) {
+ dev_warn(port->dev,
+ "timeout while draining hardware tx queue\n");
+ break;
+ }
+
+ udelay(uap->rs485_tx_drain_interval);
+ i++;
+ }
+
+ if (port->rs485.delay_rts_after_send)
+ mdelay(port->rs485.delay_rts_after_send);
+
+ cr = pl011_read(uap, REG_CR);
+
+ if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
+ cr &= ~UART011_CR_RTS;
+ else
+ cr |= UART011_CR_RTS;
+
+ /* Disable the transmitter and reenable the transceiver */
+ cr &= ~UART011_CR_TXE;
+ cr |= UART011_CR_RXE;
+ pl011_write(cr, uap, REG_CR);
+
+ uap->rs485_tx_started = false;
+}
+
static void pl011_stop_tx(struct uart_port *port)
{
struct uart_amba_port *uap =
@@ -1290,6 +1330,9 @@ static void pl011_stop_tx(struct uart_port *port)
uap->im &= ~UART011_TXIM;
pl011_write(uap->im, uap, REG_IMSC);
pl011_dma_tx_stop(uap);
+
+ if ((port->rs485.flags & SER_RS485_ENABLED) && uap->rs485_tx_started)
+ pl011_rs485_tx_stop(uap);
}
static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq);
@@ -1380,6 +1423,32 @@ static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c,
return true;
}
+static void pl011_rs485_tx_start(struct uart_amba_port *uap)
+{
+ struct uart_port *port = &uap->port;
+ u32 cr;
+
+ /* Enable transmitter */
+ cr = pl011_read(uap, REG_CR);
+ cr |= UART011_CR_TXE;
+
+ /* Disable receiver if half-duplex */
+ if (!(port->rs485.flags & SER_RS485_RX_DURING_TX))
+ cr &= ~UART011_CR_RXE;
+
+ if (port->rs485.flags & SER_RS485_RTS_ON_SEND)
+ cr &= ~UART011_CR_RTS;
+ else
+ cr |= UART011_CR_RTS;
+
+ pl011_write(cr, uap, REG_CR);
+
+ if (port->rs485.delay_rts_before_send)
+ mdelay(port->rs485.delay_rts_before_send);
+
+ uap->rs485_tx_started = true;
+}
+
/* Returns true if tx interrupts have to be (kept) enabled */
static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq)
{
@@ -1397,6 +1466,10 @@ static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq)
return false;
}
+ if ((uap->port.rs485.flags & SER_RS485_ENABLED) &&
+ !uap->rs485_tx_started)
+ pl011_rs485_tx_start(uap);
+
/* If we are using DMA mode, try to send some characters. */
if (pl011_dma_tx_irq(uap))
return true;
@@ -1542,6 +1615,9 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
container_of(port, struct uart_amba_port, port);
unsigned int cr;
+ if (port->rs485.flags & SER_RS485_ENABLED)
+ mctrl &= ~TIOCM_RTS;
+
cr = pl011_read(uap, REG_CR);
#define TIOCMBIT(tiocmbit, uartbit) \
@@ -1763,7 +1839,17 @@ static int pl011_startup(struct uart_port *port)
/* restore RTS and DTR */
cr = uap->old_cr & (UART011_CR_RTS | UART011_CR_DTR);
- cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE;
+ cr |= UART01x_CR_UARTEN | UART011_CR_RXE;
+
+ if (port->rs485.flags & SER_RS485_ENABLED) {
+ if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
+ cr &= ~UART011_CR_RTS;
+ else
+ cr |= UART011_CR_RTS;
+ } else {
+ cr |= UART011_CR_TXE;
+ }
+
pl011_write(cr, uap, REG_CR);
spin_unlock_irq(&uap->port.lock);
@@ -1864,6 +1950,9 @@ static void pl011_shutdown(struct uart_port *port)
pl011_dma_shutdown(uap);
+ if ((port->rs485.flags & SER_RS485_ENABLED) && uap->rs485_tx_started)
+ pl011_rs485_tx_stop(uap);
+
free_irq(uap->port.irq, uap);
pl011_disable_uart(uap);
@@ -1941,6 +2030,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
unsigned int lcr_h, old_cr;
unsigned long flags;
unsigned int baud, quot, clkdiv;
+ unsigned int bits;
if (uap->vendor->oversampling)
clkdiv = 8;
@@ -1991,6 +2081,8 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
if (uap->fifosize > 1)
lcr_h |= UART01x_LCRH_FEN;
+ bits = tty_get_frame_size(termios->c_cflag);
+
spin_lock_irqsave(&port->lock, flags);
/*
@@ -1998,11 +2090,21 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
*/
uart_update_timeout(port, termios->c_cflag, baud);
+ /*
+ * Calculate the approximated time it takes to transmit one character
+ * with the given baud rate. We use this as the poll interval when we
+ * wait for the tx queue to empty.
+ */
+ uap->rs485_tx_drain_interval = (bits * 1000 * 1000) / baud;
+
pl011_setup_status_masks(port, termios);
if (UART_ENABLE_MS(port, termios->c_cflag))
pl011_enable_ms(port);
+ if (port->rs485.flags & SER_RS485_ENABLED)
+ termios->c_cflag &= ~CRTSCTS;
+
/* first, disable everything */
old_cr = pl011_read(uap, REG_CR);
pl011_write(0, uap, REG_CR);
@@ -2124,6 +2226,41 @@ static int pl011_verify_port(struct uart_port *port, struct serial_struct *ser)
return ret;
}
+static int pl011_rs485_config(struct uart_port *port,
+ struct serial_rs485 *rs485)
+{
+ struct uart_amba_port *uap =
+ container_of(port, struct uart_amba_port, port);
+
+ /* pick sane settings if the user hasn't */
+ if (!(rs485->flags & SER_RS485_RTS_ON_SEND) ==
+ !(rs485->flags & SER_RS485_RTS_AFTER_SEND)) {
+ rs485->flags |= SER_RS485_RTS_ON_SEND;
+ rs485->flags &= ~SER_RS485_RTS_AFTER_SEND;
+ }
+ /* clamp the delays to [0, 100ms] */
+ rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
+ rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U);
+ memset(rs485->padding, 0, sizeof(rs485->padding));
+
+ if (port->rs485.flags & SER_RS485_ENABLED)
+ pl011_rs485_tx_stop(uap);
+
+ /* Set new configuration */
+ port->rs485 = *rs485;
+
+ /* Make sure auto RTS is disabled */
+ if (port->rs485.flags & SER_RS485_ENABLED) {
+ u32 cr = pl011_read(uap, REG_CR);
+
+ cr &= ~UART011_CR_RTSEN;
+ pl011_write(cr, uap, REG_CR);
+ port->status &= ~UPSTAT_AUTORTS;
+ }
+
+ return 0;
+}
+
static const struct uart_ops amba_pl011_pops = {
.tx_empty = pl011_tx_empty,
.set_mctrl = pl011_set_mctrl,
@@ -2588,10 +2725,28 @@ static int pl011_find_free_port(void)
return -EBUSY;
}
+static int pl011_get_rs485_mode(struct uart_amba_port *uap)
+{
+ struct uart_port *port = &uap->port;
+ struct serial_rs485 *rs485 = &port->rs485;
+ int ret;
+
+ ret = uart_get_rs485_mode(port);
+ if (ret)
+ return ret;
+
+ /* clamp the delays to [0, 100ms] */
+ rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
+ rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U);
+
+ return 0;
+}
+
static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap,
struct resource *mmiobase, int index)
{
void __iomem *base;
+ int ret;
base = devm_ioremap_resource(dev, mmiobase);
if (IS_ERR(base))
@@ -2608,6 +2763,10 @@ static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap,
uap->port.flags = UPF_BOOT_AUTOCONF;
uap->port.line = index;
+ ret = pl011_get_rs485_mode(uap);
+ if (ret)
+ return ret;
+
amba_ports[index] = uap;
return 0;
@@ -2665,7 +2824,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
uap->port.iotype = vendor->access_32b ? UPIO_MEM32 : UPIO_MEM;
uap->port.irq = dev->irq[0];
uap->port.ops = &amba_pl011_pops;
-
+ uap->port.rs485_config = pl011_rs485_config;
snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev));
ret = pl011_setup_port(&dev->dev, uap, &dev->res, portnr);
diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c
index d87048073abe..283757264608 100644
--- a/drivers/tty/serial/fsl_linflexuart.c
+++ b/drivers/tty/serial/fsl_linflexuart.c
@@ -861,11 +861,7 @@ static int linflex_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, sport);
- ret = uart_add_one_port(&linflex_reg, sport);
- if (ret)
- return ret;
-
- return 0;
+ return uart_add_one_port(&linflex_reg, sport);
}
static int linflex_remove(struct platform_device *pdev)
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index f0e5da77ed6d..b1e7190ae483 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -7,6 +7,7 @@
#include <linux/clk.h>
#include <linux/console.h>
+#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/dmapool.h>
@@ -109,6 +110,11 @@
#define UARTSFIFO_TXOF 0x02
#define UARTSFIFO_RXUF 0x01
+/* 32-bit global registers only for i.MX7ULP/i.MX8x
+ * Used to reset all internal logic and registers, except the Global Register.
+ */
+#define UART_GLOBAL 0x8
+
/* 32-bit register definition */
#define UARTBAUD 0x00
#define UARTSTAT 0x04
@@ -219,6 +225,10 @@
#define UARTWATER_TXWATER_OFF 0
#define UARTWATER_RXWATER_OFF 16
+#define UART_GLOBAL_RST 0x2
+#define GLOBAL_RST_MIN_US 20
+#define GLOBAL_RST_MAX_US 40
+
/* Rx DMA timeout in ms, which is used to calculate Rx ring buffer size */
#define DMA_RX_TIMEOUT (10)
@@ -320,6 +330,11 @@ static inline bool is_layerscape_lpuart(struct lpuart_port *sport)
sport->devtype == LS1028A_LPUART);
}
+static inline bool is_imx7ulp_lpuart(struct lpuart_port *sport)
+{
+ return sport->devtype == IMX7ULP_LPUART;
+}
+
static inline bool is_imx8qxp_lpuart(struct lpuart_port *sport)
{
return sport->devtype == IMX8QXP_LPUART;
@@ -383,6 +398,33 @@ static unsigned int lpuart_get_baud_clk_rate(struct lpuart_port *sport)
#define lpuart_enable_clks(x) __lpuart_enable_clks(x, true)
#define lpuart_disable_clks(x) __lpuart_enable_clks(x, false)
+static int lpuart_global_reset(struct lpuart_port *sport)
+{
+ struct uart_port *port = &sport->port;
+ void __iomem *global_addr;
+ int ret;
+
+ if (uart_console(port))
+ return 0;
+
+ ret = clk_prepare_enable(sport->ipg_clk);
+ if (ret) {
+ dev_err(sport->port.dev, "failed to enable uart ipg clk: %d\n", ret);
+ return ret;
+ }
+
+ if (is_imx7ulp_lpuart(sport) || is_imx8qxp_lpuart(sport)) {
+ global_addr = port->membase + UART_GLOBAL - IMX_REG_OFF;
+ writel(UART_GLOBAL_RST, global_addr);
+ usleep_range(GLOBAL_RST_MIN_US, GLOBAL_RST_MAX_US);
+ writel(0, global_addr);
+ usleep_range(GLOBAL_RST_MIN_US, GLOBAL_RST_MAX_US);
+ }
+
+ clk_disable_unprepare(sport->ipg_clk);
+ return 0;
+}
+
static void lpuart_stop_tx(struct uart_port *port)
{
unsigned char temp;
@@ -479,6 +521,10 @@ static void lpuart_dma_tx_complete(void *arg)
unsigned long flags;
spin_lock_irqsave(&sport->port.lock, flags);
+ if (!sport->dma_tx_in_progress) {
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+ return;
+ }
dma_unmap_sg(chan->device->dev, sgl, sport->dma_tx_nents,
DMA_TO_DEVICE);
@@ -2045,11 +2091,12 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
unsigned long flags;
- unsigned long ctrl, old_ctrl, modem;
+ unsigned long ctrl, old_ctrl, bd, modem;
unsigned int baud;
unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
ctrl = old_ctrl = lpuart32_read(&sport->port, UARTCTRL);
+ bd = lpuart32_read(&sport->port, UARTBAUD);
modem = lpuart32_read(&sport->port, UARTMODIR);
/*
* only support CS8 and CS7, and for CS7 must enable PE.
@@ -2093,7 +2140,9 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
}
if (termios->c_cflag & CSTOPB)
- termios->c_cflag &= ~CSTOPB;
+ bd |= UARTBAUD_SBNS;
+ else
+ bd &= ~UARTBAUD_SBNS;
/* parity must be enabled when CS7 to match 8-bits format */
if ((termios->c_cflag & CSIZE) == CS7)
@@ -2163,6 +2212,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
lpuart32_write(&sport->port, old_ctrl & ~(UARTCTRL_TE | UARTCTRL_RE),
UARTCTRL);
+ lpuart32_write(&sport->port, bd, UARTBAUD);
lpuart32_serial_setbrg(sport, baud);
lpuart32_write(&sport->port, modem, UARTMODIR);
lpuart32_write(&sport->port, ctrl, UARTCTRL);
@@ -2611,7 +2661,7 @@ static int lpuart_probe(struct platform_device *pdev)
return PTR_ERR(sport->port.membase);
sport->port.membase += sdata->reg_off;
- sport->port.mapbase = res->start;
+ sport->port.mapbase = res->start + sdata->reg_off;
sport->port.dev = &pdev->dev;
sport->port.type = PORT_LPUART;
sport->devtype = sdata->devtype;
@@ -2691,6 +2741,10 @@ static int lpuart_probe(struct platform_device *pdev)
if (ret)
goto failed_attach_port;
+ ret = lpuart_global_reset(sport);
+ if (ret)
+ goto failed_reset;
+
ret = uart_get_rs485_mode(&sport->port);
if (ret)
goto failed_get_rs485;
@@ -2707,6 +2761,8 @@ static int lpuart_probe(struct platform_device *pdev)
return 0;
failed_get_rs485:
+failed_reset:
+ uart_remove_one_port(&lpuart_reg, &sport->port);
failed_attach_port:
failed_irq_request:
lpuart_disable_clks(sport);
diff --git a/drivers/tty/serial/jsm/jsm_neo.c b/drivers/tty/serial/jsm/jsm_neo.c
index bf0e2a4cb0ce..c6f927a76c3b 100644
--- a/drivers/tty/serial/jsm/jsm_neo.c
+++ b/drivers/tty/serial/jsm/jsm_neo.c
@@ -815,7 +815,9 @@ static void neo_parse_isr(struct jsm_board *brd, u32 port)
/* Parse any modem signal changes */
jsm_dbg(INTR, &ch->ch_bd->pci_dev,
"MOD_STAT: sending to parse_modem_sigs\n");
+ spin_lock_irqsave(&ch->uart_port.lock, lock_flags);
neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr));
+ spin_unlock_irqrestore(&ch->uart_port.lock, lock_flags);
}
}
diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c
index 8e42a7682c63..d74cbbbf33c6 100644
--- a/drivers/tty/serial/jsm/jsm_tty.c
+++ b/drivers/tty/serial/jsm/jsm_tty.c
@@ -187,6 +187,7 @@ static void jsm_tty_break(struct uart_port *port, int break_state)
static int jsm_tty_open(struct uart_port *port)
{
+ unsigned long lock_flags;
struct jsm_board *brd;
struct jsm_channel *channel =
container_of(port, struct jsm_channel, uart_port);
@@ -240,6 +241,7 @@ static int jsm_tty_open(struct uart_port *port)
channel->ch_cached_lsr = 0;
channel->ch_stops_sent = 0;
+ spin_lock_irqsave(&port->lock, lock_flags);
termios = &port->state->port.tty->termios;
channel->ch_c_cflag = termios->c_cflag;
channel->ch_c_iflag = termios->c_iflag;
@@ -259,6 +261,7 @@ static int jsm_tty_open(struct uart_port *port)
jsm_carrier(channel);
channel->ch_open_count++;
+ spin_unlock_irqrestore(&port->lock, lock_flags);
jsm_dbg(OPEN, &channel->ch_bd->pci_dev, "finish\n");
return 0;
diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c
index 3e7c6ee8e4b3..55c3c9db7462 100644
--- a/drivers/tty/serial/kgdb_nmi.c
+++ b/drivers/tty/serial/kgdb_nmi.c
@@ -330,17 +330,16 @@ int kgdb_register_nmi_console(void)
if (!arch_kgdb_ops.enable_nmi)
return 0;
- kgdb_nmi_tty_driver = alloc_tty_driver(1);
- if (!kgdb_nmi_tty_driver) {
+ kgdb_nmi_tty_driver = tty_alloc_driver(1, TTY_DRIVER_REAL_RAW);
+ if (IS_ERR(kgdb_nmi_tty_driver)) {
pr_err("%s: cannot allocate tty\n", __func__);
- return -ENOMEM;
+ return PTR_ERR(kgdb_nmi_tty_driver);
}
kgdb_nmi_tty_driver->driver_name = "ttyNMI";
kgdb_nmi_tty_driver->name = "ttyNMI";
kgdb_nmi_tty_driver->num = 1;
kgdb_nmi_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
kgdb_nmi_tty_driver->subtype = SERIAL_TYPE_NORMAL;
- kgdb_nmi_tty_driver->flags = TTY_DRIVER_REAL_RAW;
kgdb_nmi_tty_driver->init_termios = tty_std_termios;
tty_termios_encode_baud_rate(&kgdb_nmi_tty_driver->init_termios,
KGDB_NMI_BAUD, KGDB_NMI_BAUD);
@@ -356,7 +355,7 @@ int kgdb_register_nmi_console(void)
return 0;
err_drv_reg:
- put_tty_driver(kgdb_nmi_tty_driver);
+ tty_driver_kref_put(kgdb_nmi_tty_driver);
return ret;
}
EXPORT_SYMBOL_GPL(kgdb_register_nmi_console);
@@ -374,7 +373,7 @@ int kgdb_unregister_nmi_console(void)
return ret;
tty_unregister_driver(kgdb_nmi_tty_driver);
- put_tty_driver(kgdb_nmi_tty_driver);
+ tty_driver_kref_put(kgdb_nmi_tty_driver);
return 0;
}
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index ef11860cd69e..3df0788ddeb0 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -1271,18 +1271,13 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
/* Always ask for fixed clock rate from a property. */
device_property_read_u32(dev, "clock-frequency", &uartclk);
- s->clk = devm_clk_get_optional(dev, "osc");
+ xtal = device_property_match_string(dev, "clock-names", "osc") < 0;
+ if (xtal)
+ s->clk = devm_clk_get_optional(dev, "xtal");
+ else
+ s->clk = devm_clk_get_optional(dev, "osc");
if (IS_ERR(s->clk))
return PTR_ERR(s->clk);
- if (s->clk) {
- xtal = false;
- } else {
- s->clk = devm_clk_get_optional(dev, "xtal");
- if (IS_ERR(s->clk))
- return PTR_ERR(s->clk);
-
- xtal = true;
- }
ret = clk_prepare_enable(s->clk);
if (ret)
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 9e81b09ba08e..0862941862c8 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -276,11 +276,8 @@ static void serial_omap_enable_ms(struct uart_port *port)
dev_dbg(up->port.dev, "serial_omap_enable_ms+%d\n", up->port.line);
- pm_runtime_get_sync(up->dev);
up->ier |= UART_IER_MSI;
serial_out(up, UART_IER, up->ier);
- pm_runtime_mark_last_busy(up->dev);
- pm_runtime_put_autosuspend(up->dev);
}
static void serial_omap_stop_tx(struct uart_port *port)
@@ -288,8 +285,6 @@ static void serial_omap_stop_tx(struct uart_port *port)
struct uart_omap_port *up = to_uart_omap_port(port);
int res;
- pm_runtime_get_sync(up->dev);
-
/* Handle RS-485 */
if (port->rs485.flags & SER_RS485_ENABLED) {
if (up->scr & OMAP_UART_SCR_TX_EMPTY) {
@@ -330,21 +325,15 @@ static void serial_omap_stop_tx(struct uart_port *port)
up->ier &= ~UART_IER_THRI;
serial_out(up, UART_IER, up->ier);
}
-
- pm_runtime_mark_last_busy(up->dev);
- pm_runtime_put_autosuspend(up->dev);
}
static void serial_omap_stop_rx(struct uart_port *port)
{
struct uart_omap_port *up = to_uart_omap_port(port);
- pm_runtime_get_sync(up->dev);
up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
up->port.read_status_mask &= ~UART_LSR_DR;
serial_out(up, UART_IER, up->ier);
- pm_runtime_mark_last_busy(up->dev);
- pm_runtime_put_autosuspend(up->dev);
}
static void transmit_chars(struct uart_omap_port *up, unsigned int lsr)
@@ -399,8 +388,6 @@ static void serial_omap_start_tx(struct uart_port *port)
struct uart_omap_port *up = to_uart_omap_port(port);
int res;
- pm_runtime_get_sync(up->dev);
-
/* Handle RS-485 */
if (port->rs485.flags & SER_RS485_ENABLED) {
/* Fire THR interrupts when FIFO is below trigger level */
@@ -421,8 +408,6 @@ static void serial_omap_start_tx(struct uart_port *port)
up->rs485_tx_filter_count = 0;
serial_omap_enable_ier_thri(up);
- pm_runtime_mark_last_busy(up->dev);
- pm_runtime_put_autosuspend(up->dev);
}
static void serial_omap_throttle(struct uart_port *port)
@@ -430,13 +415,10 @@ static void serial_omap_throttle(struct uart_port *port)
struct uart_omap_port *up = to_uart_omap_port(port);
unsigned long flags;
- pm_runtime_get_sync(up->dev);
spin_lock_irqsave(&up->port.lock, flags);
up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
serial_out(up, UART_IER, up->ier);
spin_unlock_irqrestore(&up->port.lock, flags);
- pm_runtime_mark_last_busy(up->dev);
- pm_runtime_put_autosuspend(up->dev);
}
static void serial_omap_unthrottle(struct uart_port *port)
@@ -444,13 +426,10 @@ static void serial_omap_unthrottle(struct uart_port *port)
struct uart_omap_port *up = to_uart_omap_port(port);
unsigned long flags;
- pm_runtime_get_sync(up->dev);
spin_lock_irqsave(&up->port.lock, flags);
up->ier |= UART_IER_RLSI | UART_IER_RDI;
serial_out(up, UART_IER, up->ier);
spin_unlock_irqrestore(&up->port.lock, flags);
- pm_runtime_mark_last_busy(up->dev);
- pm_runtime_put_autosuspend(up->dev);
}
static unsigned int check_modem_status(struct uart_omap_port *up)
@@ -576,7 +555,6 @@ static irqreturn_t serial_omap_irq(int irq, void *dev_id)
int max_count = 256;
spin_lock(&up->port.lock);
- pm_runtime_get_sync(up->dev);
do {
iir = serial_in(up, UART_IIR);
@@ -616,8 +594,6 @@ static irqreturn_t serial_omap_irq(int irq, void *dev_id)
tty_flip_buffer_push(&up->port.state->port);
- pm_runtime_mark_last_busy(up->dev);
- pm_runtime_put_autosuspend(up->dev);
up->port_activity = jiffies;
return ret;
@@ -629,13 +605,11 @@ static unsigned int serial_omap_tx_empty(struct uart_port *port)
unsigned long flags;
unsigned int ret = 0;
- pm_runtime_get_sync(up->dev);
dev_dbg(up->port.dev, "serial_omap_tx_empty+%d\n", up->port.line);
spin_lock_irqsave(&up->port.lock, flags);
ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
spin_unlock_irqrestore(&up->port.lock, flags);
- pm_runtime_mark_last_busy(up->dev);
- pm_runtime_put_autosuspend(up->dev);
+
return ret;
}
@@ -645,10 +619,7 @@ static unsigned int serial_omap_get_mctrl(struct uart_port *port)
unsigned int status;
unsigned int ret = 0;
- pm_runtime_get_sync(up->dev);
status = check_modem_status(up);
- pm_runtime_mark_last_busy(up->dev);
- pm_runtime_put_autosuspend(up->dev);
dev_dbg(up->port.dev, "serial_omap_get_mctrl+%d\n", up->port.line);
@@ -680,7 +651,6 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
if (mctrl & TIOCM_LOOP)
mcr |= UART_MCR_LOOP;
- pm_runtime_get_sync(up->dev);
old_mcr = serial_in(up, UART_MCR);
old_mcr &= ~(UART_MCR_LOOP | UART_MCR_OUT2 | UART_MCR_OUT1 |
UART_MCR_DTR | UART_MCR_RTS);
@@ -696,9 +666,6 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
up->efr &= ~UART_EFR_RTS;
serial_out(up, UART_EFR, up->efr);
serial_out(up, UART_LCR, lcr);
-
- pm_runtime_mark_last_busy(up->dev);
- pm_runtime_put_autosuspend(up->dev);
}
static void serial_omap_break_ctl(struct uart_port *port, int break_state)
@@ -707,7 +674,6 @@ static void serial_omap_break_ctl(struct uart_port *port, int break_state)
unsigned long flags;
dev_dbg(up->port.dev, "serial_omap_break_ctl+%d\n", up->port.line);
- pm_runtime_get_sync(up->dev);
spin_lock_irqsave(&up->port.lock, flags);
if (break_state == -1)
up->lcr |= UART_LCR_SBC;
@@ -715,8 +681,6 @@ static void serial_omap_break_ctl(struct uart_port *port, int break_state)
up->lcr &= ~UART_LCR_SBC;
serial_out(up, UART_LCR, up->lcr);
spin_unlock_irqrestore(&up->port.lock, flags);
- pm_runtime_mark_last_busy(up->dev);
- pm_runtime_put_autosuspend(up->dev);
}
static int serial_omap_startup(struct uart_port *port)
@@ -788,8 +752,6 @@ static int serial_omap_startup(struct uart_port *port)
serial_out(up, UART_OMAP_WER, up->wer);
- pm_runtime_mark_last_busy(up->dev);
- pm_runtime_put_autosuspend(up->dev);
up->port_activity = jiffies;
return 0;
}
@@ -801,7 +763,6 @@ static void serial_omap_shutdown(struct uart_port *port)
dev_dbg(up->port.dev, "serial_omap_shutdown+%d\n", up->port.line);
- pm_runtime_get_sync(up->dev);
/*
* Disable interrupts from this port
*/
@@ -825,8 +786,7 @@ static void serial_omap_shutdown(struct uart_port *port)
if (serial_in(up, UART_LSR) & UART_LSR_DR)
(void) serial_in(up, UART_RX);
- pm_runtime_mark_last_busy(up->dev);
- pm_runtime_put_autosuspend(up->dev);
+ pm_runtime_put_sync(up->dev);
free_irq(up->port.irq, up);
dev_pm_clear_wake_irq(up->dev);
}
@@ -896,7 +856,6 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
* Ok, we're now changing the port state. Do it with
* interrupts disabled.
*/
- pm_runtime_get_sync(up->dev);
spin_lock_irqsave(&up->port.lock, flags);
/*
@@ -1096,8 +1055,6 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
serial_omap_set_mctrl(&up->port, up->port.mctrl);
spin_unlock_irqrestore(&up->port.lock, flags);
- pm_runtime_mark_last_busy(up->dev);
- pm_runtime_put_autosuspend(up->dev);
dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->port.line);
}
@@ -1110,7 +1067,6 @@ serial_omap_pm(struct uart_port *port, unsigned int state,
dev_dbg(up->port.dev, "serial_omap_pm+%d\n", up->port.line);
- pm_runtime_get_sync(up->dev);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
efr = serial_in(up, UART_EFR);
serial_out(up, UART_EFR, efr | UART_EFR_ECB);
@@ -1120,9 +1076,6 @@ serial_omap_pm(struct uart_port *port, unsigned int state,
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
serial_out(up, UART_EFR, efr);
serial_out(up, UART_LCR, 0);
-
- pm_runtime_mark_last_busy(up->dev);
- pm_runtime_put_autosuspend(up->dev);
}
static void serial_omap_release_port(struct uart_port *port)
@@ -1202,11 +1155,8 @@ static void serial_omap_poll_put_char(struct uart_port *port, unsigned char ch)
{
struct uart_omap_port *up = to_uart_omap_port(port);
- pm_runtime_get_sync(up->dev);
wait_for_xmitr(up);
serial_out(up, UART_TX, ch);
- pm_runtime_mark_last_busy(up->dev);
- pm_runtime_put_autosuspend(up->dev);
}
static int serial_omap_poll_get_char(struct uart_port *port)
@@ -1214,7 +1164,6 @@ static int serial_omap_poll_get_char(struct uart_port *port)
struct uart_omap_port *up = to_uart_omap_port(port);
unsigned int status;
- pm_runtime_get_sync(up->dev);
status = serial_in(up, UART_LSR);
if (!(status & UART_LSR_DR)) {
status = NO_POLL_CHAR;
@@ -1224,9 +1173,6 @@ static int serial_omap_poll_get_char(struct uart_port *port)
status = serial_in(up, UART_RX);
out:
- pm_runtime_mark_last_busy(up->dev);
- pm_runtime_put_autosuspend(up->dev);
-
return status;
}
@@ -1309,8 +1255,6 @@ serial_omap_console_write(struct console *co, const char *s,
unsigned int ier;
int locked = 1;
- pm_runtime_get_sync(up->dev);
-
local_irq_save(flags);
if (up->port.sysrq)
locked = 0;
@@ -1343,8 +1287,6 @@ serial_omap_console_write(struct console *co, const char *s,
if (up->msr_saved_flags)
check_modem_status(up);
- pm_runtime_mark_last_busy(up->dev);
- pm_runtime_put_autosuspend(up->dev);
if (locked)
spin_unlock(&up->port.lock);
local_irq_restore(flags);
@@ -1403,8 +1345,6 @@ serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
unsigned int mode;
int val;
- pm_runtime_get_sync(up->dev);
-
/* Disable interrupts from this port */
mode = up->ier;
up->ier = 0;
@@ -1438,9 +1378,6 @@ serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
serial_out(up, UART_OMAP_SCR, up->scr);
}
- pm_runtime_mark_last_busy(up->dev);
- pm_runtime_put_autosuspend(up->dev);
-
return 0;
}
@@ -1737,11 +1674,7 @@ static int serial_omap_probe(struct platform_device *pdev)
omap_up_info->autosuspend_timeout = -1;
device_init_wakeup(up->dev, true);
- pm_runtime_use_autosuspend(&pdev->dev);
- pm_runtime_set_autosuspend_delay(&pdev->dev,
- omap_up_info->autosuspend_timeout);
- pm_runtime_irq_safe(&pdev->dev);
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
@@ -1755,12 +1688,9 @@ static int serial_omap_probe(struct platform_device *pdev)
if (ret != 0)
goto err_add_port;
- pm_runtime_mark_last_busy(up->dev);
- pm_runtime_put_autosuspend(up->dev);
return 0;
err_add_port:
- pm_runtime_dont_use_autosuspend(&pdev->dev);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
cpu_latency_qos_remove_request(&up->pm_qos_request);
@@ -1778,7 +1708,6 @@ static int serial_omap_remove(struct platform_device *dev)
uart_remove_one_port(&serial_omap_reg, &up->port);
- pm_runtime_dont_use_autosuspend(up->dev);
pm_runtime_put_sync(up->dev);
pm_runtime_disable(up->dev);
cpu_latency_qos_remove_request(&up->pm_qos_request);
diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c
index 9fbc61151c2e..e2f49863e9c2 100644
--- a/drivers/tty/serial/samsung_tty.c
+++ b/drivers/tty/serial/samsung_tty.c
@@ -65,6 +65,7 @@ enum s3c24xx_port_type {
struct s3c24xx_uart_info {
char *name;
enum s3c24xx_port_type type;
+ unsigned int has_usi;
unsigned int port_type;
unsigned int fifosize;
unsigned long rx_fifomask;
@@ -305,8 +306,9 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port)
dmaengine_pause(dma->tx_chan);
dmaengine_tx_status(dma->tx_chan, dma->tx_cookie, &state);
dmaengine_terminate_all(dma->tx_chan);
- dma_sync_single_for_cpu(ourport->port.dev,
- dma->tx_transfer_addr, dma->tx_size, DMA_TO_DEVICE);
+ dma_sync_single_for_cpu(dma->tx_chan->device->dev,
+ dma->tx_transfer_addr, dma->tx_size,
+ DMA_TO_DEVICE);
async_tx_ack(dma->tx_desc);
count = dma->tx_bytes_requested - state.residue;
xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
@@ -338,8 +340,9 @@ static void s3c24xx_serial_tx_dma_complete(void *args)
count = dma->tx_bytes_requested - state.residue;
async_tx_ack(dma->tx_desc);
- dma_sync_single_for_cpu(ourport->port.dev, dma->tx_transfer_addr,
- dma->tx_size, DMA_TO_DEVICE);
+ dma_sync_single_for_cpu(dma->tx_chan->device->dev,
+ dma->tx_transfer_addr, dma->tx_size,
+ DMA_TO_DEVICE);
spin_lock_irqsave(&port->lock, flags);
@@ -443,8 +446,9 @@ static int s3c24xx_serial_start_tx_dma(struct s3c24xx_uart_port *ourport,
dma->tx_size = count & ~(dma_get_cache_alignment() - 1);
dma->tx_transfer_addr = dma->tx_addr + xmit->tail;
- dma_sync_single_for_device(ourport->port.dev, dma->tx_transfer_addr,
- dma->tx_size, DMA_TO_DEVICE);
+ dma_sync_single_for_device(dma->tx_chan->device->dev,
+ dma->tx_transfer_addr, dma->tx_size,
+ DMA_TO_DEVICE);
dma->tx_desc = dmaengine_prep_slave_single(dma->tx_chan,
dma->tx_transfer_addr, dma->tx_size,
@@ -515,7 +519,7 @@ static void s3c24xx_uart_copy_rx_to_tty(struct s3c24xx_uart_port *ourport,
if (!count)
return;
- dma_sync_single_for_cpu(ourport->port.dev, dma->rx_addr,
+ dma_sync_single_for_cpu(dma->rx_chan->device->dev, dma->rx_addr,
dma->rx_size, DMA_FROM_DEVICE);
ourport->port.icount.rx += count;
@@ -636,8 +640,8 @@ static void s3c64xx_start_rx_dma(struct s3c24xx_uart_port *ourport)
{
struct s3c24xx_uart_dma *dma = ourport->dma;
- dma_sync_single_for_device(ourport->port.dev, dma->rx_addr,
- dma->rx_size, DMA_FROM_DEVICE);
+ dma_sync_single_for_device(dma->rx_chan->device->dev, dma->rx_addr,
+ dma->rx_size, DMA_FROM_DEVICE);
dma->rx_desc = dmaengine_prep_slave_single(dma->rx_chan,
dma->rx_addr, dma->rx_size, DMA_DEV_TO_MEM,
@@ -1102,18 +1106,19 @@ static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
goto err_release_tx;
}
- dma->rx_addr = dma_map_single(p->port.dev, dma->rx_buf,
- dma->rx_size, DMA_FROM_DEVICE);
- if (dma_mapping_error(p->port.dev, dma->rx_addr)) {
+ dma->rx_addr = dma_map_single(dma->rx_chan->device->dev, dma->rx_buf,
+ dma->rx_size, DMA_FROM_DEVICE);
+ if (dma_mapping_error(dma->rx_chan->device->dev, dma->rx_addr)) {
reason = "DMA mapping error for RX buffer";
ret = -EIO;
goto err_free_rx;
}
/* TX buffer */
- dma->tx_addr = dma_map_single(p->port.dev, p->port.state->xmit.buf,
- UART_XMIT_SIZE, DMA_TO_DEVICE);
- if (dma_mapping_error(p->port.dev, dma->tx_addr)) {
+ dma->tx_addr = dma_map_single(dma->tx_chan->device->dev,
+ p->port.state->xmit.buf, UART_XMIT_SIZE,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(dma->tx_chan->device->dev, dma->tx_addr)) {
reason = "DMA mapping error for TX buffer";
ret = -EIO;
goto err_unmap_rx;
@@ -1122,8 +1127,8 @@ static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
return 0;
err_unmap_rx:
- dma_unmap_single(p->port.dev, dma->rx_addr, dma->rx_size,
- DMA_FROM_DEVICE);
+ dma_unmap_single(dma->rx_chan->device->dev, dma->rx_addr,
+ dma->rx_size, DMA_FROM_DEVICE);
err_free_rx:
kfree(dma->rx_buf);
err_release_tx:
@@ -1142,8 +1147,8 @@ static void s3c24xx_serial_release_dma(struct s3c24xx_uart_port *p)
if (dma->rx_chan) {
dmaengine_terminate_all(dma->rx_chan);
- dma_unmap_single(p->port.dev, dma->rx_addr,
- dma->rx_size, DMA_FROM_DEVICE);
+ dma_unmap_single(dma->rx_chan->device->dev, dma->rx_addr,
+ dma->rx_size, DMA_FROM_DEVICE);
kfree(dma->rx_buf);
dma_release_channel(dma->rx_chan);
dma->rx_chan = NULL;
@@ -1151,8 +1156,8 @@ static void s3c24xx_serial_release_dma(struct s3c24xx_uart_port *p)
if (dma->tx_chan) {
dmaengine_terminate_all(dma->tx_chan);
- dma_unmap_single(p->port.dev, dma->tx_addr,
- UART_XMIT_SIZE, DMA_TO_DEVICE);
+ dma_unmap_single(dma->tx_chan->device->dev, dma->tx_addr,
+ UART_XMIT_SIZE, DMA_TO_DEVICE);
dma_release_channel(dma->tx_chan);
dma->tx_chan = NULL;
}
@@ -1352,6 +1357,28 @@ static int apple_s5l_serial_startup(struct uart_port *port)
return ret;
}
+static void exynos_usi_init(struct uart_port *port)
+{
+ struct s3c24xx_uart_port *ourport = to_ourport(port);
+ struct s3c24xx_uart_info *info = ourport->info;
+ unsigned int val;
+
+ if (!info->has_usi)
+ return;
+
+ /* Clear the software reset of USI block (it's set at startup) */
+ val = rd_regl(port, USI_CON);
+ val &= ~USI_CON_RESET_MASK;
+ wr_regl(port, USI_CON, val);
+ udelay(1);
+
+ /* Continuously provide the clock to USI IP w/o gating (for Rx mode) */
+ val = rd_regl(port, USI_OPTION);
+ val &= ~USI_OPTION_HWACG_MASK;
+ val |= USI_OPTION_HWACG_CLKREQ_ON;
+ wr_regl(port, USI_OPTION, val);
+}
+
/* power power management control */
static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
@@ -1379,6 +1406,7 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
if (!IS_ERR(ourport->baudclk))
clk_prepare_enable(ourport->baudclk);
+ exynos_usi_init(port);
break;
default:
dev_err(port->dev, "s3c24xx_serial: unknown pm %d\n", level);
@@ -2102,6 +2130,8 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
if (ret)
pr_warn("uart: failed to enable baudclk\n");
+ exynos_usi_init(port);
+
/* Keep all interrupts masked and cleared */
switch (ourport->info->type) {
case TYPE_S3C6400:
@@ -2750,10 +2780,11 @@ static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = {
#endif
#if defined(CONFIG_ARCH_EXYNOS)
-#define EXYNOS_COMMON_SERIAL_DRV_DATA \
+#define EXYNOS_COMMON_SERIAL_DRV_DATA_USI(_has_usi) \
.info = &(struct s3c24xx_uart_info) { \
.name = "Samsung Exynos UART", \
.type = TYPE_S3C6400, \
+ .has_usi = _has_usi, \
.port_type = PORT_S3C6400, \
.has_divslot = 1, \
.rx_fifomask = S5PV210_UFSTAT_RXMASK, \
@@ -2773,6 +2804,9 @@ static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = {
.has_fracval = 1, \
} \
+#define EXYNOS_COMMON_SERIAL_DRV_DATA \
+ EXYNOS_COMMON_SERIAL_DRV_DATA_USI(0)
+
static struct s3c24xx_serial_drv_data exynos4210_serial_drv_data = {
EXYNOS_COMMON_SERIAL_DRV_DATA,
.fifosize = { 256, 64, 16, 16 },
@@ -2783,11 +2817,19 @@ static struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = {
.fifosize = { 64, 256, 16, 256 },
};
+static struct s3c24xx_serial_drv_data exynos850_serial_drv_data = {
+ EXYNOS_COMMON_SERIAL_DRV_DATA_USI(1),
+ .fifosize = { 256, 64, 64, 64 },
+};
+
#define EXYNOS4210_SERIAL_DRV_DATA ((kernel_ulong_t)&exynos4210_serial_drv_data)
#define EXYNOS5433_SERIAL_DRV_DATA ((kernel_ulong_t)&exynos5433_serial_drv_data)
+#define EXYNOS850_SERIAL_DRV_DATA ((kernel_ulong_t)&exynos850_serial_drv_data)
+
#else
-#define EXYNOS4210_SERIAL_DRV_DATA (kernel_ulong_t)NULL
-#define EXYNOS5433_SERIAL_DRV_DATA (kernel_ulong_t)NULL
+#define EXYNOS4210_SERIAL_DRV_DATA ((kernel_ulong_t)NULL)
+#define EXYNOS5433_SERIAL_DRV_DATA ((kernel_ulong_t)NULL)
+#define EXYNOS850_SERIAL_DRV_DATA ((kernel_ulong_t)NULL)
#endif
#ifdef CONFIG_ARCH_APPLE
@@ -2843,6 +2885,9 @@ static const struct platform_device_id s3c24xx_serial_driver_ids[] = {
}, {
.name = "s5l-uart",
.driver_data = S5L_SERIAL_DRV_DATA,
+ }, {
+ .name = "exynos850-uart",
+ .driver_data = EXYNOS850_SERIAL_DRV_DATA,
},
{ },
};
@@ -2866,6 +2911,8 @@ static const struct of_device_id s3c24xx_uart_dt_match[] = {
.data = (void *)EXYNOS5433_SERIAL_DRV_DATA },
{ .compatible = "apple,s5l-uart",
.data = (void *)S5L_SERIAL_DRV_DATA },
+ { .compatible = "samsung,exynos850-uart",
+ .data = (void *)EXYNOS850_SERIAL_DRV_DATA },
{},
};
MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match);
diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c
index eba5b9ecba34..45e2e4109acd 100644
--- a/drivers/tty/serial/serial-tegra.c
+++ b/drivers/tty/serial/serial-tegra.c
@@ -1568,14 +1568,12 @@ static int tegra_uart_probe(struct platform_device *pdev)
struct resource *resource;
int ret;
const struct tegra_uart_chip_data *cdata;
- const struct of_device_id *match;
- match = of_match_device(tegra_uart_of_match, &pdev->dev);
- if (!match) {
+ cdata = of_device_get_match_data(&pdev->dev);
+ if (!cdata) {
dev_err(&pdev->dev, "Error: No device match found\n");
return -ENODEV;
}
- cdata = match->data;
tup = devm_kzalloc(&pdev->dev, sizeof(*tup), GFP_KERNEL);
if (!tup) {
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 69092deba11f..0e2e35ab64c7 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -2314,6 +2314,14 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
port->dev ? ": " : "",
port->name,
address, port->irq, port->uartclk / 16, uart_type(port));
+
+ /* The magic multiplier feature is a bit obscure, so report it too. */
+ if (port->flags & UPF_MAGIC_MULTIPLIER)
+ pr_info("%s%s%s extra baud rates supported: %d, %d",
+ port->dev ? dev_name(port->dev) : "",
+ port->dev ? ": " : "",
+ port->name,
+ port->uartclk / 8, port->uartclk / 4);
}
static void
@@ -2522,9 +2530,12 @@ int uart_register_driver(struct uart_driver *drv)
if (!drv->state)
goto out;
- normal = alloc_tty_driver(drv->nr);
- if (!normal)
+ normal = tty_alloc_driver(drv->nr, TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV);
+ if (IS_ERR(normal)) {
+ retval = PTR_ERR(normal);
goto out_kfree;
+ }
drv->tty_driver = normal;
@@ -2537,7 +2548,6 @@ int uart_register_driver(struct uart_driver *drv)
normal->init_termios = tty_std_termios;
normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600;
- normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
normal->driver_state = drv;
tty_set_operations(normal, &uart_ops);
@@ -2558,7 +2568,7 @@ int uart_register_driver(struct uart_driver *drv)
for (i = 0; i < drv->nr; i++)
tty_port_destroy(&drv->state[i].port);
- put_tty_driver(normal);
+ tty_driver_kref_put(normal);
out_kfree:
kfree(drv->state);
out:
@@ -2580,7 +2590,7 @@ void uart_unregister_driver(struct uart_driver *drv)
unsigned int i;
tty_unregister_driver(p);
- put_tty_driver(p);
+ tty_driver_kref_put(p);
for (i = 0; i < drv->nr; i++)
tty_port_destroy(&drv->state[i].port);
kfree(drv->state);
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 07eb56294371..89ee43061d3a 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -1758,6 +1758,10 @@ static irqreturn_t sci_br_interrupt(int irq, void *ptr)
/* Handle BREAKs */
sci_handle_breaks(port);
+
+ /* drop invalid character received before break was detected */
+ serial_port_in(port, SCxRDR);
+
sci_clear_SCxSR(port, SCxSR_BREAK_CLEAR(port));
return IRQ_HANDLED;
@@ -1837,7 +1841,8 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
ret = sci_er_interrupt(irq, ptr);
/* Break Interrupt */
- if ((ssr_status & SCxSR_BRK(port)) && err_enabled)
+ if (s->irqs[SCIx_ERI_IRQ] != s->irqs[SCIx_BRI_IRQ] &&
+ (ssr_status & SCxSR_BRK(port)) && err_enabled)
ret = sci_br_interrupt(irq, ptr);
/* Overrun Interrupt */
diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index ef793b3b4591..8f032e77b954 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -1034,8 +1034,8 @@ static int stm32_usart_init_port(struct stm32_port *stm32port,
int ret, irq;
irq = platform_get_irq(pdev, 0);
- if (irq <= 0)
- return irq ? : -ENODEV;
+ if (irq < 0)
+ return irq;
port->iotype = UPIO_MEM;
port->flags = UPF_BOOT_AUTOCONF;
@@ -1064,8 +1064,7 @@ static int stm32_usart_init_port(struct stm32_port *stm32port,
&stm32port->txftcfg);
}
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- port->membase = devm_ioremap_resource(&pdev->dev, res);
+ port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(port->membase))
return PTR_ERR(port->membase);
port->mapbase = res->start;
@@ -1177,7 +1176,7 @@ static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port,
if (uart_console(port))
return -ENODEV;
- stm32port->rx_buf = dma_alloc_coherent(&pdev->dev, RX_BUF_L,
+ stm32port->rx_buf = dma_alloc_coherent(dev, RX_BUF_L,
&stm32port->rx_dma_buf,
GFP_KERNEL);
if (!stm32port->rx_buf)
@@ -1243,7 +1242,7 @@ static int stm32_usart_of_dma_tx_probe(struct stm32_port *stm32port,
stm32port->tx_dma_busy = false;
- stm32port->tx_buf = dma_alloc_coherent(&pdev->dev, TX_BUF_L,
+ stm32port->tx_buf = dma_alloc_coherent(dev, TX_BUF_L,
&stm32port->tx_dma_buf,
GFP_KERNEL);
if (!stm32port->tx_buf)
diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c
index a5f15f22d9ef..dfc1ba4e1572 100644
--- a/drivers/tty/serial/uartlite.c
+++ b/drivers/tty/serial/uartlite.c
@@ -17,11 +17,13 @@
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/clk.h>
+#include <linux/pm_runtime.h>
#define ULITE_NAME "ttyUL"
#define ULITE_MAJOR 204
@@ -54,6 +56,7 @@
#define ULITE_CONTROL_RST_TX 0x01
#define ULITE_CONTROL_RST_RX 0x02
#define ULITE_CONTROL_IE 0x10
+#define UART_AUTOSUSPEND_TIMEOUT 3000 /* ms */
/* Static pointer to console port */
#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
@@ -390,12 +393,16 @@ static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser)
static void ulite_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate)
{
- struct uartlite_data *pdata = port->private_data;
+ int ret;
- if (!state)
- clk_enable(pdata->clk);
- else
- clk_disable(pdata->clk);
+ if (!state) {
+ ret = pm_runtime_get_sync(port->dev);
+ if (ret < 0)
+ dev_err(port->dev, "Failed to enable clocks\n");
+ } else {
+ pm_runtime_mark_last_busy(port->dev);
+ pm_runtime_put_autosuspend(port->dev);
+ }
}
#ifdef CONFIG_CONSOLE_POLL
@@ -448,24 +455,15 @@ static const struct uart_ops ulite_ops = {
static void ulite_console_wait_tx(struct uart_port *port)
{
u8 val;
- unsigned long timeout;
/*
* Spin waiting for TX fifo to have space available.
* When using the Microblaze Debug Module this can take up to 1s
*/
- timeout = jiffies + msecs_to_jiffies(1000);
- while (1) {
- val = uart_in32(ULITE_STATUS, port);
- if ((val & ULITE_STATUS_TXFULL) == 0)
- break;
- if (time_after(jiffies, timeout)) {
- dev_warn(port->dev,
- "timeout waiting for TX buffer empty\n");
- break;
- }
- cpu_relax();
- }
+ if (read_poll_timeout_atomic(uart_in32, val, !(val & ULITE_STATUS_TXFULL),
+ 0, 1000000, false, ULITE_STATUS, port))
+ dev_warn(port->dev,
+ "timeout waiting for TX buffer empty\n");
}
static void ulite_console_putchar(struct uart_port *port, int ch)
@@ -555,16 +553,15 @@ static void early_uartlite_putc(struct uart_port *port, int c)
* This limit is pretty arbitrary, unless we are at about 10 baud
* we'll never timeout on a working UART.
*/
-
unsigned retries = 1000000;
- /* read status bit - 0x8 offset */
- while (--retries && (readl(port->membase + 8) & (1 << 3)))
+
+ while (--retries &&
+ (readl(port->membase + ULITE_STATUS) & ULITE_STATUS_TXFULL))
;
/* Only attempt the iowrite if we didn't timeout */
- /* write to TX_FIFO - 0x4 offset */
if (retries)
- writel(c & 0xff, port->membase + 4);
+ writel(c & 0xff, port->membase + ULITE_TX);
}
static void early_uartlite_write(struct console *console,
@@ -719,11 +716,38 @@ static int __maybe_unused ulite_resume(struct device *dev)
return 0;
}
+static int __maybe_unused ulite_runtime_suspend(struct device *dev)
+{
+ struct uart_port *port = dev_get_drvdata(dev);
+ struct uartlite_data *pdata = port->private_data;
+
+ clk_disable(pdata->clk);
+ return 0;
+};
+
+static int __maybe_unused ulite_runtime_resume(struct device *dev)
+{
+ struct uart_port *port = dev_get_drvdata(dev);
+ struct uartlite_data *pdata = port->private_data;
+ int ret;
+
+ ret = clk_enable(pdata->clk);
+ if (ret) {
+ dev_err(dev, "Cannot enable clock.\n");
+ return ret;
+ }
+ return 0;
+}
+
/* ---------------------------------------------------------------------
* Platform bus binding
*/
-static SIMPLE_DEV_PM_OPS(ulite_pm_ops, ulite_suspend, ulite_resume);
+static const struct dev_pm_ops ulite_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(ulite_suspend, ulite_resume)
+ SET_RUNTIME_PM_OPS(ulite_runtime_suspend,
+ ulite_runtime_resume, NULL)
+};
#if defined(CONFIG_OF)
/* Match table for of_platform binding */
@@ -779,18 +803,25 @@ static int ulite_probe(struct platform_device *pdev)
return ret;
}
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
if (!ulite_uart_driver.state) {
dev_dbg(&pdev->dev, "uartlite: calling uart_register_driver()\n");
ret = uart_register_driver(&ulite_uart_driver);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register driver\n");
+ clk_disable_unprepare(pdata->clk);
return ret;
}
}
ret = ulite_assign(&pdev->dev, id, res->start, irq, pdata);
- clk_disable(pdata->clk);
+ pm_runtime_mark_last_busy(&pdev->dev);
+ pm_runtime_put_autosuspend(&pdev->dev);
return ret;
}
@@ -799,9 +830,14 @@ static int ulite_remove(struct platform_device *pdev)
{
struct uart_port *port = dev_get_drvdata(&pdev->dev);
struct uartlite_data *pdata = port->private_data;
+ int rc;
clk_disable_unprepare(pdata->clk);
- return ulite_release(&pdev->dev);
+ rc = ulite_release(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
+ return rc;
}
/* work with hotplug and coldplug */
diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c
index c5edd56ff830..e15b2bf69904 100644
--- a/drivers/tty/serial/vt8500_serial.c
+++ b/drivers/tty/serial/vt8500_serial.c
@@ -623,17 +623,14 @@ 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)
+ flags = of_device_get_match_data(&pdev->dev);
+ if (!flags)
return -EINVAL;
- flags = match->data;
-
mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!mmres || !irqres)
diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c
index 3e3b8873fa29..a9acd93e85b7 100644
--- a/drivers/tty/synclink_gt.c
+++ b/drivers/tty/synclink_gt.c
@@ -3647,7 +3647,7 @@ static void slgt_cleanup(void)
for (info=slgt_device_list ; info != NULL ; info=info->next_device)
tty_unregister_device(serial_driver, info->line);
tty_unregister_driver(serial_driver);
- put_tty_driver(serial_driver);
+ tty_driver_kref_put(serial_driver);
}
/* reset devices */
@@ -3686,10 +3686,11 @@ static int __init slgt_init(void)
printk(KERN_INFO "%s\n", driver_name);
- serial_driver = alloc_tty_driver(MAX_DEVICES);
- if (!serial_driver) {
+ serial_driver = tty_alloc_driver(MAX_DEVICES, TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV);
+ if (IS_ERR(serial_driver)) {
printk("%s can't allocate tty driver\n", driver_name);
- return -ENOMEM;
+ return PTR_ERR(serial_driver);
}
/* Initialize the tty_driver structure */
@@ -3705,11 +3706,10 @@ static int __init slgt_init(void)
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
serial_driver->init_termios.c_ispeed = 9600;
serial_driver->init_termios.c_ospeed = 9600;
- serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
tty_set_operations(serial_driver, &ops);
if ((rc = tty_register_driver(serial_driver)) < 0) {
DBGERR(("%s can't register serial driver\n", driver_name));
- put_tty_driver(serial_driver);
+ tty_driver_kref_put(serial_driver);
serial_driver = NULL;
goto error;
}
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index 6628792431dc..c911196ac893 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -258,7 +258,7 @@ static void sysrq_handle_showallcpus(int key)
if (!trigger_all_cpu_backtrace()) {
struct pt_regs *regs = NULL;
- if (in_irq())
+ if (in_hardirq())
regs = get_irq_regs();
if (regs) {
pr_info("CPU%d:\n", smp_processor_id());
@@ -280,7 +280,7 @@ static void sysrq_handle_showregs(int key)
{
struct pt_regs *regs = NULL;
- if (in_irq())
+ if (in_hardirq())
regs = get_irq_regs();
if (regs)
show_regs(regs);
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 26debec26b4e..6616d4a0d41d 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -2290,8 +2290,6 @@ static int tty_fasync(int fd, struct file *filp, int on)
* Locking:
* Called functions take tty_ldiscs_lock
* current->signal->tty check is safe without locks
- *
- * FIXME: may race normal receive processing
*/
static int tiocsti(struct tty_struct *tty, char __user *p)
@@ -2307,8 +2305,10 @@ static int tiocsti(struct tty_struct *tty, char __user *p)
ld = tty_ldisc_ref_wait(tty);
if (!ld)
return -EIO;
+ tty_buffer_lock_exclusive(tty->port);
if (ld->ops->receive_buf)
ld->ops->receive_buf(tty, &ch, &mbz, 1);
+ tty_buffer_unlock_exclusive(tty->port);
tty_ldisc_deref(ld);
return 0;
}
@@ -3438,19 +3438,6 @@ void tty_driver_kref_put(struct tty_driver *driver)
}
EXPORT_SYMBOL(tty_driver_kref_put);
-void tty_set_operations(struct tty_driver *driver,
- const struct tty_operations *op)
-{
- driver->ops = op;
-};
-EXPORT_SYMBOL(tty_set_operations);
-
-void put_tty_driver(struct tty_driver *d)
-{
- tty_driver_kref_put(d);
-}
-EXPORT_SYMBOL(put_tty_driver);
-
/*
* Called by a tty driver to register itself.
*/
diff --git a/drivers/tty/ttynull.c b/drivers/tty/ttynull.c
index af3311a24917..1d4438472442 100644
--- a/drivers/tty/ttynull.c
+++ b/drivers/tty/ttynull.c
@@ -84,7 +84,7 @@ static int __init ttynull_init(void)
ret = tty_register_driver(driver);
if (ret < 0) {
- put_tty_driver(driver);
+ tty_driver_kref_put(driver);
tty_port_destroy(&ttynull_port);
return ret;
}
@@ -99,7 +99,7 @@ static void __exit ttynull_exit(void)
{
unregister_console(&ttynull_console);
tty_unregister_driver(ttynull_driver);
- put_tty_driver(ttynull_driver);
+ tty_driver_kref_put(ttynull_driver);
tty_port_destroy(&ttynull_port);
}
diff --git a/drivers/tty/vcc.c b/drivers/tty/vcc.c
index d06bcc3b4c07..e11383ae1e7e 100644
--- a/drivers/tty/vcc.c
+++ b/drivers/tty/vcc.c
@@ -1028,7 +1028,7 @@ static int vcc_tty_init(void)
rv = tty_register_driver(vcc_tty_driver);
if (rv) {
pr_err("VCC: TTY driver registration failed\n");
- put_tty_driver(vcc_tty_driver);
+ tty_driver_kref_put(vcc_tty_driver);
vcc_tty_driver = NULL;
return rv;
}
@@ -1041,7 +1041,7 @@ static int vcc_tty_init(void)
static void vcc_tty_exit(void)
{
tty_unregister_driver(vcc_tty_driver);
- put_tty_driver(vcc_tty_driver);
+ tty_driver_kref_put(vcc_tty_driver);
vccdbg("VCC: TTY driver unregistered\n");
vcc_tty_driver = NULL;
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 4b0d69042ceb..c7fbbcdcc346 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -1171,9 +1171,9 @@ static inline unsigned char getleds(void)
*
* Check the status of a keyboard led flag and report it back
*/
-int vt_get_leds(int console, int flag)
+int vt_get_leds(unsigned int console, int flag)
{
- struct kbd_struct *kb = kbd_table + console;
+ struct kbd_struct *kb = &kbd_table[console];
int ret;
unsigned long flags;
@@ -1193,9 +1193,9 @@ EXPORT_SYMBOL_GPL(vt_get_leds);
* Set the LEDs on a console. This is a wrapper for the VT layer
* so that we can keep kbd knowledge internal
*/
-void vt_set_led_state(int console, int leds)
+void vt_set_led_state(unsigned int console, int leds)
{
- struct kbd_struct *kb = kbd_table + console;
+ struct kbd_struct *kb = &kbd_table[console];
setledstate(kb, leds);
}
@@ -1212,9 +1212,9 @@ void vt_set_led_state(int console, int leds)
* don't hold the lock. We probably need to split out an LED lock
* but not during an -rc release!
*/
-void vt_kbd_con_start(int console)
+void vt_kbd_con_start(unsigned int console)
{
- struct kbd_struct *kb = kbd_table + console;
+ struct kbd_struct *kb = &kbd_table[console];
unsigned long flags;
spin_lock_irqsave(&led_lock, flags);
clr_vc_kbd_led(kb, VC_SCROLLOCK);
@@ -1229,9 +1229,9 @@ void vt_kbd_con_start(int console)
* Handle console stop. This is a wrapper for the VT layer
* so that we can keep kbd knowledge internal
*/
-void vt_kbd_con_stop(int console)
+void vt_kbd_con_stop(unsigned int console)
{
- struct kbd_struct *kb = kbd_table + console;
+ struct kbd_struct *kb = &kbd_table[console];
unsigned long flags;
spin_lock_irqsave(&led_lock, flags);
set_vc_kbd_led(kb, VC_SCROLLOCK);
@@ -1377,7 +1377,7 @@ static void kbd_rawcode(unsigned char data)
{
struct vc_data *vc = vc_cons[fg_console].d;
- kbd = kbd_table + vc->vc_num;
+ kbd = &kbd_table[vc->vc_num];
if (kbd->kbdmode == VC_RAW)
put_queue(vc, data);
}
@@ -1400,7 +1400,7 @@ static void kbd_keycode(unsigned int keycode, int down, bool hw_raw)
tty->driver_data = vc;
}
- kbd = kbd_table + vc->vc_num;
+ kbd = &kbd_table[vc->vc_num];
#ifdef CONFIG_SPARC
if (keycode == KEY_STOP)
@@ -1825,9 +1825,9 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm)
* Update the keyboard mode bits while holding the correct locks.
* Return 0 for success or an error code.
*/
-int vt_do_kdskbmode(int console, unsigned int arg)
+int vt_do_kdskbmode(unsigned int console, unsigned int arg)
{
- struct kbd_struct *kb = kbd_table + console;
+ struct kbd_struct *kb = &kbd_table[console];
int ret = 0;
unsigned long flags;
@@ -1865,9 +1865,9 @@ int vt_do_kdskbmode(int console, unsigned int arg)
* Update the keyboard meta bits while holding the correct locks.
* Return 0 for success or an error code.
*/
-int vt_do_kdskbmeta(int console, unsigned int arg)
+int vt_do_kdskbmeta(unsigned int console, unsigned int arg)
{
- struct kbd_struct *kb = kbd_table + console;
+ struct kbd_struct *kb = &kbd_table[console];
int ret = 0;
unsigned long flags;
@@ -2008,9 +2008,9 @@ out:
}
int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm,
- int console)
+ unsigned int console)
{
- struct kbd_struct *kb = kbd_table + console;
+ struct kbd_struct *kb = &kbd_table[console];
struct kbentry kbe;
if (copy_from_user(&kbe, user_kbe, sizeof(struct kbentry)))
@@ -2097,9 +2097,9 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
return ret;
}
-int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm)
+int vt_do_kdskled(unsigned int console, int cmd, unsigned long arg, int perm)
{
- struct kbd_struct *kb = kbd_table + console;
+ struct kbd_struct *kb = &kbd_table[console];
unsigned long flags;
unsigned char ucval;
@@ -2139,9 +2139,9 @@ int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm)
return -ENOIOCTLCMD;
}
-int vt_do_kdgkbmode(int console)
+int vt_do_kdgkbmode(unsigned int console)
{
- struct kbd_struct *kb = kbd_table + console;
+ struct kbd_struct *kb = &kbd_table[console];
/* This is a spot read so needs no locking */
switch (kb->kbdmode) {
case VC_RAW:
@@ -2163,9 +2163,9 @@ int vt_do_kdgkbmode(int console)
*
* Report the meta flag status of this console
*/
-int vt_do_kdgkbmeta(int console)
+int vt_do_kdgkbmeta(unsigned int console)
{
- struct kbd_struct *kb = kbd_table + console;
+ struct kbd_struct *kb = &kbd_table[console];
/* Again a spot read so no locking */
return vc_kbd_mode(kb, VC_META) ? K_ESCPREFIX : K_METABIT;
}
@@ -2176,7 +2176,7 @@ int vt_do_kdgkbmeta(int console)
*
* Restore the unicode console state to its default
*/
-void vt_reset_unicode(int console)
+void vt_reset_unicode(unsigned int console)
{
unsigned long flags;
@@ -2204,9 +2204,9 @@ int vt_get_shift_state(void)
* Reset the keyboard bits for a console as part of a general console
* reset event
*/
-void vt_reset_keyboard(int console)
+void vt_reset_keyboard(unsigned int console)
{
- struct kbd_struct *kb = kbd_table + console;
+ struct kbd_struct *kb = &kbd_table[console];
unsigned long flags;
spin_lock_irqsave(&kbd_event_lock, flags);
@@ -2234,9 +2234,9 @@ void vt_reset_keyboard(int console)
* caller must be sure that there are no synchronization needs
*/
-int vt_get_kbd_mode_bit(int console, int bit)
+int vt_get_kbd_mode_bit(unsigned int console, int bit)
{
- struct kbd_struct *kb = kbd_table + console;
+ struct kbd_struct *kb = &kbd_table[console];
return vc_kbd_mode(kb, bit);
}
@@ -2249,9 +2249,9 @@ int vt_get_kbd_mode_bit(int console, int bit)
* caller must be sure that there are no synchronization needs
*/
-void vt_set_kbd_mode_bit(int console, int bit)
+void vt_set_kbd_mode_bit(unsigned int console, int bit)
{
- struct kbd_struct *kb = kbd_table + console;
+ struct kbd_struct *kb = &kbd_table[console];
unsigned long flags;
spin_lock_irqsave(&kbd_event_lock, flags);
@@ -2268,9 +2268,9 @@ void vt_set_kbd_mode_bit(int console, int bit)
* caller must be sure that there are no synchronization needs
*/
-void vt_clr_kbd_mode_bit(int console, int bit)
+void vt_clr_kbd_mode_bit(unsigned int console, int bit)
{
- struct kbd_struct *kb = kbd_table + console;
+ struct kbd_struct *kb = &kbd_table[console];
unsigned long flags;
spin_lock_irqsave(&kbd_event_lock, flags);
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index cb72393f92d3..7359c3e80d63 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -1219,8 +1219,25 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
new_row_size = new_cols << 1;
new_screen_size = new_row_size * new_rows;
- if (new_cols == vc->vc_cols && new_rows == vc->vc_rows)
- return 0;
+ if (new_cols == vc->vc_cols && new_rows == vc->vc_rows) {
+ /*
+ * This function is being called here to cover the case
+ * where the userspace calls the FBIOPUT_VSCREENINFO twice,
+ * passing the same fb_var_screeninfo containing the fields
+ * yres/xres equal to a number non-multiple of vc_font.height
+ * and yres_virtual/xres_virtual equal to number lesser than the
+ * vc_font.height and yres/xres.
+ * In the second call, the struct fb_var_screeninfo isn't
+ * being modified by the underlying driver because of the
+ * if above, and this causes the fbcon_display->vrows to become
+ * negative and it eventually leads to out-of-bound
+ * access by the imageblit function.
+ * To give the correct values to the struct and to not have
+ * to deal with possible errors from the code below, we call
+ * the resize_screen here as well.
+ */
+ return resize_screen(vc, new_cols, new_rows, user);
+ }
if (new_screen_size > KMALLOC_MAX_SIZE || !new_screen_size)
return -EINVAL;
@@ -3582,8 +3599,9 @@ int __init vty_init(const struct file_operations *console_fops)
vcs_init();
- console_driver = alloc_tty_driver(MAX_NR_CONSOLES);
- if (!console_driver)
+ console_driver = tty_alloc_driver(MAX_NR_CONSOLES, TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_RESET_TERMIOS);
+ if (IS_ERR(console_driver))
panic("Couldn't allocate console driver\n");
console_driver->name = "tty";
@@ -3594,7 +3612,6 @@ int __init vty_init(const struct file_operations *console_fops)
console_driver->init_termios = tty_std_termios;
if (default_utf8)
console_driver->init_termios.c_iflag |= IUTF8;
- console_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
tty_set_operations(console_driver, &con_ops);
if (tty_register_driver(console_driver))
panic("Couldn't register console driver\n");