summaryrefslogtreecommitdiff
path: root/drivers/tty
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-06-07 09:52:36 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2020-06-07 09:52:36 -0700
commit081096d98bb23946f16215357b141c5616b234bf (patch)
tree23638d3369fa0c424c1eae203b4c5821281bd2c1 /drivers/tty
parente611c0fe318c6d6827ee2bba660fbc23cf73f7dc (diff)
parenta1b44ea340b21c99b34c93acad233da727cb88ba (diff)
Merge tag 'tty-5.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty/serial driver updates from Greg KH: "Here is the tty and serial driver updates for 5.8-rc1 Nothing huge at all, just a lot of little serial driver fixes, updates for new devices and features, and other small things. Full details are in the shortlog. All of these have been in linux-next with no issues for a while" * tag 'tty-5.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (67 commits) tty: serial: qcom_geni_serial: Add 51.2MHz frequency support tty: serial: imx: clear Ageing Timer Interrupt in handler serial: 8250_fintek: Add F81966 Support sc16is7xx: Add flag to activate IrDA mode dt-bindings: sc16is7xx: Add flag to activate IrDA mode serial: 8250: Support rs485 bus termination GPIO serial: 8520_port: Fix function param documentation dt-bindings: serial: Add binding for rs485 bus termination GPIO vt: keyboard: avoid signed integer overflow in k_ascii serial: 8250: Enable 16550A variants by default on non-x86 tty: hvc_console, fix crashes on parallel open/close serial: imx: Initialize lock for non-registered console sc16is7xx: Read the LSR register for basic device presence check sc16is7xx: Allow sharing the IRQ line sc16is7xx: Use threaded IRQ sc16is7xx: Always use falling edge IRQ tty: n_gsm: Fix bogus i++ in gsm_data_kick tty: n_gsm: Remove unnecessary test in gsm_print_packet() serial: stm32: add no_console_suspend support tty: serial: fsl_lpuart: Use __maybe_unused instead of #if CONFIG_PM_SLEEP ...
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/hvc/hvc_console.c23
-rw-r--r--drivers/tty/hvc/hvcs.c2
-rw-r--r--drivers/tty/mxser.c7
-rw-r--r--drivers/tty/n_gsm.c39
-rw-r--r--drivers/tty/rocket.c10
-rw-r--r--drivers/tty/serial/8250/8250_core.c18
-rw-r--r--drivers/tty/serial/8250/8250_exar.c65
-rw-r--r--drivers/tty/serial/8250/8250_fintek.c13
-rw-r--r--drivers/tty/serial/8250/8250_port.c9
-rw-r--r--drivers/tty/serial/8250/Kconfig1
-rw-r--r--drivers/tty/serial/8250/serial_cs.c6
-rw-r--r--drivers/tty/serial/Kconfig16
-rw-r--r--drivers/tty/serial/amba-pl011.c1
-rw-r--r--drivers/tty/serial/ar933x_uart.c6
-rw-r--r--drivers/tty/serial/atmel_serial.c6
-rw-r--r--drivers/tty/serial/fsl_lpuart.c27
-rw-r--r--drivers/tty/serial/imx.c13
-rw-r--r--drivers/tty/serial/lantiq.c40
-rw-r--r--drivers/tty/serial/lpc32xx_hs.c1
-rw-r--r--drivers/tty/serial/omap-serial.c52
-rw-r--r--drivers/tty/serial/qcom_geni_serial.c7
-rw-r--r--drivers/tty/serial/samsung_tty.c84
-rw-r--r--drivers/tty/serial/sc16is7xx.c73
-rw-r--r--drivers/tty/serial/serial_core.c22
-rw-r--r--drivers/tty/serial/sh-sci.h1
-rw-r--r--drivers/tty/serial/stm32-usart.c74
-rw-r--r--drivers/tty/serial/stm32-usart.h1
-rw-r--r--drivers/tty/serial/xilinx_uartps.c12
-rw-r--r--drivers/tty/sysrq.c68
-rw-r--r--drivers/tty/vcc.c1
-rw-r--r--drivers/tty/vt/keyboard.c26
-rw-r--r--drivers/tty/vt/selection.c133
32 files changed, 552 insertions, 305 deletions
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c
index 436cc51c92c3..cdcc64ea2554 100644
--- a/drivers/tty/hvc/hvc_console.c
+++ b/drivers/tty/hvc/hvc_console.c
@@ -371,15 +371,14 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
* tty fields and return the kref reference.
*/
if (rc) {
- tty_port_tty_set(&hp->port, NULL);
- tty->driver_data = NULL;
- tty_port_put(&hp->port);
printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc);
- } else
+ } else {
/* We are ready... raise DTR/RTS */
if (C_BAUD(tty))
if (hp->ops->dtr_rts)
hp->ops->dtr_rts(hp, 1);
+ tty_port_set_initialized(&hp->port, true);
+ }
/* Force wakeup of the polling thread */
hvc_kick();
@@ -389,22 +388,12 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
static void hvc_close(struct tty_struct *tty, struct file * filp)
{
- struct hvc_struct *hp;
+ struct hvc_struct *hp = tty->driver_data;
unsigned long flags;
if (tty_hung_up_p(filp))
return;
- /*
- * No driver_data means that this close was issued after a failed
- * hvc_open by the tty layer's release_dev() function and we can just
- * exit cleanly because the kref reference wasn't made.
- */
- if (!tty->driver_data)
- return;
-
- hp = tty->driver_data;
-
spin_lock_irqsave(&hp->port.lock, flags);
if (--hp->port.count == 0) {
@@ -412,6 +401,9 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
/* We are done with the tty pointer now. */
tty_port_tty_set(&hp->port, NULL);
+ if (!tty_port_initialized(&hp->port))
+ return;
+
if (C_HUPCL(tty))
if (hp->ops->dtr_rts)
hp->ops->dtr_rts(hp, 0);
@@ -428,6 +420,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
* waking periodically to check chars_in_buffer().
*/
tty_wait_until_sent(tty, HVC_CLOSE_WAIT);
+ tty_port_set_initialized(&hp->port, false);
} else {
if (hp->port.count < 0)
printk(KERN_ERR "hvc_close %X: oops, count is %d\n",
diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c
index ee0604cd9c6b..55105ac38f89 100644
--- a/drivers/tty/hvc/hvcs.c
+++ b/drivers/tty/hvc/hvcs.c
@@ -196,8 +196,6 @@ module_param(hvcs_parm_num_devs, int, 0);
static const char hvcs_driver_name[] = "hvcs";
static const char hvcs_device_node[] = "hvcs";
-static const char hvcs_driver_string[]
- = "IBM hvcs (Hypervisor Virtual Console Server) Driver";
/* Status of partner info rescan triggered via sysfs. */
static int hvcs_rescan_status;
diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c
index 9d00ff5ef961..3703987c4666 100644
--- a/drivers/tty/mxser.c
+++ b/drivers/tty/mxser.c
@@ -638,16 +638,15 @@ static int mxser_set_baud(struct tty_struct *tty, long newspd)
* This routine is called to set the UART divisor registers to match
* the specified baud rate for a serial port.
*/
-static int mxser_change_speed(struct tty_struct *tty)
+static void mxser_change_speed(struct tty_struct *tty)
{
struct mxser_port *info = tty->driver_data;
unsigned cflag, cval, fcr;
- int ret = 0;
unsigned char status;
cflag = tty->termios.c_cflag;
if (!info->ioaddr)
- return ret;
+ return;
if (mxser_set_baud_method[tty->index] == 0)
mxser_set_baud(tty, tty_get_baud_rate(tty));
@@ -803,8 +802,6 @@ static int mxser_change_speed(struct tty_struct *tty)
outb(fcr, info->ioaddr + UART_FCR); /* set fcr */
outb(cval, info->ioaddr + UART_LCR);
-
- return ret;
}
static void mxser_check_modem_status(struct tty_struct *tty,
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index d77ed82a4840..0a29a94ec438 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -504,18 +504,7 @@ static void gsm_print_packet(const char *hdr, int addr, int cr,
else
pr_cont("(F)");
- if (dlen) {
- int ct = 0;
- while (dlen--) {
- if (ct % 8 == 0) {
- pr_cont("\n");
- pr_debug(" ");
- }
- pr_cont("%02X ", *data++);
- ct++;
- }
- }
- pr_cont("\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_NONE, data, dlen);
}
@@ -673,11 +662,10 @@ static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len,
* FIXME: lock against link layer control transmissions
*/
-static void gsm_data_kick(struct gsm_mux *gsm)
+static void gsm_data_kick(struct gsm_mux *gsm, struct gsm_dlci *dlci)
{
struct gsm_msg *msg, *nmsg;
int len;
- int skip_sof = 0;
list_for_each_entry_safe(msg, nmsg, &gsm->tx_list, list) {
if (gsm->constipated && msg->addr)
@@ -699,18 +687,23 @@ static void gsm_data_kick(struct gsm_mux *gsm)
print_hex_dump_bytes("gsm_data_kick: ",
DUMP_PREFIX_OFFSET,
gsm->txframe, len);
-
- if (gsm->output(gsm, gsm->txframe + skip_sof,
- len - skip_sof) < 0)
+ if (gsm->output(gsm, gsm->txframe, len) < 0)
break;
/* FIXME: Can eliminate one SOF in many more cases */
gsm->tx_bytes -= msg->len;
- /* For a burst of frames skip the extra SOF within the
- burst */
- skip_sof = 1;
list_del(&msg->list);
kfree(msg);
+
+ if (dlci) {
+ tty_port_tty_wakeup(&dlci->port);
+ } else {
+ int i = 0;
+
+ for (i = 0; i < NUM_DLCI; i++)
+ if (gsm->dlci[i])
+ tty_port_tty_wakeup(&gsm->dlci[i]->port);
+ }
}
}
@@ -762,7 +755,7 @@ static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
/* Add to the actual output queue */
list_add_tail(&msg->list, &gsm->tx_list);
gsm->tx_bytes += msg->len;
- gsm_data_kick(gsm);
+ gsm_data_kick(gsm, dlci);
}
/**
@@ -1223,7 +1216,7 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
gsm_control_reply(gsm, CMD_FCON, NULL, 0);
/* Kick the link in case it is idling */
spin_lock_irqsave(&gsm->tx_lock, flags);
- gsm_data_kick(gsm);
+ gsm_data_kick(gsm, NULL);
spin_unlock_irqrestore(&gsm->tx_lock, flags);
break;
case CMD_FCOFF:
@@ -2545,7 +2538,7 @@ static void gsmld_write_wakeup(struct tty_struct *tty)
/* Queue poll */
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
spin_lock_irqsave(&gsm->tx_lock, flags);
- gsm_data_kick(gsm);
+ gsm_data_kick(gsm, NULL);
if (gsm->tx_bytes < TX_THRESH_LO) {
gsm_dlci_data_sweep(gsm);
}
diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c
index e2138e7d5dc6..2540b2e4c8e8 100644
--- a/drivers/tty/rocket.c
+++ b/drivers/tty/rocket.c
@@ -1885,7 +1885,7 @@ static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
*/
static __init int register_PCI(int i, struct pci_dev *dev)
{
- int num_aiops, aiop, max_num_aiops, num_chan, chan;
+ int num_aiops, aiop, max_num_aiops, chan;
unsigned int aiopio[MAX_AIOPS_PER_BOARD];
CONTROLLER_t *ctlp;
@@ -2157,8 +2157,7 @@ static __init int register_PCI(int i, struct pci_dev *dev)
/* Reset the AIOPIC, init the serial ports */
for (aiop = 0; aiop < num_aiops; aiop++) {
sResetAiopByNum(ctlp, aiop);
- num_chan = ports_per_aiop;
- for (chan = 0; chan < num_chan; chan++)
+ for (chan = 0; chan < ports_per_aiop; chan++)
init_r_port(i, aiop, chan, dev);
}
@@ -2166,11 +2165,10 @@ static __init int register_PCI(int i, struct pci_dev *dev)
if ((rcktpt_type[i] == ROCKET_TYPE_MODEM) ||
(rcktpt_type[i] == ROCKET_TYPE_MODEMII) ||
(rcktpt_type[i] == ROCKET_TYPE_MODEMIII)) {
- num_chan = ports_per_aiop;
- for (chan = 0; chan < num_chan; chan++)
+ for (chan = 0; chan < ports_per_aiop; chan++)
sPCIModemReset(ctlp, chan, 1);
msleep(500);
- for (chan = 0; chan < num_chan; chan++)
+ for (chan = 0; chan < ports_per_aiop; chan++)
sPCIModemReset(ctlp, chan, 0);
msleep(500);
rmSpeakerReset(ctlp, rocketModel[i].model);
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 45d9117cab68..fc118f649887 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -1026,7 +1026,9 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
if (up->port.dev) {
uart->port.dev = up->port.dev;
- uart_get_rs485_mode(uart->port.dev, &uart->port.rs485);
+ ret = uart_get_rs485_mode(&uart->port);
+ if (ret)
+ goto err;
}
if (up->port.flags & UPF_FIXED_TYPE)
@@ -1040,7 +1042,7 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
gpios = mctrl_gpio_init(&uart->port, 0);
if (IS_ERR(gpios)) {
ret = PTR_ERR(gpios);
- goto out_unlock;
+ goto err;
} else {
uart->gpios = gpios;
}
@@ -1089,8 +1091,10 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
serial8250_apply_quirks(uart);
ret = uart_add_one_port(&serial8250_reg,
&uart->port);
- if (ret == 0)
- ret = uart->port.line;
+ if (ret)
+ goto err;
+
+ ret = uart->port.line;
} else {
dev_info(uart->port.dev,
"skipping CIR port at 0x%lx / 0x%llx, IRQ %d\n",
@@ -1112,10 +1116,14 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
}
}
-out_unlock:
mutex_unlock(&serial_mutex);
return ret;
+
+err:
+ uart->port.dev = NULL;
+ mutex_unlock(&serial_mutex);
+ return ret;
}
EXPORT_SYMBOL(serial8250_register_8250_port);
diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c
index 59449b6500cd..ddb6aeb76dc5 100644
--- a/drivers/tty/serial/8250/8250_exar.c
+++ b/drivers/tty/serial/8250/8250_exar.c
@@ -25,13 +25,13 @@
#include "8250.h"
-#define PCI_DEVICE_ID_ACCES_COM_2S 0x1052
-#define PCI_DEVICE_ID_ACCES_COM_4S 0x105d
-#define PCI_DEVICE_ID_ACCES_COM_8S 0x106c
-#define PCI_DEVICE_ID_ACCES_COM232_8 0x10a8
-#define PCI_DEVICE_ID_ACCES_COM_2SM 0x10d2
-#define PCI_DEVICE_ID_ACCES_COM_4SM 0x10db
-#define PCI_DEVICE_ID_ACCES_COM_8SM 0x10ea
+#define PCI_DEVICE_ID_ACCESSIO_COM_2S 0x1052
+#define PCI_DEVICE_ID_ACCESSIO_COM_4S 0x105d
+#define PCI_DEVICE_ID_ACCESSIO_COM_8S 0x106c
+#define PCI_DEVICE_ID_ACCESSIO_COM232_8 0x10a8
+#define PCI_DEVICE_ID_ACCESSIO_COM_2SM 0x10d2
+#define PCI_DEVICE_ID_ACCESSIO_COM_4SM 0x10db
+#define PCI_DEVICE_ID_ACCESSIO_COM_8SM 0x10ea
#define PCI_DEVICE_ID_COMMTECH_4224PCI335 0x0002
#define PCI_DEVICE_ID_COMMTECH_4222PCI335 0x0004
@@ -755,9 +755,7 @@ static const struct exar8250_board pbn_exar_XR17V8358 = {
(kernel_ulong_t)&bd \
}
-#define EXAR_DEVICE(vend, devid, bd) { \
- PCI_VDEVICE(vend, PCI_DEVICE_ID_##devid), (kernel_ulong_t)&bd \
- }
+#define EXAR_DEVICE(vend, devid, bd) { PCI_DEVICE_DATA(vend, devid, &bd) }
#define IBM_DEVICE(devid, sdevid, bd) { \
PCI_DEVICE_SUB( \
@@ -769,14 +767,13 @@ static const struct exar8250_board pbn_exar_XR17V8358 = {
}
static const struct pci_device_id exar_pci_tbl[] = {
- EXAR_DEVICE(ACCESSIO, ACCES_COM_2S, acces_com_2x),
- EXAR_DEVICE(ACCESSIO, ACCES_COM_4S, acces_com_4x),
- EXAR_DEVICE(ACCESSIO, ACCES_COM_8S, acces_com_8x),
- EXAR_DEVICE(ACCESSIO, ACCES_COM232_8, acces_com_8x),
- EXAR_DEVICE(ACCESSIO, ACCES_COM_2SM, acces_com_2x),
- EXAR_DEVICE(ACCESSIO, ACCES_COM_4SM, acces_com_4x),
- EXAR_DEVICE(ACCESSIO, ACCES_COM_8SM, acces_com_8x),
-
+ EXAR_DEVICE(ACCESSIO, COM_2S, acces_com_2x),
+ EXAR_DEVICE(ACCESSIO, COM_4S, acces_com_4x),
+ EXAR_DEVICE(ACCESSIO, COM_8S, acces_com_8x),
+ EXAR_DEVICE(ACCESSIO, COM232_8, acces_com_8x),
+ EXAR_DEVICE(ACCESSIO, COM_2SM, acces_com_2x),
+ EXAR_DEVICE(ACCESSIO, COM_4SM, acces_com_4x),
+ EXAR_DEVICE(ACCESSIO, COM_8SM, acces_com_8x),
CONNECT_DEVICE(XR17C152, UART_2_232, pbn_connect),
CONNECT_DEVICE(XR17C154, UART_4_232, pbn_connect),
@@ -794,24 +791,24 @@ static const struct pci_device_id exar_pci_tbl[] = {
IBM_DEVICE(XR17C152, SATURN_SERIAL_ONE_PORT, pbn_exar_ibm_saturn),
/* Exar Corp. XR17C15[248] Dual/Quad/Octal UART */
- EXAR_DEVICE(EXAR, EXAR_XR17C152, pbn_exar_XR17C15x),
- EXAR_DEVICE(EXAR, EXAR_XR17C154, pbn_exar_XR17C15x),
- EXAR_DEVICE(EXAR, EXAR_XR17C158, pbn_exar_XR17C15x),
+ EXAR_DEVICE(EXAR, XR17C152, pbn_exar_XR17C15x),
+ EXAR_DEVICE(EXAR, XR17C154, pbn_exar_XR17C15x),
+ EXAR_DEVICE(EXAR, XR17C158, pbn_exar_XR17C15x),
/* Exar Corp. XR17V[48]35[248] Dual/Quad/Octal/Hexa PCIe UARTs */
- EXAR_DEVICE(EXAR, EXAR_XR17V352, pbn_exar_XR17V35x),
- EXAR_DEVICE(EXAR, EXAR_XR17V354, pbn_exar_XR17V35x),
- EXAR_DEVICE(EXAR, EXAR_XR17V358, pbn_exar_XR17V35x),
- EXAR_DEVICE(EXAR, EXAR_XR17V4358, pbn_exar_XR17V4358),
- EXAR_DEVICE(EXAR, EXAR_XR17V8358, pbn_exar_XR17V8358),
- EXAR_DEVICE(COMMTECH, COMMTECH_4222PCIE, pbn_exar_XR17V35x),
- EXAR_DEVICE(COMMTECH, COMMTECH_4224PCIE, pbn_exar_XR17V35x),
- EXAR_DEVICE(COMMTECH, COMMTECH_4228PCIE, pbn_exar_XR17V35x),
-
- EXAR_DEVICE(COMMTECH, COMMTECH_4222PCI335, pbn_fastcom335_2),
- EXAR_DEVICE(COMMTECH, COMMTECH_4224PCI335, pbn_fastcom335_4),
- EXAR_DEVICE(COMMTECH, COMMTECH_2324PCI335, pbn_fastcom335_4),
- EXAR_DEVICE(COMMTECH, COMMTECH_2328PCI335, pbn_fastcom335_8),
+ EXAR_DEVICE(EXAR, XR17V352, pbn_exar_XR17V35x),
+ EXAR_DEVICE(EXAR, XR17V354, pbn_exar_XR17V35x),
+ EXAR_DEVICE(EXAR, XR17V358, pbn_exar_XR17V35x),
+ EXAR_DEVICE(EXAR, XR17V4358, pbn_exar_XR17V4358),
+ EXAR_DEVICE(EXAR, XR17V8358, pbn_exar_XR17V8358),
+ EXAR_DEVICE(COMMTECH, 4222PCIE, pbn_exar_XR17V35x),
+ EXAR_DEVICE(COMMTECH, 4224PCIE, pbn_exar_XR17V35x),
+ EXAR_DEVICE(COMMTECH, 4228PCIE, pbn_exar_XR17V35x),
+
+ EXAR_DEVICE(COMMTECH, 4222PCI335, pbn_fastcom335_2),
+ EXAR_DEVICE(COMMTECH, 4224PCI335, pbn_fastcom335_4),
+ EXAR_DEVICE(COMMTECH, 2324PCI335, pbn_fastcom335_4),
+ EXAR_DEVICE(COMMTECH, 2328PCI335, pbn_fastcom335_8),
{ 0, }
};
MODULE_DEVICE_TABLE(pci, exar_pci_tbl);
diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c
index 31c91c2f8c6e..d1d253c4b518 100644
--- a/drivers/tty/serial/8250/8250_fintek.c
+++ b/drivers/tty/serial/8250/8250_fintek.c
@@ -19,6 +19,7 @@
#define CHIP_ID2 0x21
#define CHIP_ID_F81865 0x0407
#define CHIP_ID_F81866 0x1010
+#define CHIP_ID_F81966 0x0215
#define CHIP_ID_F81216AD 0x1602
#define CHIP_ID_F81216H 0x0501
#define CHIP_ID_F81216 0x0802
@@ -62,9 +63,9 @@
#define F81216_LDN_HIGH 0x4
/*
- * F81866 registers
+ * F81866/966 registers
*
- * The IRQ setting mode of F81866 is not the same with F81216 series.
+ * The IRQ setting mode of F81866/966 is not the same with F81216 series.
* Level/Low: IRQ_MODE0:0, IRQ_MODE1:0
* Edge/High: IRQ_MODE0:1, IRQ_MODE1:0
*
@@ -155,6 +156,7 @@ static int fintek_8250_check_id(struct fintek_8250 *pdata)
switch (chip) {
case CHIP_ID_F81865:
case CHIP_ID_F81866:
+ case CHIP_ID_F81966:
case CHIP_ID_F81216AD:
case CHIP_ID_F81216H:
case CHIP_ID_F81216:
@@ -171,6 +173,7 @@ static int fintek_8250_get_ldn_range(struct fintek_8250 *pdata, int *min,
int *max)
{
switch (pdata->pid) {
+ case CHIP_ID_F81966:
case CHIP_ID_F81865:
case CHIP_ID_F81866:
*min = F81866_LDN_LOW;
@@ -248,6 +251,7 @@ static void fintek_8250_set_irq_mode(struct fintek_8250 *pdata, bool is_level)
sio_write_reg(pdata, LDN, pdata->index);
switch (pdata->pid) {
+ case CHIP_ID_F81966:
case CHIP_ID_F81866:
sio_write_mask_reg(pdata, F81866_FIFO_CTRL, F81866_IRQ_MODE1,
0);
@@ -274,6 +278,7 @@ static void fintek_8250_set_max_fifo(struct fintek_8250 *pdata)
{
switch (pdata->pid) {
case CHIP_ID_F81216H: /* 128Bytes FIFO */
+ case CHIP_ID_F81966:
case CHIP_ID_F81866:
sio_write_mask_reg(pdata, FIFO_CTRL,
FIFO_MODE_MASK | RXFTHR_MODE_MASK,
@@ -291,6 +296,7 @@ static void fintek_8250_goto_highspeed(struct uart_8250_port *uart,
sio_write_reg(pdata, LDN, pdata->index);
switch (pdata->pid) {
+ case CHIP_ID_F81966:
case CHIP_ID_F81866: /* set uart clock for high speed serial mode */
sio_write_mask_reg(pdata, F81866_UART_CLK,
F81866_UART_CLK_MASK,
@@ -327,6 +333,7 @@ static void fintek_8250_set_termios(struct uart_port *port,
case CHIP_ID_F81216H:
reg = RS485;
break;
+ case CHIP_ID_F81966:
case CHIP_ID_F81866:
reg = F81866_UART_CLK;
break;
@@ -373,6 +380,7 @@ static void fintek_8250_set_termios_handler(struct uart_8250_port *uart)
switch (pdata->pid) {
case CHIP_ID_F81216H:
+ case CHIP_ID_F81966:
case CHIP_ID_F81866:
uart->port.set_termios = fintek_8250_set_termios;
break;
@@ -443,6 +451,7 @@ static void fintek_8250_set_rs485_handler(struct uart_8250_port *uart)
switch (pdata->pid) {
case CHIP_ID_F81216AD:
case CHIP_ID_F81216H:
+ case CHIP_ID_F81966:
case CHIP_ID_F81866:
case CHIP_ID_F81865:
uart->port.rs485_config = fintek_8250_rs485_config;
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index f77bf820b7a3..1632f7d25acc 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -681,6 +681,9 @@ int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485)
memset(rs485->padding, 0, sizeof(rs485->padding));
port->rs485 = *rs485;
+ gpiod_set_value(port->rs485_term_gpio,
+ rs485->flags & SER_RS485_TERMINATE_BUS);
+
/*
* Both serial8250_em485_init() and serial8250_em485_destroy()
* are idempotent.
@@ -1432,7 +1435,7 @@ static void serial8250_stop_rx(struct uart_port *port)
/**
* serial8250_em485_stop_tx() - generic ->rs485_stop_tx() callback
- * @up: uart 8250 port
+ * @p: uart 8250 port
*
* Generic callback usable by 8250 uart drivers to stop rs485 transmission.
*/
@@ -2615,6 +2618,8 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port,
struct ktermios *termios,
struct ktermios *old)
{
+ unsigned int tolerance = port->uartclk / 100;
+
/*
* Ask the core to calculate the divisor for us.
* Allow 1% tolerance at the upper limit so uart clks marginally
@@ -2623,7 +2628,7 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port,
*/
return uart_get_baud_rate(port, termios, old,
port->uartclk / 16 / UART_DIV_MAX,
- port->uartclk);
+ (port->uartclk + tolerance) / 16);
}
void
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index af0688156dd0..8195a31519ea 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -63,6 +63,7 @@ config SERIAL_8250_PNP
config SERIAL_8250_16550A_VARIANTS
bool "Support for variants of the 16550A serial port"
depends on SERIAL_8250
+ default !X86
help
The 8250 driver can probe for many variants of the venerable 16550A
serial port. Doing so takes additional time at boot.
diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c
index c8186a05a453..e3d10794dbba 100644
--- a/drivers/tty/serial/8250/serial_cs.c
+++ b/drivers/tty/serial/8250/serial_cs.c
@@ -440,7 +440,7 @@ static int simple_config_check_notpicky(struct pcmcia_device *p_dev,
static int simple_config(struct pcmcia_device *link)
{
struct serial_info *info = link->priv;
- int i = -ENODEV, try;
+ int ret, try;
/*
* First pass: look for a config entry that looks normal.
@@ -472,8 +472,8 @@ found_port:
if (info->quirk && info->quirk->config)
info->quirk->config(link);
- i = pcmcia_enable_device(link);
- if (i != 0)
+ ret = pcmcia_enable_device(link);
+ if (ret != 0)
return -1;
return setup_serial(link, info, link->resource[0]->start, link->irq);
}
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index adf9e80e7dc9..0282ad9cdaa7 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1034,13 +1034,22 @@ config SERIAL_SIFIVE_CONSOLE
boot time.)
config SERIAL_LANTIQ
- bool "Lantiq serial driver"
- depends on LANTIQ
+ tristate "Lantiq serial driver"
+ depends on (LANTIQ || X86) || COMPILE_TEST
select SERIAL_CORE
+ help
+ Support for UART on Lantiq and Intel SoCs.
+ To compile this driver as a module, select M here. The
+ module will be called lantiq.
+
+config SERIAL_LANTIQ_CONSOLE
+ bool "Console on Lantiq UART"
+ depends on SERIAL_LANTIQ=y
select SERIAL_CORE_CONSOLE
select SERIAL_EARLYCON
help
- Support for console and UART on Lantiq SoCs.
+ Select this option if you would like to use a Lantiq UART as the
+ system console.
config SERIAL_QE
tristate "Freescale QUICC Engine serial port support"
@@ -1462,6 +1471,7 @@ config SERIAL_STM32
tristate "STMicroelectronics STM32 serial port support"
select SERIAL_CORE
depends on ARCH_STM32 || COMPILE_TEST
+ select SERIAL_MCTRL_GPIO if GPIOLIB
help
This driver is for the on-chip Serial Controller on
STMicroelectronics STM32 MCUs.
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index c010f639298d..8efd7c2a34fe 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -2607,6 +2607,7 @@ static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap,
uap->port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_AMBA_PL011_CONSOLE);
uap->port.flags = UPF_BOOT_AUTOCONF;
uap->port.line = index;
+ spin_lock_init(&uap->port.lock);
amba_ports[index] = uap;
diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c
index 7e7f1398019f..0c80a79d7442 100644
--- a/drivers/tty/serial/ar933x_uart.c
+++ b/drivers/tty/serial/ar933x_uart.c
@@ -766,8 +766,6 @@ 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;
@@ -786,6 +784,10 @@ 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);
+ ret = uart_get_rs485_mode(port);
+ if (ret)
+ goto err_disable_clk;
+
up->gpios = mctrl_gpio_init(port, 0);
if (IS_ERR(up->gpios) && PTR_ERR(up->gpios) != -ENOSYS)
return PTR_ERR(up->gpios);
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 8d7080efad9b..e43471b33710 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -2491,8 +2491,6 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
atmel_init_property(atmel_port, pdev);
atmel_set_ops(port);
- uart_get_rs485_mode(&mpdev->dev, &port->rs485);
-
port->iotype = UPIO_MEM;
port->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
port->ops = &atmel_pops;
@@ -2506,6 +2504,10 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring));
+ ret = uart_get_rs485_mode(port);
+ if (ret)
+ return ret;
+
/* for console, the clock could already be configured */
if (!atmel_port->clk) {
atmel_port->clk = clk_get(&mpdev->dev, "usart");
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 5d41075964f2..90298c403042 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -1231,9 +1231,7 @@ static void lpuart_dma_rx_free(struct uart_port *port)
struct lpuart_port, port);
struct dma_chan *chan = sport->dma_rx_chan;
- if (chan)
- dmaengine_terminate_all(chan);
-
+ dmaengine_terminate_all(chan);
dma_unmap_sg(chan->device->dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE);
kfree(sport->rx_ring.buf);
sport->rx_ring.tail = 0;
@@ -1514,17 +1512,17 @@ static void lpuart_request_dma(struct lpuart_port *sport)
{
sport->dma_tx_chan = dma_request_chan(sport->port.dev, "tx");
if (IS_ERR(sport->dma_tx_chan)) {
- dev_info_once(sport->port.dev,
- "DMA tx channel request failed, operating without tx DMA (%ld)\n",
- PTR_ERR(sport->dma_tx_chan));
+ dev_dbg_once(sport->port.dev,
+ "DMA tx channel request failed, operating without tx DMA (%ld)\n",
+ PTR_ERR(sport->dma_tx_chan));
sport->dma_tx_chan = NULL;
}
sport->dma_rx_chan = dma_request_chan(sport->port.dev, "rx");
if (IS_ERR(sport->dma_rx_chan)) {
- dev_info_once(sport->port.dev,
- "DMA rx channel request failed, operating without rx DMA (%ld)\n",
- PTR_ERR(sport->dma_rx_chan));
+ dev_dbg_once(sport->port.dev,
+ "DMA rx channel request failed, operating without rx DMA (%ld)\n",
+ PTR_ERR(sport->dma_rx_chan));
sport->dma_rx_chan = NULL;
}
}
@@ -2621,7 +2619,9 @@ static int lpuart_probe(struct platform_device *pdev)
if (ret)
goto failed_attach_port;
- uart_get_rs485_mode(&pdev->dev, &sport->port.rs485);
+ ret = uart_get_rs485_mode(&sport->port);
+ if (ret)
+ goto failed_get_rs485;
if (sport->port.rs485.flags & SER_RS485_RX_DURING_TX)
dev_err(&pdev->dev, "driver doesn't support RX during TX\n");
@@ -2634,6 +2634,7 @@ static int lpuart_probe(struct platform_device *pdev)
return 0;
+failed_get_rs485:
failed_attach_port:
failed_irq_request:
lpuart_disable_clks(sport);
@@ -2664,8 +2665,7 @@ static int lpuart_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
-static int lpuart_suspend(struct device *dev)
+static int __maybe_unused lpuart_suspend(struct device *dev)
{
struct lpuart_port *sport = dev_get_drvdata(dev);
unsigned long temp;
@@ -2723,7 +2723,7 @@ static int lpuart_suspend(struct device *dev)
return 0;
}
-static int lpuart_resume(struct device *dev)
+static int __maybe_unused lpuart_resume(struct device *dev)
{
struct lpuart_port *sport = dev_get_drvdata(dev);
bool irq_wake = irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq));
@@ -2754,7 +2754,6 @@ static int lpuart_resume(struct device *dev)
return 0;
}
-#endif
static SIMPLE_DEV_PM_OPS(lpuart_pm_ops, lpuart_suspend, lpuart_resume);
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index f4d68109bc8b..1265e8d86d8a 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -909,6 +909,8 @@ static irqreturn_t imx_uart_int(int irq, void *dev_id)
usr2 &= ~USR2_ORE;
if (usr1 & (USR1_RRDY | USR1_AGTIM)) {
+ imx_uart_writel(sport, USR1_AGTIM, USR1);
+
__imx_uart_rxint(irq, dev_id);
ret = IRQ_HANDLED;
}
@@ -2252,6 +2254,8 @@ static int imx_uart_probe(struct platform_device *pdev)
return PTR_ERR(base);
rxirq = platform_get_irq(pdev, 0);
+ if (rxirq < 0)
+ return rxirq;
txirq = platform_get_irq_optional(pdev, 1);
rtsirq = platform_get_irq_optional(pdev, 2);
@@ -2302,7 +2306,11 @@ static int imx_uart_probe(struct platform_device *pdev)
sport->ucr4 = readl(sport->port.membase + UCR4);
sport->ufcr = readl(sport->port.membase + UFCR);
- uart_get_rs485_mode(&pdev->dev, &sport->port.rs485);
+ ret = uart_get_rs485_mode(&sport->port);
+ if (ret) {
+ clk_disable_unprepare(sport->clk_ipg);
+ return ret;
+ }
if (sport->port.rs485.flags & SER_RS485_ENABLED &&
(!sport->have_rtscts && !sport->have_rtsgpio))
@@ -2398,6 +2406,9 @@ static int imx_uart_probe(struct platform_device *pdev)
}
}
+ /* We need to initialize lock even for non-registered console */
+ spin_lock_init(&sport->port.lock);
+
imx_uart_ports[sport->port.line] = sport;
platform_set_drvdata(pdev, sport);
diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c
index c5e46ff972e4..62813e421f12 100644
--- a/drivers/tty/serial/lantiq.c
+++ b/drivers/tty/serial/lantiq.c
@@ -15,6 +15,7 @@
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/lantiq.h>
+#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
@@ -597,6 +598,7 @@ static const struct uart_ops lqasc_pops = {
.verify_port = lqasc_verify_port,
};
+#ifdef CONFIG_SERIAL_LANTIQ_CONSOLE
static void
lqasc_console_putchar(struct uart_port *port, int ch)
{
@@ -705,6 +707,14 @@ lqasc_serial_early_console_setup(struct earlycon_device *device,
OF_EARLYCON_DECLARE(lantiq, "lantiq,asc", lqasc_serial_early_console_setup);
OF_EARLYCON_DECLARE(lantiq, "intel,lgm-asc", lqasc_serial_early_console_setup);
+#define LANTIQ_SERIAL_CONSOLE (&lqasc_console)
+
+#else
+
+#define LANTIQ_SERIAL_CONSOLE NULL
+
+#endif /* CONFIG_SERIAL_LANTIQ_CONSOLE */
+
static struct uart_driver lqasc_reg = {
.owner = THIS_MODULE,
.driver_name = DRVNAME,
@@ -712,7 +722,7 @@ static struct uart_driver lqasc_reg = {
.major = 0,
.minor = 0,
.nr = MAXPORTS,
- .cons = &lqasc_console,
+ .cons = LANTIQ_SERIAL_CONSOLE,
};
static int fetch_irq_lantiq(struct device *dev, struct ltq_uart_port *ltq_port)
@@ -814,8 +824,7 @@ static void free_irq_intel(struct uart_port *port)
free_irq(ltq_port->common_irq, port);
}
-static int __init
-lqasc_probe(struct platform_device *pdev)
+static int lqasc_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
struct ltq_uart_port *ltq_port;
@@ -899,6 +908,13 @@ lqasc_probe(struct platform_device *pdev)
return ret;
}
+static int lqasc_remove(struct platform_device *pdev)
+{
+ struct uart_port *port = platform_get_drvdata(pdev);
+
+ return uart_remove_one_port(&lqasc_reg, port);
+}
+
static const struct ltq_soc_data soc_data_lantiq = {
.fetch_irq = fetch_irq_lantiq,
.request_irq = request_irq_lantiq,
@@ -916,8 +932,11 @@ static const struct of_device_id ltq_asc_match[] = {
{ .compatible = "intel,lgm-asc", .data = &soc_data_intel },
{},
};
+MODULE_DEVICE_TABLE(of, ltq_asc_match);
static struct platform_driver lqasc_driver = {
+ .probe = lqasc_probe,
+ .remove = lqasc_remove,
.driver = {
.name = DRVNAME,
.of_match_table = ltq_asc_match,
@@ -933,10 +952,21 @@ init_lqasc(void)
if (ret != 0)
return ret;
- ret = platform_driver_probe(&lqasc_driver, lqasc_probe);
+ ret = platform_driver_register(&lqasc_driver);
if (ret != 0)
uart_unregister_driver(&lqasc_reg);
return ret;
}
-device_initcall(init_lqasc);
+
+static void __exit exit_lqasc(void)
+{
+ platform_driver_unregister(&lqasc_driver);
+ uart_unregister_driver(&lqasc_reg);
+}
+
+module_init(init_lqasc);
+module_exit(exit_lqasc);
+
+MODULE_DESCRIPTION("Serial driver for Lantiq & Intel gateway SoCs");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c
index 9a836dcac157..b5898c932036 100644
--- a/drivers/tty/serial/lpc32xx_hs.c
+++ b/drivers/tty/serial/lpc32xx_hs.c
@@ -23,7 +23,6 @@
#include <linux/nmi.h>
#include <linux/io.h>
#include <linux/irq.h>
-#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/sizes.h>
#include <linux/soc/nxp/lpc32xx-misc.h>
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index f7d6b3c9ea45..8573fc9cb0cd 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -33,8 +33,7 @@
#include <linux/pm_wakeirq.h>
#include <linux/of.h>
#include <linux/of_irq.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/platform_data/serial-omap.h>
#define OMAP_MAX_HSUART_PORTS 10
@@ -153,7 +152,7 @@ struct uart_omap_port {
u32 errata;
u32 features;
- int rts_gpio;
+ struct gpio_desc *rts_gpiod;
struct pm_qos_request pm_qos_request;
u32 latency;
@@ -303,11 +302,11 @@ static void serial_omap_stop_tx(struct uart_port *port)
serial_out(up, UART_OMAP_SCR, up->scr);
res = (port->rs485.flags & SER_RS485_RTS_AFTER_SEND) ?
1 : 0;
- if (gpio_get_value(up->rts_gpio) != res) {
+ if (gpiod_get_value(up->rts_gpiod) != res) {
if (port->rs485.delay_rts_after_send > 0)
mdelay(
port->rs485.delay_rts_after_send);
- gpio_set_value(up->rts_gpio, res);
+ gpiod_set_value(up->rts_gpiod, res);
}
} else {
/* We're asked to stop, but there's still stuff in the
@@ -412,8 +411,8 @@ static void serial_omap_start_tx(struct uart_port *port)
/* if rts not already enabled */
res = (port->rs485.flags & SER_RS485_RTS_ON_SEND) ? 1 : 0;
- if (gpio_get_value(up->rts_gpio) != res) {
- gpio_set_value(up->rts_gpio, res);
+ if (gpiod_get_value(up->rts_gpiod) != res) {
+ gpiod_set_value(up->rts_gpiod, res);
if (port->rs485.delay_rts_before_send > 0)
mdelay(port->rs485.delay_rts_before_send);
}
@@ -1414,12 +1413,12 @@ serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
* Just as a precaution, only allow rs485
* to be enabled if the gpio pin is valid
*/
- if (gpio_is_valid(up->rts_gpio)) {
+ if (up->rts_gpiod) {
/* enable / disable rts */
val = (port->rs485.flags & SER_RS485_ENABLED) ?
SER_RS485_RTS_AFTER_SEND : SER_RS485_RTS_ON_SEND;
val = (port->rs485.flags & val) ? 1 : 0;
- gpio_set_value(up->rts_gpio, val);
+ gpiod_set_value(up->rts_gpiod, val);
} else
port->rs485.flags &= ~SER_RS485_ENABLED;
@@ -1596,18 +1595,22 @@ static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev)
}
static int serial_omap_probe_rs485(struct uart_omap_port *up,
- struct device_node *np)
+ struct device *dev)
{
struct serial_rs485 *rs485conf = &up->port.rs485;
+ struct device_node *np = dev->of_node;
+ enum gpiod_flags gflags;
int ret;
rs485conf->flags = 0;
- up->rts_gpio = -EINVAL;
+ up->rts_gpiod = NULL;
if (!np)
return 0;
- uart_get_rs485_mode(up->dev, rs485conf);
+ ret = uart_get_rs485_mode(&up->port);
+ if (ret)
+ return ret;
if (of_property_read_bool(np, "rs485-rts-active-high")) {
rs485conf->flags |= SER_RS485_RTS_ON_SEND;
@@ -1618,19 +1621,20 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up,
}
/* check for tx enable gpio */
- up->rts_gpio = of_get_named_gpio(np, "rts-gpio", 0);
- if (gpio_is_valid(up->rts_gpio)) {
- ret = devm_gpio_request(up->dev, up->rts_gpio, "omap-serial");
- if (ret < 0)
- return ret;
- ret = rs485conf->flags & SER_RS485_RTS_AFTER_SEND ? 1 : 0;
- ret = gpio_direction_output(up->rts_gpio, ret);
- if (ret < 0)
+ gflags = rs485conf->flags & SER_RS485_RTS_AFTER_SEND ?
+ GPIOD_OUT_HIGH : GPIOD_OUT_LOW;
+ up->rts_gpiod = devm_gpiod_get_optional(dev, "rts", gflags);
+ if (IS_ERR(up->rts_gpiod)) {
+ ret = PTR_ERR(up->rts_gpiod);
+ if (ret == -EPROBE_DEFER)
return ret;
- } else if (up->rts_gpio == -EPROBE_DEFER) {
- return -EPROBE_DEFER;
+ /*
+ * FIXME: the code historically ignored any other error than
+ * -EPROBE_DEFER and just went on without GPIO.
+ */
+ up->rts_gpiod = NULL;
} else {
- up->rts_gpio = -EINVAL;
+ gpiod_set_consumer_name(up->rts_gpiod, "omap-serial");
}
return 0;
@@ -1703,7 +1707,7 @@ static int serial_omap_probe(struct platform_device *pdev)
dev_info(up->port.dev, "no wakeirq for uart%d\n",
up->port.line);
- ret = serial_omap_probe_rs485(up, pdev->dev.of_node);
+ ret = serial_omap_probe_rs485(up, &pdev->dev);
if (ret < 0)
goto err_rs485;
diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c
index 6bace1c6bb09..457c0bf8cbf8 100644
--- a/drivers/tty/serial/qcom_geni_serial.c
+++ b/drivers/tty/serial/qcom_geni_serial.c
@@ -141,9 +141,10 @@ static void qcom_geni_serial_stop_rx(struct uart_port *uport);
static void qcom_geni_serial_handle_rx(struct uart_port *uport, bool drop);
static const unsigned long root_freq[] = {7372800, 14745600, 19200000, 29491200,
- 32000000, 48000000, 64000000, 80000000,
- 96000000, 100000000, 102400000,
- 112000000, 120000000, 128000000};
+ 32000000, 48000000, 51200000, 64000000,
+ 80000000, 96000000, 100000000,
+ 102400000, 112000000, 120000000,
+ 128000000};
#define to_dev_port(ptr, member) \
container_of(ptr, struct qcom_geni_serial_port, member)
diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c
index 73f951d65b93..d913d9b2762a 100644
--- a/drivers/tty/serial/samsung_tty.c
+++ b/drivers/tty/serial/samsung_tty.c
@@ -154,10 +154,33 @@ struct s3c24xx_uart_port {
#define portaddrl(port, reg) \
((unsigned long *)(unsigned long)((port)->membase + (reg)))
-#define rd_regb(port, reg) (readb_relaxed(portaddr(port, reg)))
+static u32 rd_reg(struct uart_port *port, u32 reg)
+{
+ switch (port->iotype) {
+ case UPIO_MEM:
+ return readb_relaxed(portaddr(port, reg));
+ case UPIO_MEM32:
+ return readl_relaxed(portaddr(port, reg));
+ default:
+ return 0;
+ }
+ return 0;
+}
+
#define rd_regl(port, reg) (readl_relaxed(portaddr(port, reg)))
-#define wr_regb(port, reg, val) writeb_relaxed(val, portaddr(port, reg))
+static void wr_reg(struct uart_port *port, u32 reg, u32 val)
+{
+ switch (port->iotype) {
+ case UPIO_MEM:
+ writeb_relaxed(val, portaddr(port, reg));
+ break;
+ case UPIO_MEM32:
+ writel_relaxed(val, portaddr(port, reg));
+ break;
+ }
+}
+
#define wr_regl(port, reg, val) writel_relaxed(val, portaddr(port, reg))
/* Byte-order aware bit setting/clearing functions. */
@@ -714,7 +737,7 @@ static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport)
fifocnt--;
uerstat = rd_regl(port, S3C2410_UERSTAT);
- ch = rd_regb(port, S3C2410_URXH);
+ ch = rd_reg(port, S3C2410_URXH);
if (port->flags & UPF_CONS_FLOW) {
int txe = s3c24xx_serial_txempty_nofifo(port);
@@ -826,7 +849,7 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
}
if (port->x_char) {
- wr_regb(port, S3C2410_UTXH, port->x_char);
+ wr_reg(port, S3C2410_UTXH, port->x_char);
port->icount.tx++;
port->x_char = 0;
goto out;
@@ -852,7 +875,7 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)
break;
- wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]);
+ wr_reg(port, S3C2410_UTXH, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
count--;
@@ -916,7 +939,7 @@ static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port)
/* no modem control lines */
static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port)
{
- unsigned int umstat = rd_regb(port, S3C2410_UMSTAT);
+ unsigned int umstat = rd_reg(port, S3C2410_UMSTAT);
if (umstat & S3C2410_UMSTAT_CTS)
return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
@@ -1281,14 +1304,14 @@ static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport,
struct s3c24xx_uart_info *info = ourport->info;
struct clk *clk;
unsigned long rate;
- unsigned int cnt, baud, quot, clk_sel, best_quot = 0;
+ unsigned int cnt, baud, quot, best_quot = 0;
char clkname[MAX_CLK_NAME_LENGTH];
int calc_deviation, deviation = (1 << 30) - 1;
- clk_sel = (ourport->cfg->clk_sel) ? ourport->cfg->clk_sel :
- ourport->info->def_clk_sel;
for (cnt = 0; cnt < info->num_clks; cnt++) {
- if (!(clk_sel & (1 << cnt)))
+ /* Keep selected clock if provided */
+ if (ourport->cfg->clk_sel &&
+ !(ourport->cfg->clk_sel & (1 << cnt)))
continue;
sprintf(clkname, "clk_uart_baud%d", cnt);
@@ -1974,7 +1997,7 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
struct s3c24xx_uart_port *ourport;
int index = probe_index;
- int ret;
+ int ret, prop = 0;
if (np) {
ret = of_alias_get_id(np, "serial");
@@ -2000,10 +2023,27 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
dev_get_platdata(&pdev->dev) :
ourport->drv_data->def_cfg;
- if (np)
+ if (np) {
of_property_read_u32(np,
"samsung,uart-fifosize", &ourport->port.fifosize);
+ if (of_property_read_u32(np, "reg-io-width", &prop) == 0) {
+ switch (prop) {
+ case 1:
+ ourport->port.iotype = UPIO_MEM;
+ break;
+ case 4:
+ ourport->port.iotype = UPIO_MEM32;
+ break;
+ default:
+ dev_warn(&pdev->dev, "unsupported reg-io-width (%d)\n",
+ prop);
+ ret = -EINVAL;
+ break;
+ }
+ }
+ }
+
if (ourport->drv_data->fifosize[index])
ourport->port.fifosize = ourport->drv_data->fifosize[index];
else if (ourport->info->fifosize)
@@ -2185,7 +2225,7 @@ static int s3c24xx_serial_get_poll_char(struct uart_port *port)
if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0)
return NO_POLL_CHAR;
- return rd_regb(port, S3C2410_URXH);
+ return rd_reg(port, S3C2410_URXH);
}
static void s3c24xx_serial_put_poll_char(struct uart_port *port,
@@ -2200,7 +2240,7 @@ static void s3c24xx_serial_put_poll_char(struct uart_port *port,
while (!s3c24xx_serial_console_txrdy(port, ufcon))
cpu_relax();
- wr_regb(port, S3C2410_UTXH, c);
+ wr_reg(port, S3C2410_UTXH, c);
}
#endif /* CONFIG_CONSOLE_POLL */
@@ -2212,7 +2252,7 @@ s3c24xx_serial_console_putchar(struct uart_port *port, int ch)
while (!s3c24xx_serial_console_txrdy(port, ufcon))
cpu_relax();
- wr_regb(port, S3C2410_UTXH, ch);
+ wr_reg(port, S3C2410_UTXH, ch);
}
static void
@@ -2587,6 +2627,18 @@ module_platform_driver(samsung_serial_driver);
* Early console.
*/
+static void wr_reg_barrier(struct uart_port *port, u32 reg, u32 val)
+{
+ switch (port->iotype) {
+ case UPIO_MEM:
+ writeb(val, portaddr(port, reg));
+ break;
+ case UPIO_MEM32:
+ writel(val, portaddr(port, reg));
+ break;
+ }
+}
+
struct samsung_early_console_data {
u32 txfull_mask;
};
@@ -2612,7 +2664,7 @@ static void samsung_early_putc(struct uart_port *port, int c)
else
samsung_early_busyuart(port);
- writeb(c, port->membase + S3C2410_UTXH);
+ wr_reg_barrier(port, S3C2410_UTXH, c);
}
static void samsung_early_write(struct console *con, const char *s,
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index 06e8071d5601..d2e5c6c86643 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -315,6 +315,7 @@ struct sc16is7xx_one {
struct kthread_work tx_work;
struct kthread_work reg_work;
struct sc16is7xx_one_config config;
+ bool irda_mode;
};
struct sc16is7xx_port {
@@ -327,7 +328,6 @@ struct sc16is7xx_port {
unsigned char buf[SC16IS7XX_FIFO_SIZE];
struct kthread_worker kworker;
struct task_struct *kworker_task;
- struct kthread_work irq_work;
struct mutex efr_lock;
struct sc16is7xx_one p[];
};
@@ -710,9 +710,9 @@ static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
return true;
}
-static void sc16is7xx_ist(struct kthread_work *ws)
+static irqreturn_t sc16is7xx_irq(int irq, void *dev_id)
{
- struct sc16is7xx_port *s = to_sc16is7xx_port(ws, irq_work);
+ struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id;
mutex_lock(&s->efr_lock);
@@ -727,13 +727,6 @@ static void sc16is7xx_ist(struct kthread_work *ws)
}
mutex_unlock(&s->efr_lock);
-}
-
-static irqreturn_t sc16is7xx_irq(int irq, void *dev_id)
-{
- struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id;
-
- kthread_queue_work(&s->kworker, &s->irq_work);
return IRQ_HANDLED;
}
@@ -994,6 +987,7 @@ static int sc16is7xx_config_rs485(struct uart_port *port,
static int sc16is7xx_startup(struct uart_port *port)
{
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
unsigned int val;
@@ -1032,6 +1026,13 @@ static int sc16is7xx_startup(struct uart_port *port)
/* Now, initialize the UART */
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, SC16IS7XX_LCR_WORD_LEN_8);
+ /* Enable IrDA mode if requested in DT */
+ /* This bit must be written with LCR[7] = 0 */
+ sc16is7xx_port_update(port, SC16IS7XX_MCR_REG,
+ SC16IS7XX_MCR_IRDA_BIT,
+ one->irda_mode ?
+ SC16IS7XX_MCR_IRDA_BIT : 0);
+
/* Enable the Rx and Tx FIFO */
sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG,
SC16IS7XX_EFCR_RXDISABLE_BIT |
@@ -1176,10 +1177,11 @@ static int sc16is7xx_gpio_direction_output(struct gpio_chip *chip,
static int sc16is7xx_probe(struct device *dev,
const struct sc16is7xx_devtype *devtype,
- struct regmap *regmap, int irq, unsigned long flags)
+ struct regmap *regmap, int irq)
{
struct sched_param sched_param = { .sched_priority = MAX_RT_PRIO / 2 };
unsigned long freq = 0, *pfreq = dev_get_platdata(dev);
+ unsigned int val;
u32 uartclk = 0;
int i, ret;
struct sc16is7xx_port *s;
@@ -1187,6 +1189,16 @@ static int sc16is7xx_probe(struct device *dev,
if (IS_ERR(regmap))
return PTR_ERR(regmap);
+ /*
+ * This device does not have an identification register that would
+ * tell us if we are really connected to the correct device.
+ * The best we can do is to check if communication is at all possible.
+ */
+ ret = regmap_read(regmap,
+ SC16IS7XX_LSR_REG << SC16IS7XX_REG_SHIFT, &val);
+ if (ret < 0)
+ return ret;
+
/* Alloc port structure */
s = devm_kzalloc(dev, struct_size(s, p, devtype->nr_uart), GFP_KERNEL);
if (!s) {
@@ -1221,7 +1233,6 @@ static int sc16is7xx_probe(struct device *dev,
mutex_init(&s->efr_lock);
kthread_init_worker(&s->kworker);
- kthread_init_work(&s->irq_work, sc16is7xx_ist);
s->kworker_task = kthread_run(kthread_worker_fn, &s->kworker,
"sc16is7xx");
if (IS_ERR(s->kworker_task)) {
@@ -1302,9 +1313,33 @@ static int sc16is7xx_probe(struct device *dev,
sc16is7xx_power(&s->p[i].port, 0);
}
- /* Setup interrupt */
- ret = devm_request_irq(dev, irq, sc16is7xx_irq,
- flags, dev_name(dev), s);
+ if (dev->of_node) {
+ struct property *prop;
+ const __be32 *p;
+ u32 u;
+
+ of_property_for_each_u32(dev->of_node, "irda-mode-ports",
+ prop, p, u)
+ if (u < devtype->nr_uart)
+ s->p[u].irda_mode = true;
+ }
+
+ /*
+ * Setup interrupt. We first try to acquire the IRQ line as level IRQ.
+ * If that succeeds, we can allow sharing the interrupt as well.
+ * In case the interrupt controller doesn't support that, we fall
+ * back to a non-shared falling-edge trigger.
+ */
+ ret = devm_request_threaded_irq(dev, irq, NULL, sc16is7xx_irq,
+ IRQF_TRIGGER_LOW | IRQF_SHARED |
+ IRQF_ONESHOT,
+ dev_name(dev), s);
+ if (!ret)
+ return 0;
+
+ ret = devm_request_threaded_irq(dev, irq, NULL, sc16is7xx_irq,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ dev_name(dev), s);
if (!ret)
return 0;
@@ -1378,7 +1413,6 @@ static struct regmap_config regcfg = {
static int sc16is7xx_spi_probe(struct spi_device *spi)
{
const struct sc16is7xx_devtype *devtype;
- unsigned long flags = 0;
struct regmap *regmap;
int ret;
@@ -1399,14 +1433,13 @@ static int sc16is7xx_spi_probe(struct spi_device *spi)
const struct spi_device_id *id_entry = spi_get_device_id(spi);
devtype = (struct sc16is7xx_devtype *)id_entry->driver_data;
- flags = IRQF_TRIGGER_FALLING;
}
regcfg.max_register = (0xf << SC16IS7XX_REG_SHIFT) |
(devtype->nr_uart - 1);
regmap = devm_regmap_init_spi(spi, &regcfg);
- return sc16is7xx_probe(&spi->dev, devtype, regmap, spi->irq, flags);
+ return sc16is7xx_probe(&spi->dev, devtype, regmap, spi->irq);
}
static int sc16is7xx_spi_remove(struct spi_device *spi)
@@ -1445,7 +1478,6 @@ static int sc16is7xx_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
const struct sc16is7xx_devtype *devtype;
- unsigned long flags = 0;
struct regmap *regmap;
if (i2c->dev.of_node) {
@@ -1454,14 +1486,13 @@ static int sc16is7xx_i2c_probe(struct i2c_client *i2c,
return -ENODEV;
} else {
devtype = (struct sc16is7xx_devtype *)id->driver_data;
- flags = IRQF_TRIGGER_FALLING;
}
regcfg.max_register = (0xf << SC16IS7XX_REG_SHIFT) |
(devtype->nr_uart - 1);
regmap = devm_regmap_init_i2c(i2c, &regcfg);
- return sc16is7xx_probe(&i2c->dev, devtype, regmap, i2c->irq, flags);
+ return sc16is7xx_probe(&i2c->dev, devtype, regmap, i2c->irq);
}
static int sc16is7xx_i2c_remove(struct i2c_client *client)
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 66a5e2faf57e..57840cf90388 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -3295,8 +3295,10 @@ EXPORT_SYMBOL(uart_remove_one_port);
* This function implements the device tree binding described in
* Documentation/devicetree/bindings/serial/rs485.txt.
*/
-void uart_get_rs485_mode(struct device *dev, struct serial_rs485 *rs485conf)
+int uart_get_rs485_mode(struct uart_port *port)
{
+ struct serial_rs485 *rs485conf = &port->rs485;
+ struct device *dev = port->dev;
u32 rs485_delay[2];
int ret;
@@ -3315,6 +3317,7 @@ void uart_get_rs485_mode(struct device *dev, struct serial_rs485 *rs485conf)
* to get to a defined state with the following properties:
*/
rs485conf->flags &= ~(SER_RS485_RX_DURING_TX | SER_RS485_ENABLED |
+ SER_RS485_TERMINATE_BUS |
SER_RS485_RTS_AFTER_SEND);
rs485conf->flags |= SER_RS485_RTS_ON_SEND;
@@ -3328,6 +3331,23 @@ void uart_get_rs485_mode(struct device *dev, struct serial_rs485 *rs485conf)
rs485conf->flags &= ~SER_RS485_RTS_ON_SEND;
rs485conf->flags |= SER_RS485_RTS_AFTER_SEND;
}
+
+ /*
+ * Disabling termination by default is the safe choice: Else if many
+ * bus participants enable it, no communication is possible at all.
+ * Works fine for short cables and users may enable for longer cables.
+ */
+ port->rs485_term_gpio = devm_gpiod_get_optional(dev, "rs485-term",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(port->rs485_term_gpio)) {
+ ret = PTR_ERR(port->rs485_term_gpio);
+ port->rs485_term_gpio = NULL;
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Cannot get rs485-term-gpios\n");
+ return ret;
+ }
+
+ return 0;
}
EXPORT_SYMBOL_GPL(uart_get_rs485_mode);
diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h
index 0b9e804e61a9..c0dfe4382898 100644
--- a/drivers/tty/serial/sh-sci.h
+++ b/drivers/tty/serial/sh-sci.h
@@ -2,7 +2,6 @@
#include <linux/bitops.h>
#include <linux/serial_core.h>
#include <linux/io.h>
-#include <linux/gpio.h>
#define SCI_MAJOR 204
#define SCI_MINOR_START 8
diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 5e93e8d40f59..8602ff357321 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -31,6 +31,7 @@
#include <linux/tty_flip.h>
#include <linux/tty.h>
+#include "serial_mctrl_gpio.h"
#include "stm32-usart.h"
static void stm32_stop_tx(struct uart_port *port);
@@ -158,9 +159,7 @@ static int stm32_init_rs485(struct uart_port *port,
if (!pdev->dev.of_node)
return -ENODEV;
- uart_get_rs485_mode(&pdev->dev, rs485conf);
-
- return 0;
+ return uart_get_rs485_mode(port);
}
static int stm32_pending_rx(struct uart_port *port, u32 *sr, int *last_res,
@@ -510,12 +509,29 @@ static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl)
stm32_set_bits(port, ofs->cr3, USART_CR3_RTSE);
else
stm32_clr_bits(port, ofs->cr3, USART_CR3_RTSE);
+
+ mctrl_gpio_set(stm32_port->gpios, mctrl);
}
static unsigned int stm32_get_mctrl(struct uart_port *port)
{
+ struct stm32_port *stm32_port = to_stm32_port(port);
+ unsigned int ret;
+
/* This routine is used to get signals of: DCD, DSR, RI, and CTS */
- return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+ ret = TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+
+ return mctrl_gpio_get(stm32_port->gpios, &ret);
+}
+
+static void stm32_enable_ms(struct uart_port *port)
+{
+ mctrl_gpio_enable_ms(to_stm32_port(port)->gpios);
+}
+
+static void stm32_disable_ms(struct uart_port *port)
+{
+ mctrl_gpio_disable_ms(to_stm32_port(port)->gpios);
}
/* Transmit stop */
@@ -626,6 +642,9 @@ static void stm32_shutdown(struct uart_port *port)
u32 val, isr;
int ret;
+ /* Disable modem control interrupts */
+ stm32_disable_ms(port);
+
val = USART_CR1_TXEIE | USART_CR1_TE;
val |= stm32_port->cr1_irq | USART_CR1_RE;
val |= BIT(cfg->uart_enable_bit);
@@ -764,6 +783,12 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
cr3 |= USART_CR3_CTSE | USART_CR3_RTSE;
}
+ /* Handle modem control interrupts */
+ if (UART_ENABLE_MS(port, termios->c_cflag))
+ stm32_enable_ms(port);
+ else
+ stm32_disable_ms(port);
+
usartdiv = DIV_ROUND_CLOSEST(port->uartclk, baud);
/*
@@ -898,6 +923,7 @@ static const struct uart_ops stm32_uart_ops = {
.throttle = stm32_throttle,
.unthrottle = stm32_unthrottle,
.stop_rx = stm32_stop_rx,
+ .enable_ms = stm32_enable_ms,
.break_ctl = stm32_break_ctl,
.startup = stm32_startup,
.shutdown = stm32_shutdown,
@@ -931,7 +957,9 @@ static int stm32_init_port(struct stm32_port *stm32port,
port->rs485_config = stm32_config_rs485;
- stm32_init_rs485(port, pdev);
+ ret = stm32_init_rs485(port, pdev);
+ if (ret)
+ return ret;
if (stm32port->info->cfg.has_wakeup) {
stm32port->wakeirq = platform_get_irq(pdev, 1);
@@ -960,11 +988,32 @@ static int stm32_init_port(struct stm32_port *stm32port,
stm32port->port.uartclk = clk_get_rate(stm32port->clk);
if (!stm32port->port.uartclk) {
- clk_disable_unprepare(stm32port->clk);
ret = -EINVAL;
+ goto err_clk;
+ }
+
+ stm32port->gpios = mctrl_gpio_init(&stm32port->port, 0);
+ if (IS_ERR(stm32port->gpios)) {
+ ret = PTR_ERR(stm32port->gpios);
+ goto err_clk;
+ }
+
+ /* Both CTS/RTS gpios and "st,hw-flow-ctrl" should not be specified */
+ if (stm32port->hw_flow_control) {
+ if (mctrl_gpio_to_gpiod(stm32port->gpios, UART_GPIO_CTS) ||
+ mctrl_gpio_to_gpiod(stm32port->gpios, UART_GPIO_RTS)) {
+ dev_err(&pdev->dev, "Conflicting RTS/CTS config\n");
+ ret = -EINVAL;
+ goto err_clk;
+ }
}
return ret;
+
+err_clk:
+ clk_disable_unprepare(stm32port->clk);
+
+ return ret;
}
static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev)
@@ -1375,7 +1424,18 @@ static int __maybe_unused stm32_serial_suspend(struct device *dev)
else
stm32_serial_enable_wakeup(port, false);
- pinctrl_pm_select_sleep_state(dev);
+ /*
+ * When "no_console_suspend" is enabled, keep the pinctrl default state
+ * and rely on bootloader stage to restore this state upon resume.
+ * Otherwise, apply the idle or sleep states depending on wakeup
+ * capabilities.
+ */
+ if (console_suspend_enabled || !uart_console(port)) {
+ if (device_may_wakeup(dev))
+ pinctrl_pm_select_idle_state(dev);
+ else
+ pinctrl_pm_select_sleep_state(dev);
+ }
return 0;
}
diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h
index db8bf0d4982d..d4c916e78d40 100644
--- a/drivers/tty/serial/stm32-usart.h
+++ b/drivers/tty/serial/stm32-usart.h
@@ -274,6 +274,7 @@ struct stm32_port {
bool fifoen;
int wakeirq;
int rdr_mask; /* receive data register mask */
+ struct mctrl_gpios *gpios; /* modem control gpios */
};
static struct stm32_port stm32_ports[STM32_MAX_PORTS];
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index 35e9e8faf8de..b9d672af8b65 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -1235,9 +1235,7 @@ static void cdns_uart_console_write(struct console *co, const char *s,
writel(ctrl, port->membase + CDNS_UART_CR);
uart_console_write(port, s, count, cdns_uart_console_putchar);
- while ((readl(port->membase + CDNS_UART_SR) &
- (CDNS_UART_SR_TXEMPTY | CDNS_UART_SR_TACTIVE)) !=
- CDNS_UART_SR_TXEMPTY)
+ while (cdns_uart_tx_empty(port) != TIOCSER_TEMT)
cpu_relax();
/* restore interrupt state */
@@ -1262,6 +1260,7 @@ static int cdns_uart_console_setup(struct console *co, char *options)
int bits = 8;
int parity = 'n';
int flow = 'n';
+ unsigned long time_out;
if (!port->membase) {
pr_debug("console on " CDNS_UART_TTY_NAME "%i not present\n",
@@ -1272,6 +1271,13 @@ static int cdns_uart_console_setup(struct console *co, char *options)
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
+ /* Wait for tx_empty before setting up the console */
+ time_out = jiffies + usecs_to_jiffies(TX_TIMEOUT);
+
+ while (time_before(jiffies, time_out) &&
+ cdns_uart_tx_empty(port) != TIOCSER_TEMT)
+ cpu_relax();
+
return uart_set_options(port, co, baud, parity, bits, flow);
}
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index 0dc3878794fd..477cdc1e9cf3 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -106,7 +106,7 @@ static void sysrq_handle_loglevel(int key)
pr_info("Loglevel set to %d\n", i);
console_loglevel = i;
}
-static struct sysrq_key_op sysrq_loglevel_op = {
+static const struct sysrq_key_op sysrq_loglevel_op = {
.handler = sysrq_handle_loglevel,
.help_msg = "loglevel(0-9)",
.action_msg = "Changing Loglevel",
@@ -119,14 +119,14 @@ static void sysrq_handle_SAK(int key)
struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work;
schedule_work(SAK_work);
}
-static struct sysrq_key_op sysrq_SAK_op = {
+static const struct sysrq_key_op sysrq_SAK_op = {
.handler = sysrq_handle_SAK,
.help_msg = "sak(k)",
.action_msg = "SAK",
.enable_mask = SYSRQ_ENABLE_KEYBOARD,
};
#else
-#define sysrq_SAK_op (*(struct sysrq_key_op *)NULL)
+#define sysrq_SAK_op (*(const struct sysrq_key_op *)NULL)
#endif
#ifdef CONFIG_VT
@@ -135,14 +135,14 @@ static void sysrq_handle_unraw(int key)
vt_reset_unicode(fg_console);
}
-static struct sysrq_key_op sysrq_unraw_op = {
+static const struct sysrq_key_op sysrq_unraw_op = {
.handler = sysrq_handle_unraw,
.help_msg = "unraw(r)",
.action_msg = "Keyboard mode set to system default",
.enable_mask = SYSRQ_ENABLE_KEYBOARD,
};
#else
-#define sysrq_unraw_op (*(struct sysrq_key_op *)NULL)
+#define sysrq_unraw_op (*(const struct sysrq_key_op *)NULL)
#endif /* CONFIG_VT */
static void sysrq_handle_crash(int key)
@@ -152,7 +152,7 @@ static void sysrq_handle_crash(int key)
panic("sysrq triggered crash\n");
}
-static struct sysrq_key_op sysrq_crash_op = {
+static const struct sysrq_key_op sysrq_crash_op = {
.handler = sysrq_handle_crash,
.help_msg = "crash(c)",
.action_msg = "Trigger a crash",
@@ -165,18 +165,20 @@ static void sysrq_handle_reboot(int key)
local_irq_enable();
emergency_restart();
}
-static struct sysrq_key_op sysrq_reboot_op = {
+static const struct sysrq_key_op sysrq_reboot_op = {
.handler = sysrq_handle_reboot,
.help_msg = "reboot(b)",
.action_msg = "Resetting",
.enable_mask = SYSRQ_ENABLE_BOOT,
};
+const struct sysrq_key_op *__sysrq_reboot_op = &sysrq_reboot_op;
+
static void sysrq_handle_sync(int key)
{
emergency_sync();
}
-static struct sysrq_key_op sysrq_sync_op = {
+static const struct sysrq_key_op sysrq_sync_op = {
.handler = sysrq_handle_sync,
.help_msg = "sync(s)",
.action_msg = "Emergency Sync",
@@ -188,7 +190,7 @@ static void sysrq_handle_show_timers(int key)
sysrq_timer_list_show();
}
-static struct sysrq_key_op sysrq_show_timers_op = {
+static const struct sysrq_key_op sysrq_show_timers_op = {
.handler = sysrq_handle_show_timers,
.help_msg = "show-all-timers(q)",
.action_msg = "Show clockevent devices & pending hrtimers (no others)",
@@ -198,7 +200,7 @@ static void sysrq_handle_mountro(int key)
{
emergency_remount();
}
-static struct sysrq_key_op sysrq_mountro_op = {
+static const struct sysrq_key_op sysrq_mountro_op = {
.handler = sysrq_handle_mountro,
.help_msg = "unmount(u)",
.action_msg = "Emergency Remount R/O",
@@ -211,13 +213,13 @@ static void sysrq_handle_showlocks(int key)
debug_show_all_locks();
}
-static struct sysrq_key_op sysrq_showlocks_op = {
+static const struct sysrq_key_op sysrq_showlocks_op = {
.handler = sysrq_handle_showlocks,
.help_msg = "show-all-locks(d)",
.action_msg = "Show Locks Held",
};
#else
-#define sysrq_showlocks_op (*(struct sysrq_key_op *)NULL)
+#define sysrq_showlocks_op (*(const struct sysrq_key_op *)NULL)
#endif
#ifdef CONFIG_SMP
@@ -264,7 +266,7 @@ static void sysrq_handle_showallcpus(int key)
}
}
-static struct sysrq_key_op sysrq_showallcpus_op = {
+static const struct sysrq_key_op sysrq_showallcpus_op = {
.handler = sysrq_handle_showallcpus,
.help_msg = "show-backtrace-all-active-cpus(l)",
.action_msg = "Show backtrace of all active CPUs",
@@ -282,7 +284,7 @@ static void sysrq_handle_showregs(int key)
show_regs(regs);
perf_event_print_debug();
}
-static struct sysrq_key_op sysrq_showregs_op = {
+static const struct sysrq_key_op sysrq_showregs_op = {
.handler = sysrq_handle_showregs,
.help_msg = "show-registers(p)",
.action_msg = "Show Regs",
@@ -294,7 +296,7 @@ static void sysrq_handle_showstate(int key)
show_state();
show_workqueue_state();
}
-static struct sysrq_key_op sysrq_showstate_op = {
+static const struct sysrq_key_op sysrq_showstate_op = {
.handler = sysrq_handle_showstate,
.help_msg = "show-task-states(t)",
.action_msg = "Show State",
@@ -305,7 +307,7 @@ static void sysrq_handle_showstate_blocked(int key)
{
show_state_filter(TASK_UNINTERRUPTIBLE);
}
-static struct sysrq_key_op sysrq_showstate_blocked_op = {
+static const struct sysrq_key_op sysrq_showstate_blocked_op = {
.handler = sysrq_handle_showstate_blocked,
.help_msg = "show-blocked-tasks(w)",
.action_msg = "Show Blocked State",
@@ -319,21 +321,21 @@ static void sysrq_ftrace_dump(int key)
{
ftrace_dump(DUMP_ALL);
}
-static struct sysrq_key_op sysrq_ftrace_dump_op = {
+static const struct sysrq_key_op sysrq_ftrace_dump_op = {
.handler = sysrq_ftrace_dump,
.help_msg = "dump-ftrace-buffer(z)",
.action_msg = "Dump ftrace buffer",
.enable_mask = SYSRQ_ENABLE_DUMP,
};
#else
-#define sysrq_ftrace_dump_op (*(struct sysrq_key_op *)NULL)
+#define sysrq_ftrace_dump_op (*(const struct sysrq_key_op *)NULL)
#endif
static void sysrq_handle_showmem(int key)
{
show_mem(0, NULL);
}
-static struct sysrq_key_op sysrq_showmem_op = {
+static const struct sysrq_key_op sysrq_showmem_op = {
.handler = sysrq_handle_showmem,
.help_msg = "show-memory-usage(m)",
.action_msg = "Show Memory",
@@ -364,7 +366,7 @@ static void sysrq_handle_term(int key)
send_sig_all(SIGTERM);
console_loglevel = CONSOLE_LOGLEVEL_DEBUG;
}
-static struct sysrq_key_op sysrq_term_op = {
+static const struct sysrq_key_op sysrq_term_op = {
.handler = sysrq_handle_term,
.help_msg = "terminate-all-tasks(e)",
.action_msg = "Terminate All Tasks",
@@ -394,7 +396,7 @@ static void sysrq_handle_moom(int key)
{
schedule_work(&moom_work);
}
-static struct sysrq_key_op sysrq_moom_op = {
+static const struct sysrq_key_op sysrq_moom_op = {
.handler = sysrq_handle_moom,
.help_msg = "memory-full-oom-kill(f)",
.action_msg = "Manual OOM execution",
@@ -406,7 +408,7 @@ static void sysrq_handle_thaw(int key)
{
emergency_thaw_all();
}
-static struct sysrq_key_op sysrq_thaw_op = {
+static const struct sysrq_key_op sysrq_thaw_op = {
.handler = sysrq_handle_thaw,
.help_msg = "thaw-filesystems(j)",
.action_msg = "Emergency Thaw of all frozen filesystems",
@@ -419,7 +421,7 @@ static void sysrq_handle_kill(int key)
send_sig_all(SIGKILL);
console_loglevel = CONSOLE_LOGLEVEL_DEBUG;
}
-static struct sysrq_key_op sysrq_kill_op = {
+static const struct sysrq_key_op sysrq_kill_op = {
.handler = sysrq_handle_kill,
.help_msg = "kill-all-tasks(i)",
.action_msg = "Kill All Tasks",
@@ -430,7 +432,7 @@ static void sysrq_handle_unrt(int key)
{
normalize_rt_tasks();
}
-static struct sysrq_key_op sysrq_unrt_op = {
+static const struct sysrq_key_op sysrq_unrt_op = {
.handler = sysrq_handle_unrt,
.help_msg = "nice-all-RT-tasks(n)",
.action_msg = "Nice All RT Tasks",
@@ -440,7 +442,7 @@ static struct sysrq_key_op sysrq_unrt_op = {
/* Key Operations table and lock */
static DEFINE_SPINLOCK(sysrq_key_table_lock);
-static struct sysrq_key_op *sysrq_key_table[36] = {
+static const struct sysrq_key_op *sysrq_key_table[36] = {
&sysrq_loglevel_op, /* 0 */
&sysrq_loglevel_op, /* 1 */
&sysrq_loglevel_op, /* 2 */
@@ -516,9 +518,9 @@ static int sysrq_key_table_key2index(int key)
/*
* get and put functions for the table, exposed to modules.
*/
-struct sysrq_key_op *__sysrq_get_key_op(int key)
+static const struct sysrq_key_op *__sysrq_get_key_op(int key)
{
- struct sysrq_key_op *op_p = NULL;
+ const struct sysrq_key_op *op_p = NULL;
int i;
i = sysrq_key_table_key2index(key);
@@ -528,7 +530,7 @@ struct sysrq_key_op *__sysrq_get_key_op(int key)
return op_p;
}
-static void __sysrq_put_key_op(int key, struct sysrq_key_op *op_p)
+static void __sysrq_put_key_op(int key, const struct sysrq_key_op *op_p)
{
int i = sysrq_key_table_key2index(key);
@@ -538,7 +540,7 @@ static void __sysrq_put_key_op(int key, struct sysrq_key_op *op_p)
void __handle_sysrq(int key, bool check_mask)
{
- struct sysrq_key_op *op_p;
+ const struct sysrq_key_op *op_p;
int orig_log_level;
int orig_suppress_printk;
int i;
@@ -1061,8 +1063,8 @@ int sysrq_toggle_support(int enable_mask)
}
EXPORT_SYMBOL_GPL(sysrq_toggle_support);
-static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p,
- struct sysrq_key_op *remove_op_p)
+static int __sysrq_swap_key_ops(int key, const struct sysrq_key_op *insert_op_p,
+ const struct sysrq_key_op *remove_op_p)
{
int retval;
@@ -1085,13 +1087,13 @@ static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p,
return retval;
}
-int register_sysrq_key(int key, struct sysrq_key_op *op_p)
+int register_sysrq_key(int key, const struct sysrq_key_op *op_p)
{
return __sysrq_swap_key_ops(key, op_p, NULL);
}
EXPORT_SYMBOL(register_sysrq_key);
-int unregister_sysrq_key(int key, struct sysrq_key_op *op_p)
+int unregister_sysrq_key(int key, const struct sysrq_key_op *op_p)
{
return __sysrq_swap_key_ops(key, NULL, op_p);
}
diff --git a/drivers/tty/vcc.c b/drivers/tty/vcc.c
index d2a1e1228c82..9ffd42e333b8 100644
--- a/drivers/tty/vcc.c
+++ b/drivers/tty/vcc.c
@@ -605,6 +605,7 @@ static int vcc_probe(struct vio_dev *vdev, const struct vio_device_id *id)
port->index = vcc_table_add(port);
if (port->index == -1) {
pr_err("VCC: no more TTY indices left for allocation\n");
+ rv = -ENOMEM;
goto free_ldc;
}
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 15d33fa0c925..568b2171f335 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -127,7 +127,11 @@ static DEFINE_SPINLOCK(func_buf_lock); /* guard 'func_buf' and friends */
static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */
static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */
static bool dead_key_next;
-static int npadch = -1; /* -1 or number assembled on pad */
+
+/* Handles a number being assembled on the number pad */
+static bool npadch_active;
+static unsigned int npadch_value;
+
static unsigned int diacr;
static char rep; /* flag telling character repeat */
@@ -845,12 +849,12 @@ static void k_shift(struct vc_data *vc, unsigned char value, char up_flag)
shift_state &= ~(1 << value);
/* kludge */
- if (up_flag && shift_state != old_state && npadch != -1) {
+ if (up_flag && shift_state != old_state && npadch_active) {
if (kbd->kbdmode == VC_UNICODE)
- to_utf8(vc, npadch);
+ to_utf8(vc, npadch_value);
else
- put_queue(vc, npadch & 0xff);
- npadch = -1;
+ put_queue(vc, npadch_value & 0xff);
+ npadch_active = false;
}
}
@@ -868,7 +872,7 @@ static void k_meta(struct vc_data *vc, unsigned char value, char up_flag)
static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag)
{
- int base;
+ unsigned int base;
if (up_flag)
return;
@@ -882,10 +886,12 @@ static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag)
base = 16;
}
- if (npadch == -1)
- npadch = value;
- else
- npadch = npadch * base + value;
+ if (!npadch_active) {
+ npadch_value = 0;
+ npadch_active = true;
+ }
+
+ npadch_value = npadch_value * base + value;
}
static void k_lock(struct vc_data *vc, unsigned char value, char up_flag)
diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c
index d54a549c5892..31bb3647a99c 100644
--- a/drivers/tty/vt/selection.c
+++ b/drivers/tty/vt/selection.c
@@ -185,47 +185,54 @@ int set_selection_user(const struct tiocl_selection __user *sel,
return set_selection_kernel(&v, tty);
}
-static int __set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty)
+static int vc_selection_store_chars(struct vc_data *vc, bool unicode)
{
- struct vc_data *vc = vc_cons[fg_console].d;
- int new_sel_start, new_sel_end, spc;
char *bp, *obp;
- int i, ps, pe;
- u32 c;
- int ret = 0;
- bool unicode;
-
- poke_blanked_console();
-
- v->xs = min_t(u16, v->xs - 1, vc->vc_cols - 1);
- v->ys = min_t(u16, v->ys - 1, vc->vc_rows - 1);
- v->xe = min_t(u16, v->xe - 1, vc->vc_cols - 1);
- v->ye = min_t(u16, v->ye - 1, vc->vc_rows - 1);
- ps = v->ys * vc->vc_size_row + (v->xs << 1);
- pe = v->ye * vc->vc_size_row + (v->xe << 1);
+ unsigned int i;
- if (v->sel_mode == TIOCL_SELCLEAR) {
- /* useful for screendump without selection highlights */
+ /* Allocate a new buffer before freeing the old one ... */
+ /* 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 0;
+ return -ENOMEM;
}
+ kfree(vc_sel.buffer);
+ vc_sel.buffer = bp;
- if (mouse_reporting() && (v->sel_mode & TIOCL_SELMOUSEREPORT)) {
- mouse_report(tty, v->sel_mode & TIOCL_SELBUTTONMASK, v->xs,
- v->ys);
- return 0;
+ obp = bp;
+ for (i = vc_sel.start; i <= vc_sel.end; i += 2) {
+ u32 c = sel_pos(i, unicode);
+ if (unicode)
+ bp += store_utf8(c, bp);
+ else
+ *bp++ = c;
+ if (!isspace(c))
+ obp = bp;
+ if (!((i + 2) % vc->vc_size_row)) {
+ /* strip trailing blanks from line and add newline,
+ unless non-space at end of line. */
+ if (obp != bp) {
+ bp = obp;
+ *bp++ = '\r';
+ }
+ obp = bp;
+ }
}
+ vc_sel.buf_len = bp - vc_sel.buffer;
- if (ps > pe) /* make vc_sel.start <= vc_sel.end */
- swap(ps, pe);
+ return 0;
+}
- if (vc_sel.cons != vc_cons[fg_console].d) {
- clear_selection();
- vc_sel.cons = vc_cons[fg_console].d;
- }
- unicode = vt_do_kdgkbmode(fg_console) == K_UNICODE;
+static int vc_do_selection(struct vc_data *vc, unsigned short mode, int ps,
+ int pe)
+{
+ int new_sel_start, new_sel_end, spc;
+ bool unicode = vt_do_kdgkbmode(fg_console) == K_UNICODE;
- switch (v->sel_mode) {
+ switch (mode) {
case TIOCL_SELCHAR: /* character-by-character selection */
new_sel_start = ps;
new_sel_end = pe;
@@ -303,40 +310,44 @@ static int __set_selection_kernel(struct tiocl_selection *v, struct tty_struct *
vc_sel.start = new_sel_start;
vc_sel.end = new_sel_end;
- /* Allocate a new buffer before freeing the old one ... */
- /* 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");
+ return vc_selection_store_chars(vc, unicode);
+}
+
+static int vc_selection(struct vc_data *vc, struct tiocl_selection *v,
+ struct tty_struct *tty)
+{
+ int ps, pe;
+
+ poke_blanked_console();
+
+ if (v->sel_mode == TIOCL_SELCLEAR) {
+ /* useful for screendump without selection highlights */
clear_selection();
- return -ENOMEM;
+ return 0;
}
- kfree(vc_sel.buffer);
- vc_sel.buffer = bp;
- obp = bp;
- 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;
- if (!isspace(c))
- obp = bp;
- if (! ((i + 2) % vc->vc_size_row)) {
- /* strip trailing blanks from line and add newline,
- unless non-space at end of line. */
- if (obp != bp) {
- bp = obp;
- *bp++ = '\r';
- }
- obp = bp;
- }
+ v->xs = min_t(u16, v->xs - 1, vc->vc_cols - 1);
+ v->ys = min_t(u16, v->ys - 1, vc->vc_rows - 1);
+ v->xe = min_t(u16, v->xe - 1, vc->vc_cols - 1);
+ v->ye = min_t(u16, v->ye - 1, vc->vc_rows - 1);
+
+ if (mouse_reporting() && (v->sel_mode & TIOCL_SELMOUSEREPORT)) {
+ mouse_report(tty, v->sel_mode & TIOCL_SELBUTTONMASK, v->xs,
+ v->ys);
+ return 0;
}
- vc_sel.buf_len = bp - vc_sel.buffer;
- return ret;
+ ps = v->ys * vc->vc_size_row + (v->xs << 1);
+ pe = v->ye * vc->vc_size_row + (v->xe << 1);
+ if (ps > pe) /* make vc_sel.start <= vc_sel.end */
+ swap(ps, pe);
+
+ if (vc_sel.cons != vc) {
+ clear_selection();
+ vc_sel.cons = vc;
+ }
+
+ return vc_do_selection(vc, v->sel_mode, ps, pe);
}
int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty)
@@ -345,7 +356,7 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty)
mutex_lock(&vc_sel.lock);
console_lock();
- ret = __set_selection_kernel(v, tty);
+ ret = vc_selection(vc_cons[fg_console].d, v, tty);
console_unlock();
mutex_unlock(&vc_sel.lock);