summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/serial/fsl-imx-uart.txt4
-rw-r--r--arch/arm64/Kconfig.platforms2
-rw-r--r--drivers/tty/mips_ejtag_fdc.c1
-rw-r--r--drivers/tty/n_gsm.c140
-rw-r--r--drivers/tty/n_hdlc.c558
-rw-r--r--drivers/tty/n_tty.c6
-rw-r--r--drivers/tty/serial/8250/8250.h6
-rw-r--r--drivers/tty/serial/8250/8250_bcm2835aux.c80
-rw-r--r--drivers/tty/serial/8250/8250_core.c6
-rw-r--r--drivers/tty/serial/8250/8250_dwlib.h2
-rw-r--r--drivers/tty/serial/8250/8250_exar.c2
-rw-r--r--drivers/tty/serial/8250/8250_lpss.c6
-rw-r--r--drivers/tty/serial/8250/8250_mtk.c50
-rw-r--r--drivers/tty/serial/8250/8250_of.c67
-rw-r--r--drivers/tty/serial/8250/8250_omap.c34
-rw-r--r--drivers/tty/serial/8250/8250_pci.c2
-rw-r--r--drivers/tty/serial/8250/8250_port.c188
-rw-r--r--drivers/tty/serial/8250/8250_pxa.c2
-rw-r--r--drivers/tty/serial/8250/8250_tegra.c198
-rw-r--r--drivers/tty/serial/8250/Kconfig9
-rw-r--r--drivers/tty/serial/8250/Makefile1
-rw-r--r--drivers/tty/serial/Kconfig14
-rw-r--r--drivers/tty/serial/ar933x_uart.c113
-rw-r--r--drivers/tty/serial/atmel_serial.c3
-rw-r--r--drivers/tty/serial/atmel_serial.h2
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart.h6
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart_core.c48
-rw-r--r--drivers/tty/serial/earlycon.c11
-rw-r--r--drivers/tty/serial/efm32-uart.c2
-rw-r--r--drivers/tty/serial/icom.h2
-rw-r--r--drivers/tty/serial/ifx6x60.h2
-rw-r--r--drivers/tty/serial/imx.c44
-rw-r--r--drivers/tty/serial/jsm/jsm.h2
-rw-r--r--drivers/tty/serial/kgdboc.c4
-rw-r--r--drivers/tty/serial/lantiq.c1
-rw-r--r--drivers/tty/serial/pic32_uart.h2
-rw-r--r--drivers/tty/serial/qcom_geni_serial.c30
-rw-r--r--drivers/tty/serial/sc16is7xx.c2
-rw-r--r--drivers/tty/serial/serial_core.c171
-rw-r--r--drivers/tty/serial/serial_mctrl_gpio.h2
-rw-r--r--drivers/tty/serial/sirfsoc_uart.h2
-rw-r--r--drivers/tty/serial/stm32-usart.h2
-rw-r--r--drivers/tty/serial/timbuart.h2
-rw-r--r--drivers/tty/sysrq.c12
-rw-r--r--drivers/tty/vt/selection.c200
-rw-r--r--drivers/tty/vt/vt.c7
-rw-r--r--drivers/tty/vt/vt_ioctl.c35
-rw-r--r--include/linux/selection.h4
-rw-r--r--include/linux/serial_8250.h3
-rw-r--r--include/linux/serial_core.h1
-rw-r--r--include/linux/sysrq.h7
-rw-r--r--include/linux/vt_kern.h64
-rw-r--r--kernel/sysctl.c41
-rw-r--r--lib/Kconfig.debug8
54 files changed, 1318 insertions, 895 deletions
diff --git a/Documentation/devicetree/bindings/serial/fsl-imx-uart.txt b/Documentation/devicetree/bindings/serial/fsl-imx-uart.txt
index 35957cbf1571..c8d677f9491f 100644
--- a/Documentation/devicetree/bindings/serial/fsl-imx-uart.txt
+++ b/Documentation/devicetree/bindings/serial/fsl-imx-uart.txt
@@ -8,6 +8,10 @@ Required properties:
Optional properties:
- fsl,dte-mode : Indicate the uart works in DTE mode. The uart works
in DCE mode by default.
+- fsl,inverted-tx , fsl,inverted-rx : Indicate that the hardware attached
+ to the peripheral inverts the signal transmitted or received,
+ respectively, and that the peripheral should invert its output/input
+ using the INVT/INVR registers.
- rs485-rts-delay, rs485-rts-active-low, rs485-rx-during-tx,
linux,rs485-enabled-at-boot-time: see rs485.txt. Note that for RS485
you must enable either the "uart-has-rtscts" or the "rts-gpios"
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index b2b504ea6fd6..76778b2f520d 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -249,7 +249,7 @@ config ARCH_TEGRA
This enables support for the NVIDIA Tegra SoC family.
config ARCH_SPRD
- bool "Spreadtrum SoC platform"
+ tristate "Spreadtrum SoC platform"
help
Support for Spreadtrum ARM based SoCs
diff --git a/drivers/tty/mips_ejtag_fdc.c b/drivers/tty/mips_ejtag_fdc.c
index 620d8488b83e..21e76a2ec182 100644
--- a/drivers/tty/mips_ejtag_fdc.c
+++ b/drivers/tty/mips_ejtag_fdc.c
@@ -243,6 +243,7 @@ done:
/* Fall back to a 3 byte encoding */
word.bytes = 3;
word.word &= 0x00ffffff;
+ /* Fall through */
case 3:
/* 3 byte encoding */
word.word |= 0x82000000;
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index f1c90fa2978e..d77ed82a4840 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -97,7 +97,19 @@ struct gsm_msg {
u8 ctrl; /* Control byte + flags */
unsigned int len; /* Length of data block (can be zero) */
unsigned char *data; /* Points into buffer but not at the start */
- unsigned char buffer[0];
+ unsigned char buffer[];
+};
+
+enum gsm_dlci_state {
+ DLCI_CLOSED,
+ DLCI_OPENING, /* Sending SABM not seen UA */
+ DLCI_OPEN, /* SABM/UA complete */
+ DLCI_CLOSING, /* Sending DISC not seen UA/DM */
+};
+
+enum gsm_dlci_mode {
+ DLCI_MODE_ABM, /* Normal Asynchronous Balanced Mode */
+ DLCI_MODE_ADM, /* Asynchronous Disconnected Mode */
};
/*
@@ -113,32 +125,25 @@ struct gsm_msg {
struct gsm_dlci {
struct gsm_mux *gsm;
int addr;
- int state;
-#define DLCI_CLOSED 0
-#define DLCI_OPENING 1 /* Sending SABM not seen UA */
-#define DLCI_OPEN 2 /* SABM/UA complete */
-#define DLCI_CLOSING 3 /* Sending DISC not seen UA/DM */
+ enum gsm_dlci_state state;
struct mutex mutex;
/* Link layer */
- int mode;
-#define DLCI_MODE_ABM 0 /* Normal Asynchronous Balanced Mode */
-#define DLCI_MODE_ADM 1 /* Asynchronous Disconnected Mode */
+ enum gsm_dlci_mode mode;
spinlock_t lock; /* Protects the internal state */
struct timer_list t1; /* Retransmit timer for SABM and UA */
int retries;
/* Uplink tty if active */
struct tty_port port; /* The tty bound to this DLCI if there is one */
- struct kfifo *fifo; /* Queue fifo for the DLCI */
- struct kfifo _fifo; /* For new fifo API porting only */
+ struct kfifo fifo; /* Queue fifo for the DLCI */
int adaption; /* Adaption layer in use */
int prev_adaption;
u32 modem_rx; /* Our incoming virtual modem lines */
u32 modem_tx; /* Our outgoing modem lines */
- int dead; /* Refuse re-open */
+ bool dead; /* Refuse re-open */
/* Flow control */
- int throttled; /* Private copy of throttle state */
- int constipated; /* Throttle status for outgoing */
+ bool throttled; /* Private copy of throttle state */
+ bool constipated; /* Throttle status for outgoing */
/* Packetised I/O */
struct sk_buff *skb; /* Frame being sent */
struct sk_buff_head skb_list; /* Queued frames */
@@ -168,6 +173,20 @@ struct gsm_control {
int error; /* Error if any */
};
+enum gsm_mux_state {
+ GSM_SEARCH,
+ GSM_START,
+ GSM_ADDRESS,
+ GSM_CONTROL,
+ GSM_LEN,
+ GSM_DATA,
+ GSM_FCS,
+ GSM_OVERRUN,
+ GSM_LEN0,
+ GSM_LEN1,
+ GSM_SSOF,
+};
+
/*
* Each GSM mux we have is represented by this structure. If we are
* operating as an ldisc then we use this structure as our ldisc
@@ -192,22 +211,11 @@ struct gsm_mux {
/* Framing Layer */
unsigned char *buf;
- int state;
-#define GSM_SEARCH 0
-#define GSM_START 1
-#define GSM_ADDRESS 2
-#define GSM_CONTROL 3
-#define GSM_LEN 4
-#define GSM_DATA 5
-#define GSM_FCS 6
-#define GSM_OVERRUN 7
-#define GSM_LEN0 8
-#define GSM_LEN1 9
-#define GSM_SSOF 10
+ enum gsm_mux_state state;
unsigned int len;
unsigned int address;
unsigned int count;
- int escape;
+ bool escape;
int encoding;
u8 control;
u8 fcs;
@@ -224,9 +232,9 @@ struct gsm_mux {
unsigned int mru;
unsigned int mtu;
int initiator; /* Did we initiate connection */
- int dead; /* Has the mux been shut down */
+ bool dead; /* Has the mux been shut down */
struct gsm_dlci *dlci[NUM_DLCI];
- int constipated; /* Asked by remote to shut up */
+ bool constipated; /* Asked by remote to shut up */
spinlock_t tx_lock;
unsigned int tx_bytes; /* TX data outstanding */
@@ -796,7 +804,7 @@ static int gsm_dlci_data_output(struct gsm_mux *gsm, struct gsm_dlci *dlci)
total_size = 0;
while (1) {
- len = kfifo_len(dlci->fifo);
+ len = kfifo_len(&dlci->fifo);
if (len == 0)
return total_size;
@@ -820,7 +828,7 @@ static int gsm_dlci_data_output(struct gsm_mux *gsm, struct gsm_dlci *dlci)
*dp++ = gsm_encode_modem(dlci);
break;
}
- WARN_ON(kfifo_out_locked(dlci->fifo, dp , len, &dlci->lock) != len);
+ WARN_ON(kfifo_out_locked(&dlci->fifo, dp , len, &dlci->lock) != len);
__gsm_data_queue(dlci, msg);
total_size += size;
}
@@ -1034,9 +1042,9 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
fc = (modem & MDM_FC) || !(modem & MDM_RTR);
if (fc && !dlci->constipated) {
/* Need to throttle our output on this device */
- dlci->constipated = 1;
+ dlci->constipated = true;
} else if (!fc && dlci->constipated) {
- dlci->constipated = 0;
+ dlci->constipated = false;
gsm_dlci_data_kick(dlci);
}
@@ -1199,8 +1207,8 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
struct gsm_dlci *dlci = gsm->dlci[0];
/* Modem wishes to close down */
if (dlci) {
- dlci->dead = 1;
- gsm->dead = 1;
+ dlci->dead = true;
+ gsm->dead = true;
gsm_dlci_begin_close(dlci);
}
}
@@ -1211,7 +1219,7 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
break;
case CMD_FCON:
/* Modem can accept data again */
- gsm->constipated = 0;
+ gsm->constipated = false;
gsm_control_reply(gsm, CMD_FCON, NULL, 0);
/* Kick the link in case it is idling */
spin_lock_irqsave(&gsm->tx_lock, flags);
@@ -1220,7 +1228,7 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
break;
case CMD_FCOFF:
/* Modem wants us to STFU */
- gsm->constipated = 1;
+ gsm->constipated = true;
gsm_control_reply(gsm, CMD_FCOFF, NULL, 0);
break;
case CMD_MSC:
@@ -1424,9 +1432,9 @@ static void gsm_dlci_close(struct gsm_dlci *dlci)
dlci->state = DLCI_CLOSED;
if (dlci->addr != 0) {
tty_port_tty_hangup(&dlci->port, false);
- kfifo_reset(dlci->fifo);
+ kfifo_reset(&dlci->fifo);
} else
- dlci->gsm->dead = 1;
+ dlci->gsm->dead = true;
wake_up(&dlci->gsm->event);
/* A DLCI 0 close is a MUX termination so we need to kick that
back to userspace somehow */
@@ -1496,6 +1504,9 @@ static void gsm_dlci_t1(struct timer_list *t)
} else
gsm_dlci_close(dlci);
break;
+ default:
+ pr_debug("%s: unhandled state: %d\n", __func__, dlci->state);
+ break;
}
}
@@ -1645,8 +1656,7 @@ static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr)
return NULL;
spin_lock_init(&dlci->lock);
mutex_init(&dlci->mutex);
- dlci->fifo = &dlci->_fifo;
- if (kfifo_alloc(&dlci->_fifo, 4096, GFP_KERNEL) < 0) {
+ if (kfifo_alloc(&dlci->fifo, 4096, GFP_KERNEL) < 0) {
kfree(dlci);
return NULL;
}
@@ -1681,7 +1691,7 @@ static void gsm_dlci_free(struct tty_port *port)
del_timer_sync(&dlci->t1);
dlci->gsm->dlci[dlci->addr] = NULL;
- kfifo_free(dlci->fifo);
+ kfifo_free(&dlci->fifo);
while ((dlci->skb = skb_dequeue(&dlci->skb_list)))
dev_kfree_skb(dlci->skb);
kfree(dlci);
@@ -1810,6 +1820,10 @@ static void gsm_queue(struct gsm_mux *gsm)
case DLCI_OPENING:
gsm_dlci_open(dlci);
break;
+ default:
+ pr_debug("%s: unhandled state: %d\n", __func__,
+ dlci->state);
+ break;
}
break;
case DM: /* DM can be valid unsolicited */
@@ -1923,6 +1937,9 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
break;
}
break;
+ default:
+ pr_debug("%s: unhandled state: %d\n", __func__, gsm->state);
+ break;
}
}
@@ -1959,7 +1976,7 @@ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c)
}
if (c == GSM1_ESCAPE) {
- gsm->escape = 1;
+ gsm->escape = true;
return;
}
@@ -1969,7 +1986,7 @@ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c)
if (gsm->escape) {
c ^= GSM1_ESCAPE_BITS;
- gsm->escape = 0;
+ gsm->escape = false;
}
switch (gsm->state) {
case GSM_START: /* First byte after SOF */
@@ -1997,6 +2014,9 @@ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c)
break;
case GSM_OVERRUN: /* Over-long - eg a dropped SOF */
break;
+ default:
+ pr_debug("%s: unhandled state: %d\n", __func__, gsm->state);
+ break;
}
}
@@ -2061,7 +2081,7 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm)
struct gsm_dlci *dlci = gsm->dlci[0];
struct gsm_msg *txq, *ntxq;
- gsm->dead = 1;
+ gsm->dead = true;
spin_lock(&gsm_mux_lock);
for (i = 0; i < MAX_MUX; i++) {
@@ -2078,7 +2098,7 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm)
del_timer_sync(&gsm->t2_timer);
/* Now we are sure T2 has stopped */
if (dlci)
- dlci->dead = 1;
+ dlci->dead = true;
/* Free up any link layer users */
mutex_lock(&gsm->mutex);
@@ -2132,7 +2152,7 @@ static int gsm_activate_mux(struct gsm_mux *gsm)
dlci = gsm_dlci_alloc(gsm, 0);
if (dlci == NULL)
return -ENOMEM;
- gsm->dead = 0; /* Tty opens are now permissible */
+ gsm->dead = false; /* Tty opens are now permissible */
return 0;
}
@@ -2216,7 +2236,7 @@ static struct gsm_mux *gsm_alloc_mux(void)
gsm->encoding = 1;
gsm->mru = 64; /* Default to encoding 1 so these should be 64 */
gsm->mtu = 64;
- gsm->dead = 1; /* Avoid early tty opens */
+ gsm->dead = true; /* Avoid early tty opens */
return gsm;
}
@@ -2618,11 +2638,11 @@ static int gsmld_ioctl(struct tty_struct *tty, struct file *file,
switch (cmd) {
case GSMIOC_GETCONF:
gsm_copy_config_values(gsm, &c);
- if (copy_to_user((void *)arg, &c, sizeof(c)))
+ if (copy_to_user((void __user *)arg, &c, sizeof(c)))
return -EFAULT;
return 0;
case GSMIOC_SETCONF:
- if (copy_from_user(&c, (void *)arg, sizeof(c)))
+ if (copy_from_user(&c, (void __user *)arg, sizeof(c)))
return -EFAULT;
return gsm_config(gsm, &c);
case GSMIOC_GETFIRST:
@@ -2769,7 +2789,7 @@ static void gsm_destroy_network(struct gsm_dlci *dlci)
{
struct gsm_mux_net *mux_net;
- pr_debug("destroy network interface");
+ pr_debug("destroy network interface\n");
if (!dlci->net)
return;
mux_net = netdev_priv(dlci->net);
@@ -2798,7 +2818,7 @@ static int gsm_create_network(struct gsm_dlci *dlci, struct gsm_netconfig *nc)
if (nc->adaption != 3 && nc->adaption != 4)
return -EPROTONOSUPPORT;
- pr_debug("create network interface");
+ pr_debug("create network interface\n");
netname = "gsm%d";
if (nc->if_name[0] != '\0')
@@ -2806,7 +2826,7 @@ static int gsm_create_network(struct gsm_dlci *dlci, struct gsm_netconfig *nc)
net = alloc_netdev(sizeof(struct gsm_mux_net), netname,
NET_NAME_UNKNOWN, gsm_mux_net_init);
if (!net) {
- pr_err("alloc_netdev failed");
+ pr_err("alloc_netdev failed\n");
return -ENOMEM;
}
net->mtu = dlci->gsm->mtu;
@@ -2824,7 +2844,7 @@ static int gsm_create_network(struct gsm_dlci *dlci, struct gsm_netconfig *nc)
dlci->data = gsm_mux_rx_netchar;
dlci->net = net;
- pr_debug("register netdev");
+ pr_debug("register netdev\n");
retval = register_netdev(net);
if (retval) {
pr_err("network register fail %d\n", retval);
@@ -3030,7 +3050,7 @@ static int gsmtty_write(struct tty_struct *tty, const unsigned char *buf,
if (dlci->state == DLCI_CLOSED)
return -EINVAL;
/* Stuff the bytes into the fifo queue */
- sent = kfifo_in_locked(dlci->fifo, buf, len, &dlci->lock);
+ sent = kfifo_in_locked(&dlci->fifo, buf, len, &dlci->lock);
/* Need to kick the channel */
gsm_dlci_data_kick(dlci);
return sent;
@@ -3041,7 +3061,7 @@ static int gsmtty_write_room(struct tty_struct *tty)
struct gsm_dlci *dlci = tty->driver_data;
if (dlci->state == DLCI_CLOSED)
return -EINVAL;
- return TX_SIZE - kfifo_len(dlci->fifo);
+ return TX_SIZE - kfifo_len(&dlci->fifo);
}
static int gsmtty_chars_in_buffer(struct tty_struct *tty)
@@ -3049,7 +3069,7 @@ static int gsmtty_chars_in_buffer(struct tty_struct *tty)
struct gsm_dlci *dlci = tty->driver_data;
if (dlci->state == DLCI_CLOSED)
return -EINVAL;
- return kfifo_len(dlci->fifo);
+ return kfifo_len(&dlci->fifo);
}
static void gsmtty_flush_buffer(struct tty_struct *tty)
@@ -3061,7 +3081,7 @@ static void gsmtty_flush_buffer(struct tty_struct *tty)
then the data being transmitted can't simply be junked once
it has first hit the stack. Until then we can just blow it
away */
- kfifo_reset(dlci->fifo);
+ kfifo_reset(&dlci->fifo);
/* Need to unhook this DLCI from the transmit queue logic */
}
@@ -3152,7 +3172,7 @@ static void gsmtty_throttle(struct tty_struct *tty)
return;
if (C_CRTSCTS(tty))
dlci->modem_tx &= ~TIOCM_DTR;
- dlci->throttled = 1;
+ dlci->throttled = true;
/* Send an MSC with DTR cleared */
gsmtty_modem_update(dlci, 0);
}
@@ -3164,7 +3184,7 @@ static void gsmtty_unthrottle(struct tty_struct *tty)
return;
if (C_CRTSCTS(tty))
dlci->modem_tx |= TIOCM_DTR;
- dlci->throttled = 0;
+ dlci->throttled = false;
/* Send an MSC with DTR set */
gsmtty_modem_update(dlci, 0);
}
diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c
index 27b506bf03ce..cd1319d26c45 100644
--- a/drivers/tty/n_hdlc.c
+++ b/drivers/tty/n_hdlc.c
@@ -18,7 +18,7 @@
* All HDLC data is frame oriented which means:
*
* 1. tty write calls represent one complete transmit frame of data
- * The device driver should accept the complete frame or none of
+ * The device driver should accept the complete frame or none of
* the frame (busy) in the write method. Each write call should have
* a byte count in the range of 2-65535 bytes (2 is min HDLC frame
* with 1 addr byte and 1 ctrl byte). The max byte count of 65535
@@ -39,7 +39,7 @@
* tty read calls.
*
* 3. tty read calls returns an entire frame of data or nothing.
- *
+ *
* 4. all send and receive data is considered raw. No processing
* or translation is performed by the line discipline, regardless
* of the tty flags
@@ -87,9 +87,6 @@
#include <linux/interrupt.h>
#include <linux/ptrace.h>
-#undef VERSION
-#define VERSION(major,minor,patch) (((((major)<<8)+(minor))<<8)+(patch))
-
#include <linux/poll.h>
#include <linux/in.h>
#include <linux/ioctl.h>
@@ -107,7 +104,7 @@
/*
* Buffers for individual HDLC frames
*/
-#define MAX_HDLC_FRAME_SIZE 65535
+#define MAX_HDLC_FRAME_SIZE 65535
#define DEFAULT_RX_BUF_COUNT 10
#define MAX_RX_BUF_COUNT 60
#define DEFAULT_TX_BUF_COUNT 3
@@ -127,11 +124,8 @@ struct n_hdlc_buf_list {
/**
* struct n_hdlc - per device instance data structure
* @magic - magic value for structure
- * @flags - miscellaneous control flags
- * @tty - ptr to TTY structure
- * @backup_tty - TTY to use if tty gets closed
* @tbusy - reentrancy flag for tx wakeup code
- * @woke_up - FIXME: describe this field
+ * @woke_up - tx wakeup needs to be run again as it was called while @tbusy
* @tx_buf_list - list of pending transmit frame buffers
* @rx_buf_list - list of received frame buffers
* @tx_free_buf_list - list unused transmit frame buffers
@@ -139,11 +133,8 @@ struct n_hdlc_buf_list {
*/
struct n_hdlc {
int magic;
- __u32 flags;
- struct tty_struct *tty;
- struct tty_struct *backup_tty;
- int tbusy;
- int woke_up;
+ bool tbusy;
+ bool woke_up;
struct n_hdlc_buf_list tx_buf_list;
struct n_hdlc_buf_list rx_buf_list;
struct n_hdlc_buf_list tx_free_buf_list;
@@ -161,39 +152,14 @@ static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *list);
/* Local functions */
-static struct n_hdlc *n_hdlc_alloc (void);
-
-/* debug level can be set by insmod for debugging purposes */
-#define DEBUG_LEVEL_INFO 1
-static int debuglevel;
+static struct n_hdlc *n_hdlc_alloc(void);
/* max frame size for memory allocations */
static int maxframe = 4096;
-/* TTY callbacks */
-
-static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
- __u8 __user *buf, size_t nr);
-static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
- const unsigned char *buf, size_t nr);
-static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
- unsigned int cmd, unsigned long arg);
-static __poll_t n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
- poll_table *wait);
-static int n_hdlc_tty_open(struct tty_struct *tty);
-static void n_hdlc_tty_close(struct tty_struct *tty);
-static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *cp,
- char *fp, int count);
-static void n_hdlc_tty_wakeup(struct tty_struct *tty);
-
-#define bset(p,b) ((p)[(b) >> 5] |= (1 << ((b) & 0x1f)))
-
-#define tty2n_hdlc(tty) ((struct n_hdlc *) ((tty)->disc_data))
-#define n_hdlc2tty(n_hdlc) ((n_hdlc)->tty)
-
static void flush_rx_queue(struct tty_struct *tty)
{
- struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
+ struct n_hdlc *n_hdlc = tty->disc_data;
struct n_hdlc_buf *buf;
while ((buf = n_hdlc_buf_get(&n_hdlc->rx_buf_list)))
@@ -202,79 +168,22 @@ static void flush_rx_queue(struct tty_struct *tty)
static void flush_tx_queue(struct tty_struct *tty)
{
- struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
+ struct n_hdlc *n_hdlc = tty->disc_data;
struct n_hdlc_buf *buf;
while ((buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list)))
n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, buf);
}
-static struct tty_ldisc_ops n_hdlc_ldisc = {
- .owner = THIS_MODULE,
- .magic = TTY_LDISC_MAGIC,
- .name = "hdlc",
- .open = n_hdlc_tty_open,
- .close = n_hdlc_tty_close,
- .read = n_hdlc_tty_read,
- .write = n_hdlc_tty_write,
- .ioctl = n_hdlc_tty_ioctl,
- .poll = n_hdlc_tty_poll,
- .receive_buf = n_hdlc_tty_receive,
- .write_wakeup = n_hdlc_tty_wakeup,
- .flush_buffer = flush_rx_queue,
-};
-
-/**
- * n_hdlc_release - release an n_hdlc per device line discipline info structure
- * @n_hdlc - per device line discipline info structure
- */
-static void n_hdlc_release(struct n_hdlc *n_hdlc)
+static void n_hdlc_free_buf_list(struct n_hdlc_buf_list *list)
{
- struct tty_struct *tty = n_hdlc2tty (n_hdlc);
struct n_hdlc_buf *buf;
-
- if (debuglevel >= DEBUG_LEVEL_INFO)
- printk("%s(%d)n_hdlc_release() called\n",__FILE__,__LINE__);
-
- /* Ensure that the n_hdlcd process is not hanging on select()/poll() */
- wake_up_interruptible (&tty->read_wait);
- wake_up_interruptible (&tty->write_wait);
-
- if (tty->disc_data == n_hdlc)
- tty->disc_data = NULL; /* Break the tty->n_hdlc link */
-
- /* Release transmit and receive buffers */
- for(;;) {
- buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list);
- if (buf) {
- kfree(buf);
- } else
- break;
- }
- for(;;) {
- buf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list);
- if (buf) {
- kfree(buf);
- } else
- break;
- }
- for(;;) {
- buf = n_hdlc_buf_get(&n_hdlc->rx_buf_list);
- if (buf) {
- kfree(buf);
- } else
- break;
- }
- for(;;) {
- buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
- if (buf) {
- kfree(buf);
- } else
- break;
- }
- kfree(n_hdlc);
-
-} /* end of n_hdlc_release() */
+
+ do {
+ buf = n_hdlc_buf_get(list);
+ kfree(buf);
+ } while (buf);
+}
/**
* n_hdlc_tty_close - line discipline close
@@ -285,34 +194,26 @@ static void n_hdlc_release(struct n_hdlc *n_hdlc)
*/
static void n_hdlc_tty_close(struct tty_struct *tty)
{
- struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
-
- if (debuglevel >= DEBUG_LEVEL_INFO)
- printk("%s(%d)n_hdlc_tty_close() called\n",__FILE__,__LINE__);
-
- if (n_hdlc != NULL) {
- if (n_hdlc->magic != HDLC_MAGIC) {
- printk (KERN_WARNING"n_hdlc: trying to close unopened tty!\n");
- return;
- }
+ struct n_hdlc *n_hdlc = tty->disc_data;
+
+ if (n_hdlc->magic != HDLC_MAGIC) {
+ pr_warn("n_hdlc: trying to close unopened tty!\n");
+ return;
+ }
#if defined(TTY_NO_WRITE_SPLIT)
- clear_bit(TTY_NO_WRITE_SPLIT,&tty->flags);
+ clear_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
#endif
- tty->disc_data = NULL;
- if (tty == n_hdlc->backup_tty)
- n_hdlc->backup_tty = NULL;
- if (tty != n_hdlc->tty)
- return;
- if (n_hdlc->backup_tty) {
- n_hdlc->tty = n_hdlc->backup_tty;
- } else {
- n_hdlc_release (n_hdlc);
- }
- }
-
- if (debuglevel >= DEBUG_LEVEL_INFO)
- printk("%s(%d)n_hdlc_tty_close() success\n",__FILE__,__LINE__);
-
+ tty->disc_data = NULL;
+
+ /* Ensure that the n_hdlcd process is not hanging on select()/poll() */
+ wake_up_interruptible(&tty->read_wait);
+ wake_up_interruptible(&tty->write_wait);
+
+ n_hdlc_free_buf_list(&n_hdlc->rx_free_buf_list);
+ n_hdlc_free_buf_list(&n_hdlc->tx_free_buf_list);
+ n_hdlc_free_buf_list(&n_hdlc->rx_buf_list);
+ n_hdlc_free_buf_list(&n_hdlc->tx_buf_list);
+ kfree(n_hdlc);
} /* end of n_hdlc_tty_close() */
/**
@@ -321,44 +222,36 @@ static void n_hdlc_tty_close(struct tty_struct *tty)
*
* Returns 0 if success, otherwise error code
*/
-static int n_hdlc_tty_open (struct tty_struct *tty)
+static int n_hdlc_tty_open(struct tty_struct *tty)
{
- struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
+ struct n_hdlc *n_hdlc = tty->disc_data;
+
+ pr_debug("%s(%d)%s() called (device=%s)\n",
+ __FILE__, __LINE__, __func__, tty->name);
- if (debuglevel >= DEBUG_LEVEL_INFO)
- printk("%s(%d)n_hdlc_tty_open() called (device=%s)\n",
- __FILE__,__LINE__,
- tty->name);
-
/* There should not be an existing table for this slot. */
if (n_hdlc) {
- printk (KERN_ERR"n_hdlc_tty_open:tty already associated!\n" );
+ pr_err("%s: tty already associated!\n", __func__);
return -EEXIST;
}
-
+
n_hdlc = n_hdlc_alloc();
if (!n_hdlc) {
- printk (KERN_ERR "n_hdlc_alloc failed\n");
+ pr_err("%s: n_hdlc_alloc failed\n", __func__);
return -ENFILE;
}
-
+
tty->disc_data = n_hdlc;
- n_hdlc->tty = tty;
tty->receive_room = 65536;
-
-#if defined(TTY_NO_WRITE_SPLIT)
+
/* change tty_io write() to not split large writes into 8K chunks */
- set_bit(TTY_NO_WRITE_SPLIT,&tty->flags);
-#endif
-
+ set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
+
/* flush receive data from driver */
tty_driver_flush_buffer(tty);
-
- if (debuglevel >= DEBUG_LEVEL_INFO)
- printk("%s(%d)n_hdlc_tty_open() success\n",__FILE__,__LINE__);
-
+
return 0;
-
+
} /* end of n_tty_hdlc_open() */
/**
@@ -376,26 +269,23 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
unsigned long flags;
struct n_hdlc_buf *tbuf;
- if (debuglevel >= DEBUG_LEVEL_INFO)
- printk("%s(%d)n_hdlc_send_frames() called\n",__FILE__,__LINE__);
- check_again:
-
- spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
+check_again:
+
+ spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
if (n_hdlc->tbusy) {
- n_hdlc->woke_up = 1;
- spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
+ n_hdlc->woke_up = true;
+ spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
return;
}
- n_hdlc->tbusy = 1;
- n_hdlc->woke_up = 0;
+ n_hdlc->tbusy = true;
+ n_hdlc->woke_up = false;
spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
while (tbuf) {
- if (debuglevel >= DEBUG_LEVEL_INFO)
- printk("%s(%d)sending frame %p, count=%d\n",
- __FILE__,__LINE__,tbuf,tbuf->count);
-
+ pr_debug("%s(%d)sending frame %p, count=%d\n",
+ __FILE__, __LINE__, tbuf, tbuf->count);
+
/* Send the next block of data to device */
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
actual = tty->ops->write(tty, tbuf->buf, tbuf->count);
@@ -409,24 +299,22 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
/* pretending it was accepted by driver */
if (actual < 0)
actual = tbuf->count;
-
+
if (actual == tbuf->count) {
- if (debuglevel >= DEBUG_LEVEL_INFO)
- printk("%s(%d)frame %p completed\n",
- __FILE__,__LINE__,tbuf);
-
+ pr_debug("%s(%d)frame %p completed\n",
+ __FILE__, __LINE__, tbuf);
+
/* free current transmit buffer */
n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, tbuf);
/* wait up sleeping writers */
wake_up_interruptible(&tty->write_wait);
-
+
/* get next pending transmit buffer */
tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
} else {
- if (debuglevel >= DEBUG_LEVEL_INFO)
- printk("%s(%d)frame %p pending\n",
- __FILE__,__LINE__,tbuf);
+ pr_debug("%s(%d)frame %p pending\n",
+ __FILE__, __LINE__, tbuf);
/*
* the buffer was not accepted by driver,
@@ -436,21 +324,17 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
break;
}
}
-
+
if (!tbuf)
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
-
+
/* Clear the re-entry flag */
spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
- n_hdlc->tbusy = 0;
- spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
-
- if (n_hdlc->woke_up)
- goto check_again;
-
- if (debuglevel >= DEBUG_LEVEL_INFO)
- printk("%s(%d)n_hdlc_send_frames() exit\n",__FILE__,__LINE__);
-
+ n_hdlc->tbusy = false;
+ spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
+
+ if (n_hdlc->woke_up)
+ goto check_again;
} /* end of n_hdlc_send_frames() */
/**
@@ -461,21 +345,9 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
*/
static void n_hdlc_tty_wakeup(struct tty_struct *tty)
{
- struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
+ struct n_hdlc *n_hdlc = tty->disc_data;
- if (debuglevel >= DEBUG_LEVEL_INFO)
- printk("%s(%d)n_hdlc_tty_wakeup() called\n",__FILE__,__LINE__);
-
- if (!n_hdlc)
- return;
-
- if (tty != n_hdlc->tty) {
- clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- return;
- }
-
- n_hdlc_send_frames (n_hdlc, tty);
-
+ n_hdlc_send_frames(n_hdlc, tty);
} /* end of n_hdlc_tty_wakeup() */
/**
@@ -491,59 +363,54 @@ static void n_hdlc_tty_wakeup(struct tty_struct *tty)
static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data,
char *flags, int count)
{
- register struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
+ register struct n_hdlc *n_hdlc = tty->disc_data;
register struct n_hdlc_buf *buf;
- if (debuglevel >= DEBUG_LEVEL_INFO)
- printk("%s(%d)n_hdlc_tty_receive() called count=%d\n",
- __FILE__,__LINE__, count);
-
- /* This can happen if stuff comes in on the backup tty */
- if (!n_hdlc || tty != n_hdlc->tty)
- return;
-
+ pr_debug("%s(%d)%s() called count=%d\n",
+ __FILE__, __LINE__, __func__, count);
+
/* verify line is using HDLC discipline */
if (n_hdlc->magic != HDLC_MAGIC) {
- printk("%s(%d) line not using HDLC discipline\n",
- __FILE__,__LINE__);
+ pr_err("%s(%d) line not using HDLC discipline\n",
+ __FILE__, __LINE__);
return;
}
-
- if ( count>maxframe ) {
- if (debuglevel >= DEBUG_LEVEL_INFO)
- printk("%s(%d) rx count>maxframesize, data discarded\n",
- __FILE__,__LINE__);
+
+ if (count > maxframe) {
+ pr_debug("%s(%d) rx count>maxframesize, data discarded\n",
+ __FILE__, __LINE__);
return;
}
- /* get a free HDLC buffer */
+ /* get a free HDLC buffer */
buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list);
if (!buf) {
- /* no buffers in free list, attempt to allocate another rx buffer */
- /* unless the maximum count has been reached */
+ /*
+ * no buffers in free list, attempt to allocate another rx
+ * buffer unless the maximum count has been reached
+ */
if (n_hdlc->rx_buf_list.count < MAX_RX_BUF_COUNT)
buf = kmalloc(struct_size(buf, buf, maxframe),
GFP_ATOMIC);
}
-
+
if (!buf) {
- if (debuglevel >= DEBUG_LEVEL_INFO)
- printk("%s(%d) no more rx buffers, data discarded\n",
- __FILE__,__LINE__);
+ pr_debug("%s(%d) no more rx buffers, data discarded\n",
+ __FILE__, __LINE__);
return;
}
-
+
/* copy received data to HDLC buffer */
- memcpy(buf->buf,data,count);
- buf->count=count;
+ memcpy(buf->buf, data, count);
+ buf->count = count;
/* add HDLC buffer to list of received frames */
n_hdlc_buf_put(&n_hdlc->rx_buf_list, buf);
-
+
/* wake up any blocked reads and perform async signalling */
- wake_up_interruptible (&tty->read_wait);
- if (n_hdlc->tty->fasync != NULL)
- kill_fasync (&n_hdlc->tty->fasync, SIGIO, POLL_IN);
+ wake_up_interruptible(&tty->read_wait);
+ if (tty->fasync != NULL)
+ kill_fasync(&tty->fasync, SIGIO, POLL_IN);
} /* end of n_hdlc_tty_receive() */
@@ -553,28 +420,21 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data,
* @file - pointer to open file object
* @buf - pointer to returned data buffer
* @nr - size of returned data buffer
- *
+ *
* Returns the number of bytes returned or error code.
*/
static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
__u8 __user *buf, size_t nr)
{
- struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
+ struct n_hdlc *n_hdlc = tty->disc_data;
int ret = 0;
struct n_hdlc_buf *rbuf;
DECLARE_WAITQUEUE(wait, current);
- if (debuglevel >= DEBUG_LEVEL_INFO)
- printk("%s(%d)n_hdlc_tty_read() called\n",__FILE__,__LINE__);
-
- /* Validate the pointers */
- if (!n_hdlc)
- return -EIO;
-
/* verify user access to buffer */
if (!access_ok(buf, nr)) {
- printk(KERN_WARNING "%s(%d) n_hdlc_tty_read() can't verify user "
- "buffer\n", __FILE__, __LINE__);
+ pr_warn("%s(%d) %s() can't verify user buffer\n",
+ __FILE__, __LINE__, __func__);
return -EFAULT;
}
@@ -610,7 +470,7 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
n_hdlc_buf_put(&n_hdlc->rx_free_buf_list, rbuf);
break;
}
-
+
/* no data */
if (tty_io_nonblock(tty, file)) {
ret = -EAGAIN;
@@ -629,7 +489,7 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
__set_current_state(TASK_RUNNING);
return ret;
-
+
} /* end of n_hdlc_tty_read() */
/**
@@ -638,43 +498,35 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
* @file - pointer to file object data
* @data - pointer to transmit data (one frame)
* @count - size of transmit frame in bytes
- *
+ *
* Returns the number of bytes written (or error code).
*/
static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
const unsigned char *data, size_t count)
{
- struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
+ struct n_hdlc *n_hdlc = tty->disc_data;
int error = 0;
DECLARE_WAITQUEUE(wait, current);
struct n_hdlc_buf *tbuf;
- if (debuglevel >= DEBUG_LEVEL_INFO)
- printk("%s(%d)n_hdlc_tty_write() called count=%zd\n",
- __FILE__,__LINE__,count);
-
- /* Verify pointers */
- if (!n_hdlc)
- return -EIO;
+ pr_debug("%s(%d)%s() called count=%zd\n", __FILE__, __LINE__, __func__,
+ count);
if (n_hdlc->magic != HDLC_MAGIC)
return -EIO;
/* verify frame size */
- if (count > maxframe ) {
- if (debuglevel & DEBUG_LEVEL_INFO)
- printk (KERN_WARNING
- "n_hdlc_tty_write: truncating user packet "
- "from %lu to %d\n", (unsigned long) count,
- maxframe );
+ if (count > maxframe) {
+ pr_debug("%s: truncating user packet from %zu to %d\n",
+ __func__, count, maxframe);
count = maxframe;
}
-
+
add_wait_queue(&tty->write_wait, &wait);
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
-
+
tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list);
if (tbuf)
break;
@@ -684,15 +536,7 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
break;
}
schedule();
-
- n_hdlc = tty2n_hdlc (tty);
- if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC ||
- tty != n_hdlc->tty) {
- printk("n_hdlc_tty_write: %p invalid after wait!\n", n_hdlc);
- error = -EIO;
- break;
- }
-
+
if (signal_pending(current)) {
error = -EINTR;
break;
@@ -702,18 +546,18 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
__set_current_state(TASK_RUNNING);
remove_wait_queue(&tty->write_wait, &wait);
- if (!error) {
+ if (!error) {
/* Retrieve the user's buffer */
memcpy(tbuf->buf, data, count);
/* Send the data */
tbuf->count = error = count;
- n_hdlc_buf_put(&n_hdlc->tx_buf_list,tbuf);
- n_hdlc_send_frames(n_hdlc,tty);
+ n_hdlc_buf_put(&n_hdlc->tx_buf_list, tbuf);
+ n_hdlc_send_frames(n_hdlc, tty);
}
return error;
-
+
} /* end of n_hdlc_tty_write() */
/**
@@ -728,32 +572,30 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
- struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
+ struct n_hdlc *n_hdlc = tty->disc_data;
int error = 0;
int count;
unsigned long flags;
struct n_hdlc_buf *buf = NULL;
- if (debuglevel >= DEBUG_LEVEL_INFO)
- printk("%s(%d)n_hdlc_tty_ioctl() called %d\n",
- __FILE__,__LINE__,cmd);
-
+ pr_debug("%s(%d)%s() called %d\n", __FILE__, __LINE__, __func__, cmd);
+
/* Verify the status of the device */
- if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC)
+ if (n_hdlc->magic != HDLC_MAGIC)
return -EBADF;
switch (cmd) {
case FIONREAD:
/* report count of read data available */
/* in next available frame (if any) */
- spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock,flags);
+ spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock, flags);
buf = list_first_entry_or_null(&n_hdlc->rx_buf_list.list,
struct n_hdlc_buf, list_item);
if (buf)
count = buf->count;
else
count = 0;
- spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock,flags);
+ spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock, flags);
error = put_user(count, (int __user *)arg);
break;
@@ -761,12 +603,12 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
/* get the pending tx byte count in the driver */
count = tty_chars_in_buffer(tty);
/* add size of next output frame in queue */
- spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock,flags);
+ spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
buf = list_first_entry_or_null(&n_hdlc->tx_buf_list.list,
struct n_hdlc_buf, list_item);
if (buf)
count += buf->count;
- spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock,flags);
+ spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
error = put_user(count, (int __user *)arg);
break;
@@ -783,7 +625,7 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
break;
}
return error;
-
+
} /* end of n_hdlc_tty_ioctl() */
/**
@@ -791,7 +633,7 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
* @tty - pointer to tty instance data
* @filp - pointer to open file object for device
* @poll_table - wait queue for operations
- *
+ *
* Determine which operations (read/write) will not block and return info
* to caller.
* Returns a bit mask containing info on which ops will not block.
@@ -799,33 +641,50 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
static __poll_t n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
poll_table *wait)
{
- struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
+ struct n_hdlc *n_hdlc = tty->disc_data;
__poll_t mask = 0;
- if (debuglevel >= DEBUG_LEVEL_INFO)
- printk("%s(%d)n_hdlc_tty_poll() called\n",__FILE__,__LINE__);
-
- if (n_hdlc && n_hdlc->magic == HDLC_MAGIC && tty == n_hdlc->tty) {
- /* queue current process into any wait queue that */
- /* may awaken in the future (read and write) */
-
- poll_wait(filp, &tty->read_wait, wait);
- poll_wait(filp, &tty->write_wait, wait);
-
- /* set bits for operations that won't block */
- if (!list_empty(&n_hdlc->rx_buf_list.list))
- mask |= EPOLLIN | EPOLLRDNORM; /* readable */
- if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
- mask |= EPOLLHUP;
- if (tty_hung_up_p(filp))
- mask |= EPOLLHUP;
- if (!tty_is_writelocked(tty) &&
- !list_empty(&n_hdlc->tx_free_buf_list.list))
- mask |= EPOLLOUT | EPOLLWRNORM; /* writable */
- }
+ if (n_hdlc->magic != HDLC_MAGIC)
+ return 0;
+
+ /*
+ * queue the current process into any wait queue that may awaken in the
+ * future (read and write)
+ */
+ poll_wait(filp, &tty->read_wait, wait);
+ poll_wait(filp, &tty->write_wait, wait);
+
+ /* set bits for operations that won't block */
+ if (!list_empty(&n_hdlc->rx_buf_list.list))
+ mask |= EPOLLIN | EPOLLRDNORM; /* readable */
+ if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
+ mask |= EPOLLHUP;
+ if (tty_hung_up_p(filp))
+ mask |= EPOLLHUP;
+ if (!tty_is_writelocked(tty) &&
+ !list_empty(&n_hdlc->tx_free_buf_list.list))
+ mask |= EPOLLOUT | EPOLLWRNORM; /* writable */
+
return mask;
} /* end of n_hdlc_tty_poll() */
+static void n_hdlc_alloc_buf(struct n_hdlc_buf_list *list, unsigned int count,
+ const char *name)
+{
+ struct n_hdlc_buf *buf;
+ unsigned int i;
+
+ for (i = 0; i < count; i++) {
+ buf = kmalloc(struct_size(buf, buf, maxframe), GFP_KERNEL);
+ if (!buf) {
+ pr_debug("%s(%d)%s(), kmalloc() failed for %s buffer %u\n",
+ __FILE__, __LINE__, __func__, name, i);
+ return;
+ }
+ n_hdlc_buf_put(list, buf);
+ }
+}
+
/**
* n_hdlc_alloc - allocate an n_hdlc instance data structure
*
@@ -833,8 +692,6 @@ static __poll_t n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
*/
static struct n_hdlc *n_hdlc_alloc(void)
{
- struct n_hdlc_buf *buf;
- int i;
struct n_hdlc *n_hdlc = kzalloc(sizeof(*n_hdlc), GFP_KERNEL);
if (!n_hdlc)
@@ -850,30 +707,14 @@ static struct n_hdlc *n_hdlc_alloc(void)
INIT_LIST_HEAD(&n_hdlc->rx_buf_list.list);
INIT_LIST_HEAD(&n_hdlc->tx_buf_list.list);
- /* allocate free rx buffer list */
- for(i=0;i<DEFAULT_RX_BUF_COUNT;i++) {
- buf = kmalloc(struct_size(buf, buf, maxframe), GFP_KERNEL);
- if (buf)
- n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,buf);
- else if (debuglevel >= DEBUG_LEVEL_INFO)
- printk("%s(%d)n_hdlc_alloc(), kalloc() failed for rx buffer %d\n",__FILE__,__LINE__, i);
- }
-
- /* allocate free tx buffer list */
- for(i=0;i<DEFAULT_TX_BUF_COUNT;i++) {
- buf = kmalloc(struct_size(buf, buf, maxframe), GFP_KERNEL);
- if (buf)
- n_hdlc_buf_put(&n_hdlc->tx_free_buf_list,buf);
- else if (debuglevel >= DEBUG_LEVEL_INFO)
- printk("%s(%d)n_hdlc_alloc(), kalloc() failed for tx buffer %d\n",__FILE__,__LINE__, i);
- }
-
+ n_hdlc_alloc_buf(&n_hdlc->rx_free_buf_list, DEFAULT_RX_BUF_COUNT, "rx");
+ n_hdlc_alloc_buf(&n_hdlc->tx_free_buf_list, DEFAULT_TX_BUF_COUNT, "tx");
+
/* Initialize the control block */
n_hdlc->magic = HDLC_MAGIC;
- n_hdlc->flags = 0;
-
+
return n_hdlc;
-
+
} /* end of n_hdlc_alloc() */
/**
@@ -915,7 +756,7 @@ static void n_hdlc_buf_put(struct n_hdlc_buf_list *buf_list,
/**
* n_hdlc_buf_get - remove and return an HDLC buffer from list
* @buf_list - pointer to HDLC buffer list
- *
+ *
* Remove and return an HDLC buffer from the head of the specified HDLC buffer
* list.
* Returns a pointer to HDLC buffer if available, otherwise %NULL.
@@ -938,44 +779,39 @@ static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *buf_list)
return buf;
} /* end of n_hdlc_buf_get() */
-static const char hdlc_banner[] __initconst =
- KERN_INFO "HDLC line discipline maxframe=%u\n";
-static const char hdlc_register_ok[] __initconst =
- KERN_INFO "N_HDLC line discipline registered.\n";
-static const char hdlc_register_fail[] __initconst =
- KERN_ERR "error registering line discipline: %d\n";
+static struct tty_ldisc_ops n_hdlc_ldisc = {
+ .owner = THIS_MODULE,
+ .magic = TTY_LDISC_MAGIC,
+ .name = "hdlc",
+ .open = n_hdlc_tty_open,
+ .close = n_hdlc_tty_close,
+ .read = n_hdlc_tty_read,
+ .write = n_hdlc_tty_write,
+ .ioctl = n_hdlc_tty_ioctl,
+ .poll = n_hdlc_tty_poll,
+ .receive_buf = n_hdlc_tty_receive,
+ .write_wakeup = n_hdlc_tty_wakeup,
+ .flush_buffer = flush_rx_queue,
+};
static int __init n_hdlc_init(void)
{
int status;
/* range check maxframe arg */
- if (maxframe < 4096)
- maxframe = 4096;
- else if (maxframe > 65535)
- maxframe = 65535;
-
- printk(hdlc_banner, maxframe);
+ maxframe = clamp(maxframe, 4096, MAX_HDLC_FRAME_SIZE);
status = tty_register_ldisc(N_HDLC, &n_hdlc_ldisc);
if (!status)
- printk(hdlc_register_ok);
+ pr_info("N_HDLC line discipline registered with maxframe=%d\n",
+ maxframe);
else
- printk(hdlc_register_fail, status);
+ pr_err("N_HDLC: error registering line discipline: %d\n",
+ status);
return status;
-
-} /* end of init_module() */
-
-#ifdef CONFIG_SPARC
-#undef __exitdata
-#define __exitdata
-#endif
-static const char hdlc_unregister_ok[] __exitdata =
- KERN_INFO "N_HDLC: line discipline unregistered\n";
-static const char hdlc_unregister_fail[] __exitdata =
- KERN_ERR "N_HDLC: can't unregister line discipline (err = %d)\n";
+} /* end of init_module() */
static void __exit n_hdlc_exit(void)
{
@@ -983,9 +819,10 @@ static void __exit n_hdlc_exit(void)
int status = tty_unregister_ldisc(N_HDLC);
if (status)
- printk(hdlc_unregister_fail, status);
+ pr_err("N_HDLC: can't unregister line discipline (err = %d)\n",
+ status);
else
- printk(hdlc_unregister_ok);
+ pr_info("N_HDLC: line discipline unregistered\n");
}
module_init(n_hdlc_init);
@@ -993,6 +830,5 @@ module_exit(n_hdlc_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Paul Fulghum paulkf@microgate.com");
-module_param(debuglevel, int, 0);
module_param(maxframe, int, 0);
MODULE_ALIAS_LDISC(N_HDLC);
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index f9c584244f72..1794d84e7bf6 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -84,7 +84,7 @@
#ifdef N_TTY_TRACE
# define n_tty_trace(f, args...) trace_printk(f, ##args)
#else
-# define n_tty_trace(f, args...)
+# define n_tty_trace(f, args...) no_printk(f, ##args)
#endif
struct n_tty_data {
@@ -654,9 +654,9 @@ static size_t __process_echoes(struct tty_struct *tty)
op = echo_buf(ldata, tail + 1);
switch (op) {
+ case ECHO_OP_ERASE_TAB: {
unsigned int num_chars, num_bs;
- case ECHO_OP_ERASE_TAB:
if (MASK(ldata->echo_commit) == MASK(tail + 2))
goto not_yet_stored;
num_chars = echo_buf(ldata, tail + 2);
@@ -687,7 +687,7 @@ static size_t __process_echoes(struct tty_struct *tty)
}
tail += 3;
break;
-
+ }
case ECHO_OP_SET_CANON_COL:
ldata->canon_column = ldata->column;
tail += 2;
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index 33ad9d6de532..52bb21205bb6 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Driver for 8250/16550-type serial ports
*
@@ -156,7 +156,9 @@ void serial8250_rpm_put(struct uart_8250_port *p);
void serial8250_rpm_get_tx(struct uart_8250_port *p);
void serial8250_rpm_put_tx(struct uart_8250_port *p);
-int serial8250_em485_init(struct uart_8250_port *p);
+int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485);
+void serial8250_em485_start_tx(struct uart_8250_port *p);
+void serial8250_em485_stop_tx(struct uart_8250_port *p);
void serial8250_em485_destroy(struct uart_8250_port *p);
/* MCR <-> TIOCM conversion */
diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c
index e70e3cc30050..12d03e678295 100644
--- a/drivers/tty/serial/8250/8250_bcm2835aux.c
+++ b/drivers/tty/serial/8250/8250_bcm2835aux.c
@@ -6,6 +6,10 @@
*
* Based on 8250_lpc18xx.c:
* Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
+ *
+ * The bcm2835aux is capable of RTS auto flow-control, but this driver doesn't
+ * take advantage of it yet. When adding support, be sure not to enable it
+ * simultaneously to rs485.
*/
#include <linux/clk.h>
@@ -16,16 +20,64 @@
#include "8250.h"
+#define BCM2835_AUX_UART_CNTL 8
+#define BCM2835_AUX_UART_CNTL_RXEN 0x01 /* Receiver enable */
+#define BCM2835_AUX_UART_CNTL_TXEN 0x02 /* Transmitter enable */
+#define BCM2835_AUX_UART_CNTL_AUTORTS 0x04 /* RTS set by RX fill level */
+#define BCM2835_AUX_UART_CNTL_AUTOCTS 0x08 /* CTS stops transmitter */
+#define BCM2835_AUX_UART_CNTL_RTS3 0x00 /* RTS set until 3 chars left */
+#define BCM2835_AUX_UART_CNTL_RTS2 0x10 /* RTS set until 2 chars left */
+#define BCM2835_AUX_UART_CNTL_RTS1 0x20 /* RTS set until 1 chars left */
+#define BCM2835_AUX_UART_CNTL_RTS4 0x30 /* RTS set until 4 chars left */
+#define BCM2835_AUX_UART_CNTL_RTSINV 0x40 /* Invert auto RTS polarity */
+#define BCM2835_AUX_UART_CNTL_CTSINV 0x80 /* Invert auto CTS polarity */
+
/**
* struct bcm2835aux_data - driver private data of BCM2835 auxiliary UART
* @clk: clock producer of the port's uartclk
* @line: index of the port's serial8250_ports[] entry
+ * @cntl: cached copy of CNTL register
*/
struct bcm2835aux_data {
struct clk *clk;
int line;
+ u32 cntl;
};
+static void bcm2835aux_rs485_start_tx(struct uart_8250_port *up)
+{
+ if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
+ struct bcm2835aux_data *data = dev_get_drvdata(up->port.dev);
+
+ data->cntl &= ~BCM2835_AUX_UART_CNTL_RXEN;
+ serial_out(up, BCM2835_AUX_UART_CNTL, data->cntl);
+ }
+
+ /*
+ * On the bcm2835aux, the MCR register contains no other
+ * flags besides RTS. So no need for a read-modify-write.
+ */
+ if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND)
+ serial8250_out_MCR(up, 0);
+ else
+ serial8250_out_MCR(up, UART_MCR_RTS);
+}
+
+static void bcm2835aux_rs485_stop_tx(struct uart_8250_port *up)
+{
+ if (up->port.rs485.flags & SER_RS485_RTS_AFTER_SEND)
+ serial8250_out_MCR(up, 0);
+ else
+ serial8250_out_MCR(up, UART_MCR_RTS);
+
+ if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
+ struct bcm2835aux_data *data = dev_get_drvdata(up->port.dev);
+
+ data->cntl |= BCM2835_AUX_UART_CNTL_RXEN;
+ serial_out(up, BCM2835_AUX_UART_CNTL, data->cntl);
+ }
+}
+
static int bcm2835aux_serial_probe(struct platform_device *pdev)
{
struct uart_8250_port up = { };
@@ -47,6 +99,14 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
up.port.fifosize = 8;
up.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE |
UPF_SKIP_TEST | UPF_IOREMAP;
+ up.port.rs485_config = serial8250_em485_config;
+ up.rs485_start_tx = bcm2835aux_rs485_start_tx;
+ up.rs485_stop_tx = bcm2835aux_rs485_stop_tx;
+
+ /* initialize cached copy with power-on reset value */
+ data->cntl = BCM2835_AUX_UART_CNTL_RXEN | BCM2835_AUX_UART_CNTL_TXEN;
+
+ platform_set_drvdata(pdev, data);
/* get the clock - this also enables the HW */
data->clk = devm_clk_get(&pdev->dev, NULL);
@@ -102,8 +162,6 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
}
data->line = ret;
- platform_set_drvdata(pdev, data);
-
return 0;
dis_clk:
@@ -137,6 +195,24 @@ static struct platform_driver bcm2835aux_serial_driver = {
};
module_platform_driver(bcm2835aux_serial_driver);
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+
+static int __init early_bcm2835aux_setup(struct earlycon_device *device,
+ const char *options)
+{
+ if (!device->port.membase)
+ return -ENODEV;
+
+ device->port.iotype = UPIO_MEM32;
+ device->port.regshift = 2;
+
+ return early_serial8250_setup(device, NULL);
+}
+
+OF_EARLYCON_DECLARE(bcm2835aux, "brcm,bcm2835-aux-uart",
+ early_bcm2835aux_setup);
+#endif
+
MODULE_DESCRIPTION("BCM2835 auxiliar UART driver");
MODULE_AUTHOR("Martin Sperl <kernel@martin.sperl.org>");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index f2a33c9082a6..f6eb00406ddf 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -1007,14 +1007,18 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
uart->port.unthrottle = up->port.unthrottle;
uart->port.rs485_config = up->port.rs485_config;
uart->port.rs485 = up->port.rs485;
+ uart->rs485_start_tx = up->rs485_start_tx;
+ uart->rs485_stop_tx = up->rs485_stop_tx;
uart->dma = up->dma;
/* Take tx_loadsz from fifosize if it wasn't set separately */
if (uart->port.fifosize && !uart->tx_loadsz)
uart->tx_loadsz = uart->port.fifosize;
- if (up->port.dev)
+ if (up->port.dev) {
uart->port.dev = up->port.dev;
+ uart_get_rs485_mode(uart->port.dev, &uart->port.rs485);
+ }
if (up->port.flags & UPF_FIXED_TYPE)
uart->port.type = up->port.type;
diff --git a/drivers/tty/serial/8250/8250_dwlib.h b/drivers/tty/serial/8250/8250_dwlib.h
index 87a4db2a8aba..9a12953832d3 100644
--- a/drivers/tty/serial/8250/8250_dwlib.h
+++ b/drivers/tty/serial/8250/8250_dwlib.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+/* SPDX-License-Identifier: GPL-2.0+ */
/* Synopsys DesignWare 8250 library header file. */
#include <linux/types.h>
diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c
index d330da76d6b6..59449b6500cd 100644
--- a/drivers/tty/serial/8250/8250_exar.c
+++ b/drivers/tty/serial/8250/8250_exar.c
@@ -135,7 +135,7 @@ struct exar8250 {
unsigned int nr;
struct exar8250_board *board;
void __iomem *virt;
- int line[0];
+ int line[];
};
static void exar_pm(struct uart_port *port, unsigned int state, unsigned int old)
diff --git a/drivers/tty/serial/8250/8250_lpss.c b/drivers/tty/serial/8250/8250_lpss.c
index 60eff3240c8a..4dee8a9e0c95 100644
--- a/drivers/tty/serial/8250/8250_lpss.c
+++ b/drivers/tty/serial/8250/8250_lpss.c
@@ -156,6 +156,11 @@ static int byt_serial_setup(struct lpss8250 *lpss, struct uart_port *port)
return 0;
}
+static int ehl_serial_setup(struct lpss8250 *lpss, struct uart_port *port)
+{
+ return 0;
+}
+
#ifdef CONFIG_SERIAL_8250_DMA
static const struct dw_dma_platform_data qrk_serial_dma_pdata = {
.nr_channels = 2,
@@ -356,6 +361,7 @@ static const struct lpss8250_board byt_board = {
static const struct lpss8250_board ehl_board = {
.freq = 200000000,
.base_baud = 12500000,
+ .setup = ehl_serial_setup,
};
static const struct lpss8250_board qrk_board = {
diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c
index 4d067f515f74..f839380c2f4c 100644
--- a/drivers/tty/serial/8250/8250_mtk.c
+++ b/drivers/tty/serial/8250/8250_mtk.c
@@ -32,6 +32,7 @@
#define MTK_UART_RXTRI_AD 0x14 /* RX Trigger address */
#define MTK_UART_FRACDIV_L 0x15 /* Fractional divider LSB address */
#define MTK_UART_FRACDIV_M 0x16 /* Fractional divider MSB address */
+#define MTK_UART_DEBUG0 0x18
#define MTK_UART_IER_XOFFI 0x20 /* Enable XOFF character interrupt */
#define MTK_UART_IER_RTSI 0x40 /* Enable RTS Modem status interrupt */
#define MTK_UART_IER_CTSI 0x80 /* Enable CTS Modem status interrupt */
@@ -388,9 +389,18 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
static int __maybe_unused mtk8250_runtime_suspend(struct device *dev)
{
struct mtk8250_data *data = dev_get_drvdata(dev);
+ struct uart_8250_port *up = serial8250_get_port(data->line);
- clk_disable_unprepare(data->uart_clk);
- clk_disable_unprepare(data->bus_clk);
+ /* wait until UART in idle status */
+ while
+ (serial_in(up, MTK_UART_DEBUG0));
+
+ if (data->clk_count == 0U) {
+ dev_dbg(dev, "%s clock count is 0\n", __func__);
+ } else {
+ clk_disable_unprepare(data->bus_clk);
+ data->clk_count--;
+ }
return 0;
}
@@ -400,16 +410,16 @@ static int __maybe_unused mtk8250_runtime_resume(struct device *dev)
struct mtk8250_data *data = dev_get_drvdata(dev);
int err;
- err = clk_prepare_enable(data->uart_clk);
- if (err) {
- dev_warn(dev, "Can't enable clock\n");
- return err;
- }
-
- err = clk_prepare_enable(data->bus_clk);
- if (err) {
- dev_warn(dev, "Can't enable bus clock\n");
- return err;
+ if (data->clk_count > 0U) {
+ dev_dbg(dev, "%s clock count is %d\n", __func__,
+ data->clk_count);
+ } else {
+ err = clk_prepare_enable(data->bus_clk);
+ if (err) {
+ dev_warn(dev, "Can't enable bus clock\n");
+ return err;
+ }
+ data->clk_count++;
}
return 0;
@@ -419,12 +429,14 @@ static void
mtk8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old)
{
if (!state)
- pm_runtime_get_sync(port->dev);
+ if (!mtk8250_runtime_resume(port->dev))
+ pm_runtime_get_sync(port->dev);
serial8250_do_pm(port, state, old);
if (state)
- pm_runtime_put_sync_suspend(port->dev);
+ if (!pm_runtime_put_sync_suspend(port->dev))
+ mtk8250_runtime_suspend(port->dev);
}
#ifdef CONFIG_SERIAL_8250_DMA
@@ -501,6 +513,8 @@ static int mtk8250_probe(struct platform_device *pdev)
if (!data)
return -ENOMEM;
+ data->clk_count = 0;
+
if (pdev->dev.of_node) {
err = mtk8250_probe_of(pdev, &uart.port, data);
if (err)
@@ -533,6 +547,7 @@ static int mtk8250_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, data);
+ pm_runtime_enable(&pdev->dev);
err = mtk8250_runtime_resume(&pdev->dev);
if (err)
return err;
@@ -541,9 +556,6 @@ static int mtk8250_probe(struct platform_device *pdev)
if (data->line < 0)
return data->line;
- pm_runtime_set_active(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
-
data->rx_wakeup_irq = platform_get_irq_optional(pdev, 1);
return 0;
@@ -556,11 +568,13 @@ static int mtk8250_remove(struct platform_device *pdev)
pm_runtime_get_sync(&pdev->dev);
serial8250_unregister_port(data->line);
- mtk8250_runtime_suspend(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ mtk8250_runtime_suspend(&pdev->dev);
+
return 0;
}
diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c
index f6687756ec5e..65e9045dafe6 100644
--- a/drivers/tty/serial/8250/8250_of.c
+++ b/drivers/tty/serial/8250/8250_of.c
@@ -7,7 +7,6 @@
#include <linux/console.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/delay.h>
#include <linux/serial_core.h>
#include <linux/serial_reg.h>
#include <linux/of_address.h>
@@ -26,67 +25,16 @@ struct of_serial_info {
int line;
};
-#ifdef CONFIG_ARCH_TEGRA
-static void tegra_serial_handle_break(struct uart_port *p)
-{
- unsigned int status, tmout = 10000;
-
- do {
- status = p->serial_in(p, UART_LSR);
- if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS))
- status = p->serial_in(p, UART_RX);
- else
- break;
- if (--tmout == 0)
- break;
- udelay(1);
- } while (1);
-}
-#else
-static inline void tegra_serial_handle_break(struct uart_port *port)
-{
-}
-#endif
-
-static int of_8250_rs485_config(struct uart_port *port,
- struct serial_rs485 *rs485)
-{
- struct uart_8250_port *up = up_to_u8250p(port);
-
- /* Clamp the delays to [0, 100ms] */
- rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
- rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U);
-
- port->rs485 = *rs485;
-
- /*
- * Both serial8250_em485_init and serial8250_em485_destroy
- * are idempotent
- */
- if (rs485->flags & SER_RS485_ENABLED) {
- int ret = serial8250_em485_init(up);
-
- if (ret) {
- rs485->flags &= ~SER_RS485_ENABLED;
- port->rs485.flags &= ~SER_RS485_ENABLED;
- }
- return ret;
- }
-
- serial8250_em485_destroy(up);
-
- return 0;
-}
-
/*
* Fill a struct uart_port for a given device node
*/
static int of_platform_serial_setup(struct platform_device *ofdev,
- int type, struct uart_port *port,
+ int type, struct uart_8250_port *up,
struct of_serial_info *info)
{
struct resource resource;
struct device_node *np = ofdev->dev.of_node;
+ struct uart_port *port = &up->port;
u32 clk, spd, prop;
int ret, irq;
@@ -207,13 +155,11 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
port->flags |= UPF_SKIP_TEST;
port->dev = &ofdev->dev;
- port->rs485_config = of_8250_rs485_config;
+ port->rs485_config = serial8250_em485_config;
+ up->rs485_start_tx = serial8250_em485_start_tx;
+ up->rs485_stop_tx = serial8250_em485_stop_tx;
switch (type) {
- case PORT_TEGRA:
- port->handle_break = tegra_serial_handle_break;
- break;
-
case PORT_RT2880:
port->iotype = UPIO_AU;
break;
@@ -258,7 +204,7 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
return -ENOMEM;
memset(&port8250, 0, sizeof(port8250));
- ret = of_platform_serial_setup(ofdev, port_type, &port8250.port, info);
+ ret = of_platform_serial_setup(ofdev, port_type, &port8250, info);
if (ret)
goto err_free;
@@ -358,7 +304,6 @@ static const struct of_device_id of_platform_serial_table[] = {
{ .compatible = "ns16550", .data = (void *)PORT_16550, },
{ .compatible = "ns16750", .data = (void *)PORT_16750, },
{ .compatible = "ns16850", .data = (void *)PORT_16850, },
- { .compatible = "nvidia,tegra20-uart", .data = (void *)PORT_TEGRA, },
{ .compatible = "nxp,lpc3220-uart", .data = (void *)PORT_LPC3220, },
{ .compatible = "ralink,rt2880-uart", .data = (void *)PORT_RT2880, },
{ .compatible = "intel,xscale-uart", .data = (void *)PORT_XSCALE, },
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 6f343ca08440..dd69226ce918 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -714,36 +714,6 @@ static void omap_8250_throttle(struct uart_port *port)
pm_runtime_put_autosuspend(port->dev);
}
-static int omap_8250_rs485_config(struct uart_port *port,
- struct serial_rs485 *rs485)
-{
- struct uart_8250_port *up = up_to_u8250p(port);
-
- /* Clamp the delays to [0, 100ms] */
- rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
- rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U);
-
- port->rs485 = *rs485;
-
- /*
- * Both serial8250_em485_init and serial8250_em485_destroy
- * are idempotent
- */
- if (rs485->flags & SER_RS485_ENABLED) {
- int ret = serial8250_em485_init(up);
-
- if (ret) {
- rs485->flags &= ~SER_RS485_ENABLED;
- port->rs485.flags &= ~SER_RS485_ENABLED;
- }
- return ret;
- }
-
- serial8250_em485_destroy(up);
-
- return 0;
-}
-
static void omap_8250_unthrottle(struct uart_port *port)
{
struct omap8250_priv *priv = port->private_data;
@@ -1187,7 +1157,9 @@ static int omap8250_probe(struct platform_device *pdev)
up.port.shutdown = omap_8250_shutdown;
up.port.throttle = omap_8250_throttle;
up.port.unthrottle = omap_8250_unthrottle;
- up.port.rs485_config = omap_8250_rs485_config;
+ up.port.rs485_config = serial8250_em485_config;
+ up.rs485_start_tx = serial8250_em485_start_tx;
+ up.rs485_stop_tx = serial8250_em485_stop_tx;
up.port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE);
ret = of_alias_get_id(np, "serial");
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 939685fed396..0804469ff052 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -53,7 +53,7 @@ struct serial_private {
unsigned int nr;
struct pci_serial_quirk *quirk;
const struct pciserial_board *board;
- int line[0];
+ int line[];
};
static const struct pci_device_id pci_use_msi[] = {
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 0325f2e53b74..0879bb8855cf 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -557,17 +557,6 @@ static void serial8250_clear_fifos(struct uart_8250_port *p)
}
}
-static inline void serial8250_em485_rts_after_send(struct uart_8250_port *p)
-{
- unsigned char mcr = serial8250_in_MCR(p);
-
- if (p->port.rs485.flags & SER_RS485_RTS_AFTER_SEND)
- mcr |= UART_MCR_RTS;
- else
- mcr &= ~UART_MCR_RTS;
- serial8250_out_MCR(p, mcr);
-}
-
static enum hrtimer_restart serial8250_em485_handle_start_tx(struct hrtimer *t);
static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t);
@@ -615,7 +604,7 @@ EXPORT_SYMBOL_GPL(serial8250_rpm_put);
*
* Return 0 - success, -errno - otherwise
*/
-int serial8250_em485_init(struct uart_8250_port *p)
+static int serial8250_em485_init(struct uart_8250_port *p)
{
if (p->em485)
return 0;
@@ -632,11 +621,12 @@ int serial8250_em485_init(struct uart_8250_port *p)
p->em485->start_tx_timer.function = &serial8250_em485_handle_start_tx;
p->em485->port = p;
p->em485->active_timer = NULL;
- serial8250_em485_rts_after_send(p);
+ p->em485->tx_stopped = true;
+
+ p->rs485_stop_tx(p);
return 0;
}
-EXPORT_SYMBOL_GPL(serial8250_em485_init);
/**
* serial8250_em485_destroy() - put uart_8250_port into normal state
@@ -664,6 +654,52 @@ void serial8250_em485_destroy(struct uart_8250_port *p)
}
EXPORT_SYMBOL_GPL(serial8250_em485_destroy);
+/**
+ * serial8250_em485_config() - generic ->rs485_config() callback
+ * @port: uart port
+ * @rs485: rs485 settings
+ *
+ * Generic callback usable by 8250 uart drivers to activate rs485 settings
+ * if the uart is incapable of driving RTS as a Transmit Enable signal in
+ * hardware, relying on software emulation instead.
+ */
+int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485)
+{
+ struct uart_8250_port *up = up_to_u8250p(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));
+ port->rs485 = *rs485;
+
+ /*
+ * Both serial8250_em485_init() and serial8250_em485_destroy()
+ * are idempotent.
+ */
+ if (rs485->flags & SER_RS485_ENABLED) {
+ int ret = serial8250_em485_init(up);
+
+ if (ret) {
+ rs485->flags &= ~SER_RS485_ENABLED;
+ port->rs485.flags &= ~SER_RS485_ENABLED;
+ }
+ return ret;
+ }
+
+ serial8250_em485_destroy(up);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(serial8250_em485_config);
+
/*
* These two wrappers ensure that enable_runtime_pm_tx() can be called more than
* once and disable_runtime_pm_tx() will still disable RPM because the fifo is
@@ -1318,8 +1354,8 @@ out_lock:
fintek_8250_probe(up);
if (up->capabilities != old_capabilities) {
- pr_warn("%s: detected caps %08x should be %08x\n",
- port->name, old_capabilities, up->capabilities);
+ dev_warn(port->dev, "detected caps %08x should be %08x\n",
+ old_capabilities, up->capabilities);
}
out:
DEBUG_AUTOCONF("iir=%d ", scratch);
@@ -1394,9 +1430,21 @@ static void serial8250_stop_rx(struct uart_port *port)
serial8250_rpm_put(up);
}
-static void __do_stop_tx_rs485(struct uart_8250_port *p)
+/**
+ * serial8250_em485_stop_tx() - generic ->rs485_stop_tx() callback
+ * @up: uart 8250 port
+ *
+ * Generic callback usable by 8250 uart drivers to stop rs485 transmission.
+ */
+void serial8250_em485_stop_tx(struct uart_8250_port *p)
{
- serial8250_em485_rts_after_send(p);
+ unsigned char mcr = serial8250_in_MCR(p);
+
+ if (p->port.rs485.flags & SER_RS485_RTS_AFTER_SEND)
+ mcr |= UART_MCR_RTS;
+ else
+ mcr &= ~UART_MCR_RTS;
+ serial8250_out_MCR(p, mcr);
/*
* Empty the RX FIFO, we are not interested in anything
@@ -1410,6 +1458,8 @@ static void __do_stop_tx_rs485(struct uart_8250_port *p)
serial_port_out(&p->port, UART_IER, p->ier);
}
}
+EXPORT_SYMBOL_GPL(serial8250_em485_stop_tx);
+
static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t)
{
struct uart_8250_em485 *em485;
@@ -1422,8 +1472,9 @@ static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t)
serial8250_rpm_get(p);
spin_lock_irqsave(&p->port.lock, flags);
if (em485->active_timer == &em485->stop_tx_timer) {
- __do_stop_tx_rs485(p);
+ p->rs485_stop_tx(p);
em485->active_timer = NULL;
+ em485->tx_stopped = true;
}
spin_unlock_irqrestore(&p->port.lock, flags);
serial8250_rpm_put(p);
@@ -1444,7 +1495,7 @@ static void __stop_tx_rs485(struct uart_8250_port *p)
struct uart_8250_em485 *em485 = p->em485;
/*
- * __do_stop_tx_rs485 is going to set RTS according to config
+ * rs485_stop_tx() is going to set RTS according to config
* AND flush RX FIFO if required.
*/
if (p->port.rs485.delay_rts_after_send > 0) {
@@ -1452,7 +1503,9 @@ static void __stop_tx_rs485(struct uart_8250_port *p)
start_hrtimer_ms(&em485->stop_tx_timer,
p->port.rs485.delay_rts_after_send);
} else {
- __do_stop_tx_rs485(p);
+ p->rs485_stop_tx(p);
+ em485->active_timer = NULL;
+ em485->tx_stopped = true;
}
}
@@ -1477,8 +1530,6 @@ static inline void __stop_tx(struct uart_8250_port *p)
if ((lsr & BOTH_EMPTY) != BOTH_EMPTY)
return;
- em485->active_timer = NULL;
-
__stop_tx_rs485(p);
}
__do_stop_tx(p);
@@ -1528,25 +1579,42 @@ static inline void __start_tx(struct uart_port *port)
}
}
-static inline void start_tx_rs485(struct uart_port *port)
+/**
+ * serial8250_em485_start_tx() - generic ->rs485_start_tx() callback
+ * @up: uart 8250 port
+ *
+ * Generic callback usable by 8250 uart drivers to start rs485 transmission.
+ * Assumes that setting the RTS bit in the MCR register means RTS is high.
+ * (Some chips use inverse semantics.) Further assumes that reception is
+ * stoppable by disabling the UART_IER_RDI interrupt. (Some chips set the
+ * UART_LSR_DR bit even when UART_IER_RDI is disabled, foiling this approach.)
+ */
+void serial8250_em485_start_tx(struct uart_8250_port *up)
{
- struct uart_8250_port *up = up_to_u8250p(port);
- struct uart_8250_em485 *em485 = up->em485;
- unsigned char mcr;
+ unsigned char mcr = serial8250_in_MCR(up);
if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX))
serial8250_stop_rx(&up->port);
+ if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND)
+ mcr |= UART_MCR_RTS;
+ else
+ mcr &= ~UART_MCR_RTS;
+ serial8250_out_MCR(up, mcr);
+}
+EXPORT_SYMBOL_GPL(serial8250_em485_start_tx);
+
+static inline void start_tx_rs485(struct uart_port *port)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+ struct uart_8250_em485 *em485 = up->em485;
+
em485->active_timer = NULL;
- mcr = serial8250_in_MCR(up);
- if (!!(up->port.rs485.flags & SER_RS485_RTS_ON_SEND) !=
- !!(mcr & UART_MCR_RTS)) {
- if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND)
- mcr |= UART_MCR_RTS;
- else
- mcr &= ~UART_MCR_RTS;
- serial8250_out_MCR(up, mcr);
+ if (em485->tx_stopped) {
+ em485->tx_stopped = false;
+
+ up->rs485_start_tx(up);
if (up->port.rs485.delay_rts_before_send > 0) {
em485->active_timer = &em485->start_tx_timer;
@@ -1683,7 +1751,7 @@ void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr)
lsr &= port->read_status_mask;
if (lsr & UART_LSR_BI) {
- pr_debug("%s: handling break\n", __func__);
+ dev_dbg(port->dev, "handling break\n");
flag = TTY_BREAK;
} else if (lsr & UART_LSR_PE)
flag = TTY_PARITY;
@@ -1924,6 +1992,13 @@ void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl)
struct uart_8250_port *up = up_to_u8250p(port);
unsigned char mcr;
+ if (port->rs485.flags & SER_RS485_ENABLED) {
+ if (serial8250_in_MCR(up) & UART_MCR_RTS)
+ mctrl |= TIOCM_RTS;
+ else
+ mctrl &= ~TIOCM_RTS;
+ }
+
mcr = serial8250_TIOCM_to_MCR(mctrl);
mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr;
@@ -2134,7 +2209,7 @@ int serial8250_do_startup(struct uart_port *port)
*/
if (!(port->flags & UPF_BUGGY_UART) &&
(serial_port_in(port, UART_LSR) == 0xff)) {
- pr_info_ratelimited("%s: LSR safety check engaged!\n", port->name);
+ dev_info_ratelimited(port->dev, "LSR safety check engaged!\n");
retval = -ENODEV;
goto out;
}
@@ -2166,8 +2241,7 @@ int serial8250_do_startup(struct uart_port *port)
(port->type == PORT_ALTR_16550_F128)) && (port->fifosize > 1)) {
/* Bounds checking of TX threshold (valid 0 to fifosize-2) */
if ((up->tx_loadsz < 2) || (up->tx_loadsz > port->fifosize)) {
- pr_err("%s TX FIFO Threshold errors, skipping\n",
- port->name);
+ dev_err(port->dev, "TX FIFO Threshold errors, skipping\n");
} else {
serial_port_out(port, UART_ALTR_AFR,
UART_ALTR_EN_TXFIFO_LW);
@@ -2268,8 +2342,7 @@ int serial8250_do_startup(struct uart_port *port)
if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) {
if (!(up->bugs & UART_BUG_TXEN)) {
up->bugs |= UART_BUG_TXEN;
- pr_debug("%s - enabling bad tx status workarounds\n",
- port->name);
+ dev_dbg(port->dev, "enabling bad tx status workarounds\n");
}
} else {
up->bugs &= ~UART_BUG_TXEN;
@@ -2296,8 +2369,7 @@ dont_test_tx_en:
if (up->dma) {
retval = serial8250_request_dma(up);
if (retval) {
- pr_warn_ratelimited("%s - failed to request DMA\n",
- port->name);
+ dev_warn_ratelimited(port->dev, "failed to request DMA\n");
up->dma = NULL;
}
}
@@ -2880,7 +2952,7 @@ static int do_serial8250_get_rxtrig(struct tty_port *port)
return rxtrig_bytes;
}
-static ssize_t serial8250_get_attr_rx_trig_bytes(struct device *dev,
+static ssize_t rx_trig_bytes_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct tty_port *port = dev_get_drvdata(dev);
@@ -2926,7 +2998,7 @@ static int do_serial8250_set_rxtrig(struct tty_port *port, unsigned char bytes)
return ret;
}
-static ssize_t serial8250_set_attr_rx_trig_bytes(struct device *dev,
+static ssize_t rx_trig_bytes_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct tty_port *port = dev_get_drvdata(dev);
@@ -2947,18 +3019,16 @@ static ssize_t serial8250_set_attr_rx_trig_bytes(struct device *dev,
return count;
}
-static DEVICE_ATTR(rx_trig_bytes, S_IRUSR | S_IWUSR | S_IRGRP,
- serial8250_get_attr_rx_trig_bytes,
- serial8250_set_attr_rx_trig_bytes);
+static DEVICE_ATTR_RW(rx_trig_bytes);
static struct attribute *serial8250_dev_attrs[] = {
&dev_attr_rx_trig_bytes.attr,
- NULL,
- };
+ NULL
+};
static struct attribute_group serial8250_dev_attr_group = {
.attrs = serial8250_dev_attrs,
- };
+};
static void register_dev_spec_attr_grp(struct uart_8250_port *up)
{
@@ -2987,6 +3057,9 @@ static void serial8250_config_port(struct uart_port *port, int flags)
if (flags & UART_CONFIG_TYPE)
autoconfig(up);
+ if (port->rs485.flags & SER_RS485_ENABLED)
+ port->rs485_config(port, &port->rs485);
+
/* if access method is AU, it is a 16550 with a quirk */
if (port->type == PORT_16550A && port->iotype == UPIO_AU)
up->bugs |= UART_BUG_NOMSR;
@@ -3131,6 +3204,7 @@ static void serial8250_console_restore(struct uart_8250_port *up)
void serial8250_console_write(struct uart_8250_port *up, const char *s,
unsigned int count)
{
+ struct uart_8250_em485 *em485 = up->em485;
struct uart_port *port = &up->port;
unsigned long flags;
unsigned int ier;
@@ -3161,6 +3235,12 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
up->canary = 0;
}
+ if (em485) {
+ if (em485->tx_stopped)
+ up->rs485_start_tx(up);
+ mdelay(port->rs485.delay_rts_before_send);
+ }
+
uart_console_write(port, s, count, serial8250_console_putchar);
/*
@@ -3170,6 +3250,12 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
wait_for_xmitr(up, BOTH_EMPTY);
serial_port_out(port, UART_IER, ier);
+ if (em485) {
+ mdelay(port->rs485.delay_rts_before_send);
+ if (em485->tx_stopped)
+ up->rs485_stop_tx(up);
+ }
+
/*
* The receive handling will happen properly because the
* receive ready bit will still be set; it is not cleared
diff --git a/drivers/tty/serial/8250/8250_pxa.c b/drivers/tty/serial/8250/8250_pxa.c
index c47188860e32..11612d174716 100644
--- a/drivers/tty/serial/8250/8250_pxa.c
+++ b/drivers/tty/serial/8250/8250_pxa.c
@@ -123,7 +123,7 @@ static int serial_pxa_probe(struct platform_device *pdev)
uart.port.regshift = 2;
uart.port.irq = irqres->start;
uart.port.fifosize = 64;
- uart.port.flags = UPF_IOREMAP | UPF_SKIP_TEST;
+ uart.port.flags = UPF_IOREMAP | UPF_SKIP_TEST | UPF_FIXED_TYPE;
uart.port.dev = &pdev->dev;
uart.port.uartclk = clk_get_rate(data->clk);
uart.port.pm = serial_pxa_pm;
diff --git a/drivers/tty/serial/8250/8250_tegra.c b/drivers/tty/serial/8250/8250_tegra.c
new file mode 100644
index 000000000000..c0ffad1572c6
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_tegra.c
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Serial Port driver for Tegra devices
+ *
+ * Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
+ */
+
+#include <linux/acpi.h>
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+
+#include "8250.h"
+
+struct tegra_uart {
+ struct clk *clk;
+ struct reset_control *rst;
+ int line;
+};
+
+static void tegra_uart_handle_break(struct uart_port *p)
+{
+ unsigned int status, tmout = 10000;
+
+ do {
+ status = p->serial_in(p, UART_LSR);
+ if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS))
+ status = p->serial_in(p, UART_RX);
+ else
+ break;
+ if (--tmout == 0)
+ break;
+ udelay(1);
+ } while (1);
+}
+
+static int tegra_uart_probe(struct platform_device *pdev)
+{
+ struct uart_8250_port port8250;
+ struct tegra_uart *uart;
+ struct uart_port *port;
+ struct resource *res;
+ int ret;
+
+ uart = devm_kzalloc(&pdev->dev, sizeof(*uart), GFP_KERNEL);
+ if (!uart)
+ return -ENOMEM;
+
+ memset(&port8250, 0, sizeof(port8250));
+
+ port = &port8250.port;
+ spin_lock_init(&port->lock);
+
+ port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT |
+ UPF_FIXED_TYPE;
+ port->iotype = UPIO_MEM32;
+ port->regshift = 2;
+ port->type = PORT_TEGRA;
+ port->irqflags |= IRQF_SHARED;
+ port->dev = &pdev->dev;
+ port->handle_break = tegra_uart_handle_break;
+
+ ret = of_alias_get_id(pdev->dev.of_node, "serial");
+ if (ret >= 0)
+ port->line = ret;
+
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0)
+ return ret;
+
+ port->irq = ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ port->membase = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!port->membase)
+ return -ENOMEM;
+
+ port->mapbase = res->start;
+ port->mapsize = resource_size(res);
+
+ uart->rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL);
+ if (IS_ERR(uart->rst))
+ return PTR_ERR(uart->rst);
+
+ if (device_property_read_u32(&pdev->dev, "clock-frequency",
+ &port->uartclk)) {
+ uart->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(uart->clk)) {
+ dev_err(&pdev->dev, "failed to get clock!\n");
+ return -ENODEV;
+ }
+
+ ret = clk_prepare_enable(uart->clk);
+ if (ret < 0)
+ return ret;
+
+ port->uartclk = clk_get_rate(uart->clk);
+ }
+
+ ret = reset_control_deassert(uart->rst);
+ if (ret)
+ goto err_clkdisable;
+
+ ret = serial8250_register_8250_port(&port8250);
+ if (ret < 0)
+ goto err_clkdisable;
+
+ platform_set_drvdata(pdev, uart);
+ uart->line = ret;
+
+ return 0;
+
+err_clkdisable:
+ clk_disable_unprepare(uart->clk);
+
+ return ret;
+}
+
+static int tegra_uart_remove(struct platform_device *pdev)
+{
+ struct tegra_uart *uart = platform_get_drvdata(pdev);
+
+ serial8250_unregister_port(uart->line);
+ reset_control_assert(uart->rst);
+ clk_disable_unprepare(uart->clk);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int tegra_uart_suspend(struct device *dev)
+{
+ struct tegra_uart *uart = dev_get_drvdata(dev);
+ struct uart_8250_port *port8250 = serial8250_get_port(uart->line);
+ struct uart_port *port = &port8250->port;
+
+ serial8250_suspend_port(uart->line);
+
+ if (!uart_console(port) || console_suspend_enabled)
+ clk_disable_unprepare(uart->clk);
+
+ return 0;
+}
+
+static int tegra_uart_resume(struct device *dev)
+{
+ struct tegra_uart *uart = dev_get_drvdata(dev);
+ struct uart_8250_port *port8250 = serial8250_get_port(uart->line);
+ struct uart_port *port = &port8250->port;
+
+ if (!uart_console(port) || console_suspend_enabled)
+ clk_prepare_enable(uart->clk);
+
+ serial8250_resume_port(uart->line);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(tegra_uart_pm_ops, tegra_uart_suspend,
+ tegra_uart_resume);
+
+static const struct of_device_id tegra_uart_of_match[] = {
+ { .compatible = "nvidia,tegra20-uart", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, tegra_uart_of_match);
+
+static const struct acpi_device_id tegra_uart_acpi_match[] = {
+ { "NVDA0100", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, tegra_uart_acpi_match);
+
+static struct platform_driver tegra_uart_driver = {
+ .driver = {
+ .name = "tegra-uart",
+ .pm = &tegra_uart_pm_ops,
+ .of_match_table = tegra_uart_of_match,
+ .acpi_match_table = ACPI_PTR(tegra_uart_acpi_match),
+ },
+ .probe = tegra_uart_probe,
+ .remove = tegra_uart_remove,
+};
+
+module_platform_driver(tegra_uart_driver);
+
+MODULE_AUTHOR("Jeff Brasen <jbrasen@nvidia.com>");
+MODULE_DESCRIPTION("NVIDIA Tegra 8250 Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index f16824bbb573..af0688156dd0 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -500,6 +500,15 @@ config SERIAL_8250_PXA
applicable to both devicetree and legacy boards, and early console is
part of its support.
+config SERIAL_8250_TEGRA
+ tristate "8250 support for Tegra serial ports"
+ default SERIAL_8250
+ depends on SERIAL_8250
+ depends on ARCH_TEGRA || COMPILE_TEST
+ help
+ Select this option if you have machine with an NVIDIA Tegra SoC and
+ wish to enable 8250 serial driver for the Tegra serial interfaces.
+
config SERIAL_OF_PLATFORM
tristate "Devicetree based probing for 8250 ports"
depends on SERIAL_8250 && OF
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index 51a6079d3f1f..a8bfb654d490 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_SERIAL_8250_INGENIC) += 8250_ingenic.o
obj-$(CONFIG_SERIAL_8250_LPSS) += 8250_lpss.o
obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o
obj-$(CONFIG_SERIAL_8250_PXA) += 8250_pxa.o
+obj-$(CONFIG_SERIAL_8250_TEGRA) += 8250_tegra.o
obj-$(CONFIG_SERIAL_OF_PLATFORM) += 8250_of.o
CFLAGS_8250_ingenic.o += -I$(srctree)/scripts/dtc/libfdt
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 52eaac21ff9f..b43dce785a58 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -237,7 +237,6 @@ config SERIAL_CLPS711X_CONSOLE
config SERIAL_SAMSUNG
tristate "Samsung SoC serial support"
- depends on PLAT_SAMSUNG || ARCH_EXYNOS || COMPILE_TEST
select SERIAL_CORE
help
Support for the on-chip UARTs on the Samsung S3C24XX series CPUs,
@@ -260,15 +259,6 @@ config SERIAL_SAMSUNG_UARTS
help
Select the number of available UART ports for the Samsung S3C
serial driver
-
-config SERIAL_SAMSUNG_DEBUG
- bool "Samsung SoC serial debug"
- depends on SERIAL_SAMSUNG && DEBUG_LL
- help
- Add support for debugging the serial driver. Since this is
- generally being used as a console, we use our own output
- routines that go via the low-level debug printascii()
- function.
config SERIAL_SAMSUNG_CONSOLE
bool "Support for console on Samsung SoC serial port"
@@ -1111,7 +1101,7 @@ config SERIAL_SC16IS7XX_SPI
help
Enable SC16IS7xx driver on SPI bus,
If required say y, and say n to spi if not required,
- This is additional support to exsisting driver.
+ This is additional support to existing driver.
You must select at least one bus for the driver to be built.
config SERIAL_TIMBERDALE
@@ -1279,6 +1269,7 @@ config SERIAL_AR933X
tristate "AR933X serial port support"
depends on HAVE_CLK && ATH79
select SERIAL_CORE
+ select SERIAL_MCTRL_GPIO if GPIOLIB
help
If you have an Atheros AR933X SOC based board and want to use the
built-in UART of the SoC, say Y to this option.
@@ -1452,7 +1443,6 @@ config SERIAL_MEN_Z135
config SERIAL_SPRD
tristate "Support for Spreadtrum serial"
- depends on ARCH_SPRD
select SERIAL_CORE
help
This enables the driver for the Spreadtrum's serial.
diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c
index ea12f10610b6..7e7f1398019f 100644
--- a/drivers/tty/serial/ar933x_uart.c
+++ b/drivers/tty/serial/ar933x_uart.c
@@ -13,6 +13,7 @@
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_platform.h>
@@ -29,6 +30,8 @@
#include <asm/mach-ath79/ar933x_uart.h>
+#include "serial_mctrl_gpio.h"
+
#define DRIVER_NAME "ar933x-uart"
#define AR933X_UART_MAX_SCALE 0xff
@@ -47,6 +50,8 @@ struct ar933x_uart_port {
unsigned int min_baud;
unsigned int max_baud;
struct clk *clk;
+ struct mctrl_gpios *gpios;
+ struct gpio_desc *rts_gpiod;
};
static inline unsigned int ar933x_uart_read(struct ar933x_uart_port *up,
@@ -100,6 +105,18 @@ static inline void ar933x_uart_stop_tx_interrupt(struct ar933x_uart_port *up)
ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
}
+static inline void ar933x_uart_start_rx_interrupt(struct ar933x_uart_port *up)
+{
+ up->ier |= AR933X_UART_INT_RX_VALID;
+ ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
+}
+
+static inline void ar933x_uart_stop_rx_interrupt(struct ar933x_uart_port *up)
+{
+ up->ier &= ~AR933X_UART_INT_RX_VALID;
+ ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
+}
+
static inline void ar933x_uart_putc(struct ar933x_uart_port *up, int ch)
{
unsigned int rdata;
@@ -125,11 +142,21 @@ static unsigned int ar933x_uart_tx_empty(struct uart_port *port)
static unsigned int ar933x_uart_get_mctrl(struct uart_port *port)
{
- return TIOCM_CAR;
+ struct ar933x_uart_port *up =
+ container_of(port, struct ar933x_uart_port, port);
+ int ret = TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+
+ mctrl_gpio_get(up->gpios, &ret);
+
+ return ret;
}
static void ar933x_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
+ struct ar933x_uart_port *up =
+ container_of(port, struct ar933x_uart_port, port);
+
+ mctrl_gpio_set(up->gpios, mctrl);
}
static void ar933x_uart_start_tx(struct uart_port *port)
@@ -140,6 +167,37 @@ static void ar933x_uart_start_tx(struct uart_port *port)
ar933x_uart_start_tx_interrupt(up);
}
+static void ar933x_uart_wait_tx_complete(struct ar933x_uart_port *up)
+{
+ unsigned int status;
+ unsigned int timeout = 60000;
+
+ /* Wait up to 60ms for the character(s) to be sent. */
+ do {
+ status = ar933x_uart_read(up, AR933X_UART_CS_REG);
+ if (--timeout == 0)
+ break;
+ udelay(1);
+ } while (status & AR933X_UART_CS_TX_BUSY);
+
+ if (timeout == 0)
+ dev_err(up->port.dev, "waiting for TX timed out\n");
+}
+
+static void ar933x_uart_rx_flush(struct ar933x_uart_port *up)
+{
+ unsigned int status;
+
+ /* clear RX_VALID interrupt */
+ ar933x_uart_write(up, AR933X_UART_INT_REG, AR933X_UART_INT_RX_VALID);
+
+ /* remove characters from the RX FIFO */
+ do {
+ ar933x_uart_write(up, AR933X_UART_DATA_REG, AR933X_UART_DATA_RX_CSR);
+ status = ar933x_uart_read(up, AR933X_UART_DATA_REG);
+ } while (status & AR933X_UART_DATA_RX_CSR);
+}
+
static void ar933x_uart_stop_tx(struct uart_port *port)
{
struct ar933x_uart_port *up =
@@ -153,8 +211,7 @@ static void ar933x_uart_stop_rx(struct uart_port *port)
struct ar933x_uart_port *up =
container_of(port, struct ar933x_uart_port, port);
- up->ier &= ~AR933X_UART_INT_RX_VALID;
- ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
+ ar933x_uart_stop_rx_interrupt(up);
}
static void ar933x_uart_break_ctl(struct uart_port *port, int break_state)
@@ -336,11 +393,20 @@ static void ar933x_uart_rx_chars(struct ar933x_uart_port *up)
static void ar933x_uart_tx_chars(struct ar933x_uart_port *up)
{
struct circ_buf *xmit = &up->port.state->xmit;
+ struct serial_rs485 *rs485conf = &up->port.rs485;
int count;
+ bool half_duplex_send = false;
if (uart_tx_stopped(&up->port))
return;
+ if ((rs485conf->flags & SER_RS485_ENABLED) &&
+ (up->port.x_char || !uart_circ_empty(xmit))) {
+ ar933x_uart_stop_rx_interrupt(up);
+ gpiod_set_value(up->rts_gpiod, !!(rs485conf->flags & SER_RS485_RTS_ON_SEND));
+ half_duplex_send = true;
+ }
+
count = up->port.fifosize;
do {
unsigned int rdata;
@@ -368,8 +434,14 @@ static void ar933x_uart_tx_chars(struct ar933x_uart_port *up)
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&up->port);
- if (!uart_circ_empty(xmit))
+ if (!uart_circ_empty(xmit)) {
ar933x_uart_start_tx_interrupt(up);
+ } else if (half_duplex_send) {
+ ar933x_uart_wait_tx_complete(up);
+ ar933x_uart_rx_flush(up);
+ ar933x_uart_start_rx_interrupt(up);
+ gpiod_set_value(up->rts_gpiod, !!(rs485conf->flags & SER_RS485_RTS_AFTER_SEND));
+ }
}
static irqreturn_t ar933x_uart_interrupt(int irq, void *dev_id)
@@ -427,8 +499,7 @@ static int ar933x_uart_startup(struct uart_port *port)
AR933X_UART_CS_TX_READY_ORIDE | AR933X_UART_CS_RX_READY_ORIDE);
/* Enable RX interrupts */
- up->ier = AR933X_UART_INT_RX_VALID;
- ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
+ ar933x_uart_start_rx_interrupt(up);
spin_unlock_irqrestore(&up->port.lock, flags);
@@ -511,6 +582,21 @@ static const struct uart_ops ar933x_uart_ops = {
.verify_port = ar933x_uart_verify_port,
};
+static int ar933x_config_rs485(struct uart_port *port,
+ struct serial_rs485 *rs485conf)
+{
+ struct ar933x_uart_port *up =
+ container_of(port, struct ar933x_uart_port, port);
+
+ if ((rs485conf->flags & SER_RS485_ENABLED) &&
+ !up->rts_gpiod) {
+ dev_err(port->dev, "RS485 needs rts-gpio\n");
+ return 1;
+ }
+ port->rs485 = *rs485conf;
+ return 0;
+}
+
#ifdef CONFIG_SERIAL_AR933X_CONSOLE
static struct ar933x_uart_port *
ar933x_console_ports[CONFIG_SERIAL_AR933X_NR_UARTS];
@@ -680,6 +766,8 @@ static int ar933x_uart_probe(struct platform_device *pdev)
goto err_disable_clk;
}
+ uart_get_rs485_mode(&pdev->dev, &port->rs485);
+
port->mapbase = mem_res->start;
port->line = id;
port->irq = irq_res->start;
@@ -690,6 +778,7 @@ static int ar933x_uart_probe(struct platform_device *pdev)
port->regshift = 2;
port->fifosize = AR933X_UART_FIFO_SIZE;
port->ops = &ar933x_uart_ops;
+ port->rs485_config = ar933x_config_rs485;
baud = ar933x_uart_get_baud(port->uartclk, AR933X_UART_MAX_SCALE, 1);
up->min_baud = max_t(unsigned int, baud, AR933X_UART_MIN_BAUD);
@@ -697,6 +786,18 @@ static int ar933x_uart_probe(struct platform_device *pdev)
baud = ar933x_uart_get_baud(port->uartclk, 0, AR933X_UART_MAX_STEP);
up->max_baud = min_t(unsigned int, baud, AR933X_UART_MAX_BAUD);
+ up->gpios = mctrl_gpio_init(port, 0);
+ if (IS_ERR(up->gpios) && PTR_ERR(up->gpios) != -ENOSYS)
+ return PTR_ERR(up->gpios);
+
+ up->rts_gpiod = mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_RTS);
+
+ if ((port->rs485.flags & SER_RS485_ENABLED) &&
+ !up->rts_gpiod) {
+ dev_err(&pdev->dev, "lacking rts-gpio, disabling RS485\n");
+ port->rs485.flags &= ~SER_RS485_ENABLED;
+ }
+
#ifdef CONFIG_SERIAL_AR933X_CONSOLE
ar933x_console_ports[up->port.line] = up;
#endif
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index a39c87a7c2e1..d1ab6a0a5c74 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -20,15 +20,12 @@
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
-#include <linux/of_gpio.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/atmel_pdc.h>
#include <linux/uaccess.h>
#include <linux/platform_data/atmel.h>
#include <linux/timer.h>
-#include <linux/gpio.h>
-#include <linux/gpio/consumer.h>
#include <linux/err.h>
#include <linux/irq.h>
#include <linux/suspend.h>
diff --git a/drivers/tty/serial/atmel_serial.h b/drivers/tty/serial/atmel_serial.h
index d811d4f2d0c0..0d8a0f9cc5c3 100644
--- a/drivers/tty/serial/atmel_serial.h
+++ b/drivers/tty/serial/atmel_serial.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+/* SPDX-License-Identifier: GPL-2.0+ */
/*
* include/linux/atmel_serial.h
*
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart.h b/drivers/tty/serial/cpm_uart/cpm_uart.h
index 9f175a92fb5d..6113b953ce25 100644
--- a/drivers/tty/serial/cpm_uart/cpm_uart.h
+++ b/drivers/tty/serial/cpm_uart/cpm_uart.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Driver for CPM (SCC/SMC) serial ports
*
@@ -13,6 +13,8 @@
#include <linux/platform_device.h>
#include <linux/fs_uart_pd.h>
+struct gpio_desc;
+
#if defined(CONFIG_CPM2)
#include "cpm_uart_cpm2.h"
#elif defined(CONFIG_CPM1)
@@ -80,7 +82,7 @@ struct uart_cpm_port {
int wait_closing;
/* value to combine with opcode to form cpm command */
u32 command;
- int gpios[NUM_GPIOS];
+ struct gpio_desc *gpios[NUM_GPIOS];
};
extern int cpm_uart_nr;
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
index d4b81b06e0cb..a04f74d2e854 100644
--- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
@@ -30,8 +30,7 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/clk.h>
#include <asm/io.h>
@@ -88,11 +87,11 @@ static void cpm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
struct uart_cpm_port *pinfo =
container_of(port, struct uart_cpm_port, port);
- if (pinfo->gpios[GPIO_RTS] >= 0)
- gpio_set_value(pinfo->gpios[GPIO_RTS], !(mctrl & TIOCM_RTS));
+ if (pinfo->gpios[GPIO_RTS])
+ gpiod_set_value(pinfo->gpios[GPIO_RTS], !(mctrl & TIOCM_RTS));
- if (pinfo->gpios[GPIO_DTR] >= 0)
- gpio_set_value(pinfo->gpios[GPIO_DTR], !(mctrl & TIOCM_DTR));
+ if (pinfo->gpios[GPIO_DTR])
+ gpiod_set_value(pinfo->gpios[GPIO_DTR], !(mctrl & TIOCM_DTR));
}
static unsigned int cpm_uart_get_mctrl(struct uart_port *port)
@@ -101,23 +100,23 @@ static unsigned int cpm_uart_get_mctrl(struct uart_port *port)
container_of(port, struct uart_cpm_port, port);
unsigned int mctrl = TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
- if (pinfo->gpios[GPIO_CTS] >= 0) {
- if (gpio_get_value(pinfo->gpios[GPIO_CTS]))
+ if (pinfo->gpios[GPIO_CTS]) {
+ if (gpiod_get_value(pinfo->gpios[GPIO_CTS]))
mctrl &= ~TIOCM_CTS;
}
- if (pinfo->gpios[GPIO_DSR] >= 0) {
- if (gpio_get_value(pinfo->gpios[GPIO_DSR]))
+ if (pinfo->gpios[GPIO_DSR]) {
+ if (gpiod_get_value(pinfo->gpios[GPIO_DSR]))
mctrl &= ~TIOCM_DSR;
}
- if (pinfo->gpios[GPIO_DCD] >= 0) {
- if (gpio_get_value(pinfo->gpios[GPIO_DCD]))
+ if (pinfo->gpios[GPIO_DCD]) {
+ if (gpiod_get_value(pinfo->gpios[GPIO_DCD]))
mctrl &= ~TIOCM_CAR;
}
- if (pinfo->gpios[GPIO_RI] >= 0) {
- if (!gpio_get_value(pinfo->gpios[GPIO_RI]))
+ if (pinfo->gpios[GPIO_RI]) {
+ if (!gpiod_get_value(pinfo->gpios[GPIO_RI]))
mctrl |= TIOCM_RNG;
}
@@ -1139,6 +1138,7 @@ static int cpm_uart_init_port(struct device_node *np,
{
const u32 *data;
void __iomem *mem, *pram;
+ struct device *dev = pinfo->port.dev;
int len;
int ret;
int i;
@@ -1211,29 +1211,23 @@ static int cpm_uart_init_port(struct device_node *np,
}
for (i = 0; i < NUM_GPIOS; i++) {
- int gpio;
+ struct gpio_desc *gpiod;
- pinfo->gpios[i] = -1;
+ pinfo->gpios[i] = NULL;
- gpio = of_get_gpio(np, i);
+ gpiod = devm_gpiod_get_index(dev, NULL, i, GPIOD_ASIS);
- if (gpio_is_valid(gpio)) {
- ret = gpio_request(gpio, "cpm_uart");
- if (ret) {
- pr_err("can't request gpio #%d: %d\n", i, ret);
- continue;
- }
+ if (gpiod) {
if (i == GPIO_RTS || i == GPIO_DTR)
- ret = gpio_direction_output(gpio, 0);
+ ret = gpiod_direction_output(gpiod, 0);
else
- ret = gpio_direction_input(gpio);
+ ret = gpiod_direction_input(gpiod);
if (ret) {
pr_err("can't set direction for gpio #%d: %d\n",
i, ret);
- gpio_free(gpio);
continue;
}
- pinfo->gpios[i] = gpio;
+ pinfo->gpios[i] = gpiod;
}
}
diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c
index c14873b67803..2ae9190b64bb 100644
--- a/drivers/tty/serial/earlycon.c
+++ b/drivers/tty/serial/earlycon.c
@@ -170,6 +170,7 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match)
int __init setup_earlycon(char *buf)
{
const struct earlycon_id **p_match;
+ bool empty_compatible = true;
if (!buf || !buf[0])
return -EINVAL;
@@ -177,6 +178,7 @@ int __init setup_earlycon(char *buf)
if (early_con.flags & CON_ENABLED)
return -EALREADY;
+again:
for (p_match = __earlycon_table; p_match < __earlycon_table_end;
p_match++) {
const struct earlycon_id *match = *p_match;
@@ -185,6 +187,10 @@ int __init setup_earlycon(char *buf)
if (strncmp(buf, match->name, len))
continue;
+ /* prefer entries with empty compatible */
+ if (empty_compatible && *match->compatible)
+ continue;
+
if (buf[len]) {
if (buf[len] != ',')
continue;
@@ -195,6 +201,11 @@ int __init setup_earlycon(char *buf)
return register_earlycon(buf, match);
}
+ if (empty_compatible) {
+ empty_compatible = false;
+ goto again;
+ }
+
return -ENOENT;
}
diff --git a/drivers/tty/serial/efm32-uart.c b/drivers/tty/serial/efm32-uart.c
index 2ac87128d7fd..f12f29cf4f31 100644
--- a/drivers/tty/serial/efm32-uart.c
+++ b/drivers/tty/serial/efm32-uart.c
@@ -200,7 +200,7 @@ static void efm32_uart_rx_chars(struct efm32_uart_port *efm_port)
/*
* This is a reserved bit and I only saw it read as 0. But to be
* sure not to be confused too much by new devices adhere to the
- * warning in the reference manual that reserverd bits might
+ * warning in the reference manual that reserved bits might
* read as 1 in the future.
*/
rxdata &= ~SW_UARTn_RXDATAX_BERR;
diff --git a/drivers/tty/serial/icom.h b/drivers/tty/serial/icom.h
index 8a77e739b333..26e3aa7b01e2 100644
--- a/drivers/tty/serial/icom.h
+++ b/drivers/tty/serial/icom.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+/* SPDX-License-Identifier: GPL-2.0+ */
/*
* icom.h
*
diff --git a/drivers/tty/serial/ifx6x60.h b/drivers/tty/serial/ifx6x60.h
index c5a2514212ff..cacca5be7390 100644
--- a/drivers/tty/serial/ifx6x60.h
+++ b/drivers/tty/serial/ifx6x60.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
/****************************************************************************
*
* Driver for the IFX spi modem.
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index d337782b3648..f4d68109bc8b 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -195,6 +195,8 @@ struct imx_port {
unsigned int have_rtscts:1;
unsigned int have_rtsgpio:1;
unsigned int dte_mode:1;
+ unsigned int inverted_tx:1;
+ unsigned int inverted_rx:1;
struct clk *clk_ipg;
struct clk *clk_per;
const struct imx_uart_data *devdata;
@@ -1335,7 +1337,7 @@ static int imx_uart_startup(struct uart_port *port)
int retval, i;
unsigned long flags;
int dma_is_inited = 0;
- u32 ucr1, ucr2, ucr4;
+ u32 ucr1, ucr2, ucr3, ucr4;
retval = clk_prepare_enable(sport->clk_per);
if (retval)
@@ -1387,11 +1389,29 @@ static int imx_uart_startup(struct uart_port *port)
imx_uart_writel(sport, ucr1, UCR1);
- ucr4 = imx_uart_readl(sport, UCR4) & ~UCR4_OREN;
+ ucr4 = imx_uart_readl(sport, UCR4) & ~(UCR4_OREN | UCR4_INVR);
if (!sport->dma_is_enabled)
ucr4 |= UCR4_OREN;
+ if (sport->inverted_rx)
+ ucr4 |= UCR4_INVR;
imx_uart_writel(sport, ucr4, UCR4);
+ ucr3 = imx_uart_readl(sport, UCR3) & ~UCR3_INVT;
+ /*
+ * configure tx polarity before enabling tx
+ */
+ if (sport->inverted_tx)
+ ucr3 |= UCR3_INVT;
+
+ if (!imx_uart_is_imx1(sport)) {
+ ucr3 |= UCR3_DTRDEN | UCR3_RI | UCR3_DCD;
+
+ if (sport->dte_mode)
+ /* disable broken interrupts */
+ ucr3 &= ~(UCR3_RI | UCR3_DCD);
+ }
+ imx_uart_writel(sport, ucr3, UCR3);
+
ucr2 = imx_uart_readl(sport, UCR2) & ~UCR2_ATEN;
ucr2 |= (UCR2_RXEN | UCR2_TXEN);
if (!sport->have_rtscts)
@@ -1404,20 +1424,6 @@ static int imx_uart_startup(struct uart_port *port)
ucr2 &= ~UCR2_RTSEN;
imx_uart_writel(sport, ucr2, UCR2);
- if (!imx_uart_is_imx1(sport)) {
- u32 ucr3;
-
- ucr3 = imx_uart_readl(sport, UCR3);
-
- ucr3 |= UCR3_DTRDEN | UCR3_RI | UCR3_DCD;
-
- if (sport->dte_mode)
- /* disable broken interrupts */
- ucr3 &= ~(UCR3_RI | UCR3_DCD);
-
- imx_uart_writel(sport, ucr3, UCR3);
- }
-
/*
* Enable modem status interrupts
*/
@@ -2184,6 +2190,12 @@ static int imx_uart_probe_dt(struct imx_port *sport,
if (of_get_property(np, "rts-gpios", NULL))
sport->have_rtsgpio = 1;
+ if (of_get_property(np, "fsl,inverted-tx", NULL))
+ sport->inverted_tx = 1;
+
+ if (of_get_property(np, "fsl,inverted-rx", NULL))
+ sport->inverted_rx = 1;
+
return 0;
}
#else
diff --git a/drivers/tty/serial/jsm/jsm.h b/drivers/tty/serial/jsm/jsm.h
index 7a128aaa3a66..8489c07f4cd5 100644
--- a/drivers/tty/serial/jsm/jsm.h
+++ b/drivers/tty/serial/jsm/jsm.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+/* SPDX-License-Identifier: GPL-2.0+ */
/************************************************************************
* Copyright 2003 Digi International (www.digi.com)
*
diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c
index c7d51b51898f..c9f94fa82be4 100644
--- a/drivers/tty/serial/kgdboc.c
+++ b/drivers/tty/serial/kgdboc.c
@@ -169,15 +169,13 @@ static int configure_kgdboc(void)
if (!p)
goto noconfig;
- cons = console_drivers;
- while (cons) {
+ for_each_console(cons) {
int idx;
if (cons->device && cons->device(cons, &idx) == p &&
idx == tty_line) {
kgdboc_io_ops.is_console = 1;
break;
}
- cons = cons->next;
}
kgdb_tty_driver = p;
diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c
index f67226df30d4..c5e46ff972e4 100644
--- a/drivers/tty/serial/lantiq.c
+++ b/drivers/tty/serial/lantiq.c
@@ -11,7 +11,6 @@
#include <linux/clk.h>
#include <linux/console.h>
#include <linux/device.h>
-#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/ioport.h>
diff --git a/drivers/tty/serial/pic32_uart.h b/drivers/tty/serial/pic32_uart.h
index 2f2b56927dc6..b15639cc336b 100644
--- a/drivers/tty/serial/pic32_uart.h
+++ b/drivers/tty/serial/pic32_uart.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+/* SPDX-License-Identifier: GPL-2.0+ */
/*
* PIC32 Integrated Serial Driver.
*
diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c
index 0bd1684cabb3..272bae0eebc7 100644
--- a/drivers/tty/serial/qcom_geni_serial.c
+++ b/drivers/tty/serial/qcom_geni_serial.c
@@ -21,6 +21,7 @@
/* UART specific GENI registers */
#define SE_UART_LOOPBACK_CFG 0x22c
+#define SE_UART_IO_MACRO_CTRL 0x240
#define SE_UART_TX_TRANS_CFG 0x25c
#define SE_UART_TX_WORD_LEN 0x268
#define SE_UART_TX_STOP_BIT_LEN 0x26c
@@ -95,6 +96,12 @@
#define CTS_RTS_SORTED BIT(1)
#define RX_TX_CTS_RTS_SORTED (RX_TX_SORTED | CTS_RTS_SORTED)
+/* UART pin swap value */
+#define DEFAULT_IO_MACRO_IO0_IO1_MASK GENMASK(3, 0)
+#define IO_MACRO_IO0_SEL 0x3
+#define DEFAULT_IO_MACRO_IO2_IO3_MASK GENMASK(15, 4)
+#define IO_MACRO_IO2_IO3_SWAP 0x4640
+
#ifdef CONFIG_CONSOLE_POLL
#define CONSOLE_RX_BYTES_PW 1
#else
@@ -119,6 +126,8 @@ struct qcom_geni_serial_port {
unsigned int tx_remaining;
int wakeup_irq;
+ bool rx_tx_swap;
+ bool cts_rts_swap;
};
static const struct uart_ops qcom_geni_console_pops;
@@ -836,6 +845,7 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport)
struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
u32 rxstale = DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT;
u32 proto;
+ u32 pin_swap;
if (uart_console(uport)) {
port->tx_bytes_pw = 1;
@@ -856,6 +866,20 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport)
get_tx_fifo_size(port);
writel(rxstale, uport->membase + SE_UART_RX_STALE_CNT);
+
+ pin_swap = readl(uport->membase + SE_UART_IO_MACRO_CTRL);
+ if (port->rx_tx_swap) {
+ pin_swap &= ~DEFAULT_IO_MACRO_IO2_IO3_MASK;
+ pin_swap |= IO_MACRO_IO2_IO3_SWAP;
+ }
+ if (port->cts_rts_swap) {
+ pin_swap &= ~DEFAULT_IO_MACRO_IO0_IO1_MASK;
+ pin_swap |= IO_MACRO_IO0_SEL;
+ }
+ /* Configure this register if RX-TX, CTS-RTS pins are swapped */
+ if (port->rx_tx_swap || port->cts_rts_swap)
+ writel(pin_swap, uport->membase + SE_UART_IO_MACRO_CTRL);
+
/*
* Make an unconditional cancel on the main sequencer to reset
* it else we could end up in data loss scenarios.
@@ -1299,6 +1323,12 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
if (!console)
port->wakeup_irq = platform_get_irq_optional(pdev, 1);
+ if (of_property_read_bool(pdev->dev.of_node, "rx-tx-swap"))
+ port->rx_tx_swap = true;
+
+ if (of_property_read_bool(pdev->dev.of_node, "cts-rts-swap"))
+ port->cts_rts_swap = true;
+
uport->private_data = drv;
platform_set_drvdata(pdev, port);
port->handle_rx = console ? handle_rx_console : handle_rx_uart;
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index 7d3ae31cc720..06e8071d5601 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -329,7 +329,7 @@ struct sc16is7xx_port {
struct task_struct *kworker_task;
struct kthread_work irq_work;
struct mutex efr_lock;
- struct sc16is7xx_one p[0];
+ struct sc16is7xx_one p[];
};
static unsigned long sc16is7xx_lines;
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 76e506ee335c..863e3e0c2d39 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -20,6 +20,7 @@
#include <linux/device.h>
#include <linux/serial.h> /* for serial_state and serial_icounter_struct */
#include <linux/serial_core.h>
+#include <linux/sysrq.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/security.h>
@@ -40,6 +41,8 @@ static struct lock_class_key port_lock_key;
#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
+#define SYSRQ_TIMEOUT (HZ * 5)
+
static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
struct ktermios *old_termios);
static void uart_wait_until_sent(struct tty_struct *tty, int timeout);
@@ -1908,6 +1911,24 @@ static int uart_proc_show(struct seq_file *m, void *v)
}
#endif
+static inline bool uart_console_enabled(struct uart_port *port)
+{
+ return uart_console(port) && (port->cons->flags & CON_ENABLED);
+}
+
+/*
+ * Ensure that the serial console lock is initialised early.
+ * If this port is a console, then the spinlock is already initialised.
+ */
+static inline void uart_port_spin_lock_init(struct uart_port *port)
+{
+ if (uart_console_enabled(port))
+ return;
+
+ spin_lock_init(&port->lock);
+ lockdep_set_class(&port->lock, &port_lock_key);
+}
+
#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL)
/**
* uart_console_write - write a console message to a serial port
@@ -2060,16 +2081,7 @@ uart_set_options(struct uart_port *port, struct console *co,
struct ktermios termios;
static struct ktermios dummy;
- /*
- * Ensure that the serial console lock is initialised
- * early.
- * If this port is a console, then the spinlock is already
- * initialised.
- */
- if (!(uart_console(port) && (port->cons->flags & CON_ENABLED))) {
- spin_lock_init(&port->lock);
- lockdep_set_class(&port->lock, &port_lock_key);
- }
+ uart_port_spin_lock_init(port);
memset(&termios, 0, sizeof(struct ktermios));
@@ -2605,7 +2617,7 @@ struct tty_driver *uart_console_device(struct console *co, int *index)
}
EXPORT_SYMBOL_GPL(uart_console_device);
-static ssize_t uart_get_attr_uartclk(struct device *dev,
+static ssize_t uartclk_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct serial_struct tmp;
@@ -2615,7 +2627,7 @@ static ssize_t uart_get_attr_uartclk(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%d\n", tmp.baud_base * 16);
}
-static ssize_t uart_get_attr_type(struct device *dev,
+static ssize_t type_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct serial_struct tmp;
@@ -2624,7 +2636,8 @@ static ssize_t uart_get_attr_type(struct device *dev,
uart_get_info(port, &tmp);
return snprintf(buf, PAGE_SIZE, "%d\n", tmp.type);
}
-static ssize_t uart_get_attr_line(struct device *dev,
+
+static ssize_t line_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct serial_struct tmp;
@@ -2634,7 +2647,7 @@ static ssize_t uart_get_attr_line(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%d\n", tmp.line);
}
-static ssize_t uart_get_attr_port(struct device *dev,
+static ssize_t port_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct serial_struct tmp;
@@ -2648,7 +2661,7 @@ static ssize_t uart_get_attr_port(struct device *dev,
return snprintf(buf, PAGE_SIZE, "0x%lX\n", ioaddr);
}
-static ssize_t uart_get_attr_irq(struct device *dev,
+static ssize_t irq_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct serial_struct tmp;
@@ -2658,7 +2671,7 @@ static ssize_t uart_get_attr_irq(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%d\n", tmp.irq);
}
-static ssize_t uart_get_attr_flags(struct device *dev,
+static ssize_t flags_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct serial_struct tmp;
@@ -2668,7 +2681,7 @@ static ssize_t uart_get_attr_flags(struct device *dev,
return snprintf(buf, PAGE_SIZE, "0x%X\n", tmp.flags);
}
-static ssize_t uart_get_attr_xmit_fifo_size(struct device *dev,
+static ssize_t xmit_fifo_size_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct serial_struct tmp;
@@ -2678,8 +2691,7 @@ static ssize_t uart_get_attr_xmit_fifo_size(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%d\n", tmp.xmit_fifo_size);
}
-
-static ssize_t uart_get_attr_close_delay(struct device *dev,
+static ssize_t close_delay_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct serial_struct tmp;
@@ -2689,8 +2701,7 @@ static ssize_t uart_get_attr_close_delay(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%d\n", tmp.close_delay);
}
-
-static ssize_t uart_get_attr_closing_wait(struct device *dev,
+static ssize_t closing_wait_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct serial_struct tmp;
@@ -2700,7 +2711,7 @@ static ssize_t uart_get_attr_closing_wait(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%d\n", tmp.closing_wait);
}
-static ssize_t uart_get_attr_custom_divisor(struct device *dev,
+static ssize_t custom_divisor_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct serial_struct tmp;
@@ -2710,7 +2721,7 @@ static ssize_t uart_get_attr_custom_divisor(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%d\n", tmp.custom_divisor);
}
-static ssize_t uart_get_attr_io_type(struct device *dev,
+static ssize_t io_type_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct serial_struct tmp;
@@ -2720,7 +2731,7 @@ static ssize_t uart_get_attr_io_type(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%d\n", tmp.io_type);
}
-static ssize_t uart_get_attr_iomem_base(struct device *dev,
+static ssize_t iomem_base_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct serial_struct tmp;
@@ -2730,7 +2741,7 @@ static ssize_t uart_get_attr_iomem_base(struct device *dev,
return snprintf(buf, PAGE_SIZE, "0x%lX\n", (unsigned long)tmp.iomem_base);
}
-static ssize_t uart_get_attr_iomem_reg_shift(struct device *dev,
+static ssize_t iomem_reg_shift_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct serial_struct tmp;
@@ -2740,28 +2751,28 @@ static ssize_t uart_get_attr_iomem_reg_shift(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%d\n", tmp.iomem_reg_shift);
}
-static DEVICE_ATTR(type, S_IRUSR | S_IRGRP, uart_get_attr_type, NULL);
-static DEVICE_ATTR(line, S_IRUSR | S_IRGRP, uart_get_attr_line, NULL);
-static DEVICE_ATTR(port, S_IRUSR | S_IRGRP, uart_get_attr_port, NULL);
-static DEVICE_ATTR(irq, S_IRUSR | S_IRGRP, uart_get_attr_irq, NULL);
-static DEVICE_ATTR(flags, S_IRUSR | S_IRGRP, uart_get_attr_flags, NULL);
-static DEVICE_ATTR(xmit_fifo_size, S_IRUSR | S_IRGRP, uart_get_attr_xmit_fifo_size, NULL);
-static DEVICE_ATTR(uartclk, S_IRUSR | S_IRGRP, uart_get_attr_uartclk, NULL);
-static DEVICE_ATTR(close_delay, S_IRUSR | S_IRGRP, uart_get_attr_close_delay, NULL);
-static DEVICE_ATTR(closing_wait, S_IRUSR | S_IRGRP, uart_get_attr_closing_wait, NULL);
-static DEVICE_ATTR(custom_divisor, S_IRUSR | S_IRGRP, uart_get_attr_custom_divisor, NULL);
-static DEVICE_ATTR(io_type, S_IRUSR | S_IRGRP, uart_get_attr_io_type, NULL);
-static DEVICE_ATTR(iomem_base, S_IRUSR | S_IRGRP, uart_get_attr_iomem_base, NULL);
-static DEVICE_ATTR(iomem_reg_shift, S_IRUSR | S_IRGRP, uart_get_attr_iomem_reg_shift, NULL);
+static DEVICE_ATTR_RO(uartclk);
+static DEVICE_ATTR_RO(type);
+static DEVICE_ATTR_RO(line);
+static DEVICE_ATTR_RO(port);
+static DEVICE_ATTR_RO(irq);
+static DEVICE_ATTR_RO(flags);
+static DEVICE_ATTR_RO(xmit_fifo_size);
+static DEVICE_ATTR_RO(close_delay);
+static DEVICE_ATTR_RO(closing_wait);
+static DEVICE_ATTR_RO(custom_divisor);
+static DEVICE_ATTR_RO(io_type);
+static DEVICE_ATTR_RO(iomem_base);
+static DEVICE_ATTR_RO(iomem_reg_shift);
static struct attribute *tty_dev_attrs[] = {
+ &dev_attr_uartclk.attr,
&dev_attr_type.attr,
&dev_attr_line.attr,
&dev_attr_port.attr,
&dev_attr_irq.attr,
&dev_attr_flags.attr,
&dev_attr_xmit_fifo_size.attr,
- &dev_attr_uartclk.attr,
&dev_attr_close_delay.attr,
&dev_attr_closing_wait.attr,
&dev_attr_custom_divisor.attr,
@@ -2824,14 +2835,8 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
goto out;
}
- /*
- * If this port is a console, then the spinlock is already
- * initialised.
- */
- if (!(uart_console(uport) && (uport->cons->flags & CON_ENABLED))) {
- spin_lock_init(&uport->lock);
- lockdep_set_class(&uport->lock, &port_lock_key);
- }
+ uart_port_spin_lock_init(uport);
+
if (uport->cons && uport->dev)
of_console_check(uport->dev->of_node, uport->cons->name, uport->line);
@@ -3082,6 +3087,56 @@ void uart_insert_char(struct uart_port *port, unsigned int status,
}
EXPORT_SYMBOL_GPL(uart_insert_char);
+#ifdef CONFIG_MAGIC_SYSRQ_SERIAL
+static const char sysrq_toggle_seq[] = CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE;
+
+static void uart_sysrq_on(struct work_struct *w)
+{
+ sysrq_toggle_support(1);
+ pr_info("SysRq is enabled by magic sequence on serial\n");
+}
+static DECLARE_WORK(sysrq_enable_work, uart_sysrq_on);
+
+/**
+ * uart_try_toggle_sysrq - Enables SysRq from serial line
+ * @port: uart_port structure where char(s) after BREAK met
+ * @ch: new character in the sequence after received BREAK
+ *
+ * Enables magic SysRq when the required sequence is met on port
+ * (see CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE).
+ *
+ * Returns false if @ch is out of enabling sequence and should be
+ * handled some other way, true if @ch was consumed.
+ */
+static bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch)
+{
+ if (ARRAY_SIZE(sysrq_toggle_seq) <= 1)
+ return false;
+
+ BUILD_BUG_ON(ARRAY_SIZE(sysrq_toggle_seq) >= U8_MAX);
+ if (sysrq_toggle_seq[port->sysrq_seq] != ch) {
+ port->sysrq_seq = 0;
+ return false;
+ }
+
+ /* Without the last \0 */
+ if (++port->sysrq_seq < (ARRAY_SIZE(sysrq_toggle_seq) - 1)) {
+ port->sysrq = jiffies + SYSRQ_TIMEOUT;
+ return true;
+ }
+
+ schedule_work(&sysrq_enable_work);
+
+ port->sysrq = 0;
+ return true;
+}
+#else
+static inline bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch)
+{
+ return false;
+}
+#endif
+
int uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
{
if (!IS_ENABLED(CONFIG_MAGIC_SYSRQ_SERIAL))
@@ -3091,9 +3146,13 @@ int uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
return 0;
if (ch && time_before(jiffies, port->sysrq)) {
- handle_sysrq(ch);
- port->sysrq = 0;
- return 1;
+ if (sysrq_mask()) {
+ handle_sysrq(ch);
+ port->sysrq = 0;
+ return 1;
+ }
+ if (uart_try_toggle_sysrq(port, ch))
+ return 1;
}
port->sysrq = 0;
@@ -3110,9 +3169,13 @@ int uart_prepare_sysrq_char(struct uart_port *port, unsigned int ch)
return 0;
if (ch && time_before(jiffies, port->sysrq)) {
- port->sysrq_ch = ch;
- port->sysrq = 0;
- return 1;
+ if (sysrq_mask()) {
+ port->sysrq_ch = ch;
+ port->sysrq = 0;
+ return 1;
+ }
+ if (uart_try_toggle_sysrq(port, ch))
+ return 1;
}
port->sysrq = 0;
@@ -3152,7 +3215,7 @@ int uart_handle_break(struct uart_port *port)
if (port->has_sysrq) {
if (port->cons && port->cons->index == port->line) {
if (!port->sysrq) {
- port->sysrq = jiffies + HZ*5;
+ port->sysrq = jiffies + SYSRQ_TIMEOUT;
return 1;
}
port->sysrq = 0;
diff --git a/drivers/tty/serial/serial_mctrl_gpio.h b/drivers/tty/serial/serial_mctrl_gpio.h
index 1b2ff503b2c2..b134a0ffc894 100644
--- a/drivers/tty/serial/serial_mctrl_gpio.h
+++ b/drivers/tty/serial/serial_mctrl_gpio.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Helpers for controlling modem lines via GPIO
*
diff --git a/drivers/tty/serial/sirfsoc_uart.h b/drivers/tty/serial/sirfsoc_uart.h
index 637b09d3fe79..fb88ac565227 100644
--- a/drivers/tty/serial/sirfsoc_uart.h
+++ b/drivers/tty/serial/sirfsoc_uart.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Drivers for CSR SiRFprimaII onboard UARTs.
*
diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h
index a175c1094dc8..db8bf0d4982d 100644
--- a/drivers/tty/serial/stm32-usart.h
+++ b/drivers/tty/serial/stm32-usart.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) Maxime Coquelin 2015
* Copyright (C) STMicroelectronics SA 2017
diff --git a/drivers/tty/serial/timbuart.h b/drivers/tty/serial/timbuart.h
index fb00b172117d..007e59af636d 100644
--- a/drivers/tty/serial/timbuart.h
+++ b/drivers/tty/serial/timbuart.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* timbuart.c timberdale FPGA GPIO driver
* Copyright (c) 2009 Intel Corporation
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index f724962a5906..5e0d0813da55 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -63,6 +63,18 @@ static bool sysrq_on(void)
return sysrq_enabled || sysrq_always_enabled;
}
+/**
+ * sysrq_mask - Getter for sysrq_enabled mask.
+ *
+ * Return: 1 if sysrq is always enabled, enabled sysrq_key_op mask otherwise.
+ */
+int sysrq_mask(void)
+{
+ if (sysrq_always_enabled)
+ return 1;
+ return sysrq_enabled;
+}
+
/*
* A value of 1 means 'all', other nonzero values are an op mask:
*/
diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c
index d7d2e4b844bc..1a069979866c 100644
--- a/drivers/tty/vt/selection.c
+++ b/drivers/tty/vt/selection.c
@@ -35,18 +35,18 @@
/* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */
#define isspace(c) ((c) == ' ')
-extern void poke_blanked_console(void);
-
/* FIXME: all this needs locking */
-/* Variables for selection control. */
-/* Use a dynamic buffer, instead of static (Dec 1994) */
-struct vc_data *sel_cons; /* must not be deallocated */
-static int use_unicode;
-static volatile int sel_start = -1; /* cleared by clear_selection */
-static int sel_end;
-static int sel_buffer_lth;
-static char *sel_buffer;
-static DEFINE_MUTEX(sel_lock);
+static struct vc_selection {
+ struct mutex lock;
+ struct vc_data *cons; /* must not be deallocated */
+ char *buffer;
+ unsigned int buf_len;
+ volatile int start; /* cleared by clear_selection */
+ int end;
+} vc_sel = {
+ .lock = __MUTEX_INITIALIZER(vc_sel.lock),
+ .start = -1,
+};
/* clear_selection, highlight and highlight_pointer can be called
from interrupt (via scrollback/front) */
@@ -54,22 +54,21 @@ static DEFINE_MUTEX(sel_lock);
/* set reverse video on characters s-e of console with selection. */
static inline void highlight(const int s, const int e)
{
- invert_screen(sel_cons, s, e-s+2, 1);
+ invert_screen(vc_sel.cons, s, e-s+2, 1);
}
/* use complementary color to show the pointer */
static inline void highlight_pointer(const int where)
{
- complement_pos(sel_cons, where);
+ complement_pos(vc_sel.cons, where);
}
static u32
-sel_pos(int n)
+sel_pos(int n, bool unicode)
{
- if (use_unicode)
- return screen_glyph_unicode(sel_cons, n / 2);
- return inverse_translate(sel_cons, screen_glyph(sel_cons, n),
- 0);
+ if (unicode)
+ return screen_glyph_unicode(vc_sel.cons, n / 2);
+ return inverse_translate(vc_sel.cons, screen_glyph(vc_sel.cons, n), 0);
}
/**
@@ -81,13 +80,18 @@ sel_pos(int n)
void clear_selection(void)
{
highlight_pointer(-1); /* hide the pointer */
- if (sel_start != -1) {
- highlight(sel_start, sel_end);
- sel_start = -1;
+ if (vc_sel.start != -1) {
+ highlight(vc_sel.start, vc_sel.end);
+ vc_sel.start = -1;
}
}
EXPORT_SYMBOL_GPL(clear_selection);
+bool vc_is_sel(struct vc_data *vc)
+{
+ return vc == vc_sel.cons;
+}
+
/*
* User settable table: what characters are to be considered alphabetic?
* 128 bits. Locked by the console lock.
@@ -186,9 +190,10 @@ static int __set_selection_kernel(struct tiocl_selection *v, struct tty_struct *
struct vc_data *vc = vc_cons[fg_console].d;
int new_sel_start, new_sel_end, spc;
char *bp, *obp;
- int i, ps, pe, multiplier;
+ int i, ps, pe;
u32 c;
- int mode, ret = 0;
+ int ret = 0;
+ bool unicode;
poke_blanked_console();
@@ -211,57 +216,52 @@ static int __set_selection_kernel(struct tiocl_selection *v, struct tty_struct *
return 0;
}
- if (ps > pe) /* make sel_start <= sel_end */
+ if (ps > pe) /* make vc_sel.start <= vc_sel.end */
swap(ps, pe);
- if (sel_cons != vc_cons[fg_console].d) {
+ mutex_lock(&vc_sel.lock);
+ if (vc_sel.cons != vc_cons[fg_console].d) {
clear_selection();
- sel_cons = vc_cons[fg_console].d;
+ vc_sel.cons = vc_cons[fg_console].d;
}
- mode = vt_do_kdgkbmode(fg_console);
- if (mode == K_UNICODE)
- use_unicode = 1;
- else
- use_unicode = 0;
-
- switch (v->sel_mode)
- {
- case TIOCL_SELCHAR: /* character-by-character selection */
+ unicode = vt_do_kdgkbmode(fg_console) == K_UNICODE;
+
+ switch (v->sel_mode) {
+ case TIOCL_SELCHAR: /* character-by-character selection */
+ new_sel_start = ps;
+ new_sel_end = pe;
+ break;
+ case TIOCL_SELWORD: /* word-by-word selection */
+ spc = isspace(sel_pos(ps, unicode));
+ for (new_sel_start = ps; ; ps -= 2) {
+ if ((spc && !isspace(sel_pos(ps, unicode))) ||
+ (!spc && !inword(sel_pos(ps, unicode))))
+ break;
new_sel_start = ps;
+ if (!(ps % vc->vc_size_row))
+ break;
+ }
+
+ spc = isspace(sel_pos(pe, unicode));
+ for (new_sel_end = pe; ; pe += 2) {
+ if ((spc && !isspace(sel_pos(pe, unicode))) ||
+ (!spc && !inword(sel_pos(pe, unicode))))
+ break;
new_sel_end = pe;
- break;
- case TIOCL_SELWORD: /* word-by-word selection */
- spc = isspace(sel_pos(ps));
- for (new_sel_start = ps; ; ps -= 2)
- {
- if ((spc && !isspace(sel_pos(ps))) ||
- (!spc && !inword(sel_pos(ps))))
- break;
- new_sel_start = ps;
- if (!(ps % vc->vc_size_row))
- break;
- }
- spc = isspace(sel_pos(pe));
- for (new_sel_end = pe; ; pe += 2)
- {
- if ((spc && !isspace(sel_pos(pe))) ||
- (!spc && !inword(sel_pos(pe))))
- break;
- new_sel_end = pe;
- if (!((pe + 2) % vc->vc_size_row))
- break;
- }
- break;
- case TIOCL_SELLINE: /* line-by-line selection */
- new_sel_start = ps - ps % vc->vc_size_row;
- new_sel_end = pe + vc->vc_size_row
- - pe % vc->vc_size_row - 2;
- break;
- case TIOCL_SELPOINTER:
- highlight_pointer(pe);
- return 0;
- default:
- return -EINVAL;
+ if (!((pe + 2) % vc->vc_size_row))
+ break;
+ }
+ break;
+ case TIOCL_SELLINE: /* line-by-line selection */
+ new_sel_start = ps - ps % vc->vc_size_row;
+ new_sel_end = pe + vc->vc_size_row
+ - pe % vc->vc_size_row - 2;
+ break;
+ case TIOCL_SELPOINTER:
+ highlight_pointer(pe);
+ return 0;
+ default:
+ return -EINVAL;
}
/* remove the pointer */
@@ -270,56 +270,56 @@ static int __set_selection_kernel(struct tiocl_selection *v, struct tty_struct *
/* select to end of line if on trailing space */
if (new_sel_end > new_sel_start &&
!atedge(new_sel_end, vc->vc_size_row) &&
- isspace(sel_pos(new_sel_end))) {
+ isspace(sel_pos(new_sel_end, unicode))) {
for (pe = new_sel_end + 2; ; pe += 2)
- if (!isspace(sel_pos(pe)) ||
+ if (!isspace(sel_pos(pe, unicode)) ||
atedge(pe, vc->vc_size_row))
break;
- if (isspace(sel_pos(pe)))
+ if (isspace(sel_pos(pe, unicode)))
new_sel_end = pe;
}
- if (sel_start == -1) /* no current selection */
+ if (vc_sel.start == -1) /* no current selection */
highlight(new_sel_start, new_sel_end);
- else if (new_sel_start == sel_start)
+ else if (new_sel_start == vc_sel.start)
{
- if (new_sel_end == sel_end) /* no action required */
+ if (new_sel_end == vc_sel.end) /* no action required */
return 0;
- else if (new_sel_end > sel_end) /* extend to right */
- highlight(sel_end + 2, new_sel_end);
+ else if (new_sel_end > vc_sel.end) /* extend to right */
+ highlight(vc_sel.end + 2, new_sel_end);
else /* contract from right */
- highlight(new_sel_end + 2, sel_end);
+ highlight(new_sel_end + 2, vc_sel.end);
}
- else if (new_sel_end == sel_end)
+ else if (new_sel_end == vc_sel.end)
{
- if (new_sel_start < sel_start) /* extend to left */
- highlight(new_sel_start, sel_start - 2);
+ if (new_sel_start < vc_sel.start) /* extend to left */
+ highlight(new_sel_start, vc_sel.start - 2);
else /* contract from left */
- highlight(sel_start, new_sel_start - 2);
+ highlight(vc_sel.start, new_sel_start - 2);
}
else /* some other case; start selection from scratch */
{
clear_selection();
highlight(new_sel_start, new_sel_end);
}
- sel_start = new_sel_start;
- sel_end = new_sel_end;
+ vc_sel.start = new_sel_start;
+ vc_sel.end = new_sel_end;
/* Allocate a new buffer before freeing the old one ... */
- multiplier = use_unicode ? 4 : 1; /* chars can take up to 4 bytes */
- bp = kmalloc_array((sel_end - sel_start) / 2 + 1, multiplier,
+ /* chars can take up to 4 bytes with unicode */
+ bp = kmalloc_array((vc_sel.end - vc_sel.start) / 2 + 1, unicode ? 4 : 1,
GFP_KERNEL);
if (!bp) {
printk(KERN_WARNING "selection: kmalloc() failed\n");
clear_selection();
return -ENOMEM;
}
- kfree(sel_buffer);
- sel_buffer = bp;
+ kfree(vc_sel.buffer);
+ vc_sel.buffer = bp;
obp = bp;
- for (i = sel_start; i <= sel_end; i += 2) {
- c = sel_pos(i);
- if (use_unicode)
+ for (i = vc_sel.start; i <= vc_sel.end; i += 2) {
+ c = sel_pos(i, unicode);
+ if (unicode)
bp += store_utf8(c, bp);
else
*bp++ = c;
@@ -335,7 +335,7 @@ static int __set_selection_kernel(struct tiocl_selection *v, struct tty_struct *
obp = bp;
}
}
- sel_buffer_lth = bp - sel_buffer;
+ vc_sel.buf_len = bp - vc_sel.buffer;
return ret;
}
@@ -344,11 +344,11 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty)
{
int ret;
- mutex_lock(&sel_lock);
+ mutex_lock(&vc_sel.lock);
console_lock();
ret = __set_selection_kernel(v, tty);
console_unlock();
- mutex_unlock(&sel_lock);
+ mutex_unlock(&vc_sel.lock);
return ret;
}
@@ -380,26 +380,26 @@ int paste_selection(struct tty_struct *tty)
tty_buffer_lock_exclusive(&vc->port);
add_wait_queue(&vc->paste_wait, &wait);
- mutex_lock(&sel_lock);
- while (sel_buffer && sel_buffer_lth > pasted) {
+ mutex_lock(&vc_sel.lock);
+ while (vc_sel.buffer && vc_sel.buf_len > pasted) {
set_current_state(TASK_INTERRUPTIBLE);
if (signal_pending(current)) {
ret = -EINTR;
break;
}
if (tty_throttled(tty)) {
- mutex_unlock(&sel_lock);
+ mutex_unlock(&vc_sel.lock);
schedule();
- mutex_lock(&sel_lock);
+ mutex_lock(&vc_sel.lock);
continue;
}
__set_current_state(TASK_RUNNING);
- count = sel_buffer_lth - pasted;
- count = tty_ldisc_receive_buf(ld, sel_buffer + pasted, NULL,
+ count = vc_sel.buf_len - pasted;
+ count = tty_ldisc_receive_buf(ld, vc_sel.buffer + pasted, NULL,
count);
pasted += count;
}
- mutex_unlock(&sel_lock);
+ mutex_unlock(&vc_sel.lock);
remove_wait_queue(&vc->paste_wait, &wait);
__set_current_state(TASK_RUNNING);
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 15d27698054a..c4d75edde923 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -890,8 +890,9 @@ static void hide_softcursor(struct vc_data *vc)
static void hide_cursor(struct vc_data *vc)
{
- if (vc == sel_cons)
+ if (vc_is_sel(vc))
clear_selection();
+
vc->vc_sw->con_cursor(vc, CM_ERASE);
hide_softcursor(vc);
}
@@ -901,7 +902,7 @@ static void set_cursor(struct vc_data *vc)
if (!con_is_fg(vc) || console_blanked || vc->vc_mode == KD_GRAPHICS)
return;
if (vc->vc_deccm) {
- if (vc == sel_cons)
+ if (vc_is_sel(vc))
clear_selection();
add_softcursor(vc);
if ((vc->vc_cursor_type & 0x0f) != 1)
@@ -1207,7 +1208,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
}
}
- if (vc == sel_cons)
+ if (vc_is_sel(vc))
clear_selection();
old_rows = vc->vc_rows;
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index ee6c91ef1f6c..38948ac5fc49 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -39,11 +39,26 @@
#include <linux/kbd_diacr.h>
#include <linux/selection.h>
-char vt_dont_switch;
-extern struct tty_driver *console_driver;
+bool vt_dont_switch;
-#define VT_IS_IN_USE(i) (console_driver->ttys[i] && console_driver->ttys[i]->count)
-#define VT_BUSY(i) (VT_IS_IN_USE(i) || i == fg_console || vc_cons[i].d == sel_cons)
+static inline bool vt_in_use(unsigned int i)
+{
+ extern struct tty_driver *console_driver;
+
+ return console_driver->ttys[i] && console_driver->ttys[i]->count;
+}
+
+static inline bool vt_busy(int i)
+{
+ if (vt_in_use(i))
+ return true;
+ if (i == fg_console)
+ return true;
+ if (vc_is_sel(vc_cons[i].d))
+ return true;
+
+ return false;
+}
/*
* Console (vt and kd) routines, as defined by USL SVR4 manual, and by
@@ -289,7 +304,7 @@ static int vt_disallocate(unsigned int vc_num)
int ret = 0;
console_lock();
- if (VT_BUSY(vc_num))
+ if (vt_busy(vc_num))
ret = -EBUSY;
else if (vc_num)
vc = vc_deallocate(vc_num);
@@ -311,7 +326,7 @@ static void vt_disallocate_all(void)
console_lock();
for (i = 1; i < MAX_NR_CONSOLES; i++)
- if (!VT_BUSY(i))
+ if (!vt_busy(i))
vc[i] = vc_deallocate(i);
else
vc[i] = NULL;
@@ -648,7 +663,7 @@ int vt_ioctl(struct tty_struct *tty,
state = 1; /* /dev/tty0 is always open */
for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask;
++i, mask <<= 1)
- if (VT_IS_IN_USE(i))
+ if (vt_in_use(i))
state |= mask;
ret = put_user(state, &vtstat->v_state);
}
@@ -661,7 +676,7 @@ int vt_ioctl(struct tty_struct *tty,
case VT_OPENQRY:
/* FIXME: locking ? - but then this is a stupid API */
for (i = 0; i < MAX_NR_CONSOLES; ++i)
- if (! VT_IS_IN_USE(i))
+ if (!vt_in_use(i))
break;
uival = i < MAX_NR_CONSOLES ? (i+1) : -1;
goto setint;
@@ -1011,12 +1026,12 @@ int vt_ioctl(struct tty_struct *tty,
case VT_LOCKSWITCH:
if (!capable(CAP_SYS_TTY_CONFIG))
return -EPERM;
- vt_dont_switch = 1;
+ vt_dont_switch = true;
break;
case VT_UNLOCKSWITCH:
if (!capable(CAP_SYS_TTY_CONFIG))
return -EPERM;
- vt_dont_switch = 0;
+ vt_dont_switch = false;
break;
case VT_GETHIFONTMASK:
ret = put_user(vc->vc_hi_font_mask,
diff --git a/include/linux/selection.h b/include/linux/selection.h
index e2c1f96bf059..5b890ef5b59f 100644
--- a/include/linux/selection.h
+++ b/include/linux/selection.h
@@ -11,8 +11,8 @@
#include <linux/tiocl.h>
#include <linux/vt_buffer.h>
-extern struct vc_data *sel_cons;
struct tty_struct;
+struct vc_data;
extern void clear_selection(void);
extern int set_selection_user(const struct tiocl_selection __user *sel,
@@ -24,6 +24,8 @@ extern int sel_loadlut(char __user *p);
extern int mouse_reporting(void);
extern void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry);
+bool vc_is_sel(struct vc_data *vc);
+
extern int console_blanked;
extern const unsigned char color_table[];
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
index 6a8e8c48c882..0901c2aa366c 100644
--- a/include/linux/serial_8250.h
+++ b/include/linux/serial_8250.h
@@ -81,6 +81,7 @@ struct uart_8250_em485 {
struct hrtimer stop_tx_timer; /* "rs485 stop tx" timer */
struct hrtimer *active_timer; /* pointer to active timer */
struct uart_8250_port *port; /* for hrtimer callbacks */
+ unsigned int tx_stopped:1; /* tx is currently stopped */
};
/*
@@ -132,6 +133,8 @@ struct uart_8250_port {
void (*dl_write)(struct uart_8250_port *, int);
struct uart_8250_em485 *em485;
+ void (*rs485_start_tx)(struct uart_8250_port *);
+ void (*rs485_stop_tx)(struct uart_8250_port *);
/* Serial port overrun backoff */
struct delayed_work overrun_backoff;
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 52404ef1694e..1f4443db5474 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -243,6 +243,7 @@ struct uart_port {
unsigned long sysrq; /* sysrq timeout */
unsigned int sysrq_ch; /* char for sysrq */
unsigned char has_sysrq;
+ unsigned char sysrq_seq; /* index in sysrq_toggle_seq */
unsigned char hub6; /* this should be in the 8250 driver */
unsigned char suspended;
diff --git a/include/linux/sysrq.h b/include/linux/sysrq.h
index 8c71874e8485..8e159e16850f 100644
--- a/include/linux/sysrq.h
+++ b/include/linux/sysrq.h
@@ -50,6 +50,7 @@ int unregister_sysrq_key(int key, struct sysrq_key_op *op);
struct sysrq_key_op *__sysrq_get_key_op(int key);
int sysrq_toggle_support(int enable_mask);
+int sysrq_mask(void);
#else
@@ -71,6 +72,12 @@ static inline int unregister_sysrq_key(int key, struct sysrq_key_op *op)
return -EINVAL;
}
+static inline int sysrq_mask(void)
+{
+ /* Magic SysRq disabled mask */
+ return 0;
+}
+
#endif
#endif /* _LINUX_SYSRQ_H */
diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h
index 8dc77e40bc03..abf5bccf906a 100644
--- a/include/linux/vt_kern.h
+++ b/include/linux/vt_kern.h
@@ -28,8 +28,9 @@
#define BROKEN_GRAPHICS_PROGRAMS 1
#endif
-extern void kd_mksound(unsigned int hz, unsigned int ticks);
-extern int kbd_rate(struct kbd_repeat *rep);
+void kd_mksound(unsigned int hz, unsigned int ticks);
+int kbd_rate(struct kbd_repeat *rep);
+
extern int fg_console, last_console, want_console;
/* console.c */
@@ -131,11 +132,11 @@ void vt_event_post(unsigned int event, unsigned int old, unsigned int new);
int vt_waitactive(int n);
void change_console(struct vc_data *new_vc);
void reset_vc(struct vc_data *vc);
-extern int do_unbind_con_driver(const struct consw *csw, int first, int last,
- int deflt);
+int do_unbind_con_driver(const struct consw *csw, int first, int last,
+ int deflt);
int vty_init(const struct file_operations *console_fops);
-extern char vt_dont_switch;
+extern bool vt_dont_switch;
extern int default_utf8;
extern int global_cursor_default;
@@ -146,7 +147,7 @@ struct vt_spawn_console {
};
extern struct vt_spawn_console vt_spawn_con;
-extern int vt_move_to_console(unsigned int vt, int alloc);
+int vt_move_to_console(unsigned int vt, int alloc);
/* Interfaces for VC notification of character events (for accessibility etc) */
@@ -155,35 +156,34 @@ struct vt_notifier_param {
unsigned int c; /* Printed char */
};
-extern int register_vt_notifier(struct notifier_block *nb);
-extern int unregister_vt_notifier(struct notifier_block *nb);
+int register_vt_notifier(struct notifier_block *nb);
+int unregister_vt_notifier(struct notifier_block *nb);
-extern void hide_boot_cursor(bool hide);
+void hide_boot_cursor(bool hide);
/* keyboard provided interfaces */
-extern int vt_do_diacrit(unsigned int cmd, void __user *up, int eperm);
-extern int vt_do_kdskbmode(int console, unsigned int arg);
-extern int vt_do_kdskbmeta(int console, unsigned int arg);
-extern int vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc,
- int perm);
-extern int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe,
- int perm, int console);
-extern int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb,
- int perm);
-extern int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm);
-extern int vt_do_kdgkbmode(int console);
-extern int vt_do_kdgkbmeta(int console);
-extern void vt_reset_unicode(int console);
-extern int vt_get_shift_state(void);
-extern void vt_reset_keyboard(int console);
-extern int vt_get_leds(int console, int flag);
-extern int vt_get_kbd_mode_bit(int console, int bit);
-extern void vt_set_kbd_mode_bit(int console, int bit);
-extern void vt_clr_kbd_mode_bit(int console, int bit);
-extern void vt_set_led_state(int console, int leds);
-extern void vt_set_led_state(int console, int leds);
-extern void vt_kbd_con_start(int console);
-extern void vt_kbd_con_stop(int console);
+int vt_do_diacrit(unsigned int cmd, void __user *up, int eperm);
+int vt_do_kdskbmode(int console, unsigned int arg);
+int vt_do_kdskbmeta(int console, unsigned int arg);
+int vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc,
+ int perm);
+int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm,
+ int console);
+int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm);
+int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm);
+int vt_do_kdgkbmode(int console);
+int vt_do_kdgkbmeta(int console);
+void vt_reset_unicode(int console);
+int vt_get_shift_state(void);
+void vt_reset_keyboard(int console);
+int vt_get_leds(int console, int flag);
+int vt_get_kbd_mode_bit(int console, int bit);
+void vt_set_kbd_mode_bit(int console, int bit);
+void vt_clr_kbd_mode_bit(int console, int bit);
+void vt_set_led_state(int console, int leds);
+void vt_set_led_state(int console, int leds);
+void vt_kbd_con_start(int console);
+void vt_kbd_con_stop(int console);
void vc_scrolldelta_helper(struct vc_data *c, int lines,
unsigned int rolled_over, void *_base, unsigned int size);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index ad5b88a53c5a..94638f695e60 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -229,25 +229,8 @@ static int proc_dopipe_max_size(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos);
#ifdef CONFIG_MAGIC_SYSRQ
-/* Note: sysrq code uses its own private copy */
-static int __sysrq_enabled = CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE;
-
static int sysrq_sysctl_handler(struct ctl_table *table, int write,
- void __user *buffer, size_t *lenp,
- loff_t *ppos)
-{
- int error;
-
- error = proc_dointvec(table, write, buffer, lenp, ppos);
- if (error)
- return error;
-
- if (write)
- sysrq_toggle_support(__sysrq_enabled);
-
- return 0;
-}
-
+ void __user *buffer, size_t *lenp, loff_t *ppos);
#endif
static struct ctl_table kern_table[];
@@ -747,7 +730,7 @@ static struct ctl_table kern_table[] = {
#ifdef CONFIG_MAGIC_SYSRQ
{
.procname = "sysrq",
- .data = &__sysrq_enabled,
+ .data = NULL,
.maxlen = sizeof (int),
.mode = 0644,
.proc_handler = sysrq_sysctl_handler,
@@ -2835,6 +2818,26 @@ static int proc_dostring_coredump(struct ctl_table *table, int write,
}
#endif
+#ifdef CONFIG_MAGIC_SYSRQ
+static int sysrq_sysctl_handler(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ int tmp, ret;
+
+ tmp = sysrq_mask();
+
+ ret = __do_proc_dointvec(&tmp, table, write, buffer,
+ lenp, ppos, NULL, NULL);
+ if (ret || !write)
+ return ret;
+
+ if (write)
+ sysrq_toggle_support(tmp);
+
+ return 0;
+}
+#endif
+
static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int write,
void __user *buffer,
size_t *lenp, loff_t *ppos,
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 69def4a9df00..38a8f3c99579 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -431,6 +431,14 @@ config MAGIC_SYSRQ_SERIAL
This option allows you to decide whether you want to enable the
magic SysRq key.
+config MAGIC_SYSRQ_SERIAL_SEQUENCE
+ string "Char sequence that enables magic SysRq over serial"
+ depends on MAGIC_SYSRQ_SERIAL
+ default ""
+ help
+ Specifies a sequence of characters that can follow BREAK to enable
+ SysRq on a serial console.
+
config DEBUG_FS
bool "Debug Filesystem"
help