summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-02-17 09:30:52 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2026-02-17 09:30:52 -0800
commit3ad7945754000d868ed86315d33085a914c422c1 (patch)
treec886bab36fec7168426865f05be13356da98b63b /drivers
parenta5f22b9b139762685810aa5a41fd0181488aea13 (diff)
parent0a15f43b92ddaa2fdb476891a12ac2e207c7fcd2 (diff)
Merge tag 'tty-7.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty / serial driver updates from Greg KH: "Here is the small amount of tty and serial driver updates for 7.0-rc1. Nothing major in here at all, just some driver updates and minor tweaks and cleanups including: - sh-sci serial driver updates - 8250 driver updates - attempt to make the tty ports have their own workqueue, but was reverted after testing found it to have problems on some platforms. This will probably come back for 7.1 after it has been reworked and resubmitted - other tiny tty driver changes All of these have been in linux-next for a while with no reported problems" * tag 'tty-7.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (49 commits) Revert "tty: tty_port: add workqueue to flip TTY buffer" tty: tty_port: add workqueue to flip TTY buffer serial: 8250_pci: Remove custom deprecated baud setting routine serial: 8250_omap: Remove custom deprecated baud setting routine dt-bindings: serial: renesas,scif: Document RZ/G3L SoC serial: 8250: omap: set out-of-band wakeup if wakeup pinctrl exists tty: hvc-iucv: Remove KMSG_COMPONENT macro dt-bindings: serial: google,goldfish-tty: Convert to DT schema dt-bindings: serial: sh-sci: Fold single-entry compatibles into enum serial: 8250: 8250_omap.c: Clear DMA RX running status only after DMA termination is done serial: 8250: 8250_omap.c: Add support for handling UART error conditions serial: SH_SCI: improve "DMA support" prompt serial: Kconfig: fix ordering of entries for menu display serial: 8250: fix ordering of entries for menu display serial: imx: change SERIAL_IMX_CONSOLE to bool 8250_men_mcb: drop unneeded MODULE_ALIAS serial: men_z135_uart: drop unneeded MODULE_ALIAS dt-bindings: serial: renesas,rsci: Document RZ/V2H(P) and RZ/V2N SoCs serial: rsci: Convert to FIELD_MODIFY() dt-bindings: serial: 8250: add SpacemiT K3 UART compatible ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/bluetooth/hci_aml.c16
-rw-r--r--drivers/bluetooth/hci_qca.c5
-rw-r--r--drivers/platform/surface/aggregator/core.c6
-rw-r--r--drivers/tty/hvc/hvc_iucv.c5
-rw-r--r--drivers/tty/n_hdlc.c2
-rw-r--r--drivers/tty/serdev/core.c21
-rw-r--r--drivers/tty/serial/8250/8250_dw.c23
-rw-r--r--drivers/tty/serial/8250/8250_keba.c27
-rw-r--r--drivers/tty/serial/8250/8250_men_mcb.c15
-rw-r--r--drivers/tty/serial/8250/8250_omap.c43
-rw-r--r--drivers/tty/serial/8250/8250_pci.c91
-rw-r--r--drivers/tty/serial/8250/Kconfig95
-rw-r--r--drivers/tty/serial/Kconfig34
-rw-r--r--drivers/tty/serial/men_z135_uart.c1
-rw-r--r--drivers/tty/serial/rsci.c309
-rw-r--r--drivers/tty/serial/rsci.h3
-rw-r--r--drivers/tty/serial/sh-sci-common.h10
-rw-r--r--drivers/tty/serial/sh-sci.c80
-rw-r--r--drivers/tty/vt/keyboard.c221
19 files changed, 654 insertions, 353 deletions
diff --git a/drivers/bluetooth/hci_aml.c b/drivers/bluetooth/hci_aml.c
index b1f32c5a8a3f..4981c82d634d 100644
--- a/drivers/bluetooth/hci_aml.c
+++ b/drivers/bluetooth/hci_aml.c
@@ -677,13 +677,6 @@ static const struct hci_uart_proto aml_hci_proto = {
.dequeue = aml_dequeue,
};
-static void aml_device_driver_shutdown(struct device *dev)
-{
- struct aml_serdev *amldev = dev_get_drvdata(dev);
-
- aml_power_off(amldev);
-}
-
static int aml_serdev_probe(struct serdev_device *serdev)
{
struct aml_serdev *amldev;
@@ -714,6 +707,13 @@ static void aml_serdev_remove(struct serdev_device *serdev)
hci_uart_unregister_device(&amldev->serdev_hu);
}
+static void aml_serdev_shutdown(struct serdev_device *serdev)
+{
+ struct aml_serdev *amldev = serdev_device_get_drvdata(serdev);
+
+ aml_power_off(amldev);
+}
+
static const struct aml_device_data data_w155s2 = {
.iccm_offset = 256 * 1024,
};
@@ -732,10 +732,10 @@ MODULE_DEVICE_TABLE(of, aml_bluetooth_of_match);
static struct serdev_device_driver aml_serdev_driver = {
.probe = aml_serdev_probe,
.remove = aml_serdev_remove,
+ .shutdown = aml_serdev_shutdown,
.driver = {
.name = "hci_uart_aml",
.of_match_table = aml_bluetooth_of_match,
- .shutdown = aml_device_driver_shutdown,
},
};
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index 51309f5b5714..c511546f793e 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -2570,11 +2570,10 @@ static void qca_serdev_remove(struct serdev_device *serdev)
hci_uart_unregister_device(&qcadev->serdev_hu);
}
-static void qca_serdev_shutdown(struct device *dev)
+static void qca_serdev_shutdown(struct serdev_device *serdev)
{
int ret;
int timeout = msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS);
- struct serdev_device *serdev = to_serdev_device(dev);
struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
struct hci_uart *hu = &qcadev->serdev_hu;
struct hci_dev *hdev = hu->hdev;
@@ -2796,11 +2795,11 @@ static void hciqca_coredump(struct device *dev)
static struct serdev_device_driver qca_serdev_driver = {
.probe = qca_serdev_probe,
.remove = qca_serdev_remove,
+ .shutdown = qca_serdev_shutdown,
.driver = {
.name = "hci_uart_qca",
.of_match_table = of_match_ptr(qca_bluetooth_of_match),
.acpi_match_table = ACPI_PTR(qca_bluetooth_acpi_match),
- .shutdown = qca_serdev_shutdown,
.pm = &qca_pm_ops,
#ifdef CONFIG_DEV_COREDUMP
.coredump = hciqca_coredump,
diff --git a/drivers/platform/surface/aggregator/core.c b/drivers/platform/surface/aggregator/core.c
index c7e05f7bc199..82e531023911 100644
--- a/drivers/platform/surface/aggregator/core.c
+++ b/drivers/platform/surface/aggregator/core.c
@@ -380,9 +380,9 @@ static int ssam_serdev_setup(struct acpi_device *ssh, struct serdev_device *serd
/* -- Power management. ----------------------------------------------------- */
-static void ssam_serial_hub_shutdown(struct device *dev)
+static void ssam_serial_hub_shutdown(struct serdev_device *serdev)
{
- struct ssam_controller *c = dev_get_drvdata(dev);
+ struct ssam_controller *c = dev_get_drvdata(&serdev->dev);
int status;
/*
@@ -834,12 +834,12 @@ MODULE_DEVICE_TABLE(of, ssam_serial_hub_of_match);
static struct serdev_device_driver ssam_serial_hub = {
.probe = ssam_serial_hub_probe,
.remove = ssam_serial_hub_remove,
+ .shutdown = ssam_serial_hub_shutdown,
.driver = {
.name = "surface_serial_hub",
.acpi_match_table = ACPI_PTR(ssam_serial_hub_acpi_match),
.of_match_table = of_match_ptr(ssam_serial_hub_of_match),
.pm = &ssam_serial_hub_pm_ops,
- .shutdown = ssam_serial_hub_shutdown,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
};
diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c
index 4ca7472c38e0..a7939c49c9cf 100644
--- a/drivers/tty/hvc/hvc_iucv.c
+++ b/drivers/tty/hvc/hvc_iucv.c
@@ -9,8 +9,7 @@
*
* Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
*/
-#define KMSG_COMPONENT "hvc_iucv"
-#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+#define pr_fmt(fmt) "hvc_iucv: " fmt
#include <linux/types.h>
#include <linux/slab.h>
@@ -1344,7 +1343,7 @@ static int __init hvc_iucv_init(void)
}
}
- hvc_iucv_buffer_cache = kmem_cache_create(KMSG_COMPONENT,
+ hvc_iucv_buffer_cache = kmem_cache_create("hvc_iucv",
sizeof(struct iucv_tty_buffer),
0, 0, NULL);
if (!hvc_iucv_buffer_cache) {
diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c
index 3c9dcb0928c6..f242d73ee4e0 100644
--- a/drivers/tty/n_hdlc.c
+++ b/drivers/tty/n_hdlc.c
@@ -127,6 +127,8 @@ struct n_hdlc_buf_list {
* @rx_buf_list: list of received frame buffers
* @tx_free_buf_list: list unused transmit frame buffers
* @rx_free_buf_list: list unused received frame buffers
+ * @write_work: work struct for deferred frame transmission
+ * @tty_for_write_work: pointer to tty instance used by the @write_work
*/
struct n_hdlc {
bool tbusy;
diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c
index b33e708cb245..40eedc15277c 100644
--- a/drivers/tty/serdev/core.c
+++ b/drivers/tty/serdev/core.c
@@ -414,11 +414,21 @@ static void serdev_drv_remove(struct device *dev)
sdrv->remove(to_serdev_device(dev));
}
+static void serdev_drv_shutdown(struct device *dev)
+{
+ const struct serdev_device_driver *sdrv =
+ to_serdev_device_driver(dev->driver);
+
+ if (dev->driver && sdrv->shutdown)
+ sdrv->shutdown(to_serdev_device(dev));
+}
+
static const struct bus_type serdev_bus_type = {
.name = "serial",
.match = serdev_device_match,
.probe = serdev_drv_probe,
.remove = serdev_drv_remove,
+ .shutdown = serdev_drv_shutdown,
};
/**
@@ -814,6 +824,14 @@ void serdev_controller_remove(struct serdev_controller *ctrl)
}
EXPORT_SYMBOL_GPL(serdev_controller_remove);
+static void serdev_legacy_shutdown(struct serdev_device *serdev)
+{
+ struct device *dev = &serdev->dev;
+ struct device_driver *driver = dev->driver;
+
+ driver->shutdown(dev);
+}
+
/**
* __serdev_device_driver_register() - Register client driver with serdev core
* @sdrv: client driver to be associated with client-device.
@@ -830,6 +848,9 @@ int __serdev_device_driver_register(struct serdev_device_driver *sdrv, struct mo
/* force drivers to async probe so I/O is possible in probe */
sdrv->driver.probe_type = PROBE_PREFER_ASYNCHRONOUS;
+ if (!sdrv->shutdown && sdrv->driver.shutdown)
+ sdrv->shutdown = serdev_legacy_shutdown;
+
return driver_register(&sdrv->driver);
}
EXPORT_SYMBOL_GPL(__serdev_device_driver_register);
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index 27af83f0ff46..db73b2ae17fa 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -643,6 +643,10 @@ static int dw8250_probe(struct platform_device *pdev)
if (err)
return err;
+ err = pm_runtime_set_active(dev);
+ if (err)
+ return dev_err_probe(dev, err, "Failed to set the runtime suspend as active\n");
+
data->uart_16550_compatible = device_property_read_bool(dev, "snps,uart-16550-compatible");
data->pdata = device_get_match_data(p->dev);
@@ -685,7 +689,6 @@ static int dw8250_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, data);
- pm_runtime_set_active(dev);
pm_runtime_enable(dev);
return 0;
@@ -741,19 +744,25 @@ static int dw8250_runtime_suspend(struct device *dev)
static int dw8250_runtime_resume(struct device *dev)
{
+ int ret;
struct dw8250_data *data = dev_get_drvdata(dev);
- clk_prepare_enable(data->pclk);
+ ret = clk_prepare_enable(data->pclk);
+ if (ret)
+ return ret;
- clk_prepare_enable(data->clk);
+ ret = clk_prepare_enable(data->clk);
+ if (ret) {
+ clk_disable_unprepare(data->pclk);
+ return ret;
+ }
return 0;
}
-static const struct dev_pm_ops dw8250_pm_ops = {
- SYSTEM_SLEEP_PM_OPS(dw8250_suspend, dw8250_resume)
- RUNTIME_PM_OPS(dw8250_runtime_suspend, dw8250_runtime_resume, NULL)
-};
+static _DEFINE_DEV_PM_OPS(dw8250_pm_ops, dw8250_suspend, dw8250_resume,
+ dw8250_runtime_suspend, dw8250_runtime_resume,
+ NULL);
static const struct dw8250_platform_data dw8250_dw_apb = {
.usr_reg = DW_UART_USR,
diff --git a/drivers/tty/serial/8250/8250_keba.c b/drivers/tty/serial/8250/8250_keba.c
index c05b89551b12..f94d97e69dc5 100644
--- a/drivers/tty/serial/8250/8250_keba.c
+++ b/drivers/tty/serial/8250/8250_keba.c
@@ -6,10 +6,18 @@
*/
#include <linux/auxiliary_bus.h>
-#include <linux/device.h>
+#include <linux/bits.h>
+#include <linux/container_of.h>
+#include <linux/dev_printk.h>
+#include <linux/device/devres.h>
+#include <linux/err.h>
#include <linux/io.h>
#include <linux/misc/keba.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
+#include <linux/serial_core.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
#include "8250.h"
@@ -43,6 +51,10 @@ enum kuart_mode {
#define KUART_CAPABILITY_RS232 BIT(KUART_MODE_RS232)
#define KUART_CAPABILITY_MASK GENMASK(3, 0)
+/* registers for Indexed Control Register access in enhanced mode */
+#define KUART_EMODE_ICR_OFFSET UART_SCR
+#define KUART_EMODE_ICR_VALUE UART_LSR
+
/* Additional Control Register DTR line configuration */
#define UART_ACR_DTRLC_MASK 0x18
#define UART_ACR_DTRLC_COMPAT 0x00
@@ -90,13 +102,13 @@ static void kuart_dtr_line_config(struct uart_8250_port *up, u8 dtrlc)
u8 acr;
/* set index register to 0 to access ACR register */
- serial_out(up, UART_SCR, UART_ACR);
+ serial_out(up, KUART_EMODE_ICR_OFFSET, UART_ACR);
/* set value register to 0x10 writing DTR mode (1,0) */
- acr = serial_in(up, UART_LSR);
+ acr = serial_in(up, KUART_EMODE_ICR_VALUE);
acr &= ~UART_ACR_DTRLC_MASK;
acr |= dtrlc;
- serial_out(up, UART_LSR, acr);
+ serial_out(up, KUART_EMODE_ICR_VALUE, acr);
}
static int kuart_rs485_config(struct uart_port *port, struct ktermios *termios,
@@ -240,10 +252,9 @@ static int kuart_probe(struct auxiliary_device *auxdev,
}
retval = serial8250_register_8250_port(&uart);
- if (retval < 0) {
- dev_err(&auxdev->dev, "UART registration failed!\n");
- return retval;
- }
+ if (retval < 0)
+ return dev_err_probe(&auxdev->dev, retval,
+ "UART registration failed!\n");
kuart->line = retval;
return 0;
diff --git a/drivers/tty/serial/8250/8250_men_mcb.c b/drivers/tty/serial/8250/8250_men_mcb.c
index a78ef35c8187..6373234da03d 100644
--- a/drivers/tty/serial/8250/8250_men_mcb.c
+++ b/drivers/tty/serial/8250/8250_men_mcb.c
@@ -28,8 +28,6 @@
#define MEN_UART3_MASK 0x04
#define MEN_UART4_MASK 0x08
-#define MEN_Z125_UARTS_AVAILABLE 0x01
-
#define MEN_Z025_MAX_UARTS 4
#define MEN_UART_MEM_SIZE 0x10
#define MEM_UART_REGISTER_SIZE 0x01
@@ -42,12 +40,10 @@
#define MEN_READ_REGISTER(addr) readb(addr)
-#define MAX_PORTS 4
-
struct serial_8250_men_mcb_data {
int num_ports;
- int line[MAX_PORTS];
- unsigned int offset[MAX_PORTS];
+ int line[MEN_Z025_MAX_UARTS];
+ unsigned int offset[MEN_Z025_MAX_UARTS];
};
/*
@@ -126,7 +122,7 @@ static int read_serial_data(struct mcb_device *mdev,
if (res < 0)
return res;
- for (i = 0; i < MAX_PORTS; i++) {
+ for (i = 0; i < MEN_Z025_MAX_UARTS; i++) {
mask = 0x1 << i;
switch (uarts_available & mask) {
case MEN_UART1_MASK:
@@ -150,7 +146,7 @@ static int read_serial_data(struct mcb_device *mdev,
}
}
- if (count <= 0 || count > MAX_PORTS) {
+ if (count <= 0 || count > MEN_Z025_MAX_UARTS) {
dev_err(&mdev->dev, "unexpected number of ports: %u\n",
count);
return -ENODEV;
@@ -268,7 +264,4 @@ module_mcb_driver(mcb_driver);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("MEN 8250 UART driver");
MODULE_AUTHOR("Michael Moese <michael.moese@men.de");
-MODULE_ALIAS("mcb:16z125");
-MODULE_ALIAS("mcb:16z025");
-MODULE_ALIAS("mcb:16z057");
MODULE_IMPORT_NS("MCB");
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 9e49ef48b851..c552c6b9a037 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -100,6 +100,9 @@
#define OMAP_UART_REV_52 0x0502
#define OMAP_UART_REV_63 0x0603
+/* Resume register */
+#define UART_OMAP_RESUME 0x0B
+
/* Interrupt Enable Register 2 */
#define UART_OMAP_IER2 0x1B
#define UART_OMAP_IER2_RHR_IT_DIS BIT(2)
@@ -119,7 +122,6 @@
/* Timeout low and High */
#define UART_OMAP_TO_L 0x26
#define UART_OMAP_TO_H 0x27
-
struct omap8250_priv {
void __iomem *membase;
int line;
@@ -241,22 +243,6 @@ static void omap_8250_get_divisor(struct uart_port *port, unsigned int baud,
unsigned int div_13, div_16;
unsigned int abs_d13, abs_d16;
- /*
- * Old custom speed handling.
- */
- if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) {
- priv->quot = port->custom_divisor & UART_DIV_MAX;
- /*
- * I assume that nobody is using this. But hey, if somebody
- * would like to specify the divisor _and_ the mode then the
- * driver is ready and waiting for it.
- */
- if (port->custom_divisor & (1 << 16))
- priv->mdr1 = UART_OMAP_MDR1_13X_MODE;
- else
- priv->mdr1 = UART_OMAP_MDR1_16X_MODE;
- return;
- }
div_13 = DIV_ROUND_CLOSEST(uartclk, 13 * baud);
div_16 = DIV_ROUND_CLOSEST(uartclk, 16 * baud);
@@ -929,7 +915,6 @@ static void __dma_rx_do_complete(struct uart_8250_port *p)
goto out;
cookie = dma->rx_cookie;
- dma->rx_running = 0;
/* Re-enable RX FIFO interrupt now that transfer is complete */
if (priv->habit & UART_HAS_RHR_IT_DIS) {
@@ -963,6 +948,7 @@ static void __dma_rx_do_complete(struct uart_8250_port *p)
goto out;
ret = tty_insert_flip_string(tty_port, dma->rx_buf, count);
+ dma->rx_running = 0;
p->port.icount.rx += ret;
p->port.icount.buf_overrun += count - ret;
out:
@@ -1256,6 +1242,20 @@ static u16 omap_8250_handle_rx_dma(struct uart_8250_port *up, u8 iir, u16 status
return status;
}
+static void am654_8250_handle_uart_errors(struct uart_8250_port *up, u8 iir, u16 status)
+{
+ if (status & UART_LSR_OE) {
+ serial8250_clear_and_reinit_fifos(up);
+ serial_in(up, UART_LSR);
+ serial_in(up, UART_OMAP_RESUME);
+ } else {
+ if (status & (UART_LSR_FE | UART_LSR_PE | UART_LSR_BI))
+ serial_in(up, UART_RX);
+ if (iir & UART_IIR_XOFF)
+ serial_in(up, UART_IIR);
+ }
+}
+
static void am654_8250_handle_rx_dma(struct uart_8250_port *up, u8 iir,
u16 status)
{
@@ -1266,7 +1266,8 @@ static void am654_8250_handle_rx_dma(struct uart_8250_port *up, u8 iir,
* Queue a new transfer if FIFO has data.
*/
if ((status & (UART_LSR_DR | UART_LSR_BI)) &&
- (up->ier & UART_IER_RDI)) {
+ (up->ier & UART_IER_RDI) && !(status & UART_LSR_OE)) {
+ am654_8250_handle_uart_errors(up, iir, status);
omap_8250_rx_dma(up);
serial_out(up, UART_OMAP_EFR2, UART_OMAP_EFR2_TIMEOUT_BEHAVE);
} else if ((iir & 0x3f) == UART_IIR_RX_TIMEOUT) {
@@ -1282,6 +1283,8 @@ static void am654_8250_handle_rx_dma(struct uart_8250_port *up, u8 iir,
serial_out(up, UART_OMAP_EFR2, 0x0);
up->ier |= UART_IER_RLSI | UART_IER_RDI;
serial_out(up, UART_IER, up->ier);
+ } else {
+ am654_8250_handle_uart_errors(up, iir, status);
}
}
@@ -1363,6 +1366,8 @@ static int omap8250_select_wakeup_pinctrl(struct device *dev,
if (!device_may_wakeup(dev))
return 0;
+ device_set_out_band_wakeup(dev);
+
return pinctrl_select_state(priv->pinctrl, priv->pinctrl_wakeup);
}
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 3efe075ef7b2..6589bb531cc6 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -1205,60 +1205,49 @@ static unsigned int pci_oxsemi_tornado_get_divisor(struct uart_port *port,
u8 tcr;
int i;
- /* Old custom speed handling. */
- if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) {
- unsigned int cust_div = port->custom_divisor;
-
- quot = cust_div & UART_DIV_MAX;
- tcr = (cust_div >> 16) & OXSEMI_TORNADO_TCR_MASK;
- cpr = (cust_div >> 20) & OXSEMI_TORNADO_CPR_MASK;
- if (cpr < OXSEMI_TORNADO_CPR_MIN)
- cpr = OXSEMI_TORNADO_CPR_DEF;
- } else {
- best_squot = quot_scale;
- for (i = 0; i < ARRAY_SIZE(p); i++) {
- unsigned int spre;
- unsigned int srem;
- u8 cp;
- u8 tc;
-
- tc = p[i][0];
- cp = p[i][1];
- spre = tc * cp;
-
- srem = sdiv % spre;
- if (srem > spre / 2)
- srem = spre - srem;
- squot = DIV_ROUND_CLOSEST(srem * quot_scale, spre);
-
- if (srem == 0) {
- tcr = tc;
- cpr = cp;
- quot = sdiv / spre;
- break;
- } else if (squot < best_squot) {
- best_squot = squot;
- tcr = tc;
- cpr = cp;
- quot = DIV_ROUND_CLOSEST(sdiv, spre);
- }
+ best_squot = quot_scale;
+ for (i = 0; i < ARRAY_SIZE(p); i++) {
+ unsigned int spre;
+ unsigned int srem;
+ u8 cp;
+ u8 tc;
+
+ tc = p[i][0];
+ cp = p[i][1];
+ spre = tc * cp;
+
+ srem = sdiv % spre;
+ if (srem > spre / 2)
+ srem = spre - srem;
+ squot = DIV_ROUND_CLOSEST(srem * quot_scale, spre);
+
+ if (srem == 0) {
+ tcr = tc;
+ cpr = cp;
+ quot = sdiv / spre;
+ break;
+ } else if (squot < best_squot) {
+ best_squot = squot;
+ tcr = tc;
+ cpr = cp;
+ quot = DIV_ROUND_CLOSEST(sdiv, spre);
}
- while (tcr <= (OXSEMI_TORNADO_TCR_MASK + 1) >> 1 &&
- quot % 2 == 0) {
+ }
+ while (tcr <= (OXSEMI_TORNADO_TCR_MASK + 1) >> 1 &&
+ quot % 2 == 0) {
+ quot >>= 1;
+ tcr <<= 1;
+ }
+ while (quot > UART_DIV_MAX) {
+ if (tcr <= (OXSEMI_TORNADO_TCR_MASK + 1) >> 1) {
quot >>= 1;
tcr <<= 1;
- }
- while (quot > UART_DIV_MAX) {
- if (tcr <= (OXSEMI_TORNADO_TCR_MASK + 1) >> 1) {
- quot >>= 1;
- tcr <<= 1;
- } else if (cpr <= OXSEMI_TORNADO_CPR_MASK >> 1) {
- quot >>= 1;
- cpr <<= 1;
- } else {
- quot = quot * cpr / OXSEMI_TORNADO_CPR_MASK;
- cpr = OXSEMI_TORNADO_CPR_MASK;
- }
+ } else if (cpr <= OXSEMI_TORNADO_CPR_MASK >> 1) {
+ quot >>= 1;
+ cpr <<= 1;
+ } else {
+ quot = quot * cpr / OXSEMI_TORNADO_CPR_MASK;
+ cpr = OXSEMI_TORNADO_CPR_MASK;
}
}
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index c488ff6f2865..fd4e8b6ab60d 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -116,6 +116,7 @@ config SERIAL_8250_DMA
config SERIAL_8250_PCILIB
bool
+ depends on SERIAL_8250 && PCI
config SERIAL_8250_PCI
tristate "8250/16550 PCI device support"
@@ -205,6 +206,37 @@ config SERIAL_8250_EXTENDED
kernel: saying N will just cause the configurator to skip all
the questions about serial driver options. If unsure, say N.
+config SERIAL_8250_SHARE_IRQ
+ bool "Support for sharing serial interrupts"
+ depends on SERIAL_8250_EXTENDED
+ help
+ Some serial boards have hardware support which allows multiple dumb
+ serial ports on the same board to share a single IRQ. To enable
+ support for this in the serial driver, say Y here.
+
+config SERIAL_8250_DETECT_IRQ
+ bool "Autodetect IRQ on standard ports (unsafe)"
+ depends on SERIAL_8250_EXTENDED
+ help
+ Say Y here if you want the kernel to try to guess which IRQ
+ to use for your serial port.
+
+ This is considered unsafe; it is far better to configure the IRQ in
+ a boot script using the setserial command.
+
+ If unsure, say N.
+
+config SERIAL_8250_RSA
+ bool "Support RSA serial ports"
+ depends on SERIAL_8250_EXTENDED
+ help
+ Say Y here if you have a IODATA RSA-DV II/S ISA card and
+ would like to use its >115kbps speeds.
+ You will need to provide module parameter "probe_rsa", or boot-time
+ parameter 8250.probe_rsa with I/O addresses of this card then.
+
+ If you don't have such card, or if unsure, say N.
+
config SERIAL_8250_MANY_PORTS
bool "Support more than 4 legacy serial ports"
depends on SERIAL_8250_EXTENDED
@@ -240,19 +272,6 @@ config SERIAL_8250_ACCENT
To compile this driver as a module, choose M here: the module
will be called 8250_accent.
-config SERIAL_8250_ASPEED_VUART
- tristate "Aspeed Virtual UART"
- depends on SERIAL_8250
- depends on OF
- depends on MFD_SYSCON
- depends on ARCH_ASPEED || COMPILE_TEST
- select REGMAP
- help
- If you want to use the virtual UART (VUART) device on Aspeed
- BMC platforms, enable this option. This enables the 16550A-
- compatible device on the local LPC bus, giving a UART device
- with no physical RS232 connections.
-
config SERIAL_8250_BOCA
tristate "Support Boca cards"
depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
@@ -293,44 +312,23 @@ config SERIAL_8250_PCI1XXXX
serial driver for the serial interface. This driver support
will ensure to support baud rates upto 1.5Mpbs.
+config SERIAL_8250_ASPEED_VUART
+ tristate "Aspeed Virtual UART"
+ depends on SERIAL_8250
+ depends on OF
+ depends on MFD_SYSCON
+ depends on ARCH_ASPEED || COMPILE_TEST
+ select REGMAP
+ help
+ If you want to use the virtual UART (VUART) device on Aspeed
+ BMC platforms, enable this option. This enables the 16550A-
+ compatible device on the local LPC bus, giving a UART device
+ with no physical RS232 connections.
+
#
# Misc. options/drivers.
#
-config SERIAL_8250_SHARE_IRQ
- bool "Support for sharing serial interrupts"
- depends on SERIAL_8250_EXTENDED
- help
- Some serial boards have hardware support which allows multiple dumb
- serial ports on the same board to share a single IRQ. To enable
- support for this in the serial driver, say Y here.
-
-config SERIAL_8250_DETECT_IRQ
- bool "Autodetect IRQ on standard ports (unsafe)"
- depends on SERIAL_8250_EXTENDED
- help
- Say Y here if you want the kernel to try to guess which IRQ
- to use for your serial port.
-
- This is considered unsafe; it is far better to configure the IRQ in
- a boot script using the setserial command.
-
- If unsure, say N.
-
-config SERIAL_8250_RSA
- bool "Support RSA serial ports"
- depends on SERIAL_8250_EXTENDED
- help
- Say Y here if you have a IODATA RSA-DV II/S ISA card and
- would like to use its >115kbps speeds.
- You will need to provide module parameter "probe_rsa", or boot-time
- parameter 8250.probe_rsa with I/O addresses of this card then.
-
- If you don't have such card, or if unsure, say N.
-
-config SERIAL_8250_DWLIB
- bool
-
config SERIAL_8250_ACORN
tristate "Acorn expansion card serial port support"
depends on ARCH_ACORN && SERIAL_8250
@@ -596,3 +594,6 @@ config SERIAL_OF_PLATFORM
are probed through devicetree, including Open Firmware based
PowerPC systems and embedded systems on architectures using the
flattened device tree format.
+
+config SERIAL_8250_DWLIB
+ bool
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 59221cce0028..f86775cfdcc9 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -413,6 +413,10 @@ config SERIAL_21285_CONSOLE
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
+config SERIAL_PXA_NON8250
+ bool
+ depends on !SERIAL_8250 || COMPILE_TEST
+
config SERIAL_PXA
bool "PXA serial port support (DEPRECATED)"
depends on ARCH_PXA || ARCH_MMP
@@ -426,10 +430,6 @@ config SERIAL_PXA
Unless you have a specific need, you should use SERIAL_8250_PXA
instead of this.
-config SERIAL_PXA_NON8250
- bool
- depends on !SERIAL_8250 || COMPILE_TEST
-
config SERIAL_PXA_CONSOLE
bool "Console on PXA serial port (DEPRECATED)"
depends on SERIAL_PXA
@@ -486,14 +486,14 @@ config SERIAL_IMX
can enable its onboard serial port by enabling this option.
config SERIAL_IMX_CONSOLE
- tristate "Console on IMX serial port"
+ bool "Console on IMX serial port"
depends on SERIAL_IMX
select SERIAL_CORE_CONSOLE
help
If you have enabled the serial port on the Freescale IMX
- CPU you can make it the console by answering Y/M to this option.
+ CPU you can make it the console by answering Y to this option.
- Even if you say Y/M here, the currently visible virtual console
+ Even if you say Y here, the currently visible virtual console
(/dev/tty0) will still be used as the system console by default, but
you can alter that using a kernel command line option such as
"console=ttymxc0". (Try "man bootparam" or see the documentation of
@@ -671,7 +671,7 @@ config SERIAL_SH_SCI_EARLYCON
default ARCH_RENESAS
config SERIAL_SH_SCI_DMA
- bool "DMA support" if EXPERT
+ bool "Support for DMA on SuperH SCI(F)" if EXPERT
depends on SERIAL_SH_SCI && DMA_ENGINE
default ARCH_RENESAS
@@ -863,15 +863,15 @@ config SERIAL_ICOM
This driver can also be built as a module. If so, the module
will be called icom.
+config HAS_TXX9_SERIAL
+ bool
+
config SERIAL_TXX9
bool "TMPTX39XX/49XX SIO support"
depends on HAS_TXX9_SERIAL
select SERIAL_CORE
default y
-config HAS_TXX9_SERIAL
- bool
-
config SERIAL_TXX9_NR_UARTS
int "Maximum number of TMPTX39XX/49XX SIO ports"
depends on SERIAL_TXX9
@@ -1251,12 +1251,6 @@ config SERIAL_AR933X_NR_UARTS
Set this to the number of serial ports you want the driver
to support.
-config SERIAL_MPS2_UART_CONSOLE
- bool "MPS2 UART console support"
- depends on SERIAL_MPS2_UART
- select SERIAL_CORE_CONSOLE
- select SERIAL_EARLYCON
-
config SERIAL_MPS2_UART
bool "MPS2 UART port"
depends on ARCH_MPS2 || COMPILE_TEST
@@ -1264,6 +1258,12 @@ config SERIAL_MPS2_UART
help
This driver support the UART ports on ARM MPS2.
+config SERIAL_MPS2_UART_CONSOLE
+ bool "MPS2 UART console support"
+ depends on SERIAL_MPS2_UART
+ select SERIAL_CORE_CONSOLE
+ select SERIAL_EARLYCON
+
config SERIAL_ARC
tristate "ARC UART driver support"
select SERIAL_CORE
diff --git a/drivers/tty/serial/men_z135_uart.c b/drivers/tty/serial/men_z135_uart.c
index 9cc15449b673..6fad57fee912 100644
--- a/drivers/tty/serial/men_z135_uart.c
+++ b/drivers/tty/serial/men_z135_uart.c
@@ -919,5 +919,4 @@ module_exit(men_z135_exit);
MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("MEN 16z135 High Speed UART");
-MODULE_ALIAS("mcb:16z135");
MODULE_IMPORT_NS("MCB");
diff --git a/drivers/tty/serial/rsci.c b/drivers/tty/serial/rsci.c
index b3c48dc1e07d..c3f12df693ad 100644
--- a/drivers/tty/serial/rsci.c
+++ b/drivers/tty/serial/rsci.c
@@ -11,6 +11,8 @@
#include <linux/serial_core.h>
#include <linux/serial_sci.h>
#include <linux/tty_flip.h>
+
+#include "serial_mctrl_gpio.h"
#include "rsci.h"
MODULE_IMPORT_NS("SH_SCI");
@@ -24,7 +26,6 @@ MODULE_IMPORT_NS("SH_SCI");
#define CCR3 0x14
#define CCR4 0x18
#define FCR 0x24
-#define DCR 0x30
#define CSR 0x48
#define FRSR 0x50
#define FTSR 0x54
@@ -36,12 +37,6 @@ MODULE_IMPORT_NS("SH_SCI");
#define RDR_FPER BIT(11) /* FIFO Parity Error */
#define RDR_RDAT_MSK GENMASK(8, 0)
-/* TDR (Transmit Data Register) */
-#define TDR_MPBT BIT(9) /* Multiprocessor Transfer */
-#define TDR_TDAT_9BIT_LSHIFT 0
-#define TDR_TDAT_9BIT_VAL 0x1FF
-#define TDR_TDAT_9BIT_MSK (TDR_TDAT_9BIT_VAL << TDR_TDAT_9BIT_LSHIFT)
-
/* CCR0 (Common Control Register 0) */
#define CCR0_SSE BIT(24) /* SSn# Pin Function Enable */
#define CCR0_TEIE BIT(21) /* Transmit End Interrupt Enable */
@@ -66,6 +61,41 @@ MODULE_IMPORT_NS("SH_SCI");
#define CCR1_CTSPEN BIT(1) /* CTS External Pin Enable */
#define CCR1_CTSE BIT(0) /* CTS Enable */
+/* CCR2 (Common Control Register 2) */
+#define CCR2_INIT 0xFF000004
+#define CCR2_CKS_TCLK (0) /* TCLK clock */
+#define CCR2_CKS_TCLK_DIV4 BIT(20) /* TCLK/4 clock */
+#define CCR2_CKS_TCLK_DIV16 BIT(21) /* TCLK16 clock */
+#define CCR2_CKS_TCLK_DIV64 (BIT(21) | BIT(20)) /* TCLK/64 clock */
+#define CCR2_BRME BIT(16) /* Bitrate Modulation Enable */
+#define CCR2_ABCSE BIT(6) /* Asynchronous Mode Extended Base Clock Select */
+#define CCR2_ABCS BIT(5) /* Asynchronous Mode Base Clock Select */
+#define CCR2_BGDM BIT(4) /* Baud Rate Generator Double-Speed Mode Select */
+
+/* CCR3 (Common Control Register 3) */
+#define CCR3_INIT 0x1203
+#define CCR3_BLK BIT(29) /* Block Transfer Mode */
+#define CCR3_GM BIT(28) /* GSM Mode */
+#define CCR3_CKE1 BIT(25) /* Clock Enable 1 */
+#define CCR3_CKE0 BIT(24) /* Clock Enable 0 */
+#define CCR3_DEN BIT(21) /* Driver Enabled */
+#define CCR3_FM BIT(20) /* FIFO Mode Select */
+#define CCR3_MP BIT(19) /* Multi-Processor Mode */
+#define CCR3_MOD_ASYNC 0 /* Asynchronous mode (Multi-processor mode) */
+#define CCR3_MOD_IRDA BIT(16) /* Smart card interface mode */
+#define CCR3_MOD_CLK_SYNC BIT(17) /* Clock synchronous mode */
+#define CCR3_MOD_SPI (BIT(17) | BIT(16)) /* Simple SPI mode */
+#define CCR3_MOD_I2C BIT(18) /* Simple I2C mode */
+#define CCR3_RXDESEL BIT(15) /* Asynchronous Start Bit Edge Detection Select */
+#define CCR3_STP BIT(14) /* Stop bit Length */
+#define CCR3_SINV BIT(13) /* Transmitted/Received Data Invert */
+#define CCR3_LSBF BIT(12) /* LSB First select */
+#define CCR3_CHR1 BIT(9) /* Character Length */
+#define CCR3_CHR0 BIT(8) /* Character Length */
+#define CCR3_BPEN BIT(7) /* Synchronizer Bypass Enable */
+#define CCR3_CPOL BIT(1) /* Clock Polarity Select */
+#define CCR3_CPHA BIT(0) /* Clock Phase Select */
+
/* FCR (FIFO Control Register) */
#define FCR_RFRST BIT(23) /* Receive FIFO Data Register Reset */
#define FCR_TFRST BIT(15) /* Transmit FIFO Data Register Reset */
@@ -119,8 +149,6 @@ MODULE_IMPORT_NS("SH_SCI");
/* FFCLR (FIFO Flag CLear Register) */
#define FFCLR_DRC BIT(0) /* DR Clear */
-#define DCR_DEPOL BIT(0)
-
static u32 rsci_serial_in(struct uart_port *p, int offset)
{
return readl(p->membase + offset);
@@ -137,10 +165,6 @@ static void rsci_clear_DRxC(struct uart_port *port)
rsci_serial_out(port, FFCLR, FFCLR_DRC);
}
-static void rsci_clear_SCxSR(struct uart_port *port, unsigned int mask)
-{
- rsci_serial_out(port, CFCLR, mask);
-}
static void rsci_start_rx(struct uart_port *port)
{
@@ -151,21 +175,160 @@ static void rsci_start_rx(struct uart_port *port)
rsci_serial_out(port, CCR0, ctrl);
}
+static void rsci_enable_ms(struct uart_port *port)
+{
+ mctrl_gpio_enable_ms(to_sci_port(port)->gpios);
+}
+
+static void rsci_init_pins(struct uart_port *port, unsigned int cflag)
+{
+ struct sci_port *s = to_sci_port(port);
+
+ /* Use port-specific handler if provided */
+ if (s->cfg->ops && s->cfg->ops->init_pins) {
+ s->cfg->ops->init_pins(port, cflag);
+ return;
+ }
+
+ if (!s->has_rtscts)
+ return;
+
+ if (s->autorts)
+ rsci_serial_out(port, CCR1, rsci_serial_in(port, CCR1) |
+ CCR1_CTSE | CCR1_CTSPEN);
+}
+
+static int rsci_scif_set_rtrg(struct uart_port *port, int rx_trig)
+{
+ u32 fcr = rsci_serial_in(port, FCR);
+
+ if (rx_trig >= port->fifosize)
+ rx_trig = port->fifosize - 1;
+ else if (rx_trig < 1)
+ rx_trig = 0;
+
+ FIELD_MODIFY(FCR_RTRG4_0, &fcr, rx_trig);
+ rsci_serial_out(port, FCR, fcr);
+
+ return rx_trig;
+}
+
static void rsci_set_termios(struct uart_port *port, struct ktermios *termios,
const struct ktermios *old)
{
+ unsigned int ccr2_val = CCR2_INIT, ccr3_val = CCR3_INIT;
+ unsigned int ccr0_val = 0, ccr1_val = 0, ccr4_val = 0;
+ unsigned int brr1 = 255, cks1 = 0, srr1 = 15;
struct sci_port *s = to_sci_port(port);
+ unsigned int brr = 255, cks = 0;
+ int min_err = INT_MAX, err;
+ unsigned long max_freq = 0;
+ unsigned int baud, i;
unsigned long flags;
+ unsigned int ctrl;
+ int best_clk = -1;
+
+ if ((termios->c_cflag & CSIZE) == CS7) {
+ ccr3_val |= CCR3_CHR0;
+ } else {
+ termios->c_cflag &= ~CSIZE;
+ termios->c_cflag |= CS8;
+ }
+
+ if (termios->c_cflag & PARENB)
+ ccr1_val |= CCR1_PE;
+
+ if (termios->c_cflag & PARODD)
+ ccr1_val |= (CCR1_PE | CCR1_PM);
+
+ if (termios->c_cflag & CSTOPB)
+ ccr3_val |= CCR3_STP;
+
+ /* Enable noise filter function */
+ ccr1_val |= CCR1_NFEN;
+
+ /*
+ * earlyprintk comes here early on with port->uartclk set to zero.
+ * the clock framework is not up and running at this point so here
+ * we assume that 115200 is the maximum baud rate. please note that
+ * the baud rate is not programmed during earlyprintk - it is assumed
+ * that the previous boot loader has enabled required clocks and
+ * setup the baud rate generator hardware for us already.
+ */
+ if (!port->uartclk) {
+ max_freq = 115200;
+ } else {
+ for (i = 0; i < SCI_NUM_CLKS; i++)
+ max_freq = max(max_freq, s->clk_rates[i]);
+
+ max_freq /= min_sr(s);
+ }
+
+ baud = uart_get_baud_rate(port, termios, old, 0, max_freq);
+ if (!baud)
+ goto done;
+
+ /* Divided Functional Clock using standard Bit Rate Register */
+ err = sci_scbrr_calc(s, baud, &brr1, &srr1, &cks1);
+ if (abs(err) < abs(min_err)) {
+ best_clk = SCI_FCK;
+ ccr0_val = 0;
+ min_err = err;
+ brr = brr1;
+ cks = cks1;
+ }
+
+done:
+ if (best_clk >= 0)
+ dev_dbg(port->dev, "Using clk %pC for %u%+d bps\n",
+ s->clks[best_clk], baud, min_err);
sci_port_enable(s);
uart_port_lock_irqsave(port, &flags);
- /* For now, only RX enabling is supported */
- if (termios->c_cflag & CREAD)
+ uart_update_timeout(port, termios->c_cflag, baud);
+
+ rsci_serial_out(port, CCR0, ccr0_val);
+
+ ccr3_val |= CCR3_FM;
+ rsci_serial_out(port, CCR3, ccr3_val);
+
+ ccr2_val |= (cks << 20) | (brr << 8);
+ rsci_serial_out(port, CCR2, ccr2_val);
+
+ rsci_serial_out(port, CCR1, ccr1_val);
+ rsci_serial_out(port, CCR4, ccr4_val);
+
+ ctrl = rsci_serial_in(port, FCR);
+ ctrl |= (FCR_RFRST | FCR_TFRST);
+ rsci_serial_out(port, FCR, ctrl);
+
+ if (s->rx_trigger > 1)
+ rsci_scif_set_rtrg(port, s->rx_trigger);
+
+ port->status &= ~UPSTAT_AUTOCTS;
+ s->autorts = false;
+
+ if ((port->flags & UPF_HARD_FLOW) && (termios->c_cflag & CRTSCTS)) {
+ port->status |= UPSTAT_AUTOCTS;
+ s->autorts = true;
+ }
+
+ rsci_init_pins(port, termios->c_cflag);
+ rsci_serial_out(port, CFCLR, CFCLR_CLRFLAG);
+ rsci_serial_out(port, FFCLR, FFCLR_DRC);
+
+ ccr0_val |= CCR0_RE;
+ rsci_serial_out(port, CCR0, ccr0_val);
+
+ if ((termios->c_cflag & CREAD) != 0)
rsci_start_rx(port);
uart_port_unlock_irqrestore(port, flags);
sci_port_disable(s);
+
+ if (UART_ENABLE_MS(port, termios->c_cflag))
+ rsci_enable_ms(port);
}
static int rsci_txfill(struct uart_port *port)
@@ -190,13 +353,34 @@ static unsigned int rsci_tx_empty(struct uart_port *port)
static void rsci_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
- /* Not supported yet */
+ if (mctrl & TIOCM_LOOP) {
+ /* Standard loopback mode */
+ rsci_serial_out(port, CCR1, rsci_serial_in(port, CCR1) | CCR1_SPLP);
+ }
}
static unsigned int rsci_get_mctrl(struct uart_port *port)
{
- /* Not supported yet */
- return 0;
+ struct sci_port *s = to_sci_port(port);
+ struct mctrl_gpios *gpios = s->gpios;
+ unsigned int mctrl = 0;
+
+ mctrl_gpio_get(gpios, &mctrl);
+
+ /*
+ * CTS/RTS is handled in hardware when supported, while nothing
+ * else is wired up.
+ */
+ if (!mctrl_gpio_to_gpiod(gpios, UART_GPIO_CTS))
+ mctrl |= TIOCM_CTS;
+
+ if (!mctrl_gpio_to_gpiod(gpios, UART_GPIO_DSR))
+ mctrl |= TIOCM_DSR;
+
+ if (!mctrl_gpio_to_gpiod(gpios, UART_GPIO_DCD))
+ mctrl |= TIOCM_CAR;
+
+ return mctrl;
}
static void rsci_clear_CFC(struct uart_port *port, unsigned int mask)
@@ -326,7 +510,8 @@ static void rsci_receive_chars(struct uart_port *port)
continue;
}
- /* Store data and status.
+ /*
+ * Store data and status.
* Non FIFO mode is not supported
*/
if (rdat & RDR_FFER) {
@@ -360,6 +545,28 @@ static void rsci_receive_chars(struct uart_port *port)
}
}
+static void rsci_break_ctl(struct uart_port *port, int break_state)
+{
+ unsigned short ccr0_val, ccr1_val;
+ unsigned long flags;
+
+ uart_port_lock_irqsave(port, &flags);
+ ccr1_val = rsci_serial_in(port, CCR1);
+ ccr0_val = rsci_serial_in(port, CCR0);
+
+ if (break_state == -1) {
+ ccr1_val = (ccr1_val | CCR1_SPB2IO) & ~CCR1_SPB2DT;
+ ccr0_val &= ~CCR0_TE;
+ } else {
+ ccr1_val = (ccr1_val | CCR1_SPB2DT) & ~CCR1_SPB2IO;
+ ccr0_val |= CCR0_TE;
+ }
+
+ rsci_serial_out(port, CCR1, ccr1_val);
+ rsci_serial_out(port, CCR0, ccr0_val);
+ uart_port_unlock_irqrestore(port, flags);
+}
+
static void rsci_poll_put_char(struct uart_port *port, unsigned char c)
{
u32 status;
@@ -375,18 +582,27 @@ static void rsci_poll_put_char(struct uart_port *port, unsigned char c)
}
rsci_serial_out(port, TDR, c);
done:
- rsci_clear_SCxSR(port, CFCLR_TDREC);
+ rsci_clear_CFC(port, CFCLR_TDREC);
}
static void rsci_prepare_console_write(struct uart_port *port, u32 ctrl)
{
struct sci_port *s = to_sci_port(port);
- u32 ctrl_temp =
- s->params->param_bits->rxtx_enable | CCR0_TIE |
- s->hscif_tot;
+ u32 ctrl_temp = s->params->param_bits->rxtx_enable;
+
+ if (s->type == RSCI_PORT_SCIF16)
+ ctrl_temp |= CCR0_TIE | s->hscif_tot;
+
rsci_serial_out(port, CCR0, ctrl_temp);
}
+static void rsci_finish_console_write(struct uart_port *port, u32 ctrl)
+{
+ /* First set TE = 0 and then restore the CCR0 value */
+ rsci_serial_out(port, CCR0, ctrl & ~CCR0_TE);
+ rsci_serial_out(port, CCR0, ctrl);
+}
+
static const char *rsci_type(struct uart_port *port)
{
return "rsci";
@@ -416,7 +632,18 @@ static const struct sci_port_params_bits rsci_port_param_bits = {
.poll_sent_bits = CSR_TDRE | CSR_TEND,
};
-static const struct sci_port_params rsci_port_params = {
+static const struct sci_port_params rsci_rzg3e_port_params = {
+ .fifosize = 32,
+ .overrun_reg = CSR,
+ .overrun_mask = CSR_ORER,
+ .sampling_rate_mask = SCI_SR(32),
+ .error_mask = RSCI_DEFAULT_ERROR_MASK,
+ .error_clear = RSCI_ERROR_CLEAR,
+ .param_bits = &rsci_port_param_bits,
+ .common_regs = &rsci_common_regs,
+};
+
+static const struct sci_port_params rsci_rzt2h_port_params = {
.fifosize = 16,
.overrun_reg = CSR,
.overrun_mask = CSR_ORER,
@@ -434,6 +661,8 @@ static const struct uart_ops rsci_uart_ops = {
.start_tx = rsci_start_tx,
.stop_tx = rsci_stop_tx,
.stop_rx = rsci_stop_rx,
+ .enable_ms = rsci_enable_ms,
+ .break_ctl = rsci_break_ctl,
.startup = sci_startup,
.shutdown = sci_shutdown,
.set_termios = rsci_set_termios,
@@ -448,31 +677,47 @@ static const struct uart_ops rsci_uart_ops = {
static const struct sci_port_ops rsci_port_ops = {
.read_reg = rsci_serial_in,
.write_reg = rsci_serial_out,
- .clear_SCxSR = rsci_clear_SCxSR,
+ .clear_SCxSR = rsci_clear_CFC,
.transmit_chars = rsci_transmit_chars,
.receive_chars = rsci_receive_chars,
.poll_put_char = rsci_poll_put_char,
.prepare_console_write = rsci_prepare_console_write,
+ .finish_console_write = rsci_finish_console_write,
.suspend_regs_size = rsci_suspend_regs_size,
+ .set_rtrg = rsci_scif_set_rtrg,
.shutdown_complete = rsci_shutdown_complete,
};
-struct sci_of_data of_sci_rsci_data = {
- .type = SCI_PORT_RSCI,
+struct sci_of_data of_rsci_rzg3e_data = {
+ .type = RSCI_PORT_SCIF32,
+ .ops = &rsci_port_ops,
+ .uart_ops = &rsci_uart_ops,
+ .params = &rsci_rzg3e_port_params,
+};
+
+struct sci_of_data of_rsci_rzt2h_data = {
+ .type = RSCI_PORT_SCIF16,
.ops = &rsci_port_ops,
.uart_ops = &rsci_uart_ops,
- .params = &rsci_port_params,
+ .params = &rsci_rzt2h_port_params,
};
#ifdef CONFIG_SERIAL_SH_SCI_EARLYCON
-static int __init rsci_early_console_setup(struct earlycon_device *device,
- const char *opt)
+static int __init rsci_rzg3e_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ return scix_early_console_setup(device, &of_rsci_rzg3e_data);
+}
+
+static int __init rsci_rzt2h_early_console_setup(struct earlycon_device *device,
+ const char *opt)
{
- return scix_early_console_setup(device, &of_sci_rsci_data);
+ return scix_early_console_setup(device, &of_rsci_rzt2h_data);
}
-OF_EARLYCON_DECLARE(rsci, "renesas,r9a09g077-rsci", rsci_early_console_setup);
+OF_EARLYCON_DECLARE(rsci, "renesas,r9a09g047-rsci", rsci_rzg3e_early_console_setup);
+OF_EARLYCON_DECLARE(rsci, "renesas,r9a09g077-rsci", rsci_rzt2h_early_console_setup);
#endif /* CONFIG_SERIAL_SH_SCI_EARLYCON */
diff --git a/drivers/tty/serial/rsci.h b/drivers/tty/serial/rsci.h
index 2af3f28b465a..2aa2ba3973ee 100644
--- a/drivers/tty/serial/rsci.h
+++ b/drivers/tty/serial/rsci.h
@@ -5,6 +5,7 @@
#include "sh-sci-common.h"
-extern struct sci_of_data of_sci_rsci_data;
+extern struct sci_of_data of_rsci_rzg3e_data;
+extern struct sci_of_data of_rsci_rzt2h_data;
#endif /* __RSCI_H__ */
diff --git a/drivers/tty/serial/sh-sci-common.h b/drivers/tty/serial/sh-sci-common.h
index e3c028df14f1..f363a659c46a 100644
--- a/drivers/tty/serial/sh-sci-common.h
+++ b/drivers/tty/serial/sh-sci-common.h
@@ -7,7 +7,8 @@
/* Private port IDs */
enum SCI_PORT_TYPE {
- SCI_PORT_RSCI = BIT(7) | 0,
+ RSCI_PORT_SCIF16 = BIT(7) | 0,
+ RSCI_PORT_SCIF32 = BIT(7) | 1,
};
enum SCI_CLKS {
@@ -15,6 +16,9 @@ enum SCI_CLKS {
SCI_SCK, /* Optional External Clock */
SCI_BRG_INT, /* Optional BRG Internal Clock Source */
SCI_SCIF_CLK, /* Optional BRG External Clock Source */
+ SCI_FCK_DIV4, /* Optional Functional Clock frequency-divided by 4 */
+ SCI_FCK_DIV16, /* Optional Functional Clock frequency-divided by 16 */
+ SCI_FCK_DIV64, /* Optional Functional Clock frequency-divided by 64 */
SCI_NUM_CLKS
};
@@ -89,6 +93,7 @@ struct sci_port_ops {
void (*shutdown_complete)(struct uart_port *port);
void (*prepare_console_write)(struct uart_port *port, u32 ctrl);
+ void (*finish_console_write)(struct uart_port *port, u32 ctrl);
void (*console_save)(struct uart_port *port);
void (*console_restore)(struct uart_port *port);
size_t (*suspend_regs_size)(void);
@@ -165,6 +170,9 @@ void sci_port_enable(struct sci_port *sci_port);
int sci_startup(struct uart_port *port);
void sci_shutdown(struct uart_port *port);
+int sci_scbrr_calc(struct sci_port *s, unsigned int bps, unsigned int *brr,
+ unsigned int *srr, unsigned int *cks);
+
#define min_sr(_port) ffs((_port)->sampling_rate_mask)
#define max_sr(_port) fls((_port)->sampling_rate_mask)
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index fbfe5575bd3c..bd7486315338 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -1182,6 +1182,11 @@ static int sci_handle_errors(struct uart_port *port)
return copied;
}
+static bool sci_is_rsci_type(u8 type)
+{
+ return (type == RSCI_PORT_SCIF16 || type == RSCI_PORT_SCIF32);
+}
+
static int sci_handle_fifo_overrun(struct uart_port *port)
{
struct tty_port *tport = &port->state->port;
@@ -1190,7 +1195,7 @@ static int sci_handle_fifo_overrun(struct uart_port *port)
int copied = 0;
u32 status;
- if (s->type != SCI_PORT_RSCI) {
+ if (!sci_is_rsci_type(s->type)) {
reg = sci_getreg(port, s->params->overrun_reg);
if (!reg->size)
return 0;
@@ -1198,7 +1203,7 @@ static int sci_handle_fifo_overrun(struct uart_port *port)
status = s->ops->read_reg(port, s->params->overrun_reg);
if (status & s->params->overrun_mask) {
- if (s->type == SCI_PORT_RSCI) {
+ if (sci_is_rsci_type(s->type)) {
/*
* All of the CFCLR_*C clearing bits match the corresponding
* CSR_*status bits. So, reuse the overrun mask for clearing.
@@ -2015,7 +2020,7 @@ static irqreturn_t sci_tx_end_interrupt(int irq, void *ptr)
unsigned long flags;
u32 ctrl;
- if (s->type != PORT_SCI && s->type != SCI_PORT_RSCI)
+ if (s->type != PORT_SCI && !sci_is_rsci_type(s->type))
return sci_tx_interrupt(irq, ptr);
uart_port_lock_irqsave(port, &flags);
@@ -2568,9 +2573,8 @@ static int sci_brg_calc(struct sci_port *s, unsigned int bps,
}
/* calculate sample rate, BRR, and clock select */
-static int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
- unsigned int *brr, unsigned int *srr,
- unsigned int *cks)
+int sci_scbrr_calc(struct sci_port *s, unsigned int bps, unsigned int *brr,
+ unsigned int *srr, unsigned int *cks)
{
unsigned long freq = s->clk_rates[SCI_FCK];
unsigned int sr, br, prediv, scrate, c;
@@ -2634,6 +2638,7 @@ found:
min_err, *brr, *srr + 1, *cks);
return min_err;
}
+EXPORT_SYMBOL_NS_GPL(sci_scbrr_calc, "SH_SCI");
static void sci_reset(struct uart_port *port)
{
@@ -3167,15 +3172,21 @@ static int sci_init_clocks(struct sci_port *sci_port, struct device *dev)
[SCI_SCK] = "sck",
[SCI_BRG_INT] = "brg_int",
[SCI_SCIF_CLK] = "scif_clk",
+ [SCI_FCK_DIV4] = "tclk_div4",
+ [SCI_FCK_DIV16] = "tclk_div16",
+ [SCI_FCK_DIV64] = "tclk_div64",
};
struct clk *clk;
unsigned int i;
if (sci_port->type == PORT_HSCIF) {
clk_names[SCI_SCK] = "hsck";
- } else if (sci_port->type == SCI_PORT_RSCI) {
+ } else if (sci_port->type == RSCI_PORT_SCIF16) {
clk_names[SCI_FCK] = "operation";
clk_names[SCI_BRG_INT] = "bus";
+ } else if (sci_port->type == RSCI_PORT_SCIF32) {
+ clk_names[SCI_FCK] = "tclk";
+ clk_names[SCI_BRG_INT] = "pclk";
}
for (i = 0; i < SCI_NUM_CLKS; i++) {
@@ -3185,12 +3196,13 @@ static int sci_init_clocks(struct sci_port *sci_port, struct device *dev)
if (IS_ERR(clk))
return PTR_ERR(clk);
- if (!clk && sci_port->type == SCI_PORT_RSCI &&
- (i == SCI_FCK || i == SCI_BRG_INT)) {
- return dev_err_probe(dev, -ENODEV,
- "failed to get %s\n",
- name);
- }
+ if (!clk && sci_port->type == RSCI_PORT_SCIF16 &&
+ (i == SCI_FCK || i == SCI_BRG_INT))
+ return dev_err_probe(dev, -ENODEV, "failed to get %s\n", name);
+
+ if (!clk && sci_port->type == RSCI_PORT_SCIF32 &&
+ (i != SCI_SCK && i != SCI_SCIF_CLK))
+ return dev_err_probe(dev, -ENODEV, "failed to get %s\n", name);
if (!clk && i == SCI_FCK) {
/*
@@ -3200,16 +3212,13 @@ static int sci_init_clocks(struct sci_port *sci_port, struct device *dev)
*/
clk = devm_clk_get(dev, "peripheral_clk");
if (IS_ERR(clk))
- return dev_err_probe(dev, PTR_ERR(clk),
- "failed to get %s\n",
- name);
+ return dev_err_probe(dev, PTR_ERR(clk), "failed to get %s\n", name);
}
if (!clk)
dev_dbg(dev, "failed to get %s\n", name);
else
- dev_dbg(dev, "clk %s is %pC rate %lu\n", name,
- clk, clk_get_rate(clk));
+ dev_dbg(dev, "clk %s is %pC rate %lu\n", name, clk, clk_get_rate(clk));
sci_port->clks[i] = clk;
}
return 0;
@@ -3295,7 +3304,7 @@ static int sci_init_single(struct platform_device *dev,
* The fourth interrupt on SCI and RSCI port is transmit end interrupt, so
* shuffle the interrupts.
*/
- if (p->type == PORT_SCI || p->type == SCI_PORT_RSCI)
+ if (p->type == PORT_SCI || sci_is_rsci_type(p->type))
swap(sci_port->irqs[SCIx_BRI_IRQ], sci_port->irqs[SCIx_TEI_IRQ]);
/* The SCI generates several interrupts. They can be muxed together or
@@ -3320,6 +3329,7 @@ static int sci_init_single(struct platform_device *dev,
sci_port->rx_trigger = 64;
break;
case PORT_SCIFA:
+ case RSCI_PORT_SCIF32:
sci_port->rx_trigger = 32;
break;
case PORT_SCIF:
@@ -3329,8 +3339,8 @@ static int sci_init_single(struct platform_device *dev,
else
sci_port->rx_trigger = 8;
break;
- case SCI_PORT_RSCI:
- sci_port->rx_trigger = 15;
+ case RSCI_PORT_SCIF16:
+ sci_port->rx_trigger = 16;
break;
default:
sci_port->rx_trigger = 1;
@@ -3422,7 +3432,10 @@ static void serial_console_write(struct console *co, const char *s,
cpu_relax();
/* restore the SCSCR */
- sci_port->ops->write_reg(port, regs->control, ctrl);
+ if (sci_port->ops->finish_console_write)
+ sci_port->ops->finish_console_write(port, ctrl);
+ else
+ sci_port->ops->write_reg(port, regs->control, ctrl);
if (locked)
uart_port_unlock_irqrestore(port, flags);
@@ -3549,16 +3562,14 @@ static struct uart_driver sci_uart_driver = {
static void sci_remove(struct platform_device *dev)
{
struct sci_port *s = platform_get_drvdata(dev);
- unsigned int type = s->type; /* uart_remove_... clears it */
sci_ports_in_use &= ~BIT(s->port.line);
uart_remove_one_port(&sci_uart_driver, &s->port);
- if (s->port.fifosize > 1)
+ if (s->port.fifosize > 1) {
device_remove_file(&dev->dev, &dev_attr_rx_fifo_trigger);
- if (type == PORT_SCIFA || type == PORT_SCIFB || type == PORT_HSCIF ||
- type == SCI_PORT_RSCI)
device_remove_file(&dev->dev, &dev_attr_rx_fifo_timeout);
+ }
}
static const struct sci_of_data of_sci_scif_sh2 = {
@@ -3653,8 +3664,12 @@ static const struct of_device_id of_sci_match[] __maybe_unused = {
},
#ifdef CONFIG_SERIAL_RSCI
{
+ .compatible = "renesas,r9a09g047-rsci",
+ .data = &of_rsci_rzg3e_data,
+ },
+ {
.compatible = "renesas,r9a09g077-rsci",
- .data = &of_sci_rsci_data,
+ .data = &of_rsci_rzt2h_data,
},
#endif /* CONFIG_SERIAL_RSCI */
/* Family-specific types */
@@ -3716,7 +3731,7 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev,
data = of_device_get_match_data(&pdev->dev);
- rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
+ rstc = devm_reset_control_array_get_optional_exclusive(&pdev->dev);
if (IS_ERR(rstc))
return ERR_PTR(dev_err_probe(&pdev->dev, PTR_ERR(rstc),
"failed to get reset ctrl\n"));
@@ -3917,15 +3932,10 @@ static int sci_probe(struct platform_device *dev)
ret = device_create_file(&dev->dev, &dev_attr_rx_fifo_trigger);
if (ret)
return ret;
- }
- if (sp->type == PORT_SCIFA || sp->type == PORT_SCIFB ||
- sp->type == PORT_HSCIF || sp->type == SCI_PORT_RSCI) {
+
ret = device_create_file(&dev->dev, &dev_attr_rx_fifo_timeout);
if (ret) {
- if (sp->port.fifosize > 1) {
- device_remove_file(&dev->dev,
- &dev_attr_rx_fifo_trigger);
- }
+ device_remove_file(&dev->dev, &dev_attr_rx_fifo_trigger);
return ret;
}
}
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index d65fc60dd7be..3538d54d6a6a 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -1649,134 +1649,143 @@ int __init kbd_init(void)
/* Ioctl support code */
-/**
- * vt_do_diacrit - diacritical table updates
- * @cmd: ioctl request
- * @udp: pointer to user data for ioctl
- * @perm: permissions check computed by caller
- *
- * Update the diacritical tables atomically and safely. Lock them
- * against simultaneous keypresses
- */
-int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm)
+static int vt_do_kdgkbdiacr(void __user *udp)
{
- int asize;
-
- switch (cmd) {
- case KDGKBDIACR:
- {
- struct kbdiacrs __user *a = udp;
- int i;
+ struct kbdiacrs __user *a = udp;
+ int i, asize;
- struct kbdiacr __free(kfree) *dia = kmalloc_array(MAX_DIACR, sizeof(struct kbdiacr),
- GFP_KERNEL);
- if (!dia)
- return -ENOMEM;
+ struct kbdiacr __free(kfree) *dia = kmalloc_array(MAX_DIACR, sizeof(struct kbdiacr),
+ GFP_KERNEL);
+ if (!dia)
+ return -ENOMEM;
- /* Lock the diacriticals table, make a copy and then
- copy it after we unlock */
- scoped_guard(spinlock_irqsave, &kbd_event_lock) {
- asize = accent_table_size;
- for (i = 0; i < asize; i++) {
- dia[i].diacr = conv_uni_to_8bit(accent_table[i].diacr);
- dia[i].base = conv_uni_to_8bit(accent_table[i].base);
- dia[i].result = conv_uni_to_8bit(accent_table[i].result);
- }
+ /* Lock the diacriticals table, make a copy and then
+ copy it after we unlock */
+ scoped_guard(spinlock_irqsave, &kbd_event_lock) {
+ asize = accent_table_size;
+ for (i = 0; i < asize; i++) {
+ dia[i].diacr = conv_uni_to_8bit(accent_table[i].diacr);
+ dia[i].base = conv_uni_to_8bit(accent_table[i].base);
+ dia[i].result = conv_uni_to_8bit(accent_table[i].result);
}
-
- if (put_user(asize, &a->kb_cnt))
- return -EFAULT;
- if (copy_to_user(a->kbdiacr, dia, asize * sizeof(struct kbdiacr)))
- return -EFAULT;
- return 0;
}
- case KDGKBDIACRUC:
- {
- struct kbdiacrsuc __user *a = udp;
- void __free(kfree) *buf = kmalloc_array(MAX_DIACR, sizeof(struct kbdiacruc),
- GFP_KERNEL);
- if (buf == NULL)
- return -ENOMEM;
+ if (put_user(asize, &a->kb_cnt))
+ return -EFAULT;
+ if (copy_to_user(a->kbdiacr, dia, asize * sizeof(struct kbdiacr)))
+ return -EFAULT;
+ return 0;
+}
- /* Lock the diacriticals table, make a copy and then
- copy it after we unlock */
- scoped_guard(spinlock_irqsave, &kbd_event_lock) {
- asize = accent_table_size;
- memcpy(buf, accent_table, asize * sizeof(struct kbdiacruc));
- }
+static int vt_do_kdgkbdiacruc(void __user *udp)
+{
+ struct kbdiacrsuc __user *a = udp;
+ int asize;
- if (put_user(asize, &a->kb_cnt))
- return -EFAULT;
- if (copy_to_user(a->kbdiacruc, buf, asize * sizeof(struct kbdiacruc)))
- return -EFAULT;
+ void __free(kfree) *buf = kmalloc_array(MAX_DIACR, sizeof(struct kbdiacruc),
+ GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
- return 0;
+ /* Lock the diacriticals table, make a copy and then
+ copy it after we unlock */
+ scoped_guard(spinlock_irqsave, &kbd_event_lock) {
+ asize = accent_table_size;
+ memcpy(buf, accent_table, asize * sizeof(struct kbdiacruc));
}
- case KDSKBDIACR:
- {
- struct kbdiacrs __user *a = udp;
- struct kbdiacr __free(kfree) *dia = NULL;
- unsigned int ct;
- int i;
+ if (put_user(asize, &a->kb_cnt))
+ return -EFAULT;
+ if (copy_to_user(a->kbdiacruc, buf, asize * sizeof(struct kbdiacruc)))
+ return -EFAULT;
- if (!perm)
- return -EPERM;
- if (get_user(ct, &a->kb_cnt))
- return -EFAULT;
- if (ct >= MAX_DIACR)
- return -EINVAL;
+ return 0;
+}
- if (ct) {
- dia = memdup_array_user(a->kbdiacr,
- ct, sizeof(struct kbdiacr));
- if (IS_ERR(dia))
- return PTR_ERR(dia);
- }
+static int vt_do_kdskbdiacr(void __user *udp, int perm)
+{
+ struct kbdiacrs __user *a = udp;
+ struct kbdiacr __free(kfree) *dia = NULL;
+ unsigned int ct;
+ int i;
- guard(spinlock_irqsave)(&kbd_event_lock);
- accent_table_size = ct;
- for (i = 0; i < ct; i++) {
- accent_table[i].diacr =
- conv_8bit_to_uni(dia[i].diacr);
- accent_table[i].base =
- conv_8bit_to_uni(dia[i].base);
- accent_table[i].result =
- conv_8bit_to_uni(dia[i].result);
- }
+ if (!perm)
+ return -EPERM;
+ if (get_user(ct, &a->kb_cnt))
+ return -EFAULT;
+ if (ct >= MAX_DIACR)
+ return -EINVAL;
- return 0;
+ if (ct) {
+ dia = memdup_array_user(a->kbdiacr,
+ ct, sizeof(struct kbdiacr));
+ if (IS_ERR(dia))
+ return PTR_ERR(dia);
}
- case KDSKBDIACRUC:
- {
- struct kbdiacrsuc __user *a = udp;
- unsigned int ct;
- void __free(kfree) *buf = NULL;
+ guard(spinlock_irqsave)(&kbd_event_lock);
+ accent_table_size = ct;
+ for (i = 0; i < ct; i++) {
+ accent_table[i].diacr =
+ conv_8bit_to_uni(dia[i].diacr);
+ accent_table[i].base =
+ conv_8bit_to_uni(dia[i].base);
+ accent_table[i].result =
+ conv_8bit_to_uni(dia[i].result);
+ }
- if (!perm)
- return -EPERM;
+ return 0;
+}
- if (get_user(ct, &a->kb_cnt))
- return -EFAULT;
+static int vt_do_kdskbdiacruc(void __user *udp, int perm)
+{
+ struct kbdiacrsuc __user *a = udp;
+ unsigned int ct;
+ void __free(kfree) *buf = NULL;
- if (ct >= MAX_DIACR)
- return -EINVAL;
+ if (!perm)
+ return -EPERM;
- if (ct) {
- buf = memdup_array_user(a->kbdiacruc,
- ct, sizeof(struct kbdiacruc));
- if (IS_ERR(buf))
- return PTR_ERR(buf);
- }
- guard(spinlock_irqsave)(&kbd_event_lock);
- if (ct)
- memcpy(accent_table, buf,
- ct * sizeof(struct kbdiacruc));
- accent_table_size = ct;
- return 0;
+ if (get_user(ct, &a->kb_cnt))
+ return -EFAULT;
+
+ if (ct >= MAX_DIACR)
+ return -EINVAL;
+
+ if (ct) {
+ buf = memdup_array_user(a->kbdiacruc,
+ ct, sizeof(struct kbdiacruc));
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
}
+ guard(spinlock_irqsave)(&kbd_event_lock);
+ if (ct)
+ memcpy(accent_table, buf,
+ ct * sizeof(struct kbdiacruc));
+ accent_table_size = ct;
+ return 0;
+}
+
+/**
+ * vt_do_diacrit - diacritical table updates
+ * @cmd: ioctl request
+ * @udp: pointer to user data for ioctl
+ * @perm: permissions check computed by caller
+ *
+ * Update the diacritical tables atomically and safely. Lock them
+ * against simultaneous keypresses
+ */
+int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm)
+{
+ switch (cmd) {
+ case KDGKBDIACR:
+ return vt_do_kdgkbdiacr(udp);
+ case KDGKBDIACRUC:
+ return vt_do_kdgkbdiacruc(udp);
+ case KDSKBDIACR:
+ return vt_do_kdskbdiacr(udp, perm);
+ case KDSKBDIACRUC:
+ return vt_do_kdskbdiacruc(udp, perm);
}
return 0;
}