summaryrefslogtreecommitdiff
path: root/drivers/tty
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/cyclades.c2
-rw-r--r--drivers/tty/hvc/hvc_xen.c4
-rw-r--r--drivers/tty/hvc/hvsi.c2
-rw-r--r--drivers/tty/isicom.c2
-rw-r--r--drivers/tty/moxa.h2
-rw-r--r--drivers/tty/serial/8250/8250_core.c2
-rw-r--r--drivers/tty/serial/8250/8250_dw.c120
-rw-r--r--drivers/tty/serial/8250/8250_em.c16
-rw-r--r--drivers/tty/serial/8250/8250_exar.c12
-rw-r--r--drivers/tty/serial/8250/8250_ingenic.c16
-rw-r--r--drivers/tty/serial/8250/8250_men_mcb.c4
-rw-r--r--drivers/tty/serial/8250/8250_mtk.c34
-rw-r--r--drivers/tty/serial/8250/8250_omap.c16
-rw-r--r--drivers/tty/serial/8250/8250_port.c41
-rw-r--r--drivers/tty/serial/8250/8250_pxa.c14
-rw-r--r--drivers/tty/serial/8250/Kconfig4
-rw-r--r--drivers/tty/serial/Kconfig17
-rw-r--r--drivers/tty/serial/altera_jtaguart.c2
-rw-r--r--drivers/tty/serial/amba-pl011.c1
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart_core.c9
-rw-r--r--drivers/tty/serial/fsl_lpuart.c3
-rw-r--r--drivers/tty/serial/imx.c207
-rw-r--r--drivers/tty/serial/imx_earlycon.c50
-rw-r--r--drivers/tty/serial/jsm/jsm_driver.c2
-rw-r--r--drivers/tty/serial/kgdb_nmi.c2
-rw-r--r--drivers/tty/serial/kgdboc.c35
-rw-r--r--drivers/tty/serial/msm_serial.c2
-rw-r--r--drivers/tty/serial/mxs-auart.c12
-rw-r--r--drivers/tty/serial/pch_uart.c34
-rw-r--r--drivers/tty/serial/pmac_zilog.c1
-rw-r--r--drivers/tty/serial/qcom_geni_serial.c212
-rw-r--r--drivers/tty/serial/samsung_tty.c24
-rw-r--r--drivers/tty/serial/sc16is7xx.c3
-rw-r--r--drivers/tty/serial/serial-tegra.c22
-rw-r--r--drivers/tty/serial/serial_core.c120
-rw-r--r--drivers/tty/serial/sifive.c1
-rw-r--r--drivers/tty/serial/stm32-usart.c13
-rw-r--r--drivers/tty/serial/sunhv.c3
-rw-r--r--drivers/tty/serial/sunsab.c2
-rw-r--r--drivers/tty/serial/sunzilog.c2
-rw-r--r--drivers/tty/serial/uartlite.c2
-rw-r--r--drivers/tty/serial/xilinx_uartps.c9
-rw-r--r--drivers/tty/synclink.c350
-rw-r--r--drivers/tty/sysrq.c2
-rw-r--r--drivers/tty/tty_io.c52
-rw-r--r--drivers/tty/vt/consolemap.c2
-rw-r--r--drivers/tty/vt/keyboard.c5
-rw-r--r--drivers/tty/vt/selection.c2
-rw-r--r--drivers/tty/vt/vt.c1011
-rw-r--r--drivers/tty/vt/vt_ioctl.c1013
50 files changed, 1908 insertions, 1610 deletions
diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c
index a6aabfd6e2da..097266342e5e 100644
--- a/drivers/tty/cyclades.c
+++ b/drivers/tty/cyclades.c
@@ -3643,7 +3643,7 @@ static int cy_pci_probe(struct pci_dev *pdev,
struct cyclades_card *card;
void __iomem *addr0 = NULL, *addr2 = NULL;
char *card_name = NULL;
- u32 uninitialized_var(mailbox);
+ u32 mailbox;
unsigned int device_id, nchan = 0, card_no, i, j;
unsigned char plx_ver;
int retval, irq;
diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c
index 5ef08905fe05..2a0e51a20e34 100644
--- a/drivers/tty/hvc/hvc_xen.c
+++ b/drivers/tty/hvc/hvc_xen.c
@@ -603,7 +603,7 @@ static void xen_hvm_early_write(uint32_t vtermno, const char *str, int len) { }
#endif
#ifdef CONFIG_EARLY_PRINTK
-static int __init xenboot_setup_console(struct console *console, char *string)
+static int __init xenboot_console_setup(struct console *console, char *string)
{
static struct xencons_info xenboot;
@@ -647,7 +647,7 @@ static void xenboot_write_console(struct console *console, const char *string,
struct console xenboot_console = {
.name = "xenboot",
.write = xenboot_write_console,
- .setup = xenboot_setup_console,
+ .setup = xenboot_console_setup,
.flags = CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME,
.index = -1,
};
diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c
index 66f95f758be0..e8c58f9bd263 100644
--- a/drivers/tty/hvc/hvsi.c
+++ b/drivers/tty/hvc/hvsi.c
@@ -1128,7 +1128,7 @@ static int __init hvsi_console_setup(struct console *console, char *options)
int ret;
if (console->index < 0 || console->index >= hvsi_count)
- return -1;
+ return -EINVAL;
hp = &hvsi_ports[console->index];
/* give the FSP a chance to change the baud rate when we re-open */
diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c
index fc38f96475bf..3b2f9fb01aa0 100644
--- a/drivers/tty/isicom.c
+++ b/drivers/tty/isicom.c
@@ -1514,7 +1514,7 @@ static unsigned int card_count;
static int isicom_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- unsigned int uninitialized_var(signature), index;
+ unsigned int signature, index;
int retval = -EPERM;
struct isi_board *board = NULL;
diff --git a/drivers/tty/moxa.h b/drivers/tty/moxa.h
index 563d2dce80b3..f0a4381b6861 100644
--- a/drivers/tty/moxa.h
+++ b/drivers/tty/moxa.h
@@ -138,7 +138,7 @@
#define IntrQuit 0x40 /* received QUIT code */
#define IntrEOF 0x80 /* received EOF code */
-#define IntrRxTrigger 0x100 /* rx data count reach tigger value */
+#define IntrRxTrigger 0x100 /* rx data count reach trigger value */
#define IntrTxTrigger 0x200 /* tx data count below trigger value */
#define Magic_no (Config_base + 0)
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index fc118f649887..cae61d1ebec5 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -524,6 +524,7 @@ static void __init serial8250_isa_init_ports(void)
*/
up->mcr_mask = ~ALPHA_KLUDGE_MCR;
up->mcr_force = ALPHA_KLUDGE_MCR;
+ serial8250_set_defaults(up);
}
/* chain base port ops to support Remote Supervisor Adapter */
@@ -547,7 +548,6 @@ static void __init serial8250_isa_init_ports(void)
port->membase = old_serial_port[i].iomem_base;
port->iotype = old_serial_port[i].io_type;
port->regshift = old_serial_port[i].iomem_reg_shift;
- serial8250_set_defaults(up);
port->irqflags |= irqflag;
if (serial8250_isa_config != NULL)
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index aab3cccc6789..87f450b7c177 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -19,6 +19,8 @@
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/notifier.h>
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/clk.h>
@@ -43,6 +45,8 @@ struct dw8250_data {
int msr_mask_off;
struct clk *clk;
struct clk *pclk;
+ struct notifier_block clk_notifier;
+ struct work_struct clk_work;
struct reset_control *rst;
unsigned int skip_autocfg:1;
@@ -54,6 +58,16 @@ static inline struct dw8250_data *to_dw8250_data(struct dw8250_port_data *data)
return container_of(data, struct dw8250_data, data);
}
+static inline struct dw8250_data *clk_to_dw8250_data(struct notifier_block *nb)
+{
+ return container_of(nb, struct dw8250_data, clk_notifier);
+}
+
+static inline struct dw8250_data *work_to_dw8250_data(struct work_struct *work)
+{
+ return container_of(work, struct dw8250_data, clk_work);
+}
+
static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
{
struct dw8250_data *d = to_dw8250_data(p->private_data);
@@ -260,6 +274,46 @@ static int dw8250_handle_irq(struct uart_port *p)
return 0;
}
+static void dw8250_clk_work_cb(struct work_struct *work)
+{
+ struct dw8250_data *d = work_to_dw8250_data(work);
+ struct uart_8250_port *up;
+ unsigned long rate;
+
+ rate = clk_get_rate(d->clk);
+ if (rate <= 0)
+ return;
+
+ up = serial8250_get_port(d->data.line);
+
+ serial8250_update_uartclk(&up->port, rate);
+}
+
+static int dw8250_clk_notifier_cb(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ struct dw8250_data *d = clk_to_dw8250_data(nb);
+
+ /*
+ * We have no choice but to defer the uartclk update due to two
+ * deadlocks. First one is caused by a recursive mutex lock which
+ * happens when clk_set_rate() is called from dw8250_set_termios().
+ * Second deadlock is more tricky and is caused by an inverted order of
+ * the clk and tty-port mutexes lock. It happens if clock rate change
+ * is requested asynchronously while set_termios() is executed between
+ * tty-port mutex lock and clk_set_rate() function invocation and
+ * vise-versa. Anyway if we didn't have the reference clock alteration
+ * in the dw8250_set_termios() method we wouldn't have needed this
+ * deferred event handling complication.
+ */
+ if (event == POST_RATE_CHANGE) {
+ queue_work(system_unbound_wq, &d->clk_work);
+ return NOTIFY_OK;
+ }
+
+ return NOTIFY_DONE;
+}
+
static void
dw8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old)
{
@@ -275,27 +329,27 @@ dw8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old)
static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios,
struct ktermios *old)
{
- unsigned int baud = tty_termios_baud_rate(termios);
+ unsigned long newrate = tty_termios_baud_rate(termios) * 16;
struct dw8250_data *d = to_dw8250_data(p->private_data);
long rate;
int ret;
clk_disable_unprepare(d->clk);
- rate = clk_round_rate(d->clk, baud * 16);
- if (rate < 0)
- ret = rate;
- else if (rate == 0)
- ret = -ENOENT;
- else
- ret = clk_set_rate(d->clk, rate);
+ rate = clk_round_rate(d->clk, newrate);
+ if (rate > 0) {
+ /*
+ * Premilinary set the uartclk to the new clock rate so the
+ * clock update event handler caused by the clk_set_rate()
+ * calling wouldn't actually update the UART divisor since
+ * we about to do this anyway.
+ */
+ swap(p->uartclk, rate);
+ ret = clk_set_rate(d->clk, newrate);
+ if (ret)
+ swap(p->uartclk, rate);
+ }
clk_prepare_enable(d->clk);
- if (ret)
- goto out;
-
- p->uartclk = rate;
-
-out:
p->status &= ~UPSTAT_AUTOCTS;
if (termios->c_cflag & CRTSCTS)
p->status |= UPSTAT_AUTOCTS;
@@ -319,6 +373,39 @@ static void dw8250_set_ldisc(struct uart_port *p, struct ktermios *termios)
serial8250_do_set_ldisc(p, termios);
}
+static int dw8250_startup(struct uart_port *p)
+{
+ struct dw8250_data *d = to_dw8250_data(p->private_data);
+ int ret;
+
+ /*
+ * Some platforms may provide a reference clock shared between several
+ * devices. In this case before using the serial port first we have to
+ * make sure that any clock state change is known to the UART port at
+ * least post factum.
+ */
+ if (d->clk) {
+ ret = clk_notifier_register(d->clk, &d->clk_notifier);
+ if (ret)
+ dev_warn(p->dev, "Failed to set the clock notifier\n");
+ }
+
+ return serial8250_do_startup(p);
+}
+
+static void dw8250_shutdown(struct uart_port *p)
+{
+ struct dw8250_data *d = to_dw8250_data(p->private_data);
+
+ serial8250_do_shutdown(p);
+
+ if (d->clk) {
+ clk_notifier_unregister(d->clk, &d->clk_notifier);
+
+ flush_work(&d->clk_work);
+ }
+}
+
/*
* dw8250_fallback_dma_filter will prevent the UART from getting just any free
* channel on platforms that have DMA engines, but don't have any channels
@@ -414,6 +501,8 @@ static int dw8250_probe(struct platform_device *pdev)
p->serial_out = dw8250_serial_out;
p->set_ldisc = dw8250_set_ldisc;
p->set_termios = dw8250_set_termios;
+ p->startup = dw8250_startup;
+ p->shutdown = dw8250_shutdown;
p->membase = devm_ioremap(dev, regs->start, resource_size(regs));
if (!p->membase)
@@ -475,6 +564,9 @@ static int dw8250_probe(struct platform_device *pdev)
if (IS_ERR(data->clk))
return PTR_ERR(data->clk);
+ INIT_WORK(&data->clk_work, dw8250_clk_work_cb);
+ data->clk_notifier.notifier_call = dw8250_clk_notifier_cb;
+
err = clk_prepare_enable(data->clk);
if (err)
dev_warn(dev, "could not enable optional baudclk: %d\n", err);
diff --git a/drivers/tty/serial/8250/8250_em.c b/drivers/tty/serial/8250/8250_em.c
index 2a76e22d2ec0..db88dee3a399 100644
--- a/drivers/tty/serial/8250/8250_em.c
+++ b/drivers/tty/serial/8250/8250_em.c
@@ -78,14 +78,18 @@ static void serial8250_em_serial_dl_write(struct uart_8250_port *up, int value)
static int serial8250_em_probe(struct platform_device *pdev)
{
- struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
struct serial8250_em_priv *priv;
struct uart_8250_port up;
- int ret;
+ struct resource *regs;
+ int irq, ret;
- if (!regs || !irq) {
- dev_err(&pdev->dev, "missing registers or irq\n");
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs) {
+ dev_err(&pdev->dev, "missing registers\n");
return -EINVAL;
}
@@ -101,7 +105,7 @@ static int serial8250_em_probe(struct platform_device *pdev)
memset(&up, 0, sizeof(up));
up.port.mapbase = regs->start;
- up.port.irq = irq->start;
+ up.port.irq = irq;
up.port.type = PORT_UNKNOWN;
up.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_IOREMAP;
up.port.dev = &pdev->dev;
diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c
index ddb6aeb76dc5..04b9af7ed941 100644
--- a/drivers/tty/serial/8250/8250_exar.c
+++ b/drivers/tty/serial/8250/8250_exar.c
@@ -326,7 +326,17 @@ static void setup_gpio(struct pci_dev *pcidev, u8 __iomem *p)
* devices will export them as GPIOs, so we pre-configure them safely
* as inputs.
*/
- u8 dir = pcidev->vendor == PCI_VENDOR_ID_EXAR ? 0xff : 0x00;
+
+ u8 dir = 0x00;
+
+ if ((pcidev->vendor == PCI_VENDOR_ID_EXAR) &&
+ (pcidev->subsystem_vendor != PCI_VENDOR_ID_SEALEVEL)) {
+ // Configure GPIO as inputs for Commtech adapters
+ dir = 0xff;
+ } else {
+ // Configure GPIO as outputs for SeaLevel adapters
+ dir = 0x00;
+ }
writeb(0x00, p + UART_EXAR_MPIOINT_7_0);
writeb(0x00, p + UART_EXAR_MPIOLVL_7_0);
diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c
index 424c07c5f629..dde766fa465f 100644
--- a/drivers/tty/serial/8250/8250_ingenic.c
+++ b/drivers/tty/serial/8250/8250_ingenic.c
@@ -207,12 +207,11 @@ static unsigned int ingenic_uart_serial_in(struct uart_port *p, int offset)
static int ingenic_uart_probe(struct platform_device *pdev)
{
struct uart_8250_port uart = {};
- struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
struct ingenic_uart_data *data;
const struct ingenic_uart_config *cdata;
const struct of_device_id *match;
- int err, line;
+ struct resource *regs;
+ int irq, err, line;
match = of_match_device(of_match, &pdev->dev);
if (!match) {
@@ -221,8 +220,13 @@ static int ingenic_uart_probe(struct platform_device *pdev)
}
cdata = match->data;
- if (!regs || !irq) {
- dev_err(&pdev->dev, "no registers/irq defined\n");
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs) {
+ dev_err(&pdev->dev, "no registers defined\n");
return -EINVAL;
}
@@ -238,7 +242,7 @@ static int ingenic_uart_probe(struct platform_device *pdev)
uart.port.regshift = 2;
uart.port.serial_out = ingenic_uart_serial_out;
uart.port.serial_in = ingenic_uart_serial_in;
- uart.port.irq = irq->start;
+ uart.port.irq = irq;
uart.port.dev = &pdev->dev;
uart.port.fifosize = cdata->fifosize;
uart.tx_loadsz = cdata->tx_loadsz;
diff --git a/drivers/tty/serial/8250/8250_men_mcb.c b/drivers/tty/serial/8250/8250_men_mcb.c
index e985f344b2dd..737c4c31e8a0 100644
--- a/drivers/tty/serial/8250/8250_men_mcb.c
+++ b/drivers/tty/serial/8250/8250_men_mcb.c
@@ -51,7 +51,7 @@ static u32 men_lookup_uartclk(struct mcb_device *mdev)
return clkval;
}
-static unsigned int get_num_ports(struct mcb_device *mdev,
+static int get_num_ports(struct mcb_device *mdev,
void __iomem *membase)
{
switch (mdev->id) {
@@ -140,7 +140,7 @@ static void serial_8250_men_mcb_remove(struct mcb_device *mdev)
return;
num_ports = get_num_ports(mdev, data[0].uart.port.membase);
- if (num_ports < 0 || num_ports > 4) {
+ if (num_ports <= 0 || num_ports > 4) {
dev_err(&mdev->dev, "error retrieving number of ports!\n");
return;
}
diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c
index f839380c2f4c..7b0dec14c8b8 100644
--- a/drivers/tty/serial/8250/8250_mtk.c
+++ b/drivers/tty/serial/8250/8250_mtk.c
@@ -306,8 +306,21 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
}
#endif
+ /*
+ * Store the requested baud rate before calling the generic 8250
+ * set_termios method. Standard 8250 port expects bauds to be
+ * no higher than (uartclk / 16) so the baud will be clamped if it
+ * gets out of that bound. Mediatek 8250 port supports speed
+ * higher than that, therefore we'll get original baud rate back
+ * after calling the generic set_termios method and recalculate
+ * the speed later in this method.
+ */
+ baud = tty_termios_baud_rate(termios);
+
serial8250_do_set_termios(port, termios, old);
+ tty_termios_encode_baud_rate(termios, baud, baud);
+
/*
* Mediatek UARTs use an extra highspeed register (MTK_UART_HIGHS)
*
@@ -339,6 +352,11 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
*/
spin_lock_irqsave(&port->lock, flags);
+ /*
+ * Update the per-port timeout.
+ */
+ uart_update_timeout(port, termios->c_cflag, baud);
+
/* set DLAB we have cval saved in up->lcr from the call to the core */
serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB);
serial_dl_write(up, quot);
@@ -494,13 +512,17 @@ static int mtk8250_probe_of(struct platform_device *pdev, struct uart_port *p,
static int mtk8250_probe(struct platform_device *pdev)
{
struct uart_8250_port uart = {};
- struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
struct mtk8250_data *data;
- int err;
+ struct resource *regs;
+ int irq, err;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
- if (!regs || !irq) {
- dev_err(&pdev->dev, "no registers/irq defined\n");
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs) {
+ dev_err(&pdev->dev, "no registers defined\n");
return -EINVAL;
}
@@ -524,7 +546,7 @@ static int mtk8250_probe(struct platform_device *pdev)
spin_lock_init(&uart.port.lock);
uart.port.mapbase = regs->start;
- uart.port.irq = irq->start;
+ uart.port.irq = irq;
uart.port.pm = mtk8250_do_pm;
uart.port.type = PORT_16550;
uart.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 16cfb887c5a3..562087df7d33 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -1209,17 +1209,21 @@ MODULE_DEVICE_TABLE(of, omap8250_dt_ids);
static int omap8250_probe(struct platform_device *pdev)
{
- struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
struct device_node *np = pdev->dev.of_node;
struct omap8250_priv *priv;
const struct omap8250_platdata *pdata;
struct uart_8250_port up;
- int ret;
+ struct resource *regs;
void __iomem *membase;
+ int irq, ret;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
- if (!regs || !irq) {
- dev_err(&pdev->dev, "missing registers or irq\n");
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs) {
+ dev_err(&pdev->dev, "missing registers\n");
return -EINVAL;
}
@@ -1236,7 +1240,7 @@ static int omap8250_probe(struct platform_device *pdev)
up.port.dev = &pdev->dev;
up.port.mapbase = regs->start;
up.port.membase = membase;
- up.port.irq = irq->start;
+ up.port.irq = irq;
/*
* It claims to be 16C750 compatible however it is a little different.
* It has EFR and has no FCR7_64byte bit. The AFE (which it claims to
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 1632f7d25acc..09475695effd 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -16,6 +16,7 @@
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/console.h>
+#include <linux/gpio/consumer.h>
#include <linux/sysrq.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
@@ -2631,6 +2632,46 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port,
(port->uartclk + tolerance) / 16);
}
+/*
+ * Note in order to avoid the tty port mutex deadlock don't use the next method
+ * within the uart port callbacks. Primarily it's supposed to be utilized to
+ * handle a sudden reference clock rate change.
+ */
+void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+ unsigned int baud, quot, frac = 0;
+ struct ktermios *termios;
+ unsigned long flags;
+
+ mutex_lock(&port->state->port.mutex);
+
+ if (port->uartclk == uartclk)
+ goto out_lock;
+
+ port->uartclk = uartclk;
+ termios = &port->state->port.tty->termios;
+
+ baud = serial8250_get_baud_rate(port, termios, NULL);
+ quot = serial8250_get_divisor(port, baud, &frac);
+
+ serial8250_rpm_get(up);
+ spin_lock_irqsave(&port->lock, flags);
+
+ uart_update_timeout(port, termios->c_cflag, baud);
+
+ serial8250_set_divisor(port, baud, quot, frac);
+ serial_port_out(port, UART_LCR, up->lcr);
+ serial8250_out_MCR(up, UART_MCR_DTR | UART_MCR_RTS);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+ serial8250_rpm_put(up);
+
+out_lock:
+ mutex_unlock(&port->state->port.mutex);
+}
+EXPORT_SYMBOL_GPL(serial8250_update_uartclk);
+
void
serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
diff --git a/drivers/tty/serial/8250/8250_pxa.c b/drivers/tty/serial/8250/8250_pxa.c
index 11612d174716..33ca98bfa5b3 100644
--- a/drivers/tty/serial/8250/8250_pxa.c
+++ b/drivers/tty/serial/8250/8250_pxa.c
@@ -18,7 +18,6 @@
#include <linux/serial_core.h>
#include <linux/serial_reg.h>
#include <linux/of.h>
-#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -93,12 +92,15 @@ static int serial_pxa_probe(struct platform_device *pdev)
{
struct uart_8250_port uart = {};
struct pxa8250_data *data;
- struct resource *mmres, *irqres;
- int ret;
+ struct resource *mmres;
+ int irq, ret;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!mmres || !irqres)
+ if (!mmres)
return -ENODEV;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
@@ -121,7 +123,7 @@ static int serial_pxa_probe(struct platform_device *pdev)
uart.port.iotype = UPIO_MEM32;
uart.port.mapbase = mmres->start;
uart.port.regshift = 2;
- uart.port.irq = irqres->start;
+ uart.port.irq = irq;
uart.port.fifosize = 64;
uart.port.flags = UPF_IOREMAP | UPF_SKIP_TEST | UPF_FIXED_TYPE;
uart.port.dev = &pdev->dev;
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index d2ae033aea40..603137da4736 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -222,7 +222,7 @@ config SERIAL_8250_MANY_PORTS
Say Y here if you have dumb serial boards other than the four
standard COM 1/2/3/4 ports. This may happen if you have an AST
FourPort, Accent Async, Boca (read the Boca mini-HOWTO, available
- from <http://www.tldp.org/docs.html#howto>), or other custom
+ from <https://www.tldp.org/docs.html#howto>), or other custom
serial port hardware which acts similar to standard serial port
hardware. If you only use the standard COM 1/2/3/4 ports, you can
say N here to save some memory. You can also say Y if you have an
@@ -266,7 +266,7 @@ config SERIAL_8250_BOCA
depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
help
Say Y here if you have a Boca serial board. Please read the Boca
- mini-HOWTO, available from <http://www.tldp.org/docs.html#howto>
+ mini-HOWTO, available from <https://www.tldp.org/docs.html#howto>
To compile this driver as a module, choose M here: the module
will be called 8250_boca.
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 780908d43557..8a0352eb337c 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -502,20 +502,27 @@ config SERIAL_IMX
can enable its onboard serial port by enabling this option.
config SERIAL_IMX_CONSOLE
- bool "Console on IMX serial port"
- depends on SERIAL_IMX=y
+ tristate "Console on IMX serial port"
+ depends on SERIAL_IMX
select SERIAL_CORE_CONSOLE
- select SERIAL_EARLYCON if OF
help
If you have enabled the serial port on the Freescale IMX
- CPU you can make it the console by answering Y to this option.
+ CPU you can make it the console by answering Y/M to this option.
- Even if you say Y here, the currently visible virtual console
+ Even if you say Y/M 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
your bootloader about how to pass options to the kernel at boot time.)
+config SERIAL_IMX_EARLYCON
+ bool "Earlycon on IMX serial port"
+ depends on OF
+ select SERIAL_EARLYCON
+ help
+ If you have enabled the earlycon on the Freescale IMX
+ CPU you can make it the earlycon by answering Y to this option.
+
config SERIAL_UARTLITE
tristate "Xilinx uartlite serial port support"
depends on HAS_IOMEM
diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c
index c90e503d6b57..d0ca9cf29b62 100644
--- a/drivers/tty/serial/altera_jtaguart.c
+++ b/drivers/tty/serial/altera_jtaguart.c
@@ -27,7 +27,7 @@
/*
* Altera JTAG UART register definitions according to the Altera JTAG UART
- * datasheet: http://www.altera.com/literature/hb/nios2/n2cpu_nii51009.pdf
+ * datasheet: https://www.altera.com/literature/hb/nios2/n2cpu_nii51009.pdf
*/
#define ALTERA_JTAGUART_SIZE 8
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 8efd7c2a34fe..c010f639298d 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -2607,7 +2607,6 @@ 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/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
index a04f74d2e854..4df47d02b34b 100644
--- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
@@ -1215,7 +1215,12 @@ static int cpm_uart_init_port(struct device_node *np,
pinfo->gpios[i] = NULL;
- gpiod = devm_gpiod_get_index(dev, NULL, i, GPIOD_ASIS);
+ gpiod = devm_gpiod_get_index_optional(dev, NULL, i, GPIOD_ASIS);
+
+ if (IS_ERR(gpiod)) {
+ ret = PTR_ERR(gpiod);
+ goto out_irq;
+ }
if (gpiod) {
if (i == GPIO_RTS || i == GPIO_DTR)
@@ -1237,6 +1242,8 @@ static int cpm_uart_init_port(struct device_node *np,
return cpm_uart_request_port(&pinfo->port);
+out_irq:
+ irq_dispose_mapping(pinfo->port.irq);
out_pram:
cpm_uart_unmap_pram(pinfo, pram);
out_mem:
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 90298c403042..7ca642249224 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -1925,6 +1925,9 @@ static void __lpuart32_serial_setbrg(struct uart_port *port,
tmp_sbr++;
}
+ if (tmp_sbr > UARTBAUD_SBR_MASK)
+ continue;
+
if (tmp_diff <= baud_diff) {
baud_diff = tmp_diff;
osr = tmp_osr;
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 1265e8d86d8a..ce8c472cf385 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -20,6 +20,7 @@
#include <linux/serial.h>
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/ktime.h>
#include <linux/pinctrl/consumer.h>
#include <linux/rational.h>
#include <linux/slab.h>
@@ -188,6 +189,13 @@ struct imx_uart_data {
enum imx_uart_type devtype;
};
+enum imx_tx_state {
+ OFF,
+ WAIT_AFTER_RTS,
+ SEND,
+ WAIT_AFTER_SEND,
+};
+
struct imx_port {
struct uart_port port;
struct timer_list timer;
@@ -224,6 +232,10 @@ struct imx_port {
unsigned int dma_tx_nents;
unsigned int saved_reg[10];
bool context_saved;
+
+ enum imx_tx_state tx_state;
+ struct hrtimer trigger_start_tx;
+ struct hrtimer trigger_stop_tx;
};
struct imx_port_ucrs {
@@ -361,7 +373,7 @@ static inline int imx_uart_is_imx6q(struct imx_port *sport)
/*
* Save and restore functions for UCR1, UCR2 and UCR3 registers
*/
-#if defined(CONFIG_SERIAL_IMX_CONSOLE)
+#if IS_ENABLED(CONFIG_SERIAL_IMX_CONSOLE)
static void imx_uart_ucrs_save(struct imx_port *sport,
struct imx_port_ucrs *ucr)
{
@@ -400,6 +412,15 @@ static void imx_uart_rts_inactive(struct imx_port *sport, u32 *ucr2)
mctrl_gpio_set(sport->gpios, sport->port.mctrl);
}
+static void start_hrtimer_ms(struct hrtimer *hrt, unsigned long msec)
+{
+ long sec = msec / MSEC_PER_SEC;
+ long nsec = (msec % MSEC_PER_SEC) * 1000000;
+ ktime_t t = ktime_set(sec, nsec);
+
+ hrtimer_start(hrt, t, HRTIMER_MODE_REL);
+}
+
/* called with port.lock taken and irqs off */
static void imx_uart_start_rx(struct uart_port *port)
{
@@ -427,7 +448,10 @@ static void imx_uart_start_rx(struct uart_port *port)
static void imx_uart_stop_tx(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
- u32 ucr1;
+ u32 ucr1, ucr4, usr2;
+
+ if (sport->tx_state == OFF)
+ return;
/*
* We are maybe in the SMP context, so if the DMA TX thread is running
@@ -439,21 +463,44 @@ static void imx_uart_stop_tx(struct uart_port *port)
ucr1 = imx_uart_readl(sport, UCR1);
imx_uart_writel(sport, ucr1 & ~UCR1_TRDYEN, UCR1);
- /* in rs485 mode disable transmitter if shifter is empty */
- if (port->rs485.flags & SER_RS485_ENABLED &&
- imx_uart_readl(sport, USR2) & USR2_TXDC) {
- u32 ucr2 = imx_uart_readl(sport, UCR2), ucr4;
- if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
- imx_uart_rts_active(sport, &ucr2);
- else
- imx_uart_rts_inactive(sport, &ucr2);
- imx_uart_writel(sport, ucr2, UCR2);
+ usr2 = imx_uart_readl(sport, USR2);
+ if (!(usr2 & USR2_TXDC)) {
+ /* The shifter is still busy, so retry once TC triggers */
+ return;
+ }
- imx_uart_start_rx(port);
+ ucr4 = imx_uart_readl(sport, UCR4);
+ ucr4 &= ~UCR4_TCEN;
+ imx_uart_writel(sport, ucr4, UCR4);
- ucr4 = imx_uart_readl(sport, UCR4);
- ucr4 &= ~UCR4_TCEN;
- imx_uart_writel(sport, ucr4, UCR4);
+ /* in rs485 mode disable transmitter */
+ if (port->rs485.flags & SER_RS485_ENABLED) {
+ if (sport->tx_state == SEND) {
+ sport->tx_state = WAIT_AFTER_SEND;
+ start_hrtimer_ms(&sport->trigger_stop_tx,
+ port->rs485.delay_rts_after_send);
+ return;
+ }
+
+ if (sport->tx_state == WAIT_AFTER_RTS ||
+ sport->tx_state == WAIT_AFTER_SEND) {
+ u32 ucr2;
+
+ hrtimer_try_to_cancel(&sport->trigger_start_tx);
+
+ ucr2 = imx_uart_readl(sport, UCR2);
+ if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
+ imx_uart_rts_active(sport, &ucr2);
+ else
+ imx_uart_rts_inactive(sport, &ucr2);
+ imx_uart_writel(sport, ucr2, UCR2);
+
+ imx_uart_start_rx(port);
+
+ sport->tx_state = OFF;
+ }
+ } else {
+ sport->tx_state = OFF;
}
}
@@ -651,28 +698,50 @@ static void imx_uart_start_tx(struct uart_port *port)
if (!sport->port.x_char && uart_circ_empty(&port->state->xmit))
return;
+ /*
+ * We cannot simply do nothing here if sport->tx_state == SEND already
+ * because UCR1_TXMPTYEN might already have been cleared in
+ * imx_uart_stop_tx(), but tx_state is still SEND.
+ */
+
if (port->rs485.flags & SER_RS485_ENABLED) {
- u32 ucr2;
+ if (sport->tx_state == OFF) {
+ u32 ucr2 = imx_uart_readl(sport, UCR2);
+ if (port->rs485.flags & SER_RS485_RTS_ON_SEND)
+ imx_uart_rts_active(sport, &ucr2);
+ else
+ imx_uart_rts_inactive(sport, &ucr2);
+ imx_uart_writel(sport, ucr2, UCR2);
- ucr2 = imx_uart_readl(sport, UCR2);
- if (port->rs485.flags & SER_RS485_RTS_ON_SEND)
- imx_uart_rts_active(sport, &ucr2);
- else
- imx_uart_rts_inactive(sport, &ucr2);
- imx_uart_writel(sport, ucr2, UCR2);
+ if (!(port->rs485.flags & SER_RS485_RX_DURING_TX))
+ imx_uart_stop_rx(port);
+
+ sport->tx_state = WAIT_AFTER_RTS;
+ start_hrtimer_ms(&sport->trigger_start_tx,
+ port->rs485.delay_rts_before_send);
+ return;
+ }
- if (!(port->rs485.flags & SER_RS485_RX_DURING_TX))
- imx_uart_stop_rx(port);
+ if (sport->tx_state == WAIT_AFTER_SEND
+ || sport->tx_state == WAIT_AFTER_RTS) {
- /*
- * Enable transmitter and shifter empty irq only if DMA is off.
- * In the DMA case this is done in the tx-callback.
- */
- if (!sport->dma_is_enabled) {
- u32 ucr4 = imx_uart_readl(sport, UCR4);
- ucr4 |= UCR4_TCEN;
- imx_uart_writel(sport, ucr4, UCR4);
+ hrtimer_try_to_cancel(&sport->trigger_stop_tx);
+
+ /*
+ * Enable transmitter and shifter empty irq only if DMA
+ * is off. In the DMA case this is done in the
+ * tx-callback.
+ */
+ if (!sport->dma_is_enabled) {
+ u32 ucr4 = imx_uart_readl(sport, UCR4);
+ ucr4 |= UCR4_TCEN;
+ imx_uart_writel(sport, ucr4, UCR4);
+ }
+
+ sport->tx_state = SEND;
}
+ } else {
+ sport->tx_state = SEND;
}
if (!sport->dma_is_enabled) {
@@ -1630,7 +1699,6 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios,
if (termios->c_cflag & CRTSCTS)
ucr2 &= ~UCR2_IRTS;
-
if (termios->c_cflag & CSTOPB)
ucr2 |= UCR2_STPB;
if (termios->c_cflag & PARENB) {
@@ -1857,10 +1925,6 @@ static int imx_uart_rs485_config(struct uart_port *port,
struct imx_port *sport = (struct imx_port *)port;
u32 ucr2;
- /* unimplemented */
- rs485conf->delay_rts_before_send = 0;
- rs485conf->delay_rts_after_send = 0;
-
/* RTS is required to control the transmitter */
if (!sport->have_rtscts && !sport->have_rtsgpio)
rs485conf->flags &= ~SER_RS485_ENABLED;
@@ -1915,7 +1979,7 @@ static const struct uart_ops imx_uart_pops = {
static struct imx_port *imx_uart_ports[UART_NR];
-#ifdef CONFIG_SERIAL_IMX_CONSOLE
+#if IS_ENABLED(CONFIG_SERIAL_IMX_CONSOLE)
static void imx_uart_console_putchar(struct uart_port *port, int ch)
{
struct imx_port *sport = (struct imx_port *)port;
@@ -2112,39 +2176,6 @@ static struct console imx_uart_console = {
#define IMX_CONSOLE &imx_uart_console
-#ifdef CONFIG_OF
-static void imx_uart_console_early_putchar(struct uart_port *port, int ch)
-{
- struct imx_port *sport = (struct imx_port *)port;
-
- while (imx_uart_readl(sport, IMX21_UTS) & UTS_TXFULL)
- cpu_relax();
-
- imx_uart_writel(sport, ch, URTX0);
-}
-
-static void imx_uart_console_early_write(struct console *con, const char *s,
- unsigned count)
-{
- struct earlycon_device *dev = con->data;
-
- uart_console_write(&dev->port, s, count, imx_uart_console_early_putchar);
-}
-
-static int __init
-imx_console_early_setup(struct earlycon_device *dev, const char *opt)
-{
- if (!dev->port.membase)
- return -ENODEV;
-
- dev->con->write = imx_uart_console_early_write;
-
- return 0;
-}
-OF_EARLYCON_DECLARE(ec_imx6q, "fsl,imx6q-uart", imx_console_early_setup);
-OF_EARLYCON_DECLARE(ec_imx21, "fsl,imx21-uart", imx_console_early_setup);
-#endif
-
#else
#define IMX_CONSOLE NULL
#endif
@@ -2223,6 +2254,32 @@ static void imx_uart_probe_pdata(struct imx_port *sport,
sport->have_rtscts = 1;
}
+static enum hrtimer_restart imx_trigger_start_tx(struct hrtimer *t)
+{
+ struct imx_port *sport = container_of(t, struct imx_port, trigger_start_tx);
+ unsigned long flags;
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+ if (sport->tx_state == WAIT_AFTER_RTS)
+ imx_uart_start_tx(&sport->port);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+
+ return HRTIMER_NORESTART;
+}
+
+static enum hrtimer_restart imx_trigger_stop_tx(struct hrtimer *t)
+{
+ struct imx_port *sport = container_of(t, struct imx_port, trigger_stop_tx);
+ unsigned long flags;
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+ if (sport->tx_state == WAIT_AFTER_SEND)
+ imx_uart_stop_tx(&sport->port);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+
+ return HRTIMER_NORESTART;
+}
+
static int imx_uart_probe(struct platform_device *pdev)
{
struct imx_port *sport;
@@ -2369,6 +2426,11 @@ static int imx_uart_probe(struct platform_device *pdev)
clk_disable_unprepare(sport->clk_ipg);
+ hrtimer_init(&sport->trigger_start_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ hrtimer_init(&sport->trigger_stop_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ sport->trigger_start_tx.function = imx_trigger_start_tx;
+ sport->trigger_stop_tx.function = imx_trigger_stop_tx;
+
/*
* Allocate the IRQ(s) i.MX1 has three interrupts whereas later
* chips only have one interrupt.
@@ -2406,9 +2468,6 @@ 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/imx_earlycon.c b/drivers/tty/serial/imx_earlycon.c
new file mode 100644
index 000000000000..795606e1a22f
--- /dev/null
+++ b/drivers/tty/serial/imx_earlycon.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2020 NXP
+ */
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/io.h>
+
+#define URTX0 0x40 /* Transmitter Register */
+#define UTS_TXFULL (1<<4) /* TxFIFO full */
+#define IMX21_UTS 0xb4 /* UART Test Register on all other i.mx*/
+
+static void imx_uart_console_early_putchar(struct uart_port *port, int ch)
+{
+ while (readl_relaxed(port->membase + IMX21_UTS) & UTS_TXFULL)
+ cpu_relax();
+
+ writel_relaxed(ch, port->membase + URTX0);
+}
+
+static void imx_uart_console_early_write(struct console *con, const char *s,
+ unsigned count)
+{
+ struct earlycon_device *dev = con->data;
+
+ uart_console_write(&dev->port, s, count, imx_uart_console_early_putchar);
+}
+
+static int __init
+imx_console_early_setup(struct earlycon_device *dev, const char *opt)
+{
+ if (!dev->port.membase)
+ return -ENODEV;
+
+ dev->con->write = imx_uart_console_early_write;
+
+ return 0;
+}
+OF_EARLYCON_DECLARE(ec_imx6q, "fsl,imx6q-uart", imx_console_early_setup);
+OF_EARLYCON_DECLARE(ec_imx21, "fsl,imx21-uart", imx_console_early_setup);
+
+MODULE_AUTHOR("NXP");
+MODULE_DESCRIPTION("IMX earlycon driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/jsm/jsm_driver.c b/drivers/tty/serial/jsm/jsm_driver.c
index 592e51d8944e..cd30da0ef083 100644
--- a/drivers/tty/serial/jsm/jsm_driver.c
+++ b/drivers/tty/serial/jsm/jsm_driver.c
@@ -16,7 +16,7 @@
#include "jsm.h"
-MODULE_AUTHOR("Digi International, http://www.digi.com");
+MODULE_AUTHOR("Digi International, https://www.digi.com");
MODULE_DESCRIPTION("Driver for the Digi International Neo and Classic PCI based product line");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("jsm");
diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c
index 5022447afa23..6004c0c1d173 100644
--- a/drivers/tty/serial/kgdb_nmi.c
+++ b/drivers/tty/serial/kgdb_nmi.c
@@ -50,7 +50,7 @@ static int kgdb_nmi_console_setup(struct console *co, char *options)
* I/O utilities that messages sent to the console will automatically
* be displayed on the dbg_io.
*/
- dbg_io_ops->is_console = true;
+ dbg_io_ops->cons = co;
return 0;
}
diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c
index 41396982e9e0..49d0c7f2b29b 100644
--- a/drivers/tty/serial/kgdboc.c
+++ b/drivers/tty/serial/kgdboc.c
@@ -45,7 +45,6 @@ static struct platform_device *kgdboc_pdev;
#if IS_BUILTIN(CONFIG_KGDB_SERIAL_CONSOLE)
static struct kgdb_io kgdboc_earlycon_io_ops;
-static struct console *earlycon;
static int (*earlycon_orig_exit)(struct console *con);
#endif /* IS_BUILTIN(CONFIG_KGDB_SERIAL_CONSOLE) */
@@ -145,7 +144,7 @@ static void kgdboc_unregister_kbd(void)
#if IS_BUILTIN(CONFIG_KGDB_SERIAL_CONSOLE)
static void cleanup_earlycon(void)
{
- if (earlycon)
+ if (kgdboc_earlycon_io_ops.cons)
kgdb_unregister_io_module(&kgdboc_earlycon_io_ops);
}
#else /* !IS_BUILTIN(CONFIG_KGDB_SERIAL_CONSOLE) */
@@ -178,7 +177,7 @@ static int configure_kgdboc(void)
goto noconfig;
}
- kgdboc_io_ops.is_console = 0;
+ kgdboc_io_ops.cons = NULL;
kgdb_tty_driver = NULL;
kgdboc_use_kms = 0;
@@ -198,7 +197,7 @@ static int configure_kgdboc(void)
int idx;
if (cons->device && cons->device(cons, &idx) == p &&
idx == tty_line) {
- kgdboc_io_ops.is_console = 1;
+ kgdboc_io_ops.cons = cons;
break;
}
}
@@ -433,7 +432,8 @@ static int kgdboc_earlycon_get_char(void)
{
char c;
- if (!earlycon->read(earlycon, &c, 1))
+ if (!kgdboc_earlycon_io_ops.cons->read(kgdboc_earlycon_io_ops.cons,
+ &c, 1))
return NO_POLL_CHAR;
return c;
@@ -441,7 +441,8 @@ static int kgdboc_earlycon_get_char(void)
static void kgdboc_earlycon_put_char(u8 chr)
{
- earlycon->write(earlycon, &chr, 1);
+ kgdboc_earlycon_io_ops.cons->write(kgdboc_earlycon_io_ops.cons, &chr,
+ 1);
}
static void kgdboc_earlycon_pre_exp_handler(void)
@@ -461,7 +462,7 @@ static void kgdboc_earlycon_pre_exp_handler(void)
* boot if we detect this case.
*/
for_each_console(con)
- if (con == earlycon)
+ if (con == kgdboc_earlycon_io_ops.cons)
return;
already_warned = true;
@@ -484,25 +485,25 @@ static int kgdboc_earlycon_deferred_exit(struct console *con)
static void kgdboc_earlycon_deinit(void)
{
- if (!earlycon)
+ if (!kgdboc_earlycon_io_ops.cons)
return;
- if (earlycon->exit == kgdboc_earlycon_deferred_exit)
+ if (kgdboc_earlycon_io_ops.cons->exit == kgdboc_earlycon_deferred_exit)
/*
* kgdboc_earlycon is exiting but original boot console exit
* was never called (AKA kgdboc_earlycon_deferred_exit()
* didn't ever run). Undo our trap.
*/
- earlycon->exit = earlycon_orig_exit;
- else if (earlycon->exit)
+ kgdboc_earlycon_io_ops.cons->exit = earlycon_orig_exit;
+ else if (kgdboc_earlycon_io_ops.cons->exit)
/*
* We skipped calling the exit() routine so we could try to
* keep using the boot console even after it went away. We're
* finally done so call the function now.
*/
- earlycon->exit(earlycon);
+ kgdboc_earlycon_io_ops.cons->exit(kgdboc_earlycon_io_ops.cons);
- earlycon = NULL;
+ kgdboc_earlycon_io_ops.cons = NULL;
}
static struct kgdb_io kgdboc_earlycon_io_ops = {
@@ -511,7 +512,6 @@ static struct kgdb_io kgdboc_earlycon_io_ops = {
.write_char = kgdboc_earlycon_put_char,
.pre_exception = kgdboc_earlycon_pre_exp_handler,
.deinit = kgdboc_earlycon_deinit,
- .is_console = true,
};
#define MAX_CONSOLE_NAME_LEN (sizeof((struct console *) 0)->name)
@@ -538,7 +538,8 @@ static int __init kgdboc_earlycon_init(char *opt)
if (!con) {
/*
- * Both earlycon and kgdboc_earlycon are initialized during * early parameter parsing. We cannot guarantee earlycon gets
+ * Both earlycon and kgdboc_earlycon are initialized during
+ * early parameter parsing. We cannot guarantee earlycon gets
* in first and, in any case, on ACPI systems earlycon may
* defer its own initialization (usually to somewhere within
* setup_arch() ). To cope with either of these situations
@@ -557,10 +558,10 @@ static int __init kgdboc_earlycon_init(char *opt)
goto unlock;
}
- earlycon = con;
+ kgdboc_earlycon_io_ops.cons = con;
pr_info("Going to register kgdb with earlycon '%s'\n", con->name);
if (kgdb_register_io_module(&kgdboc_earlycon_io_ops) != 0) {
- earlycon = NULL;
+ kgdboc_earlycon_io_ops.cons = NULL;
pr_info("Failed to register kgdb with earlycon\n");
} else {
/* Trap exit so we can keep earlycon longer if needed. */
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index 60a9c53fa7cb..87f005e5d2af 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -696,6 +696,7 @@ static void msm_enable_ms(struct uart_port *port)
}
static void msm_handle_rx_dm(struct uart_port *port, unsigned int misr)
+ __must_hold(&port->lock)
{
struct tty_port *tport = &port->state->port;
unsigned int sr;
@@ -771,6 +772,7 @@ static void msm_handle_rx_dm(struct uart_port *port, unsigned int misr)
}
static void msm_handle_rx(struct uart_port *port)
+ __must_hold(&port->lock)
{
struct tty_port *tport = &port->state->port;
unsigned int sr;
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index b4f835e7de23..b784323a6a7b 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -1698,21 +1698,21 @@ static int mxs_auart_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
ret = irq;
- goto out_disable_clks;
+ goto out_iounmap;
}
s->port.irq = irq;
ret = devm_request_irq(&pdev->dev, irq, mxs_auart_irq_handle, 0,
dev_name(&pdev->dev), s);
if (ret)
- goto out_disable_clks;
+ goto out_iounmap;
platform_set_drvdata(pdev, s);
ret = mxs_auart_init_gpios(s, &pdev->dev);
if (ret) {
dev_err(&pdev->dev, "Failed to initialize GPIOs.\n");
- goto out_disable_clks;
+ goto out_iounmap;
}
/*
@@ -1720,7 +1720,7 @@ static int mxs_auart_probe(struct platform_device *pdev)
*/
ret = mxs_auart_request_gpio_irq(s);
if (ret)
- goto out_disable_clks;
+ goto out_iounmap;
auart_port[s->port.line] = s;
@@ -1746,6 +1746,9 @@ out_free_qpio_irq:
mxs_auart_free_gpio_irq(s);
auart_port[pdev->id] = NULL;
+out_iounmap:
+ iounmap(s->port.membase);
+
out_disable_clks:
if (is_asm9260_auart(s)) {
clk_disable_unprepare(s->clk);
@@ -1761,6 +1764,7 @@ static int mxs_auart_remove(struct platform_device *pdev)
uart_remove_one_port(&auart_driver, &s->port);
auart_port[pdev->id] = NULL;
mxs_auart_free_gpio_irq(s);
+ iounmap(s->port.membase);
if (is_asm9260_auart(s)) {
clk_disable_unprepare(s->clk);
clk_disable_unprepare(s->clk_ahb);
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index 40fa7a27722d..67aca8cb9cd4 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -1857,41 +1857,24 @@ static void pch_uart_pci_remove(struct pci_dev *pdev)
kfree(priv);
return;
}
-#ifdef CONFIG_PM
-static int pch_uart_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+
+static int __maybe_unused pch_uart_pci_suspend(struct device *dev)
{
- struct eg20t_port *priv = pci_get_drvdata(pdev);
+ struct eg20t_port *priv = dev_get_drvdata(dev);
uart_suspend_port(&pch_uart_driver, &priv->port);
- pci_save_state(pdev);
- pci_set_power_state(pdev, pci_choose_state(pdev, state));
return 0;
}
-static int pch_uart_pci_resume(struct pci_dev *pdev)
+static int __maybe_unused pch_uart_pci_resume(struct device *dev)
{
- struct eg20t_port *priv = pci_get_drvdata(pdev);
- int ret;
-
- pci_set_power_state(pdev, PCI_D0);
- pci_restore_state(pdev);
-
- ret = pci_enable_device(pdev);
- if (ret) {
- dev_err(&pdev->dev,
- "%s-pci_enable_device failed(ret=%d) ", __func__, ret);
- return ret;
- }
+ struct eg20t_port *priv = dev_get_drvdata(dev);
uart_resume_port(&pch_uart_driver, &priv->port);
return 0;
}
-#else
-#define pch_uart_pci_suspend NULL
-#define pch_uart_pci_resume NULL
-#endif
static const struct pci_device_id pch_uart_pci_id[] = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8811),
@@ -1945,13 +1928,16 @@ probe_error:
return ret;
}
+static SIMPLE_DEV_PM_OPS(pch_uart_pci_pm_ops,
+ pch_uart_pci_suspend,
+ pch_uart_pci_resume);
+
static struct pci_driver pch_uart_pci_driver = {
.name = "pch_uart",
.id_table = pch_uart_pci_id,
.probe = pch_uart_pci_probe,
.remove = pch_uart_pci_remove,
- .suspend = pch_uart_pci_suspend,
- .resume = pch_uart_pci_resume,
+ .driver.pm = &pch_uart_pci_pm_ops,
};
static int __init pch_uart_module_init(void)
diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c
index ba65a3bbd72a..96e7aa479961 100644
--- a/drivers/tty/serial/pmac_zilog.c
+++ b/drivers/tty/serial/pmac_zilog.c
@@ -213,6 +213,7 @@ static void pmz_interrupt_control(struct uart_pmac_port *uap, int enable)
}
static bool pmz_receive_chars(struct uart_pmac_port *uap)
+ __must_hold(&uap->port.lock)
{
struct tty_port *port;
unsigned char ch, r1, drop, flag;
diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c
index 457c0bf8cbf8..3aa29d201f54 100644
--- a/drivers/tty/serial/qcom_geni_serial.c
+++ b/drivers/tty/serial/qcom_geni_serial.c
@@ -9,6 +9,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/pm_opp.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/pm_wakeirq.h>
@@ -102,11 +103,19 @@
#define DEFAULT_IO_MACRO_IO2_IO3_MASK GENMASK(15, 4)
#define IO_MACRO_IO2_IO3_SWAP 0x4640
-#ifdef CONFIG_CONSOLE_POLL
-#define CONSOLE_RX_BYTES_PW 1
-#else
-#define CONSOLE_RX_BYTES_PW 4
-#endif
+/* We always configure 4 bytes per FIFO word */
+#define BYTES_PER_FIFO_WORD 4
+
+struct qcom_geni_private_data {
+ /* NOTE: earlycon port will have NULL here */
+ struct uart_driver *drv;
+
+ u32 poll_cached_bytes;
+ unsigned int poll_cached_bytes_cnt;
+
+ u32 write_cached_bytes;
+ unsigned int write_cached_bytes_cnt;
+};
struct qcom_geni_serial_port {
struct uart_port uport;
@@ -118,8 +127,6 @@ struct qcom_geni_serial_port {
bool setup;
int (*handle_rx)(struct uart_port *uport, u32 bytes, bool drop);
unsigned int baud;
- unsigned int tx_bytes_pw;
- unsigned int rx_bytes_pw;
void *rx_fifo;
u32 loopback;
bool brk;
@@ -128,6 +135,8 @@ struct qcom_geni_serial_port {
int wakeup_irq;
bool rx_tx_swap;
bool cts_rts_swap;
+
+ struct qcom_geni_private_data private_data;
};
static const struct uart_ops qcom_geni_console_pops;
@@ -263,8 +272,9 @@ static bool qcom_geni_serial_poll_bit(struct uart_port *uport,
unsigned int baud;
unsigned int fifo_bits;
unsigned long timeout_us = 20000;
+ struct qcom_geni_private_data *private_data = uport->private_data;
- if (uport->private_data) {
+ if (private_data->drv) {
port = to_dev_port(uport, uport);
baud = port->baud;
if (!baud)
@@ -330,23 +340,42 @@ static void qcom_geni_serial_abort_rx(struct uart_port *uport)
}
#ifdef CONFIG_CONSOLE_POLL
+
static int qcom_geni_serial_get_char(struct uart_port *uport)
{
- u32 rx_fifo;
+ struct qcom_geni_private_data *private_data = uport->private_data;
u32 status;
+ u32 word_cnt;
+ int ret;
+
+ if (!private_data->poll_cached_bytes_cnt) {
+ status = readl(uport->membase + SE_GENI_M_IRQ_STATUS);
+ writel(status, uport->membase + SE_GENI_M_IRQ_CLEAR);
+
+ status = readl(uport->membase + SE_GENI_S_IRQ_STATUS);
+ writel(status, uport->membase + SE_GENI_S_IRQ_CLEAR);
+
+ status = readl(uport->membase + SE_GENI_RX_FIFO_STATUS);
+ word_cnt = status & RX_FIFO_WC_MSK;
+ if (!word_cnt)
+ return NO_POLL_CHAR;
- status = readl(uport->membase + SE_GENI_M_IRQ_STATUS);
- writel(status, uport->membase + SE_GENI_M_IRQ_CLEAR);
+ if (word_cnt == 1 && (status & RX_LAST))
+ private_data->poll_cached_bytes_cnt =
+ (status & RX_LAST_BYTE_VALID_MSK) >>
+ RX_LAST_BYTE_VALID_SHFT;
+ else
+ private_data->poll_cached_bytes_cnt = 4;
- status = readl(uport->membase + SE_GENI_S_IRQ_STATUS);
- writel(status, uport->membase + SE_GENI_S_IRQ_CLEAR);
+ private_data->poll_cached_bytes =
+ readl(uport->membase + SE_GENI_RX_FIFOn);
+ }
- status = readl(uport->membase + SE_GENI_RX_FIFO_STATUS);
- if (!(status & RX_FIFO_WC_MSK))
- return NO_POLL_CHAR;
+ private_data->poll_cached_bytes_cnt--;
+ ret = private_data->poll_cached_bytes & 0xff;
+ private_data->poll_cached_bytes >>= 8;
- rx_fifo = readl(uport->membase + SE_GENI_RX_FIFOn);
- return rx_fifo & 0xff;
+ return ret;
}
static void qcom_geni_serial_poll_put_char(struct uart_port *uport,
@@ -365,13 +394,25 @@ static void qcom_geni_serial_poll_put_char(struct uart_port *uport,
#ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE
static void qcom_geni_serial_wr_char(struct uart_port *uport, int ch)
{
- writel(ch, uport->membase + SE_GENI_TX_FIFOn);
+ struct qcom_geni_private_data *private_data = uport->private_data;
+
+ private_data->write_cached_bytes =
+ (private_data->write_cached_bytes >> 8) | (ch << 24);
+ private_data->write_cached_bytes_cnt++;
+
+ if (private_data->write_cached_bytes_cnt == BYTES_PER_FIFO_WORD) {
+ writel(private_data->write_cached_bytes,
+ uport->membase + SE_GENI_TX_FIFOn);
+ private_data->write_cached_bytes_cnt = 0;
+ }
}
static void
__qcom_geni_serial_console_write(struct uart_port *uport, const char *s,
unsigned int count)
{
+ struct qcom_geni_private_data *private_data = uport->private_data;
+
int i;
u32 bytes_to_send = count;
@@ -406,6 +447,15 @@ __qcom_geni_serial_console_write(struct uart_port *uport, const char *s,
SE_GENI_M_IRQ_CLEAR);
i += chars_to_write;
}
+
+ if (private_data->write_cached_bytes_cnt) {
+ private_data->write_cached_bytes >>= BITS_PER_BYTE *
+ (BYTES_PER_FIFO_WORD - private_data->write_cached_bytes_cnt);
+ writel(private_data->write_cached_bytes,
+ uport->membase + SE_GENI_TX_FIFOn);
+ private_data->write_cached_bytes_cnt = 0;
+ }
+
qcom_geni_serial_poll_tx_done(uport);
}
@@ -478,7 +528,7 @@ static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop)
tport = &uport->state->port;
for (i = 0; i < bytes; ) {
int c;
- int chunk = min_t(int, bytes - i, port->rx_bytes_pw);
+ int chunk = min_t(int, bytes - i, BYTES_PER_FIFO_WORD);
ioread32_rep(uport->membase + SE_GENI_RX_FIFOn, buf, 1);
i += chunk;
@@ -658,11 +708,11 @@ static void qcom_geni_serial_handle_rx(struct uart_port *uport, bool drop)
if (!word_cnt)
return;
- total_bytes = port->rx_bytes_pw * (word_cnt - 1);
+ total_bytes = BYTES_PER_FIFO_WORD * (word_cnt - 1);
if (last_word_partial && last_word_byte_cnt)
total_bytes += last_word_byte_cnt;
else
- total_bytes += port->rx_bytes_pw;
+ total_bytes += BYTES_PER_FIFO_WORD;
port->handle_rx(uport, total_bytes, drop);
}
@@ -695,7 +745,7 @@ static void qcom_geni_serial_handle_tx(struct uart_port *uport, bool done,
}
avail = port->tx_fifo_depth - (status & TX_FIFO_WC);
- avail *= port->tx_bytes_pw;
+ avail *= BYTES_PER_FIFO_WORD;
tail = xmit->tail;
chunk = min(avail, pending);
@@ -718,8 +768,8 @@ static void qcom_geni_serial_handle_tx(struct uart_port *uport, bool done,
u8 buf[sizeof(u32)];
int c;
- memset(buf, 0, ARRAY_SIZE(buf));
- tx_bytes = min_t(size_t, remaining, port->tx_bytes_pw);
+ memset(buf, 0, sizeof(buf));
+ tx_bytes = min_t(size_t, remaining, BYTES_PER_FIFO_WORD);
for (c = 0; c < tx_bytes ; c++) {
buf[c] = xmit->buf[tail++];
@@ -836,14 +886,6 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport)
u32 proto;
u32 pin_swap;
- if (uart_console(uport)) {
- port->tx_bytes_pw = 1;
- port->rx_bytes_pw = CONSOLE_RX_BYTES_PW;
- } else {
- port->tx_bytes_pw = 4;
- port->rx_bytes_pw = 4;
- }
-
proto = geni_se_read_proto(&port->se);
if (proto != GENI_SE_UART) {
dev_err(uport->dev, "Invalid FW loaded, proto: %d\n", proto);
@@ -875,10 +917,8 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport)
*/
if (uart_console(uport))
qcom_geni_serial_poll_tx_done(uport);
- geni_se_config_packing(&port->se, BITS_PER_BYTE, port->tx_bytes_pw,
- false, true, false);
- geni_se_config_packing(&port->se, BITS_PER_BYTE, port->rx_bytes_pw,
- false, false, true);
+ geni_se_config_packing(&port->se, BITS_PER_BYTE, BYTES_PER_FIFO_WORD,
+ false, true, true);
geni_se_init(&port->se, UART_RX_WM, port->rx_fifo_depth - 2);
geni_se_select_mode(&port->se, GENI_SE_FIFO);
port->setup = true;
@@ -945,6 +985,7 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport,
struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
unsigned long clk_rate;
u32 ver, sampling_rate;
+ unsigned int avg_bw_core;
qcom_geni_serial_stop_rx(uport);
/* baud rate */
@@ -962,10 +1003,20 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport,
goto out_restart_rx;
uport->uartclk = clk_rate;
- clk_set_rate(port->se.clk, clk_rate);
+ dev_pm_opp_set_rate(uport->dev, clk_rate);
ser_clk_cfg = SER_CLK_EN;
ser_clk_cfg |= clk_div << CLK_DIV_SHFT;
+ /*
+ * Bump up BW vote on CPU and CORE path as driver supports FIFO mode
+ * only.
+ */
+ avg_bw_core = (baud > 115200) ? Bps_to_icc(CORE_2X_50_MHZ)
+ : GENI_DEFAULT_BW;
+ port->se.icc_paths[GENI_TO_CORE].avg_bw = avg_bw_core;
+ port->se.icc_paths[CPU_TO_GENI].avg_bw = Bps_to_icc(baud);
+ geni_icc_set_bw(&port->se);
+
/* parity */
tx_trans_cfg = readl(uport->membase + SE_UART_TX_TRANS_CFG);
tx_parity_cfg = readl(uport->membase + SE_UART_TX_PARITY_CFG);
@@ -1121,6 +1172,14 @@ static inline void qcom_geni_serial_enable_early_read(struct geni_se *se,
struct console *con) { }
#endif
+static int qcom_geni_serial_earlycon_exit(struct console *con)
+{
+ geni_remove_earlycon_icc_vote();
+ return 0;
+}
+
+static struct qcom_geni_private_data earlycon_private_data;
+
static int __init qcom_geni_serial_earlycon_setup(struct earlycon_device *dev,
const char *opt)
{
@@ -1136,6 +1195,8 @@ static int __init qcom_geni_serial_earlycon_setup(struct earlycon_device *dev,
if (!uport->membase)
return -EINVAL;
+ uport->private_data = &earlycon_private_data;
+
memset(&se, 0, sizeof(se));
se.base = uport->membase;
if (geni_se_read_proto(&se) != GENI_SE_UART)
@@ -1153,7 +1214,8 @@ static int __init qcom_geni_serial_earlycon_setup(struct earlycon_device *dev,
*/
qcom_geni_serial_poll_tx_done(uport);
qcom_geni_serial_abort_rx(uport);
- geni_se_config_packing(&se, BITS_PER_BYTE, 1, false, true, false);
+ geni_se_config_packing(&se, BITS_PER_BYTE, BYTES_PER_FIFO_WORD,
+ false, true, true);
geni_se_init(&se, DEF_FIFO_DEPTH_WORDS / 2, DEF_FIFO_DEPTH_WORDS - 2);
geni_se_select_mode(&se, GENI_SE_FIFO);
@@ -1166,6 +1228,7 @@ static int __init qcom_geni_serial_earlycon_setup(struct earlycon_device *dev,
writel(stop_bit_len, uport->membase + SE_UART_TX_STOP_BIT_LEN);
dev->con->write = qcom_geni_serial_earlycon_write;
+ dev->con->exit = qcom_geni_serial_earlycon_exit;
dev->con->setup = NULL;
qcom_geni_serial_enable_early_read(&se, dev->con);
@@ -1228,11 +1291,14 @@ static void qcom_geni_serial_pm(struct uart_port *uport,
if (old_state == UART_PM_STATE_UNDEFINED)
old_state = UART_PM_STATE_OFF;
- if (new_state == UART_PM_STATE_ON && old_state == UART_PM_STATE_OFF)
+ if (new_state == UART_PM_STATE_ON && old_state == UART_PM_STATE_OFF) {
+ geni_icc_enable(&port->se);
geni_se_resources_on(&port->se);
- else if (new_state == UART_PM_STATE_OFF &&
- old_state == UART_PM_STATE_ON)
+ } else if (new_state == UART_PM_STATE_OFF &&
+ old_state == UART_PM_STATE_ON) {
geni_se_resources_off(&port->se);
+ geni_icc_disable(&port->se);
+ }
}
static const struct uart_ops qcom_geni_console_pops = {
@@ -1330,6 +1396,17 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ ret = geni_icc_get(&port->se, NULL);
+ if (ret)
+ return ret;
+ port->se.icc_paths[GENI_TO_CORE].avg_bw = GENI_DEFAULT_BW;
+ port->se.icc_paths[CPU_TO_GENI].avg_bw = GENI_DEFAULT_BW;
+
+ /* Set BW for register access */
+ ret = geni_icc_set_bw(&port->se);
+ if (ret)
+ return ret;
+
port->name = devm_kasprintf(uport->dev, GFP_KERNEL,
"qcom_geni_serial_%s%d",
uart_console(uport) ? "console" : "uart", uport->line);
@@ -1351,13 +1428,26 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
if (of_property_read_bool(pdev->dev.of_node, "cts-rts-swap"))
port->cts_rts_swap = true;
- uport->private_data = drv;
+ port->se.opp_table = dev_pm_opp_set_clkname(&pdev->dev, "se");
+ if (IS_ERR(port->se.opp_table))
+ return PTR_ERR(port->se.opp_table);
+ /* OPP table is optional */
+ ret = dev_pm_opp_of_add_table(&pdev->dev);
+ if (!ret) {
+ port->se.has_opp_table = true;
+ } else if (ret != -ENODEV) {
+ dev_err(&pdev->dev, "invalid OPP table in device tree\n");
+ return ret;
+ }
+
+ port->private_data.drv = drv;
+ uport->private_data = &port->private_data;
platform_set_drvdata(pdev, port);
port->handle_rx = console ? handle_rx_console : handle_rx_uart;
ret = uart_add_one_port(drv, uport);
if (ret)
- return ret;
+ goto err;
irq_set_status_flags(uport->irq, IRQ_NOAUTOEN);
ret = devm_request_irq(uport->dev, uport->irq, qcom_geni_serial_isr,
@@ -1365,7 +1455,7 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
if (ret) {
dev_err(uport->dev, "Failed to get IRQ ret %d\n", ret);
uart_remove_one_port(drv, uport);
- return ret;
+ goto err;
}
/*
@@ -1382,18 +1472,26 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
if (ret) {
device_init_wakeup(&pdev->dev, false);
uart_remove_one_port(drv, uport);
- return ret;
+ goto err;
}
}
return 0;
+err:
+ if (port->se.has_opp_table)
+ dev_pm_opp_of_remove_table(&pdev->dev);
+ dev_pm_opp_put_clkname(port->se.opp_table);
+ return ret;
}
static int qcom_geni_serial_remove(struct platform_device *pdev)
{
struct qcom_geni_serial_port *port = platform_get_drvdata(pdev);
- struct uart_driver *drv = port->uport.private_data;
+ struct uart_driver *drv = port->private_data.drv;
+ if (port->se.has_opp_table)
+ dev_pm_opp_of_remove_table(&pdev->dev);
+ dev_pm_opp_put_clkname(port->se.opp_table);
dev_pm_clear_wake_irq(&pdev->dev);
device_init_wakeup(&pdev->dev, false);
uart_remove_one_port(drv, &port->uport);
@@ -1405,16 +1503,32 @@ static int __maybe_unused qcom_geni_serial_sys_suspend(struct device *dev)
{
struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
struct uart_port *uport = &port->uport;
+ struct qcom_geni_private_data *private_data = uport->private_data;
- return uart_suspend_port(uport->private_data, uport);
+ /*
+ * This is done so we can hit the lowest possible state in suspend
+ * even with no_console_suspend
+ */
+ if (uart_console(uport)) {
+ geni_icc_set_tag(&port->se, 0x3);
+ geni_icc_set_bw(&port->se);
+ }
+ return uart_suspend_port(private_data->drv, uport);
}
static int __maybe_unused qcom_geni_serial_sys_resume(struct device *dev)
{
+ int ret;
struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
struct uart_port *uport = &port->uport;
+ struct qcom_geni_private_data *private_data = uport->private_data;
- return uart_resume_port(uport->private_data, uport);
+ ret = uart_resume_port(private_data->drv, uport);
+ if (uart_console(uport)) {
+ geni_icc_set_tag(&port->se, 0x7);
+ geni_icc_set_bw(&port->se);
+ }
+ return ret;
}
static const struct dev_pm_ops qcom_geni_serial_pm_ops = {
diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c
index d913d9b2762a..8ed3482d2e1e 100644
--- a/drivers/tty/serial/samsung_tty.c
+++ b/drivers/tty/serial/samsung_tty.c
@@ -6,7 +6,7 @@
* http://armlinux.simtec.co.uk/
*/
-/* Hote on 2410 error handling
+/* Note on 2410 error handling
*
* The s3c2410 manual has a love/hate affair with the contents of the
* UERSTAT register in the UART blocks, and keeps marking some of the
@@ -327,7 +327,6 @@ static void s3c24xx_serial_tx_dma_complete(void *args)
unsigned long flags;
int count;
-
dmaengine_tx_status(dma->tx_chan, dma->tx_cookie, &state);
count = dma->tx_bytes_requested - state.residue;
async_tx_ack(dma->tx_desc);
@@ -409,7 +408,6 @@ static int s3c24xx_serial_start_tx_dma(struct s3c24xx_uart_port *ourport,
struct circ_buf *xmit = &port->state->xmit;
struct s3c24xx_uart_dma *dma = ourport->dma;
-
if (ourport->tx_mode != S3C24XX_TX_DMA)
enable_tx_dma(ourport);
@@ -816,7 +814,6 @@ static irqreturn_t s3c24xx_serial_rx_chars_pio(void *dev_id)
return IRQ_HANDLED;
}
-
static irqreturn_t s3c24xx_serial_rx_chars(int irq, void *dev_id)
{
struct s3c24xx_uart_port *ourport = dev_id;
@@ -842,8 +839,8 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
count >= ourport->min_dma_size) {
int align = dma_get_cache_alignment() -
(xmit->tail & (dma_get_cache_alignment() - 1));
- if (count-align >= ourport->min_dma_size) {
- dma_count = count-align;
+ if (count - align >= ourport->min_dma_size) {
+ dma_count = count - align;
count = align;
}
}
@@ -1589,7 +1586,6 @@ s3c24xx_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
return 0;
}
-
#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
static struct console s3c24xx_serial_console;
@@ -1672,7 +1668,6 @@ s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = {
}
},
#if CONFIG_SERIAL_SAMSUNG_UARTS > 2
-
[2] = {
.port = {
.lock = __PORT_LOCK_UNLOCKED(2),
@@ -1728,7 +1723,6 @@ static void s3c24xx_serial_resetport(struct uart_port *port,
udelay(1);
}
-
#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb,
@@ -1903,9 +1897,9 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
port->mapbase = res->start;
ret = platform_get_irq(platdev, 0);
- if (ret < 0)
+ if (ret < 0) {
port->irq = 0;
- else {
+ } else {
port->irq = ret;
ourport->rx_irq = ret;
ourport->tx_irq = ret + 1;
@@ -1977,8 +1971,8 @@ static const struct of_device_id s3c24xx_uart_dt_match[];
static int probe_index;
-static inline struct s3c24xx_serial_drv_data *s3c24xx_get_driver_data(
- struct platform_device *pdev)
+static inline struct s3c24xx_serial_drv_data *
+s3c24xx_get_driver_data(struct platform_device *pdev)
{
#ifdef CONFIG_OF
if (pdev->dev.of_node) {
@@ -2329,7 +2323,6 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud,
*baud = rate / (16 * (ubrdiv + 1));
dev_dbg(port->dev, "calculated baud %d\n", *baud);
}
-
}
static int __init
@@ -2696,6 +2689,7 @@ static int __init s3c2410_early_console_setup(struct earlycon_device *device,
device->port.private_data = &s3c2410_early_console_data;
return samsung_early_console_setup(device, opt);
}
+
OF_EARLYCON_DECLARE(s3c2410, "samsung,s3c2410-uart",
s3c2410_early_console_setup);
@@ -2710,6 +2704,7 @@ static int __init s3c2440_early_console_setup(struct earlycon_device *device,
device->port.private_data = &s3c2440_early_console_data;
return samsung_early_console_setup(device, opt);
}
+
OF_EARLYCON_DECLARE(s3c2412, "samsung,s3c2412-uart",
s3c2440_early_console_setup);
OF_EARLYCON_DECLARE(s3c2440, "samsung,s3c2440-uart",
@@ -2728,6 +2723,7 @@ static int __init s5pv210_early_console_setup(struct earlycon_device *device,
device->port.private_data = &s5pv210_early_console_data;
return samsung_early_console_setup(device, opt);
}
+
OF_EARLYCON_DECLARE(s5pv210, "samsung,s5pv210-uart",
s5pv210_early_console_setup);
OF_EARLYCON_DECLARE(exynos4210, "samsung,exynos4210-uart",
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index d2e5c6c86643..809610b37c71 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -1179,7 +1179,6 @@ static int sc16is7xx_probe(struct device *dev,
const struct sc16is7xx_devtype *devtype,
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;
@@ -1239,7 +1238,7 @@ static int sc16is7xx_probe(struct device *dev,
ret = PTR_ERR(s->kworker_task);
goto out_clk;
}
- sched_setscheduler(s->kworker_task, SCHED_FIFO, &sched_param);
+ sched_set_fifo(s->kworker_task);
#ifdef CONFIG_GPIOLIB
if (devtype->nr_gpio) {
diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c
index 8de8bac9c6c7..b87914ae6da8 100644
--- a/drivers/tty/serial/serial-tegra.c
+++ b/drivers/tty/serial/serial-tegra.c
@@ -439,16 +439,16 @@ static char tegra_uart_decode_rx_error(struct tegra_uart_port *tup,
/* Overrrun error */
flag = TTY_OVERRUN;
tup->uport.icount.overrun++;
- dev_err(tup->uport.dev, "Got overrun errors\n");
+ dev_dbg(tup->uport.dev, "Got overrun errors\n");
} else if (lsr & UART_LSR_PE) {
/* Parity error */
flag = TTY_PARITY;
tup->uport.icount.parity++;
- dev_err(tup->uport.dev, "Got Parity errors\n");
+ dev_dbg(tup->uport.dev, "Got Parity errors\n");
} else if (lsr & UART_LSR_FE) {
flag = TTY_FRAME;
tup->uport.icount.frame++;
- dev_err(tup->uport.dev, "Got frame errors\n");
+ dev_dbg(tup->uport.dev, "Got frame errors\n");
} else if (lsr & UART_LSR_BI) {
/*
* Break error
@@ -635,7 +635,7 @@ static void tegra_uart_handle_tx_pio(struct tegra_uart_port *tup)
}
static void tegra_uart_handle_rx_pio(struct tegra_uart_port *tup,
- struct tty_port *tty)
+ struct tty_port *port)
{
do {
char flag = TTY_NORMAL;
@@ -653,16 +653,18 @@ static void tegra_uart_handle_rx_pio(struct tegra_uart_port *tup,
ch = (unsigned char) tegra_uart_read(tup, UART_RX);
tup->uport.icount.rx++;
- if (!uart_handle_sysrq_char(&tup->uport, ch) && tty)
- tty_insert_flip_char(tty, ch, flag);
+ if (uart_handle_sysrq_char(&tup->uport, ch))
+ continue;
if (tup->uport.ignore_status_mask & UART_LSR_DR)
continue;
+
+ tty_insert_flip_char(port, ch, flag);
} while (1);
}
static void tegra_uart_copy_rx_to_tty(struct tegra_uart_port *tup,
- struct tty_port *tty,
+ struct tty_port *port,
unsigned int count)
{
int copied;
@@ -672,17 +674,13 @@ static void tegra_uart_copy_rx_to_tty(struct tegra_uart_port *tup,
return;
tup->uport.icount.rx += count;
- if (!tty) {
- dev_err(tup->uport.dev, "No tty port\n");
- return;
- }
if (tup->uport.ignore_status_mask & UART_LSR_DR)
return;
dma_sync_single_for_cpu(tup->uport.dev, tup->rx_dma_buf_phys,
count, DMA_FROM_DEVICE);
- copied = tty_insert_flip_string(tty,
+ copied = tty_insert_flip_string(port,
((unsigned char *)(tup->rx_dma_buf_virt)), count);
if (copied != count) {
WARN_ON(1);
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 57840cf90388..3403dd790517 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -14,6 +14,7 @@
#include <linux/sched/signal.h>
#include <linux/init.h>
#include <linux/console.h>
+#include <linux/gpio/consumer.h>
#include <linux/of.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
@@ -41,8 +42,6 @@ static struct lock_class_key port_lock_key;
#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
-#define SYSRQ_TIMEOUT (HZ * 5)
-
static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
struct ktermios *old_termios);
static void uart_wait_until_sent(struct tty_struct *tty, int timeout);
@@ -1122,7 +1121,7 @@ out:
return ret;
}
-static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state)
+static int uart_do_autoconfig(struct tty_struct *tty, struct uart_state *state)
{
struct tty_port *port = &state->port;
struct uart_port *uport;
@@ -1525,6 +1524,7 @@ static void uart_set_termios(struct tty_struct *tty,
/* Handle transition away from B0 status */
else if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
unsigned int mask = TIOCM_DTR;
+
if (!(cflag & CRTSCTS) || !tty_throttled(tty))
mask |= TIOCM_RTS;
uart_set_mctrl(uport, mask);
@@ -1916,6 +1916,12 @@ static inline bool uart_console_enabled(struct uart_port *port)
return uart_console(port) && (port->cons->flags & CON_ENABLED);
}
+static void __uart_port_spin_lock_init(struct uart_port *port)
+{
+ spin_lock_init(&port->lock);
+ lockdep_set_class(&port->lock, &port_lock_key);
+}
+
/*
* Ensure that the serial console lock is initialised early.
* If this port is a console, then the spinlock is already initialised.
@@ -1925,8 +1931,7 @@ static inline void uart_port_spin_lock_init(struct uart_port *port)
if (uart_console(port))
return;
- spin_lock_init(&port->lock);
- lockdep_set_class(&port->lock, &port_lock_key);
+ __uart_port_spin_lock_init(port);
}
#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL)
@@ -2276,6 +2281,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
if (console_suspend_enabled || !uart_console(uport)) {
/* Protected by port mutex for now */
struct tty_struct *tty = port->tty;
+
ret = ops->startup(uport);
if (ret == 0) {
if (tty)
@@ -2373,6 +2379,13 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
uart_change_pm(state, UART_PM_STATE_ON);
/*
+ * If this driver supports console, and it hasn't been
+ * successfully registered yet, initialise spin lock for it.
+ */
+ if (port->cons && !(port->cons->flags & CON_ENABLED))
+ __uart_port_spin_lock_init(port);
+
+ /*
* Ensure that the modem control lines are de-activated.
* keep the DTR setting that is set in uart_set_options()
* We probably don't need a spinlock around this, but
@@ -3163,7 +3176,7 @@ static DECLARE_WORK(sysrq_enable_work, uart_sysrq_on);
* Returns false if @ch is out of enabling sequence and should be
* handled some other way, true if @ch was consumed.
*/
-static bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch)
+bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch)
{
int sysrq_toggle_seq_len = strlen(sysrq_toggle_seq);
@@ -3186,99 +3199,9 @@ static bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch)
port->sysrq = 0;
return true;
}
-#else
-static inline bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch)
-{
- return false;
-}
+EXPORT_SYMBOL_GPL(uart_try_toggle_sysrq);
#endif
-int uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
-{
- if (!IS_ENABLED(CONFIG_MAGIC_SYSRQ_SERIAL))
- return 0;
-
- if (!port->has_sysrq || !port->sysrq)
- return 0;
-
- if (ch && time_before(jiffies, port->sysrq)) {
- if (sysrq_mask()) {
- handle_sysrq(ch);
- port->sysrq = 0;
- return 1;
- }
- if (uart_try_toggle_sysrq(port, ch))
- return 1;
- }
- port->sysrq = 0;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(uart_handle_sysrq_char);
-
-int uart_prepare_sysrq_char(struct uart_port *port, unsigned int ch)
-{
- if (!IS_ENABLED(CONFIG_MAGIC_SYSRQ_SERIAL))
- return 0;
-
- if (!port->has_sysrq || !port->sysrq)
- return 0;
-
- if (ch && time_before(jiffies, port->sysrq)) {
- if (sysrq_mask()) {
- port->sysrq_ch = ch;
- port->sysrq = 0;
- return 1;
- }
- if (uart_try_toggle_sysrq(port, ch))
- return 1;
- }
- port->sysrq = 0;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(uart_prepare_sysrq_char);
-
-void uart_unlock_and_check_sysrq(struct uart_port *port, unsigned long flags)
-__releases(&port->lock)
-{
- if (port->has_sysrq) {
- int sysrq_ch = port->sysrq_ch;
-
- port->sysrq_ch = 0;
- spin_unlock_irqrestore(&port->lock, flags);
- if (sysrq_ch)
- handle_sysrq(sysrq_ch);
- } else {
- spin_unlock_irqrestore(&port->lock, flags);
- }
-}
-EXPORT_SYMBOL_GPL(uart_unlock_and_check_sysrq);
-
-/*
- * We do the SysRQ and SAK checking like this...
- */
-int uart_handle_break(struct uart_port *port)
-{
- struct uart_state *state = port->state;
-
- if (port->handle_break)
- port->handle_break(port);
-
- if (port->has_sysrq && uart_console(port)) {
- if (!port->sysrq) {
- port->sysrq = jiffies + SYSRQ_TIMEOUT;
- return 1;
- }
- port->sysrq = 0;
- }
-
- if (port->flags & UPF_SAK)
- do_SAK(state->port.tty);
- return 0;
-}
-EXPORT_SYMBOL_GPL(uart_handle_break);
-
EXPORT_SYMBOL(uart_write_wakeup);
EXPORT_SYMBOL(uart_register_driver);
EXPORT_SYMBOL(uart_unregister_driver);
@@ -3289,8 +3212,7 @@ EXPORT_SYMBOL(uart_remove_one_port);
/**
* uart_get_rs485_mode() - retrieve rs485 properties for given uart
- * @dev: uart device
- * @rs485conf: output parameter
+ * @port: uart device's target port
*
* This function implements the device tree binding described in
* Documentation/devicetree/bindings/serial/rs485.txt.
diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c
index 0b5110dad051..13eadcb8aec4 100644
--- a/drivers/tty/serial/sifive.c
+++ b/drivers/tty/serial/sifive.c
@@ -883,7 +883,6 @@ console_initcall(sifive_console_init);
static void __ssp_add_console_port(struct sifive_serial_port *ssp)
{
- spin_lock_init(&ssp->port.lock);
sifive_serial_console_ports[ssp->port.line] = ssp;
}
diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 8602ff357321..143300a80090 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -129,9 +129,13 @@ static int stm32_config_rs485(struct uart_port *port,
if (rs485conf->flags & SER_RS485_RTS_ON_SEND) {
cr3 &= ~USART_CR3_DEP;
rs485conf->flags &= ~SER_RS485_RTS_AFTER_SEND;
+ mctrl_gpio_set(stm32_port->gpios,
+ stm32_port->port.mctrl & ~TIOCM_RTS);
} else {
cr3 |= USART_CR3_DEP;
rs485conf->flags |= SER_RS485_RTS_AFTER_SEND;
+ mctrl_gpio_set(stm32_port->gpios,
+ stm32_port->port.mctrl | TIOCM_RTS);
}
writel_relaxed(cr3, port->membase + ofs->cr3);
@@ -847,9 +851,13 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
if (rs485conf->flags & SER_RS485_RTS_ON_SEND) {
cr3 &= ~USART_CR3_DEP;
rs485conf->flags &= ~SER_RS485_RTS_AFTER_SEND;
+ mctrl_gpio_set(stm32_port->gpios,
+ stm32_port->port.mctrl & ~TIOCM_RTS);
} else {
cr3 |= USART_CR3_DEP;
rs485conf->flags |= SER_RS485_RTS_AFTER_SEND;
+ mctrl_gpio_set(stm32_port->gpios,
+ stm32_port->port.mctrl | TIOCM_RTS);
}
} else {
@@ -1033,8 +1041,9 @@ static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev)
if (WARN_ON(id >= STM32_MAX_PORTS))
return NULL;
- stm32_ports[id].hw_flow_control = of_property_read_bool(np,
- "st,hw-flow-ctrl");
+ stm32_ports[id].hw_flow_control =
+ of_property_read_bool (np, "st,hw-flow-ctrl") /*deprecated*/ ||
+ of_property_read_bool (np, "uart-has-rtscts");
stm32_ports[id].port.line = id;
stm32_ports[id].cr1_irq = USART_CR1_RXNEIE;
stm32_ports[id].cr3_irq = 0;
diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c
index e35073e93a5b..eafada8fb6fa 100644
--- a/drivers/tty/serial/sunhv.c
+++ b/drivers/tty/serial/sunhv.c
@@ -567,9 +567,6 @@ static int hv_probe(struct platform_device *op)
sunserial_console_match(&sunhv_console, op->dev.of_node,
&sunhv_reg, port->line, false);
- /* We need to initialize lock even for non-registered console */
- spin_lock_init(&port->lock);
-
err = uart_add_one_port(&sunhv_reg, port);
if (err)
goto out_unregister_driver;
diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c
index 1eb703c980e0..bab551f46963 100644
--- a/drivers/tty/serial/sunsab.c
+++ b/drivers/tty/serial/sunsab.c
@@ -886,7 +886,7 @@ static int sunsab_console_setup(struct console *con, char *options)
* though...
*/
if (up->port.type != PORT_SUNSAB)
- return -1;
+ return -EINVAL;
printk("Console: ttyS%d (SAB82532)\n",
(sunsab_reg.minor - 64) + con->index);
diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c
index 103ab8c556e7..7ea06bbc6197 100644
--- a/drivers/tty/serial/sunzilog.c
+++ b/drivers/tty/serial/sunzilog.c
@@ -1221,7 +1221,7 @@ static int __init sunzilog_console_setup(struct console *con, char *options)
int baud, brg;
if (up->port.type != PORT_SUNZILOG)
- return -1;
+ return -EINVAL;
printk(KERN_INFO "Console: ttyS%d (SunZilog zs%d)\n",
(sunzilog_reg.minor - 64) + con->index, con->index);
diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c
index 7dbd0c471d92..09379db613d8 100644
--- a/drivers/tty/serial/uartlite.c
+++ b/drivers/tty/serial/uartlite.c
@@ -32,7 +32,7 @@
* Register definitions
*
* For register details see datasheet:
- * http://www.xilinx.com/support/documentation/ip_documentation/opb_uartlite.pdf
+ * https://www.xilinx.com/support/documentation/ip_documentation/opb_uartlite.pdf
*/
#define ULITE_RX 0x00
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index b9d672af8b65..2833f1418d6d 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -1465,7 +1465,6 @@ static int cdns_uart_probe(struct platform_device *pdev)
cdns_uart_uart_driver.nr = CDNS_UART_NR_PORTS;
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
cdns_uart_uart_driver.cons = &cdns_uart_console;
- cdns_uart_console.index = id;
#endif
rc = uart_register_driver(&cdns_uart_uart_driver);
@@ -1581,8 +1580,10 @@ static int cdns_uart_probe(struct platform_device *pdev)
* If register_console() don't assign value, then console_port pointer
* is cleanup.
*/
- if (!console_port)
+ if (!console_port) {
+ cdns_uart_console.index = id;
console_port = port;
+ }
#endif
rc = uart_add_one_port(&cdns_uart_uart_driver, port);
@@ -1595,8 +1596,10 @@ static int cdns_uart_probe(struct platform_device *pdev)
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
/* This is not port which is used for console that's why clean it up */
if (console_port == port &&
- !(cdns_uart_uart_driver.cons->flags & CON_ENABLED))
+ !(cdns_uart_uart_driver.cons->flags & CON_ENABLED)) {
console_port = NULL;
+ cdns_uart_console.index = -1;
+ }
#endif
cdns_uart_data->cts_override = of_property_read_bool(pdev->dev.of_node,
diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c
index 08d2976593d5..0dba40eace46 100644
--- a/drivers/tty/synclink.c
+++ b/drivers/tty/synclink.c
@@ -252,7 +252,6 @@ struct mgsl_struct {
char device_name[25]; /* device instance name */
- unsigned int bus_type; /* expansion bus type (ISA,EISA,PCI) */
unsigned char bus; /* expansion bus number (zero based) */
unsigned char function; /* PCI device number */
@@ -3432,15 +3431,9 @@ static inline void line_info(struct seq_file *m, struct mgsl_struct *info)
char stat_buf[30];
unsigned long flags;
- if (info->bus_type == MGSL_BUS_TYPE_PCI) {
- seq_printf(m, "%s:PCI io:%04X irq:%d mem:%08X lcr:%08X",
- info->device_name, info->io_base, info->irq_level,
- info->phys_memory_base, info->phys_lcr_base);
- } else {
- seq_printf(m, "%s:(E)ISA io:%04X irq:%d dma:%d",
- info->device_name, info->io_base,
- info->irq_level, info->dma_level);
- }
+ seq_printf(m, "%s:PCI io:%04X irq:%d mem:%08X lcr:%08X",
+ info->device_name, info->io_base, info->irq_level,
+ info->phys_memory_base, info->phys_lcr_base);
/* output current serial signal states */
spin_lock_irqsave(&info->irq_spinlock,flags);
@@ -3556,54 +3549,27 @@ static int mgsl_allocate_dma_buffers(struct mgsl_struct *info)
if ( info->max_frame_size % DMABUFFERSIZE )
BuffersPerFrame++;
- if ( info->bus_type == MGSL_BUS_TYPE_PCI ) {
- /*
- * The PCI adapter has 256KBytes of shared memory to use.
- * This is 64 PAGE_SIZE buffers.
- *
- * The first page is used for padding at this time so the
- * buffer list does not begin at offset 0 of the PCI
- * adapter's shared memory.
- *
- * The 2nd page is used for the buffer list. A 4K buffer
- * list can hold 128 DMA_BUFFER structures at 32 bytes
- * each.
- *
- * This leaves 62 4K pages.
- *
- * The next N pages are used for transmit frame(s). We
- * reserve enough 4K page blocks to hold the required
- * number of transmit dma buffers (num_tx_dma_buffers),
- * each of MaxFrameSize size.
- *
- * Of the remaining pages (62-N), determine how many can
- * be used to receive full MaxFrameSize inbound frames
- */
- info->tx_buffer_count = info->num_tx_dma_buffers * BuffersPerFrame;
- info->rx_buffer_count = 62 - info->tx_buffer_count;
- } else {
- /* Calculate the number of PAGE_SIZE buffers needed for */
- /* receive and transmit DMA buffers. */
-
-
- /* Calculate the number of DMA buffers necessary to */
- /* hold 7 max size receive frames and one max size transmit frame. */
- /* The receive buffer count is bumped by one so we avoid an */
- /* End of List condition if all receive buffers are used when */
- /* using linked list DMA buffers. */
-
- info->tx_buffer_count = info->num_tx_dma_buffers * BuffersPerFrame;
- info->rx_buffer_count = (BuffersPerFrame * MAXRXFRAMES) + 6;
-
- /*
- * limit total TxBuffers & RxBuffers to 62 4K total
- * (ala PCI Allocation)
- */
-
- if ( (info->tx_buffer_count + info->rx_buffer_count) > 62 )
- info->rx_buffer_count = 62 - info->tx_buffer_count;
-
- }
+ /*
+ * The PCI adapter has 256KBytes of shared memory to use. This is 64
+ * PAGE_SIZE buffers.
+ *
+ * The first page is used for padding at this time so the buffer list
+ * does not begin at offset 0 of the PCI adapter's shared memory.
+ *
+ * The 2nd page is used for the buffer list. A 4K buffer list can hold
+ * 128 DMA_BUFFER structures at 32 bytes each.
+ *
+ * This leaves 62 4K pages.
+ *
+ * The next N pages are used for transmit frame(s). We reserve enough
+ * 4K page blocks to hold the required number of transmit dma buffers
+ * (num_tx_dma_buffers), each of MaxFrameSize size.
+ *
+ * Of the remaining pages (62-N), determine how many can be used to
+ * receive full MaxFrameSize inbound frames
+ */
+ info->tx_buffer_count = info->num_tx_dma_buffers * BuffersPerFrame;
+ info->rx_buffer_count = 62 - info->tx_buffer_count;
if ( debug_level >= DEBUG_LEVEL_INFO )
printk("%s(%d):Allocating %d TX and %d RX DMA buffers.\n",
@@ -3652,23 +3618,10 @@ static int mgsl_alloc_buffer_list_memory( struct mgsl_struct *info )
{
unsigned int i;
- if ( info->bus_type == MGSL_BUS_TYPE_PCI ) {
- /* PCI adapter uses shared memory. */
- info->buffer_list = info->memory_base + info->last_mem_alloc;
- info->buffer_list_phys = info->last_mem_alloc;
- info->last_mem_alloc += BUFFERLISTSIZE;
- } else {
- /* ISA adapter uses system memory. */
- /* The buffer lists are allocated as a common buffer that both */
- /* the processor and adapter can access. This allows the driver to */
- /* inspect portions of the buffer while other portions are being */
- /* updated by the adapter using Bus Master DMA. */
-
- info->buffer_list = dma_alloc_coherent(NULL, BUFFERLISTSIZE, &info->buffer_list_dma_addr, GFP_KERNEL);
- if (info->buffer_list == NULL)
- return -ENOMEM;
- info->buffer_list_phys = (u32)(info->buffer_list_dma_addr);
- }
+ /* PCI adapter uses shared memory. */
+ info->buffer_list = info->memory_base + info->last_mem_alloc;
+ info->buffer_list_phys = info->last_mem_alloc;
+ info->last_mem_alloc += BUFFERLISTSIZE;
/* We got the memory for the buffer entry lists. */
/* Initialize the memory block to all zeros. */
@@ -3734,9 +3687,6 @@ static int mgsl_alloc_buffer_list_memory( struct mgsl_struct *info )
*/
static void mgsl_free_buffer_list_memory( struct mgsl_struct *info )
{
- if (info->buffer_list && info->bus_type != MGSL_BUS_TYPE_PCI)
- dma_free_coherent(NULL, BUFFERLISTSIZE, info->buffer_list, info->buffer_list_dma_addr);
-
info->buffer_list = NULL;
info->rx_buffer_list = NULL;
info->tx_buffer_list = NULL;
@@ -3762,24 +3712,13 @@ static void mgsl_free_buffer_list_memory( struct mgsl_struct *info )
static int mgsl_alloc_frame_memory(struct mgsl_struct *info,DMABUFFERENTRY *BufferList,int Buffercount)
{
int i;
- u32 phys_addr;
/* Allocate page sized buffers for the receive buffer list */
for ( i = 0; i < Buffercount; i++ ) {
- if ( info->bus_type == MGSL_BUS_TYPE_PCI ) {
- /* PCI adapter uses shared memory buffers. */
- BufferList[i].virt_addr = info->memory_base + info->last_mem_alloc;
- phys_addr = info->last_mem_alloc;
- info->last_mem_alloc += DMABUFFERSIZE;
- } else {
- /* ISA adapter uses system memory. */
- BufferList[i].virt_addr = dma_alloc_coherent(NULL, DMABUFFERSIZE, &BufferList[i].dma_addr, GFP_KERNEL);
- if (BufferList[i].virt_addr == NULL)
- return -ENOMEM;
- phys_addr = (u32)(BufferList[i].dma_addr);
- }
- BufferList[i].phys_addr = phys_addr;
+ BufferList[i].virt_addr = info->memory_base + info->last_mem_alloc;
+ BufferList[i].phys_addr = info->last_mem_alloc;
+ info->last_mem_alloc += DMABUFFERSIZE;
}
return 0;
@@ -3807,8 +3746,6 @@ static void mgsl_free_frame_memory(struct mgsl_struct *info, DMABUFFERENTRY *Buf
if ( BufferList ) {
for ( i = 0 ; i < Buffercount ; i++ ) {
if ( BufferList[i].virt_addr ) {
- if ( info->bus_type != MGSL_BUS_TYPE_PCI )
- dma_free_coherent(NULL, DMABUFFERSIZE, BufferList[i].virt_addr, BufferList[i].dma_addr);
BufferList[i].virt_addr = NULL;
}
}
@@ -4040,58 +3977,40 @@ static int mgsl_claim_resources(struct mgsl_struct *info)
}
info->irq_requested = true;
- if ( info->bus_type == MGSL_BUS_TYPE_PCI ) {
- if (request_mem_region(info->phys_memory_base,0x40000,"synclink") == NULL) {
- printk( "%s(%d):mem addr conflict device %s Addr=%08X\n",
- __FILE__,__LINE__,info->device_name, info->phys_memory_base);
- goto errout;
- }
- info->shared_mem_requested = true;
- if (request_mem_region(info->phys_lcr_base + info->lcr_offset,128,"synclink") == NULL) {
- printk( "%s(%d):lcr mem addr conflict device %s Addr=%08X\n",
- __FILE__,__LINE__,info->device_name, info->phys_lcr_base + info->lcr_offset);
- goto errout;
- }
- info->lcr_mem_requested = true;
-
- info->memory_base = ioremap(info->phys_memory_base,
- 0x40000);
- if (!info->memory_base) {
- printk( "%s(%d):Can't map shared memory on device %s MemAddr=%08X\n",
- __FILE__,__LINE__,info->device_name, info->phys_memory_base );
- goto errout;
- }
-
- if ( !mgsl_memory_test(info) ) {
- printk( "%s(%d):Failed shared memory test %s MemAddr=%08X\n",
- __FILE__,__LINE__,info->device_name, info->phys_memory_base );
- goto errout;
- }
-
- info->lcr_base = ioremap(info->phys_lcr_base,
- PAGE_SIZE);
- if (!info->lcr_base) {
- printk( "%s(%d):Can't map LCR memory on device %s MemAddr=%08X\n",
- __FILE__,__LINE__,info->device_name, info->phys_lcr_base );
- goto errout;
- }
- info->lcr_base += info->lcr_offset;
+ if (request_mem_region(info->phys_memory_base,0x40000,"synclink") == NULL) {
+ printk( "%s(%d):mem addr conflict device %s Addr=%08X\n",
+ __FILE__,__LINE__,info->device_name, info->phys_memory_base);
+ goto errout;
+ }
+ info->shared_mem_requested = true;
+ if (request_mem_region(info->phys_lcr_base + info->lcr_offset,128,"synclink") == NULL) {
+ printk( "%s(%d):lcr mem addr conflict device %s Addr=%08X\n",
+ __FILE__,__LINE__,info->device_name, info->phys_lcr_base + info->lcr_offset);
+ goto errout;
+ }
+ info->lcr_mem_requested = true;
+
+ info->memory_base = ioremap(info->phys_memory_base, 0x40000);
+ if (!info->memory_base) {
+ printk( "%s(%d):Can't map shared memory on device %s MemAddr=%08X\n",
+ __FILE__,__LINE__,info->device_name, info->phys_memory_base );
+ goto errout;
+ }
- } else {
- /* claim DMA channel */
+ if ( !mgsl_memory_test(info) ) {
+ printk( "%s(%d):Failed shared memory test %s MemAddr=%08X\n",
+ __FILE__,__LINE__,info->device_name, info->phys_memory_base );
+ goto errout;
+ }
- if (request_dma(info->dma_level,info->device_name) < 0){
- printk( "%s(%d):Can't request DMA channel on device %s DMA=%d\n",
- __FILE__,__LINE__,info->device_name, info->dma_level );
- goto errout;
- }
- info->dma_requested = true;
-
- /* ISA adapter uses bus master DMA */
- set_dma_mode(info->dma_level,DMA_MODE_CASCADE);
- enable_dma(info->dma_level);
+ info->lcr_base = ioremap(info->phys_lcr_base, PAGE_SIZE);
+ if (!info->lcr_base) {
+ printk( "%s(%d):Can't map LCR memory on device %s MemAddr=%08X\n",
+ __FILE__,__LINE__,info->device_name, info->phys_lcr_base );
+ goto errout;
}
-
+ info->lcr_base += info->lcr_offset;
+
if ( mgsl_allocate_dma_buffers(info) < 0 ) {
printk( "%s(%d):Can't allocate DMA buffers on device %s DMA=%d\n",
__FILE__,__LINE__,info->device_name, info->dma_level );
@@ -4200,16 +4119,10 @@ static void mgsl_add_device( struct mgsl_struct *info )
else if ( info->max_frame_size > 65535 )
info->max_frame_size = 65535;
- if ( info->bus_type == MGSL_BUS_TYPE_PCI ) {
- printk( "SyncLink PCI v%d %s: IO=%04X IRQ=%d Mem=%08X,%08X MaxFrameSize=%u\n",
- info->hw_version + 1, info->device_name, info->io_base, info->irq_level,
- info->phys_memory_base, info->phys_lcr_base,
- info->max_frame_size );
- } else {
- printk( "SyncLink ISA %s: IO=%04X IRQ=%d DMA=%d MaxFrameSize=%u\n",
- info->device_name, info->io_base, info->irq_level, info->dma_level,
- info->max_frame_size );
- }
+ printk( "SyncLink PCI v%d %s: IO=%04X IRQ=%d Mem=%08X,%08X MaxFrameSize=%u\n",
+ info->hw_version + 1, info->device_name, info->io_base, info->irq_level,
+ info->phys_memory_base, info->phys_lcr_base,
+ info->max_frame_size );
#if SYNCLINK_GENERIC_HDLC
hdlcdev_init(info);
@@ -4420,8 +4333,7 @@ static void usc_RTCmd( struct mgsl_struct *info, u16 Cmd )
outw( Cmd + info->loopback_bits, info->io_base + CCAR );
/* Read to flush write to CCAR */
- if ( info->bus_type == MGSL_BUS_TYPE_PCI )
- inw( info->io_base + CCAR );
+ inw( info->io_base + CCAR );
} /* end of usc_RTCmd() */
@@ -4445,8 +4357,7 @@ static void usc_DmaCmd( struct mgsl_struct *info, u16 Cmd )
outw( Cmd + info->mbre_bit, info->io_base );
/* Read to flush write to DCAR */
- if ( info->bus_type == MGSL_BUS_TYPE_PCI )
- inw( info->io_base );
+ inw( info->io_base );
} /* end of usc_DmaCmd() */
@@ -4475,8 +4386,7 @@ static void usc_OutDmaReg( struct mgsl_struct *info, u16 RegAddr, u16 RegValue )
outw( RegValue, info->io_base );
/* Read to flush write to DCAR */
- if ( info->bus_type == MGSL_BUS_TYPE_PCI )
- inw( info->io_base );
+ inw( info->io_base );
} /* end of usc_OutDmaReg() */
@@ -4528,8 +4438,7 @@ static void usc_OutReg( struct mgsl_struct *info, u16 RegAddr, u16 RegValue )
outw( RegValue, info->io_base + CCAR );
/* Read to flush write to CCAR */
- if ( info->bus_type == MGSL_BUS_TYPE_PCI )
- inw( info->io_base + CCAR );
+ inw( info->io_base + CCAR );
} /* end of usc_OutReg() */
@@ -4728,10 +4637,7 @@ static void usc_set_sdlc_mode( struct mgsl_struct *info )
RegValue = usc_InReg( info, RICR ) & 0xc0;
- if ( info->bus_type == MGSL_BUS_TYPE_PCI )
- usc_OutReg( info, RICR, (u16)(0x030a | RegValue) );
- else
- usc_OutReg( info, RICR, (u16)(0x140a | RegValue) );
+ usc_OutReg( info, RICR, (u16)(0x030a | RegValue) );
/* Unlatch all Rx status bits and clear Rx status IRQ Pending */
@@ -4792,10 +4698,7 @@ static void usc_set_sdlc_mode( struct mgsl_struct *info )
* 0000 0000 0011 0110 = 0x0036
*/
- if ( info->bus_type == MGSL_BUS_TYPE_PCI )
- usc_OutReg( info, TICR, 0x0736 );
- else
- usc_OutReg( info, TICR, 0x1436 );
+ usc_OutReg( info, TICR, 0x0736 );
usc_UnlatchTxstatusBits( info, TXSTATUS_ALL );
usc_ClearIrqPendingBits( info, TRANSMIT_STATUS );
@@ -4885,10 +4788,7 @@ static void usc_set_sdlc_mode( struct mgsl_struct *info )
/* DPLL is enabled. Use BRG1 to provide continuous reference clock */
/* for DPLL. DPLL mode in HCR is dependent on the encoding used. */
- if ( info->bus_type == MGSL_BUS_TYPE_PCI )
- XtalSpeed = 11059200;
- else
- XtalSpeed = 14745600;
+ XtalSpeed = 11059200;
if ( info->params.flags & HDLC_FLAG_DPLL_DIV16 ) {
DpllDivisor = 16;
@@ -5011,13 +4911,8 @@ static void usc_set_sdlc_mode( struct mgsl_struct *info )
* 0110 0000 0000 1011 = 0x600b
*/
- if ( info->bus_type == MGSL_BUS_TYPE_PCI ) {
- /* PCI adapter does not need DMA wait state */
- usc_OutDmaReg( info, DCR, 0xa00b );
- }
- else
- usc_OutDmaReg( info, DCR, 0x800b );
-
+ /* PCI adapter does not need DMA wait state */
+ usc_OutDmaReg( info, DCR, 0xa00b );
/* Receive DMA mode Register (RDMR)
*
@@ -5109,12 +5004,8 @@ static void usc_set_sdlc_mode( struct mgsl_struct *info )
* <7..0> 0x00 Maximum number of clock cycles per bus grant
*/
- if ( info->bus_type == MGSL_BUS_TYPE_PCI ) {
- /* don't limit bus occupancy on PCI adapter */
- usc_OutDmaReg( info, BDCR, 0x0000 );
- }
- else
- usc_OutDmaReg( info, BDCR, 0x2000 );
+ /* don't limit bus occupancy on PCI adapter */
+ usc_OutDmaReg( info, BDCR, 0x0000 );
usc_stop_transmitter(info);
usc_stop_receiver(info);
@@ -5155,10 +5046,7 @@ static void usc_enable_loopback(struct mgsl_struct *info, int enable)
/* Write 16-bit Time Constant for BRG0 */
/* use clock speed if available, otherwise use 8 for diagnostics */
if (info->params.clock_speed) {
- if (info->bus_type == MGSL_BUS_TYPE_PCI)
- usc_OutReg(info, TC0R, (u16)((11059200/info->params.clock_speed)-1));
- else
- usc_OutReg(info, TC0R, (u16)((14745600/info->params.clock_speed)-1));
+ usc_OutReg(info, TC0R, (u16)((11059200/info->params.clock_speed)-1));
} else
usc_OutReg(info, TC0R, (u16)8);
@@ -5201,10 +5089,7 @@ static void usc_enable_aux_clock( struct mgsl_struct *info, u32 data_rate )
u16 Tc;
if ( data_rate ) {
- if ( info->bus_type == MGSL_BUS_TYPE_PCI )
- XtalSpeed = 11059200;
- else
- XtalSpeed = 14745600;
+ XtalSpeed = 11059200;
/* Tc = (Xtal/Speed) - 1 */
@@ -5682,44 +5567,38 @@ static void usc_load_txfifo( struct mgsl_struct *info )
*/
static void usc_reset( struct mgsl_struct *info )
{
- if ( info->bus_type == MGSL_BUS_TYPE_PCI ) {
- int i;
- u32 readval;
+ int i;
+ u32 readval;
- /* Set BIT30 of Misc Control Register */
- /* (Local Control Register 0x50) to force reset of USC. */
+ /* Set BIT30 of Misc Control Register */
+ /* (Local Control Register 0x50) to force reset of USC. */
- volatile u32 *MiscCtrl = (u32 *)(info->lcr_base + 0x50);
- u32 *LCR0BRDR = (u32 *)(info->lcr_base + 0x28);
+ volatile u32 *MiscCtrl = (u32 *)(info->lcr_base + 0x50);
+ u32 *LCR0BRDR = (u32 *)(info->lcr_base + 0x28);
- info->misc_ctrl_value |= BIT30;
- *MiscCtrl = info->misc_ctrl_value;
+ info->misc_ctrl_value |= BIT30;
+ *MiscCtrl = info->misc_ctrl_value;
- /*
- * Force at least 170ns delay before clearing
- * reset bit. Each read from LCR takes at least
- * 30ns so 10 times for 300ns to be safe.
- */
- for(i=0;i<10;i++)
- readval = *MiscCtrl;
-
- info->misc_ctrl_value &= ~BIT30;
- *MiscCtrl = info->misc_ctrl_value;
-
- *LCR0BRDR = BUS_DESCRIPTOR(
- 1, // Write Strobe Hold (0-3)
- 2, // Write Strobe Delay (0-3)
- 2, // Read Strobe Delay (0-3)
- 0, // NWDD (Write data-data) (0-3)
- 4, // NWAD (Write Addr-data) (0-31)
- 0, // NXDA (Read/Write Data-Addr) (0-3)
- 0, // NRDD (Read Data-Data) (0-3)
- 5 // NRAD (Read Addr-Data) (0-31)
- );
- } else {
- /* do HW reset */
- outb( 0,info->io_base + 8 );
- }
+ /*
+ * Force at least 170ns delay before clearing reset bit. Each read from
+ * LCR takes at least 30ns so 10 times for 300ns to be safe.
+ */
+ for(i=0;i<10;i++)
+ readval = *MiscCtrl;
+
+ info->misc_ctrl_value &= ~BIT30;
+ *MiscCtrl = info->misc_ctrl_value;
+
+ *LCR0BRDR = BUS_DESCRIPTOR(
+ 1, // Write Strobe Hold (0-3)
+ 2, // Write Strobe Delay (0-3)
+ 2, // Read Strobe Delay (0-3)
+ 0, // NWDD (Write data-data) (0-3)
+ 4, // NWAD (Write Addr-data) (0-31)
+ 0, // NXDA (Read/Write Data-Addr) (0-3)
+ 0, // NRDD (Read Data-Data) (0-3)
+ 5 // NRAD (Read Addr-Data) (0-31)
+ );
info->mbre_bit = 0;
info->loopback_bits = 0;
@@ -6228,11 +6107,7 @@ static void usc_enable_async_clock( struct mgsl_struct *info, u32 data_rate )
* ClkSpeed = 921600 (ISA), 691200 (PCI)
*/
- if ( info->bus_type == MGSL_BUS_TYPE_PCI )
- usc_OutReg( info, TC0R, (u16)((691200/data_rate) - 1) );
- else
- usc_OutReg( info, TC0R, (u16)((921600/data_rate) - 1) );
-
+ usc_OutReg( info, TC0R, (u16)((691200/data_rate) - 1) );
/*
* Hardware Configuration Register (HCR)
@@ -6837,10 +6712,7 @@ static void mgsl_load_tx_dma_buffer(struct mgsl_struct *info,
/* Actually copy data from source buffer to DMA buffer. */
/* Also set the data count for this individual DMA buffer. */
- if ( info->bus_type == MGSL_BUS_TYPE_PCI )
- mgsl_load_pci_memory(pBufEntry->virt_addr, Buffer,Copycount);
- else
- memcpy(pBufEntry->virt_addr, Buffer, Copycount);
+ mgsl_load_pci_memory(pBufEntry->virt_addr, Buffer,Copycount);
pBufEntry->count = Copycount;
@@ -7315,9 +7187,6 @@ static bool mgsl_memory_test( struct mgsl_struct *info )
unsigned long TestLimit = SHARED_MEM_ADDRESS_SIZE/sizeof(unsigned long);
unsigned long * TestAddr;
- if ( info->bus_type != MGSL_BUS_TYPE_PCI )
- return true;
-
TestAddr = (unsigned long *)info->memory_base;
/* Test data lines with test pattern at one location. */
@@ -8003,7 +7872,6 @@ static int synclink_init_one (struct pci_dev *dev,
info->lcr_offset = info->phys_lcr_base & (PAGE_SIZE-1);
info->phys_lcr_base &= ~(PAGE_SIZE-1);
- info->bus_type = MGSL_BUS_TYPE_PCI;
info->io_addr_size = 8;
info->irq_flags = IRQF_SHARED;
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index 7c95afa905a0..a8e39b2cdd55 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -403,7 +403,6 @@ static const struct sysrq_key_op sysrq_moom_op = {
.enable_mask = SYSRQ_ENABLE_SIGNAL,
};
-#ifdef CONFIG_BLOCK
static void sysrq_handle_thaw(int key)
{
emergency_thaw_all();
@@ -414,7 +413,6 @@ static const struct sysrq_key_op sysrq_thaw_op = {
.action_msg = "Emergency Thaw of all frozen filesystems",
.enable_mask = SYSRQ_ENABLE_SIGNAL,
};
-#endif
static void sysrq_handle_kill(int key)
{
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 5a6f36b391d9..ceed72c9a88f 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -1405,7 +1405,7 @@ void tty_save_termios(struct tty_struct *tty)
/* Stash the termios data */
tp = tty->driver->termios[idx];
if (tp == NULL) {
- tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL);
+ tp = kmalloc(sizeof(*tp), GFP_KERNEL);
if (tp == NULL)
return;
tty->driver->termios[idx] = tp;
@@ -2489,7 +2489,7 @@ static int tty_tiocsserial(struct tty_struct *tty, struct serial_struct __user *
struct serial_struct v;
int flags;
- if (copy_from_user(&v, ss, sizeof(struct serial_struct)))
+ if (copy_from_user(&v, ss, sizeof(*ss)))
return -EFAULT;
flags = v.flags & ASYNC_DEPRECATED;
@@ -2507,11 +2507,11 @@ static int tty_tiocgserial(struct tty_struct *tty, struct serial_struct __user *
struct serial_struct v;
int err;
- memset(&v, 0, sizeof(struct serial_struct));
+ memset(&v, 0, sizeof(v));
if (!tty->ops->get_serial)
return -ENOTTY;
err = tty->ops->get_serial(tty, &v);
- if (!err && copy_to_user(ss, &v, sizeof(struct serial_struct)))
+ if (!err && copy_to_user(ss, &v, sizeof(v)))
err = -EFAULT;
return err;
}
@@ -2673,25 +2673,25 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
#ifdef CONFIG_COMPAT
struct serial_struct32 {
- compat_int_t type;
- compat_int_t line;
- compat_uint_t port;
- compat_int_t irq;
- compat_int_t flags;
- compat_int_t xmit_fifo_size;
- compat_int_t custom_divisor;
- compat_int_t baud_base;
- unsigned short close_delay;
- char io_type;
- char reserved_char[1];
- compat_int_t hub6;
- unsigned short closing_wait; /* time to wait before closing */
- unsigned short closing_wait2; /* no longer used... */
- compat_uint_t iomem_base;
- unsigned short iomem_reg_shift;
- unsigned int port_high;
- /* compat_ulong_t iomap_base FIXME */
- compat_int_t reserved[1];
+ compat_int_t type;
+ compat_int_t line;
+ compat_uint_t port;
+ compat_int_t irq;
+ compat_int_t flags;
+ compat_int_t xmit_fifo_size;
+ compat_int_t custom_divisor;
+ compat_int_t baud_base;
+ unsigned short close_delay;
+ char io_type;
+ char reserved_char;
+ compat_int_t hub6;
+ unsigned short closing_wait; /* time to wait before closing */
+ unsigned short closing_wait2; /* no longer used... */
+ compat_uint_t iomem_base;
+ unsigned short iomem_reg_shift;
+ unsigned int port_high;
+ /* compat_ulong_t iomap_base FIXME */
+ compat_int_t reserved;
};
static int compat_tty_tiocsserial(struct tty_struct *tty,
@@ -2705,7 +2705,7 @@ static int compat_tty_tiocsserial(struct tty_struct *tty,
struct serial_struct v;
int flags;
- if (copy_from_user(&v32, ss, sizeof(struct serial_struct32)))
+ if (copy_from_user(&v32, ss, sizeof(*ss)))
return -EFAULT;
memcpy(&v, &v32, offsetof(struct serial_struct32, iomem_base));
@@ -2743,7 +2743,7 @@ static int compat_tty_tiocgserial(struct tty_struct *tty,
0xfffffff : ptr_to_compat(v.iomem_base);
v32.iomem_reg_shift = v.iomem_reg_shift;
v32.port_high = v.port_high;
- if (copy_to_user(ss, &v32, sizeof(struct serial_struct32)))
+ if (copy_to_user(ss, &v32, sizeof(v32)))
err = -EFAULT;
}
return err;
@@ -3215,7 +3215,7 @@ struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner,
if (!lines || (flags & TTY_DRIVER_UNNUMBERED_NODE && lines > 1))
return ERR_PTR(-EINVAL);
- driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);
+ driver = kzalloc(sizeof(*driver), GFP_KERNEL);
if (!driver)
return ERR_PTR(-ENOMEM);
diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c
index c1be96bb3ecf..5947b54d92be 100644
--- a/drivers/tty/vt/consolemap.c
+++ b/drivers/tty/vt/consolemap.c
@@ -542,7 +542,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
if (!ct)
return 0;
- unilist = vmemdup_user(list, ct * sizeof(struct unipair));
+ unilist = vmemdup_user(list, array_size(sizeof(struct unipair), ct));
if (IS_ERR(unilist))
return PTR_ERR(unilist);
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 568b2171f335..0db53b5b3acf 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -32,6 +32,7 @@
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/mm.h>
+#include <linux/nospec.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -1236,7 +1237,7 @@ static void kbd_bh(unsigned long dummy)
}
}
-DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0);
+DECLARE_TASKLET_DISABLED_OLD(keyboard_tasklet, kbd_bh);
#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\
defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\
@@ -2019,7 +2020,7 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
goto reterr;
}
kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0';
- i = kbs->kb_func;
+ i = array_index_nospec(kbs->kb_func, MAX_NR_FUNC);
switch (cmd) {
case KDGKBSENT:
diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c
index 31bb3647a99c..8e74654c1b27 100644
--- a/drivers/tty/vt/selection.c
+++ b/drivers/tty/vt/selection.c
@@ -193,7 +193,7 @@ static int vc_selection_store_chars(struct vc_data *vc, bool unicode)
/* 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);
+ GFP_KERNEL | __GFP_NOWARN);
if (!bp) {
printk(KERN_WARNING "selection: kmalloc() failed\n");
clear_selection();
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 48a8199f7845..ccb533fd00a2 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -127,14 +127,6 @@ struct con_driver {
static struct con_driver registered_con_driver[MAX_NR_CON_DRIVER];
const struct consw *conswitchp;
-/* A bitmap for codes <32. A bit of 1 indicates that the code
- * corresponding to that bit number invokes some special action
- * (such as cursor movement) and should not be displayed as a
- * glyph unless the disp_ctrl mode is explicitly enabled.
- */
-#define CTRL_ACTION 0x0d00ff81
-#define CTRL_ALWAYS 0x0800f501 /* Cannot be overridden by disp_ctrl */
-
/*
* Here is the default bell parameters: 750HZ, 1/8th of a second
*/
@@ -171,7 +163,7 @@ module_param(default_utf8, int, S_IRUGO | S_IWUSR);
int global_cursor_default = -1;
module_param(global_cursor_default, int, S_IRUGO | S_IWUSR);
-static int cur_default = CUR_DEFAULT;
+static int cur_default = CUR_UNDERLINE;
module_param(cur_default, int, S_IRUGO | S_IWUSR);
/*
@@ -381,7 +373,7 @@ static void vc_uniscr_putc(struct vc_data *vc, char32_t uc)
struct uni_screen *uniscr = get_vc_uniscr(vc);
if (uniscr)
- uniscr->lines[vc->vc_y][vc->vc_x] = uc;
+ uniscr->lines[vc->state.y][vc->state.x] = uc;
}
static void vc_uniscr_insert(struct vc_data *vc, unsigned int nr)
@@ -389,8 +381,8 @@ static void vc_uniscr_insert(struct vc_data *vc, unsigned int nr)
struct uni_screen *uniscr = get_vc_uniscr(vc);
if (uniscr) {
- char32_t *ln = uniscr->lines[vc->vc_y];
- unsigned int x = vc->vc_x, cols = vc->vc_cols;
+ char32_t *ln = uniscr->lines[vc->state.y];
+ unsigned int x = vc->state.x, cols = vc->vc_cols;
memmove(&ln[x + nr], &ln[x], (cols - x - nr) * sizeof(*ln));
memset32(&ln[x], ' ', nr);
@@ -402,8 +394,8 @@ static void vc_uniscr_delete(struct vc_data *vc, unsigned int nr)
struct uni_screen *uniscr = get_vc_uniscr(vc);
if (uniscr) {
- char32_t *ln = uniscr->lines[vc->vc_y];
- unsigned int x = vc->vc_x, cols = vc->vc_cols;
+ char32_t *ln = uniscr->lines[vc->state.y];
+ unsigned int x = vc->state.x, cols = vc->vc_cols;
memcpy(&ln[x], &ln[x + nr], (cols - x - nr) * sizeof(*ln));
memset32(&ln[cols - nr], ' ', nr);
@@ -416,7 +408,7 @@ static void vc_uniscr_clear_line(struct vc_data *vc, unsigned int x,
struct uni_screen *uniscr = get_vc_uniscr(vc);
if (uniscr) {
- char32_t *ln = uniscr->lines[vc->vc_y];
+ char32_t *ln = uniscr->lines[vc->state.y];
memset32(&ln[x], ' ', nr);
}
@@ -705,8 +697,9 @@ void update_region(struct vc_data *vc, unsigned long start, int count)
/* Structure of attributes is hardware-dependent */
-static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink,
- u8 _underline, u8 _reverse, u8 _italic)
+static u8 build_attr(struct vc_data *vc, u8 _color,
+ enum vc_intensity _intensity, bool _blink, bool _underline,
+ bool _reverse, bool _italic)
{
if (vc->vc_sw->con_build_attr)
return vc->vc_sw->con_build_attr(vc, _color, _intensity,
@@ -726,21 +719,21 @@ static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink,
u8 a = _color;
if (!vc->vc_can_do_color)
return _intensity |
- (_italic ? 2 : 0) |
- (_underline ? 4 : 0) |
- (_reverse ? 8 : 0) |
- (_blink ? 0x80 : 0);
+ (_italic << 1) |
+ (_underline << 2) |
+ (_reverse << 3) |
+ (_blink << 7);
if (_italic)
a = (a & 0xF0) | vc->vc_itcolor;
else if (_underline)
a = (a & 0xf0) | vc->vc_ulcolor;
- else if (_intensity == 0)
+ else if (_intensity == VCI_HALF_BRIGHT)
a = (a & 0xf0) | vc->vc_halfcolor;
if (_reverse)
- a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77);
+ a = (a & 0x88) | (((a >> 4) | (a << 4)) & 0x77);
if (_blink)
a ^= 0x80;
- if (_intensity == 2)
+ if (_intensity == VCI_BOLD)
a ^= 0x08;
if (vc->vc_hi_font_mask == 0x100)
a <<= 1;
@@ -750,10 +743,12 @@ static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink,
static void update_attr(struct vc_data *vc)
{
- vc->vc_attr = build_attr(vc, vc->vc_color, vc->vc_intensity,
- vc->vc_blink, vc->vc_underline,
- vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic);
- vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm, 0) << 8) | ' ';
+ vc->vc_attr = build_attr(vc, vc->state.color, vc->state.intensity,
+ vc->state.blink, vc->state.underline,
+ vc->state.reverse ^ vc->vc_decscnm, vc->state.italic);
+ vc->vc_video_erase_char = ' ' | (build_attr(vc, vc->state.color,
+ VCI_NORMAL, vc->state.blink, false,
+ vc->vc_decscnm, false) << 8);
}
/* Note: inverting the screen twice should revert to the original state */
@@ -782,14 +777,18 @@ void invert_screen(struct vc_data *vc, int offset, int count, int viewed)
} else if (vc->vc_hi_font_mask == 0x100) {
while (cnt--) {
a = scr_readw(q);
- a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4);
+ a = (a & 0x11ff) |
+ ((a & 0xe000) >> 4) |
+ ((a & 0x0e00) << 4);
scr_writew(a, q);
q++;
}
} else {
while (cnt--) {
a = scr_readw(q);
- a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
+ a = (a & 0x88ff) |
+ ((a & 0x7000) >> 4) |
+ ((a & 0x0700) << 4);
scr_writew(a, q);
q++;
}
@@ -842,12 +841,12 @@ static void insert_char(struct vc_data *vc, unsigned int nr)
unsigned short *p = (unsigned short *) vc->vc_pos;
vc_uniscr_insert(vc, nr);
- scr_memmovew(p + nr, p, (vc->vc_cols - vc->vc_x - nr) * 2);
+ scr_memmovew(p + nr, p, (vc->vc_cols - vc->state.x - nr) * 2);
scr_memsetw(p, vc->vc_video_erase_char, nr * 2);
vc->vc_need_wrap = 0;
if (con_should_update(vc))
do_update_region(vc, (unsigned long) p,
- vc->vc_cols - vc->vc_x);
+ vc->vc_cols - vc->state.x);
}
static void delete_char(struct vc_data *vc, unsigned int nr)
@@ -855,13 +854,13 @@ static void delete_char(struct vc_data *vc, unsigned int nr)
unsigned short *p = (unsigned short *) vc->vc_pos;
vc_uniscr_delete(vc, nr);
- scr_memcpyw(p, p + nr, (vc->vc_cols - vc->vc_x - nr) * 2);
- scr_memsetw(p + vc->vc_cols - vc->vc_x - nr, vc->vc_video_erase_char,
+ scr_memcpyw(p, p + nr, (vc->vc_cols - vc->state.x - nr) * 2);
+ scr_memsetw(p + vc->vc_cols - vc->state.x - nr, vc->vc_video_erase_char,
nr * 2);
vc->vc_need_wrap = 0;
if (con_should_update(vc))
do_update_region(vc, (unsigned long) p,
- vc->vc_cols - vc->vc_x);
+ vc->vc_cols - vc->state.x);
}
static int softcursor_original = -1;
@@ -871,16 +870,21 @@ static void add_softcursor(struct vc_data *vc)
int i = scr_readw((u16 *) vc->vc_pos);
u32 type = vc->vc_cursor_type;
- if (! (type & 0x10)) return;
- if (softcursor_original != -1) return;
+ if (!(type & CUR_SW))
+ return;
+ if (softcursor_original != -1)
+ return;
softcursor_original = i;
- i |= ((type >> 8) & 0xff00 );
- i ^= ((type) & 0xff00 );
- if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000;
- if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700;
- scr_writew(i, (u16 *) vc->vc_pos);
+ i |= CUR_SET(type);
+ i ^= CUR_CHANGE(type);
+ if ((type & CUR_ALWAYS_BG) &&
+ (softcursor_original & CUR_BG) == (i & CUR_BG))
+ i ^= CUR_BG;
+ if ((type & CUR_INVERT_FG_BG) && (i & CUR_FG) == ((i & CUR_BG) >> 4))
+ i ^= CUR_FG;
+ scr_writew(i, (u16 *)vc->vc_pos);
if (con_should_update(vc))
- vc->vc_sw->con_putc(vc, i, vc->vc_y, vc->vc_x);
+ vc->vc_sw->con_putc(vc, i, vc->state.y, vc->state.x);
}
static void hide_softcursor(struct vc_data *vc)
@@ -889,7 +893,7 @@ static void hide_softcursor(struct vc_data *vc)
scr_writew(softcursor_original, (u16 *)vc->vc_pos);
if (con_should_update(vc))
vc->vc_sw->con_putc(vc, softcursor_original,
- vc->vc_y, vc->vc_x);
+ vc->state.y, vc->state.x);
softcursor_original = -1;
}
}
@@ -911,7 +915,7 @@ static void set_cursor(struct vc_data *vc)
if (vc_is_sel(vc))
clear_selection();
add_softcursor(vc);
- if ((vc->vc_cursor_type & 0x0f) != 1)
+ if (CUR_SIZE(vc->vc_cursor_type) != CUR_NONE)
vc->vc_sw->con_cursor(vc, CM_DRAW);
} else
hide_cursor(vc);
@@ -927,7 +931,8 @@ static void set_origin(struct vc_data *vc)
vc->vc_origin = (unsigned long)vc->vc_screenbuf;
vc->vc_visible_origin = vc->vc_origin;
vc->vc_scr_end = vc->vc_origin + vc->vc_screenbuf_size;
- vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->vc_y + 2 * vc->vc_x;
+ vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->state.y +
+ 2 * vc->state.x;
}
static void save_screen(struct vc_data *vc)
@@ -1092,10 +1097,19 @@ static const struct tty_port_operations vc_port_ops = {
.destruct = vc_port_destruct,
};
+/*
+ * Change # of rows and columns (0 means unchanged/the size of fg_console)
+ * [this is to be used together with some user program
+ * like resize that changes the hardware videomode]
+ */
+#define VC_MAXCOL (32767)
+#define VC_MAXROW (32767)
+
int vc_allocate(unsigned int currcons) /* return 0 on success */
{
struct vt_notifier_param param;
struct vc_data *vc;
+ int err;
WARN_CONSOLE_UNLOCKED();
@@ -1125,6 +1139,11 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */
if (!*vc->vc_uni_pagedir_loc)
con_set_default_unimap(vc);
+ err = -EINVAL;
+ if (vc->vc_cols > VC_MAXCOL || vc->vc_rows > VC_MAXROW ||
+ vc->vc_screenbuf_size > KMALLOC_MAX_SIZE || !vc->vc_screenbuf_size)
+ goto err_free;
+ err = -ENOMEM;
vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_KERNEL);
if (!vc->vc_screenbuf)
goto err_free;
@@ -1143,7 +1162,7 @@ err_free:
visual_deinit(vc);
kfree(vc);
vc_cons[currcons].d = NULL;
- return -ENOMEM;
+ return err;
}
static inline int resize_screen(struct vc_data *vc, int width, int height,
@@ -1158,14 +1177,6 @@ static inline int resize_screen(struct vc_data *vc, int width, int height,
return err;
}
-/*
- * Change # of rows and columns (0 means unchanged/the size of fg_console)
- * [this is to be used together with some user program
- * like resize that changes the hardware videomode]
- */
-#define VC_RESIZE_MAXCOL (32767)
-#define VC_RESIZE_MAXROW (32767)
-
/**
* vc_do_resize - resizing method for the tty
* @tty: tty being resized
@@ -1201,7 +1212,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
user = vc->vc_resize_user;
vc->vc_resize_user = 0;
- if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW)
+ if (cols > VC_MAXCOL || lines > VC_MAXROW)
return -EINVAL;
new_cols = (cols ? cols : vc->vc_cols);
@@ -1212,7 +1223,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
if (new_cols == vc->vc_cols && new_rows == vc->vc_rows)
return 0;
- if (new_screen_size > KMALLOC_MAX_SIZE)
+ if (new_screen_size > KMALLOC_MAX_SIZE || !new_screen_size)
return -EINVAL;
newscreen = kzalloc(new_screen_size, GFP_USER);
if (!newscreen)
@@ -1250,8 +1261,8 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
new_origin = (long) newscreen;
new_scr_end = new_origin + new_screen_size;
- if (vc->vc_y > new_rows) {
- if (old_rows - vc->vc_y < new_rows) {
+ if (vc->state.y > new_rows) {
+ if (old_rows - vc->state.y < new_rows) {
/*
* Cursor near the bottom, copy contents from the
* bottom of buffer
@@ -1262,7 +1273,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
* Cursor is in no man's land, copy 1/2 screenful
* from the top and bottom of cursor position
*/
- first_copied_row = (vc->vc_y - new_rows/2);
+ first_copied_row = (vc->state.y - new_rows/2);
}
old_origin += first_copied_row * old_row_size;
} else
@@ -1296,7 +1307,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
/* do part of a reset_terminal() */
vc->vc_top = 0;
vc->vc_bottom = vc->vc_rows;
- gotoxy(vc, vc->vc_x, vc->vc_y);
+ gotoxy(vc, vc->state.x, vc->state.y);
save_cur(vc);
if (tty) {
@@ -1393,12 +1404,6 @@ enum { EPecma = 0, EPdec, EPeq, EPgt, EPlt};
#define kbdapplic VC_APPLIC
#define lnm VC_CRLF
-/*
- * this is what the terminal answers to a ESC-Z or csi0c query.
- */
-#define VT100ID "\033[?1;2c"
-#define VT102ID "\033[?6c"
-
const unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
8,12,10,14, 9,13,11,15 };
@@ -1431,12 +1436,12 @@ static void gotoxy(struct vc_data *vc, int new_x, int new_y)
int min_y, max_y;
if (new_x < 0)
- vc->vc_x = 0;
+ vc->state.x = 0;
else {
if (new_x >= vc->vc_cols)
- vc->vc_x = vc->vc_cols - 1;
+ vc->state.x = vc->vc_cols - 1;
else
- vc->vc_x = new_x;
+ vc->state.x = new_x;
}
if (vc->vc_decom) {
@@ -1447,12 +1452,13 @@ static void gotoxy(struct vc_data *vc, int new_x, int new_y)
max_y = vc->vc_rows;
}
if (new_y < min_y)
- vc->vc_y = min_y;
+ vc->state.y = min_y;
else if (new_y >= max_y)
- vc->vc_y = max_y - 1;
+ vc->state.y = max_y - 1;
else
- vc->vc_y = new_y;
- vc->vc_pos = vc->vc_origin + vc->vc_y * vc->vc_size_row + (vc->vc_x<<1);
+ vc->state.y = new_y;
+ vc->vc_pos = vc->vc_origin + vc->state.y * vc->vc_size_row +
+ (vc->state.x << 1);
vc->vc_need_wrap = 0;
}
@@ -1479,10 +1485,10 @@ static void lf(struct vc_data *vc)
/* don't scroll if above bottom of scrolling region, or
* if below scrolling region
*/
- if (vc->vc_y + 1 == vc->vc_bottom)
+ if (vc->state.y + 1 == vc->vc_bottom)
con_scroll(vc, vc->vc_top, vc->vc_bottom, SM_UP, 1);
- else if (vc->vc_y < vc->vc_rows - 1) {
- vc->vc_y++;
+ else if (vc->state.y < vc->vc_rows - 1) {
+ vc->state.y++;
vc->vc_pos += vc->vc_size_row;
}
vc->vc_need_wrap = 0;
@@ -1494,10 +1500,10 @@ static void ri(struct vc_data *vc)
/* don't scroll if below top of scrolling region, or
* if above scrolling region
*/
- if (vc->vc_y == vc->vc_top)
+ if (vc->state.y == vc->vc_top)
con_scroll(vc, vc->vc_top, vc->vc_bottom, SM_DOWN, 1);
- else if (vc->vc_y > 0) {
- vc->vc_y--;
+ else if (vc->state.y > 0) {
+ vc->state.y--;
vc->vc_pos -= vc->vc_size_row;
}
vc->vc_need_wrap = 0;
@@ -1505,16 +1511,16 @@ static void ri(struct vc_data *vc)
static inline void cr(struct vc_data *vc)
{
- vc->vc_pos -= vc->vc_x << 1;
- vc->vc_need_wrap = vc->vc_x = 0;
+ vc->vc_pos -= vc->state.x << 1;
+ vc->vc_need_wrap = vc->state.x = 0;
notify_write(vc, '\r');
}
static inline void bs(struct vc_data *vc)
{
- if (vc->vc_x) {
+ if (vc->state.x) {
vc->vc_pos -= 2;
- vc->vc_x--;
+ vc->state.x--;
vc->vc_need_wrap = 0;
notify_write(vc, '\b');
}
@@ -1532,16 +1538,16 @@ static void csi_J(struct vc_data *vc, int vpar)
switch (vpar) {
case 0: /* erase from cursor to end of display */
- vc_uniscr_clear_line(vc, vc->vc_x,
- vc->vc_cols - vc->vc_x);
- vc_uniscr_clear_lines(vc, vc->vc_y + 1,
- vc->vc_rows - vc->vc_y - 1);
+ vc_uniscr_clear_line(vc, vc->state.x,
+ vc->vc_cols - vc->state.x);
+ vc_uniscr_clear_lines(vc, vc->state.y + 1,
+ vc->vc_rows - vc->state.y - 1);
count = (vc->vc_scr_end - vc->vc_pos) >> 1;
start = (unsigned short *)vc->vc_pos;
break;
case 1: /* erase from start to cursor */
- vc_uniscr_clear_line(vc, 0, vc->vc_x + 1);
- vc_uniscr_clear_lines(vc, 0, vc->vc_y);
+ vc_uniscr_clear_line(vc, 0, vc->state.x + 1);
+ vc_uniscr_clear_lines(vc, 0, vc->state.y);
count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1;
start = (unsigned short *)vc->vc_origin;
break;
@@ -1571,49 +1577,51 @@ static void csi_K(struct vc_data *vc, int vpar)
switch (vpar) {
case 0: /* erase from cursor to end of line */
offset = 0;
- count = vc->vc_cols - vc->vc_x;
+ count = vc->vc_cols - vc->state.x;
break;
case 1: /* erase from start of line to cursor */
- offset = -vc->vc_x;
- count = vc->vc_x + 1;
+ offset = -vc->state.x;
+ count = vc->state.x + 1;
break;
case 2: /* erase whole line */
- offset = -vc->vc_x;
+ offset = -vc->state.x;
count = vc->vc_cols;
break;
default:
return;
}
- vc_uniscr_clear_line(vc, vc->vc_x + offset, count);
+ vc_uniscr_clear_line(vc, vc->state.x + offset, count);
scr_memsetw(start + offset, vc->vc_video_erase_char, 2 * count);
vc->vc_need_wrap = 0;
if (con_should_update(vc))
do_update_region(vc, (unsigned long)(start + offset), count);
}
-static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar positions */
+/* erase the following vpar positions */
+static void csi_X(struct vc_data *vc, unsigned int vpar)
{ /* not vt100? */
- int count;
+ unsigned int count;
if (!vpar)
vpar++;
- count = (vpar > vc->vc_cols - vc->vc_x) ? (vc->vc_cols - vc->vc_x) : vpar;
- vc_uniscr_clear_line(vc, vc->vc_x, count);
+ count = min(vpar, vc->vc_cols - vc->state.x);
+
+ vc_uniscr_clear_line(vc, vc->state.x, count);
scr_memsetw((unsigned short *)vc->vc_pos, vc->vc_video_erase_char, 2 * count);
if (con_should_update(vc))
- vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, count);
+ vc->vc_sw->con_clear(vc, vc->state.y, vc->state.x, 1, count);
vc->vc_need_wrap = 0;
}
static void default_attr(struct vc_data *vc)
{
- vc->vc_intensity = 1;
- vc->vc_italic = 0;
- vc->vc_underline = 0;
- vc->vc_reverse = 0;
- vc->vc_blink = 0;
- vc->vc_color = vc->vc_def_color;
+ vc->state.intensity = VCI_NORMAL;
+ vc->state.italic = false;
+ vc->state.underline = false;
+ vc->state.reverse = false;
+ vc->state.blink = false;
+ vc->state.color = vc->vc_def_color;
}
struct rgb { u8 r; u8 g; u8 b; };
@@ -1649,19 +1657,19 @@ static void rgb_foreground(struct vc_data *vc, const struct rgb *c)
if (hue == 7 && max <= 0x55) {
hue = 0;
- vc->vc_intensity = 2;
+ vc->state.intensity = VCI_BOLD;
} else if (max > 0xaa)
- vc->vc_intensity = 2;
+ vc->state.intensity = VCI_BOLD;
else
- vc->vc_intensity = 1;
+ vc->state.intensity = VCI_NORMAL;
- vc->vc_color = (vc->vc_color & 0xf0) | hue;
+ vc->state.color = (vc->state.color & 0xf0) | hue;
}
static void rgb_background(struct vc_data *vc, const struct rgb *c)
{
/* For backgrounds, err on the dark side. */
- vc->vc_color = (vc->vc_color & 0x0f)
+ vc->state.color = (vc->state.color & 0x0f)
| (c->r&0x80) >> 1 | (c->g&0x80) >> 2 | (c->b&0x80) >> 3;
}
@@ -1712,13 +1720,13 @@ static void csi_m(struct vc_data *vc)
default_attr(vc);
break;
case 1:
- vc->vc_intensity = 2;
+ vc->state.intensity = VCI_BOLD;
break;
case 2:
- vc->vc_intensity = 0;
+ vc->state.intensity = VCI_HALF_BRIGHT;
break;
case 3:
- vc->vc_italic = 1;
+ vc->state.italic = true;
break;
case 21:
/*
@@ -1726,21 +1734,19 @@ static void csi_m(struct vc_data *vc)
* convert it to a single underline.
*/
case 4:
- vc->vc_underline = 1;
+ vc->state.underline = true;
break;
case 5:
- vc->vc_blink = 1;
+ vc->state.blink = true;
break;
case 7:
- vc->vc_reverse = 1;
+ vc->state.reverse = true;
break;
case 10: /* ANSI X3.64-1979 (SCO-ish?)
* Select primary font, don't display control chars if
* defined, don't set bit 8 on output.
*/
- vc->vc_translate = set_translate(vc->vc_charset == 0
- ? vc->vc_G0_charset
- : vc->vc_G1_charset, vc);
+ vc->vc_translate = set_translate(vc->state.Gx_charset[vc->state.charset], vc);
vc->vc_disp_ctrl = 0;
vc->vc_toggle_meta = 0;
break;
@@ -1761,19 +1767,19 @@ static void csi_m(struct vc_data *vc)
vc->vc_toggle_meta = 1;
break;
case 22:
- vc->vc_intensity = 1;
+ vc->state.intensity = VCI_NORMAL;
break;
case 23:
- vc->vc_italic = 0;
+ vc->state.italic = false;
break;
case 24:
- vc->vc_underline = 0;
+ vc->state.underline = false;
break;
case 25:
- vc->vc_blink = 0;
+ vc->state.blink = false;
break;
case 27:
- vc->vc_reverse = 0;
+ vc->state.reverse = false;
break;
case 38:
i = vc_t416_color(vc, i, rgb_foreground);
@@ -1782,64 +1788,70 @@ static void csi_m(struct vc_data *vc)
i = vc_t416_color(vc, i, rgb_background);
break;
case 39:
- vc->vc_color = (vc->vc_def_color & 0x0f) |
- (vc->vc_color & 0xf0);
+ vc->state.color = (vc->vc_def_color & 0x0f) |
+ (vc->state.color & 0xf0);
break;
case 49:
- vc->vc_color = (vc->vc_def_color & 0xf0) |
- (vc->vc_color & 0x0f);
+ vc->state.color = (vc->vc_def_color & 0xf0) |
+ (vc->state.color & 0x0f);
break;
default:
if (vc->vc_par[i] >= 90 && vc->vc_par[i] <= 107) {
if (vc->vc_par[i] < 100)
- vc->vc_intensity = 2;
+ vc->state.intensity = VCI_BOLD;
vc->vc_par[i] -= 60;
}
if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37)
- vc->vc_color = color_table[vc->vc_par[i] - 30]
- | (vc->vc_color & 0xf0);
+ vc->state.color = color_table[vc->vc_par[i] - 30]
+ | (vc->state.color & 0xf0);
else if (vc->vc_par[i] >= 40 && vc->vc_par[i] <= 47)
- vc->vc_color = (color_table[vc->vc_par[i] - 40] << 4)
- | (vc->vc_color & 0x0f);
+ vc->state.color = (color_table[vc->vc_par[i] - 40] << 4)
+ | (vc->state.color & 0x0f);
break;
}
update_attr(vc);
}
-static void respond_string(const char *p, struct tty_port *port)
+static void respond_string(const char *p, size_t len, struct tty_port *port)
{
- while (*p) {
- tty_insert_flip_char(port, *p, 0);
- p++;
- }
+ tty_insert_flip_string(port, p, len);
tty_schedule_flip(port);
}
static void cursor_report(struct vc_data *vc, struct tty_struct *tty)
{
char buf[40];
+ int len;
- sprintf(buf, "\033[%d;%dR", vc->vc_y + (vc->vc_decom ? vc->vc_top + 1 : 1), vc->vc_x + 1);
- respond_string(buf, tty->port);
+ len = sprintf(buf, "\033[%d;%dR", vc->state.y +
+ (vc->vc_decom ? vc->vc_top + 1 : 1),
+ vc->state.x + 1);
+ respond_string(buf, len, tty->port);
}
static inline void status_report(struct tty_struct *tty)
{
- respond_string("\033[0n", tty->port); /* Terminal ok */
+ static const char teminal_ok[] = "\033[0n";
+
+ respond_string(teminal_ok, strlen(teminal_ok), tty->port);
}
static inline void respond_ID(struct tty_struct *tty)
{
- respond_string(VT102ID, tty->port);
+ /* terminal answer to an ESC-Z or csi0c query. */
+ static const char vt102_id[] = "\033[?6c";
+
+ respond_string(vt102_id, strlen(vt102_id), tty->port);
}
void mouse_report(struct tty_struct *tty, int butt, int mrx, int mry)
{
char buf[8];
+ int len;
- sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx),
- (char)('!' + mry));
- respond_string(buf, tty->port);
+ len = sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt),
+ (char)('!' + mrx), (char)('!' + mry));
+ respond_string(buf, len, tty->port);
}
/* invoked via ioctl(TIOCLINUX) and through set_selection_user */
@@ -1924,14 +1936,14 @@ static void setterm_command(struct vc_data *vc)
case 1: /* set color for underline mode */
if (vc->vc_can_do_color && vc->vc_par[1] < 16) {
vc->vc_ulcolor = color_table[vc->vc_par[1]];
- if (vc->vc_underline)
+ if (vc->state.underline)
update_attr(vc);
}
break;
case 2: /* set color for half intensity mode */
if (vc->vc_can_do_color && vc->vc_par[1] < 16) {
vc->vc_halfcolor = color_table[vc->vc_par[1]];
- if (vc->vc_intensity == 0)
+ if (vc->state.intensity == VCI_HALF_BRIGHT)
update_attr(vc);
}
break;
@@ -1985,8 +1997,8 @@ static void setterm_command(struct vc_data *vc)
/* console_lock is held */
static void csi_at(struct vc_data *vc, unsigned int nr)
{
- if (nr > vc->vc_cols - vc->vc_x)
- nr = vc->vc_cols - vc->vc_x;
+ if (nr > vc->vc_cols - vc->state.x)
+ nr = vc->vc_cols - vc->state.x;
else if (!nr)
nr = 1;
insert_char(vc, nr);
@@ -1995,19 +2007,19 @@ static void csi_at(struct vc_data *vc, unsigned int nr)
/* console_lock is held */
static void csi_L(struct vc_data *vc, unsigned int nr)
{
- if (nr > vc->vc_rows - vc->vc_y)
- nr = vc->vc_rows - vc->vc_y;
+ if (nr > vc->vc_rows - vc->state.y)
+ nr = vc->vc_rows - vc->state.y;
else if (!nr)
nr = 1;
- con_scroll(vc, vc->vc_y, vc->vc_bottom, SM_DOWN, nr);
+ con_scroll(vc, vc->state.y, vc->vc_bottom, SM_DOWN, nr);
vc->vc_need_wrap = 0;
}
/* console_lock is held */
static void csi_P(struct vc_data *vc, unsigned int nr)
{
- if (nr > vc->vc_cols - vc->vc_x)
- nr = vc->vc_cols - vc->vc_x;
+ if (nr > vc->vc_cols - vc->state.x)
+ nr = vc->vc_cols - vc->state.x;
else if (!nr)
nr = 1;
delete_char(vc, nr);
@@ -2016,44 +2028,28 @@ static void csi_P(struct vc_data *vc, unsigned int nr)
/* console_lock is held */
static void csi_M(struct vc_data *vc, unsigned int nr)
{
- if (nr > vc->vc_rows - vc->vc_y)
- nr = vc->vc_rows - vc->vc_y;
+ if (nr > vc->vc_rows - vc->state.y)
+ nr = vc->vc_rows - vc->state.y;
else if (!nr)
nr=1;
- con_scroll(vc, vc->vc_y, vc->vc_bottom, SM_UP, nr);
+ con_scroll(vc, vc->state.y, vc->vc_bottom, SM_UP, nr);
vc->vc_need_wrap = 0;
}
/* console_lock is held (except via vc_init->reset_terminal */
static void save_cur(struct vc_data *vc)
{
- vc->vc_saved_x = vc->vc_x;
- vc->vc_saved_y = vc->vc_y;
- vc->vc_s_intensity = vc->vc_intensity;
- vc->vc_s_italic = vc->vc_italic;
- vc->vc_s_underline = vc->vc_underline;
- vc->vc_s_blink = vc->vc_blink;
- vc->vc_s_reverse = vc->vc_reverse;
- vc->vc_s_charset = vc->vc_charset;
- vc->vc_s_color = vc->vc_color;
- vc->vc_saved_G0 = vc->vc_G0_charset;
- vc->vc_saved_G1 = vc->vc_G1_charset;
+ memcpy(&vc->saved_state, &vc->state, sizeof(vc->state));
}
/* console_lock is held */
static void restore_cur(struct vc_data *vc)
{
- gotoxy(vc, vc->vc_saved_x, vc->vc_saved_y);
- vc->vc_intensity = vc->vc_s_intensity;
- vc->vc_italic = vc->vc_s_italic;
- vc->vc_underline = vc->vc_s_underline;
- vc->vc_blink = vc->vc_s_blink;
- vc->vc_reverse = vc->vc_s_reverse;
- vc->vc_charset = vc->vc_s_charset;
- vc->vc_color = vc->vc_s_color;
- vc->vc_G0_charset = vc->vc_saved_G0;
- vc->vc_G1_charset = vc->vc_saved_G1;
- vc->vc_translate = set_translate(vc->vc_charset ? vc->vc_G1_charset : vc->vc_G0_charset, vc);
+ memcpy(&vc->state, &vc->saved_state, sizeof(vc->state));
+
+ gotoxy(vc, vc->state.x, vc->state.y);
+ vc->vc_translate = set_translate(vc->state.Gx_charset[vc->state.charset],
+ vc);
update_attr(vc);
vc->vc_need_wrap = 0;
}
@@ -2065,14 +2061,16 @@ enum { ESnormal, ESesc, ESsquare, ESgetpars, ESfunckey,
/* console_lock is held (except via vc_init()) */
static void reset_terminal(struct vc_data *vc, int do_clear)
{
+ unsigned int i;
+
vc->vc_top = 0;
vc->vc_bottom = vc->vc_rows;
vc->vc_state = ESnormal;
vc->vc_priv = EPecma;
vc->vc_translate = set_translate(LAT1_MAP, vc);
- vc->vc_G0_charset = LAT1_MAP;
- vc->vc_G1_charset = GRAF_MAP;
- vc->vc_charset = 0;
+ vc->state.Gx_charset[0] = LAT1_MAP;
+ vc->state.Gx_charset[1] = GRAF_MAP;
+ vc->state.charset = 0;
vc->vc_need_wrap = 0;
vc->vc_report_mouse = 0;
vc->vc_utf = default_utf8;
@@ -2095,14 +2093,9 @@ static void reset_terminal(struct vc_data *vc, int do_clear)
default_attr(vc);
update_attr(vc);
- vc->vc_tab_stop[0] =
- vc->vc_tab_stop[1] =
- vc->vc_tab_stop[2] =
- vc->vc_tab_stop[3] =
- vc->vc_tab_stop[4] =
- vc->vc_tab_stop[5] =
- vc->vc_tab_stop[6] =
- vc->vc_tab_stop[7] = 0x01010101;
+ bitmap_zero(vc->vc_tab_stop, VC_TABSTOPS_COUNT);
+ for (i = 0; i < VC_TABSTOPS_COUNT; i += 8)
+ set_bit(i, vc->vc_tab_stop);
vc->vc_bell_pitch = DEFAULT_BELL_PITCH;
vc->vc_bell_duration = DEFAULT_BELL_DURATION;
@@ -2114,6 +2107,29 @@ static void reset_terminal(struct vc_data *vc, int do_clear)
csi_J(vc, 2);
}
+static void vc_setGx(struct vc_data *vc, unsigned int which, int c)
+{
+ unsigned char *charset = &vc->state.Gx_charset[which];
+
+ switch (c) {
+ case '0':
+ *charset = GRAF_MAP;
+ break;
+ case 'B':
+ *charset = LAT1_MAP;
+ break;
+ case 'U':
+ *charset = IBMPC_MAP;
+ break;
+ case 'K':
+ *charset = USER_MAP;
+ break;
+ }
+
+ if (vc->state.charset == which)
+ vc->vc_translate = set_translate(*charset, vc);
+}
+
/* console_lock is held */
static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
{
@@ -2136,13 +2152,15 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
bs(vc);
return;
case 9:
- vc->vc_pos -= (vc->vc_x << 1);
- while (vc->vc_x < vc->vc_cols - 1) {
- vc->vc_x++;
- if (vc->vc_tab_stop[7 & (vc->vc_x >> 5)] & (1 << (vc->vc_x & 31)))
- break;
- }
- vc->vc_pos += (vc->vc_x << 1);
+ vc->vc_pos -= (vc->state.x << 1);
+
+ vc->state.x = find_next_bit(vc->vc_tab_stop,
+ min(vc->vc_cols - 1, VC_TABSTOPS_COUNT),
+ vc->state.x + 1);
+ if (vc->state.x >= VC_TABSTOPS_COUNT)
+ vc->state.x = vc->vc_cols - 1;
+
+ vc->vc_pos += (vc->state.x << 1);
notify_write(vc, '\t');
return;
case 10: case 11: case 12:
@@ -2154,13 +2172,13 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
cr(vc);
return;
case 14:
- vc->vc_charset = 1;
- vc->vc_translate = set_translate(vc->vc_G1_charset, vc);
+ vc->state.charset = 1;
+ vc->vc_translate = set_translate(vc->state.Gx_charset[1], vc);
vc->vc_disp_ctrl = 1;
return;
case 15:
- vc->vc_charset = 0;
- vc->vc_translate = set_translate(vc->vc_G0_charset, vc);
+ vc->state.charset = 0;
+ vc->vc_translate = set_translate(vc->state.Gx_charset[0], vc);
vc->vc_disp_ctrl = 0;
return;
case 24: case 26:
@@ -2200,7 +2218,8 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
lf(vc);
return;
case 'H':
- vc->vc_tab_stop[7 & (vc->vc_x >> 5)] |= (1 << (vc->vc_x & 31));
+ if (vc->state.x < VC_TABSTOPS_COUNT)
+ set_bit(vc->state.x, vc->vc_tab_stop);
return;
case 'Z':
respond_ID(tty);
@@ -2314,7 +2333,10 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
case 'c':
if (vc->vc_priv == EPdec) {
if (vc->vc_par[0])
- vc->vc_cursor_type = vc->vc_par[0] | (vc->vc_par[1] << 8) | (vc->vc_par[2] << 16);
+ vc->vc_cursor_type =
+ CUR_MAKE(vc->vc_par[0],
+ vc->vc_par[1],
+ vc->vc_par[2]);
else
vc->vc_cursor_type = cur_default;
return;
@@ -2347,42 +2369,42 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
case 'G': case '`':
if (vc->vc_par[0])
vc->vc_par[0]--;
- gotoxy(vc, vc->vc_par[0], vc->vc_y);
+ gotoxy(vc, vc->vc_par[0], vc->state.y);
return;
case 'A':
if (!vc->vc_par[0])
vc->vc_par[0]++;
- gotoxy(vc, vc->vc_x, vc->vc_y - vc->vc_par[0]);
+ gotoxy(vc, vc->state.x, vc->state.y - vc->vc_par[0]);
return;
case 'B': case 'e':
if (!vc->vc_par[0])
vc->vc_par[0]++;
- gotoxy(vc, vc->vc_x, vc->vc_y + vc->vc_par[0]);
+ gotoxy(vc, vc->state.x, vc->state.y + vc->vc_par[0]);
return;
case 'C': case 'a':
if (!vc->vc_par[0])
vc->vc_par[0]++;
- gotoxy(vc, vc->vc_x + vc->vc_par[0], vc->vc_y);
+ gotoxy(vc, vc->state.x + vc->vc_par[0], vc->state.y);
return;
case 'D':
if (!vc->vc_par[0])
vc->vc_par[0]++;
- gotoxy(vc, vc->vc_x - vc->vc_par[0], vc->vc_y);
+ gotoxy(vc, vc->state.x - vc->vc_par[0], vc->state.y);
return;
case 'E':
if (!vc->vc_par[0])
vc->vc_par[0]++;
- gotoxy(vc, 0, vc->vc_y + vc->vc_par[0]);
+ gotoxy(vc, 0, vc->state.y + vc->vc_par[0]);
return;
case 'F':
if (!vc->vc_par[0])
vc->vc_par[0]++;
- gotoxy(vc, 0, vc->vc_y - vc->vc_par[0]);
+ gotoxy(vc, 0, vc->state.y - vc->vc_par[0]);
return;
case 'd':
if (vc->vc_par[0])
vc->vc_par[0]--;
- gotoxay(vc, vc->vc_x ,vc->vc_par[0]);
+ gotoxay(vc, vc->state.x ,vc->vc_par[0]);
return;
case 'H': case 'f':
if (vc->vc_par[0])
@@ -2411,18 +2433,10 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
respond_ID(tty);
return;
case 'g':
- if (!vc->vc_par[0])
- vc->vc_tab_stop[7 & (vc->vc_x >> 5)] &= ~(1 << (vc->vc_x & 31));
- else if (vc->vc_par[0] == 3) {
- vc->vc_tab_stop[0] =
- vc->vc_tab_stop[1] =
- vc->vc_tab_stop[2] =
- vc->vc_tab_stop[3] =
- vc->vc_tab_stop[4] =
- vc->vc_tab_stop[5] =
- vc->vc_tab_stop[6] =
- vc->vc_tab_stop[7] = 0;
- }
+ if (!vc->vc_par[0] && vc->state.x < VC_TABSTOPS_COUNT)
+ set_bit(vc->state.x, vc->vc_tab_stop);
+ else if (vc->vc_par[0] == 3)
+ bitmap_zero(vc->vc_tab_stop, VC_TABSTOPS_COUNT);
return;
case 'm':
csi_m(vc);
@@ -2496,29 +2510,11 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
}
return;
case ESsetG0:
- if (c == '0')
- vc->vc_G0_charset = GRAF_MAP;
- else if (c == 'B')
- vc->vc_G0_charset = LAT1_MAP;
- else if (c == 'U')
- vc->vc_G0_charset = IBMPC_MAP;
- else if (c == 'K')
- vc->vc_G0_charset = USER_MAP;
- if (vc->vc_charset == 0)
- vc->vc_translate = set_translate(vc->vc_G0_charset, vc);
+ vc_setGx(vc, 0, c);
vc->vc_state = ESnormal;
return;
case ESsetG1:
- if (c == '0')
- vc->vc_G1_charset = GRAF_MAP;
- else if (c == 'B')
- vc->vc_G1_charset = LAT1_MAP;
- else if (c == 'U')
- vc->vc_G1_charset = IBMPC_MAP;
- else if (c == 'K')
- vc->vc_G1_charset = USER_MAP;
- if (vc->vc_charset == 1)
- vc->vc_translate = set_translate(vc->vc_G1_charset, vc);
+ vc_setGx(vc, 1, c);
vc->vc_state = ESnormal;
return;
case ESosc:
@@ -2530,7 +2526,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
/* is_double_width() is based on the wcwidth() implementation by
* Markus Kuhn -- 2007-05-26 (Unicode 5.0)
- * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
+ * Latest version: https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
*/
struct interval {
uint32_t first;
@@ -2565,30 +2561,300 @@ static int is_double_width(uint32_t ucs)
sizeof(struct interval), ucs_cmp) != NULL;
}
-static void con_flush(struct vc_data *vc, unsigned long draw_from,
- unsigned long draw_to, int *draw_x)
+struct vc_draw_region {
+ unsigned long from, to;
+ int x;
+};
+
+static void con_flush(struct vc_data *vc, struct vc_draw_region *draw)
{
- if (*draw_x < 0)
+ if (draw->x < 0)
return;
- vc->vc_sw->con_putcs(vc, (u16 *)draw_from,
- (u16 *)draw_to - (u16 *)draw_from, vc->vc_y, *draw_x);
- *draw_x = -1;
+ vc->vc_sw->con_putcs(vc, (u16 *)draw->from,
+ (u16 *)draw->to - (u16 *)draw->from, vc->state.y,
+ draw->x);
+ draw->x = -1;
+}
+
+static inline int vc_translate_ascii(const struct vc_data *vc, int c)
+{
+ if (IS_ENABLED(CONFIG_CONSOLE_TRANSLATIONS)) {
+ if (vc->vc_toggle_meta)
+ c |= 0x80;
+
+ return vc->vc_translate[c];
+ }
+
+ return c;
+}
+
+
+/**
+ * vc_sanitize_unicode -- Replace invalid Unicode code points with U+FFFD
+ * @c: the received character, or U+FFFD for invalid sequences.
+ */
+static inline int vc_sanitize_unicode(const int c)
+{
+ if ((c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff)
+ return 0xfffd;
+
+ return c;
+}
+
+/**
+ * vc_translate_unicode -- Combine UTF-8 into Unicode in @vc_utf_char
+ *
+ * @vc_utf_char is the being-constructed unicode character.
+ * @vc_utf_count is the number of continuation bytes still expected to arrive.
+ * @vc_npar is the number of continuation bytes arrived so far.
+ */
+static int vc_translate_unicode(struct vc_data *vc, int c, bool *rescan)
+{
+ static const u32 utf8_length_changes[] = {
+ 0x0000007f, 0x000007ff, 0x0000ffff,
+ 0x001fffff, 0x03ffffff, 0x7fffffff
+ };
+
+ /* Continuation byte received */
+ if ((c & 0xc0) == 0x80) {
+ /* Unexpected continuation byte? */
+ if (!vc->vc_utf_count)
+ return 0xfffd;
+
+ vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
+ vc->vc_npar++;
+ if (--vc->vc_utf_count)
+ goto need_more_bytes;
+
+ /* Got a whole character */
+ c = vc->vc_utf_char;
+ /* Reject overlong sequences */
+ if (c <= utf8_length_changes[vc->vc_npar - 1] ||
+ c > utf8_length_changes[vc->vc_npar])
+ return 0xfffd;
+
+ return vc_sanitize_unicode(c);
+ }
+
+ /* Single ASCII byte or first byte of a sequence received */
+ if (vc->vc_utf_count) {
+ /* Continuation byte expected */
+ *rescan = true;
+ vc->vc_utf_count = 0;
+ return 0xfffd;
+ }
+
+ /* Nothing to do if an ASCII byte was received */
+ if (c <= 0x7f)
+ return c;
+
+ /* First byte of a multibyte sequence received */
+ vc->vc_npar = 0;
+ if ((c & 0xe0) == 0xc0) {
+ vc->vc_utf_count = 1;
+ vc->vc_utf_char = (c & 0x1f);
+ } else if ((c & 0xf0) == 0xe0) {
+ vc->vc_utf_count = 2;
+ vc->vc_utf_char = (c & 0x0f);
+ } else if ((c & 0xf8) == 0xf0) {
+ vc->vc_utf_count = 3;
+ vc->vc_utf_char = (c & 0x07);
+ } else if ((c & 0xfc) == 0xf8) {
+ vc->vc_utf_count = 4;
+ vc->vc_utf_char = (c & 0x03);
+ } else if ((c & 0xfe) == 0xfc) {
+ vc->vc_utf_count = 5;
+ vc->vc_utf_char = (c & 0x01);
+ } else {
+ /* 254 and 255 are invalid */
+ return 0xfffd;
+ }
+
+need_more_bytes:
+ return -1;
+}
+
+static int vc_translate(struct vc_data *vc, int *c, bool *rescan)
+{
+ /* Do no translation at all in control states */
+ if (vc->vc_state != ESnormal)
+ return *c;
+
+ if (vc->vc_utf && !vc->vc_disp_ctrl)
+ return *c = vc_translate_unicode(vc, *c, rescan);
+
+ /* no utf or alternate charset mode */
+ return vc_translate_ascii(vc, *c);
+}
+
+static inline unsigned char vc_invert_attr(const struct vc_data *vc)
+{
+ if (!vc->vc_can_do_color)
+ return vc->vc_attr ^ 0x08;
+
+ if (vc->vc_hi_font_mask == 0x100)
+ return (vc->vc_attr & 0x11) |
+ ((vc->vc_attr & 0xe0) >> 4) |
+ ((vc->vc_attr & 0x0e) << 4);
+
+ return (vc->vc_attr & 0x88) |
+ ((vc->vc_attr & 0x70) >> 4) |
+ ((vc->vc_attr & 0x07) << 4);
+}
+
+static bool vc_is_control(struct vc_data *vc, int tc, int c)
+{
+ /*
+ * A bitmap for codes <32. A bit of 1 indicates that the code
+ * corresponding to that bit number invokes some special action (such
+ * as cursor movement) and should not be displayed as a glyph unless
+ * the disp_ctrl mode is explicitly enabled.
+ */
+ static const u32 CTRL_ACTION = 0x0d00ff81;
+ /* Cannot be overridden by disp_ctrl */
+ static const u32 CTRL_ALWAYS = 0x0800f501;
+
+ if (vc->vc_state != ESnormal)
+ return true;
+
+ if (!tc)
+ return true;
+
+ /*
+ * If the original code was a control character we only allow a glyph
+ * to be displayed if the code is not normally used (such as for cursor
+ * movement) or if the disp_ctrl mode has been explicitly enabled.
+ * Certain characters (as given by the CTRL_ALWAYS bitmap) are always
+ * displayed as control characters, as the console would be pretty
+ * useless without them; to display an arbitrary font position use the
+ * direct-to-font zone in UTF-8 mode.
+ */
+ if (c < 32) {
+ if (vc->vc_disp_ctrl)
+ return CTRL_ALWAYS & BIT(c);
+ else
+ return vc->vc_utf || (CTRL_ACTION & BIT(c));
+ }
+
+ if (c == 127 && !vc->vc_disp_ctrl)
+ return true;
+
+ if (c == 128 + 27)
+ return true;
+
+ return false;
+}
+
+static int vc_con_write_normal(struct vc_data *vc, int tc, int c,
+ struct vc_draw_region *draw)
+{
+ int next_c;
+ unsigned char vc_attr = vc->vc_attr;
+ u16 himask = vc->vc_hi_font_mask, charmask = himask ? 0x1ff : 0xff;
+ u8 width = 1;
+ bool inverse = false;
+
+ if (vc->vc_utf && !vc->vc_disp_ctrl) {
+ if (is_double_width(c))
+ width = 2;
+ }
+
+ /* Now try to find out how to display it */
+ tc = conv_uni_to_pc(vc, tc);
+ if (tc & ~charmask) {
+ if (tc == -1 || tc == -2)
+ return -1; /* nothing to display */
+
+ /* Glyph not found */
+ if ((!vc->vc_utf || vc->vc_disp_ctrl || c < 128) &&
+ !(c & ~charmask)) {
+ /*
+ * In legacy mode use the glyph we get by a 1:1
+ * mapping.
+ * This would make absolutely no sense with Unicode in
+ * mind, but do this for ASCII characters since a font
+ * may lack Unicode mapping info and we don't want to
+ * end up with having question marks only.
+ */
+ tc = c;
+ } else {
+ /*
+ * Display U+FFFD. If it's not found, display an inverse
+ * question mark.
+ */
+ tc = conv_uni_to_pc(vc, 0xfffd);
+ if (tc < 0) {
+ inverse = true;
+ tc = conv_uni_to_pc(vc, '?');
+ if (tc < 0)
+ tc = '?';
+
+ vc_attr = vc_invert_attr(vc);
+ con_flush(vc, draw);
+ }
+ }
+ }
+
+ next_c = c;
+ while (1) {
+ if (vc->vc_need_wrap || vc->vc_decim)
+ con_flush(vc, draw);
+ if (vc->vc_need_wrap) {
+ cr(vc);
+ lf(vc);
+ }
+ if (vc->vc_decim)
+ insert_char(vc, 1);
+ vc_uniscr_putc(vc, next_c);
+
+ if (himask)
+ tc = ((tc & 0x100) ? himask : 0) |
+ (tc & 0xff);
+ tc |= (vc_attr << 8) & ~himask;
+
+ scr_writew(tc, (u16 *)vc->vc_pos);
+
+ if (con_should_update(vc) && draw->x < 0) {
+ draw->x = vc->state.x;
+ draw->from = vc->vc_pos;
+ }
+ if (vc->state.x == vc->vc_cols - 1) {
+ vc->vc_need_wrap = vc->vc_decawm;
+ draw->to = vc->vc_pos + 2;
+ } else {
+ vc->state.x++;
+ draw->to = (vc->vc_pos += 2);
+ }
+
+ if (!--width)
+ break;
+
+ /* A space is printed in the second column */
+ tc = conv_uni_to_pc(vc, ' ');
+ if (tc < 0)
+ tc = ' ';
+ next_c = ' ';
+ }
+ notify_write(vc, c);
+
+ if (inverse)
+ con_flush(vc, draw);
+
+ return 0;
}
/* acquires console_lock */
static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count)
{
- int c, next_c, tc, ok, n = 0, draw_x = -1;
+ struct vc_draw_region draw = {
+ .x = -1,
+ };
+ int c, tc, n = 0;
unsigned int currcons;
- unsigned long draw_from = 0, draw_to = 0;
struct vc_data *vc;
- unsigned char vc_attr;
struct vt_notifier_param param;
- uint8_t rescan;
- uint8_t inverse;
- uint8_t width;
- u16 himask, charmask;
+ bool rescan;
if (in_interrupt())
return count;
@@ -2609,8 +2875,6 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
return 0;
}
- himask = vc->vc_hi_font_mask;
- charmask = himask ? 0x1ff : 0xff;
/* undraw cursor first */
if (con_is_fg(vc))
@@ -2620,209 +2884,35 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
while (!tty->stopped && count) {
int orig = *buf;
- c = orig;
buf++;
n++;
count--;
- rescan = 0;
- inverse = 0;
- width = 1;
-
- /* Do no translation at all in control states */
- if (vc->vc_state != ESnormal) {
- tc = c;
- } else if (vc->vc_utf && !vc->vc_disp_ctrl) {
- /* Combine UTF-8 into Unicode in vc_utf_char.
- * vc_utf_count is the number of continuation bytes still
- * expected to arrive.
- * vc_npar is the number of continuation bytes arrived so
- * far
- */
rescan_last_byte:
- if ((c & 0xc0) == 0x80) {
- /* Continuation byte received */
- static const uint32_t utf8_length_changes[] = { 0x0000007f, 0x000007ff, 0x0000ffff, 0x001fffff, 0x03ffffff, 0x7fffffff };
- if (vc->vc_utf_count) {
- vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
- vc->vc_npar++;
- if (--vc->vc_utf_count) {
- /* Still need some bytes */
- continue;
- }
- /* Got a whole character */
- c = vc->vc_utf_char;
- /* Reject overlong sequences */
- if (c <= utf8_length_changes[vc->vc_npar - 1] ||
- c > utf8_length_changes[vc->vc_npar])
- c = 0xfffd;
- } else {
- /* Unexpected continuation byte */
- vc->vc_utf_count = 0;
- c = 0xfffd;
- }
- } else {
- /* Single ASCII byte or first byte of a sequence received */
- if (vc->vc_utf_count) {
- /* Continuation byte expected */
- rescan = 1;
- vc->vc_utf_count = 0;
- c = 0xfffd;
- } else if (c > 0x7f) {
- /* First byte of a multibyte sequence received */
- vc->vc_npar = 0;
- if ((c & 0xe0) == 0xc0) {
- vc->vc_utf_count = 1;
- vc->vc_utf_char = (c & 0x1f);
- } else if ((c & 0xf0) == 0xe0) {
- vc->vc_utf_count = 2;
- vc->vc_utf_char = (c & 0x0f);
- } else if ((c & 0xf8) == 0xf0) {
- vc->vc_utf_count = 3;
- vc->vc_utf_char = (c & 0x07);
- } else if ((c & 0xfc) == 0xf8) {
- vc->vc_utf_count = 4;
- vc->vc_utf_char = (c & 0x03);
- } else if ((c & 0xfe) == 0xfc) {
- vc->vc_utf_count = 5;
- vc->vc_utf_char = (c & 0x01);
- } else {
- /* 254 and 255 are invalid */
- c = 0xfffd;
- }
- if (vc->vc_utf_count) {
- /* Still need some bytes */
- continue;
- }
- }
- /* Nothing to do if an ASCII byte was received */
- }
- /* End of UTF-8 decoding. */
- /* c is the received character, or U+FFFD for invalid sequences. */
- /* Replace invalid Unicode code points with U+FFFD too */
- if ((c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff)
- c = 0xfffd;
- tc = c;
- } else { /* no utf or alternate charset mode */
- tc = vc_translate(vc, c);
- }
+ c = orig;
+ rescan = false;
+
+ tc = vc_translate(vc, &c, &rescan);
+ if (tc == -1)
+ continue;
param.c = tc;
if (atomic_notifier_call_chain(&vt_notifier_list, VT_PREWRITE,
&param) == NOTIFY_STOP)
continue;
- /* If the original code was a control character we
- * only allow a glyph to be displayed if the code is
- * not normally used (such as for cursor movement) or
- * if the disp_ctrl mode has been explicitly enabled.
- * Certain characters (as given by the CTRL_ALWAYS
- * bitmap) are always displayed as control characters,
- * as the console would be pretty useless without
- * them; to display an arbitrary font position use the
- * direct-to-font zone in UTF-8 mode.
- */
- ok = tc && (c >= 32 ||
- !(vc->vc_disp_ctrl ? (CTRL_ALWAYS >> c) & 1 :
- vc->vc_utf || ((CTRL_ACTION >> c) & 1)))
- && (c != 127 || vc->vc_disp_ctrl)
- && (c != 128+27);
-
- if (vc->vc_state == ESnormal && ok) {
- if (vc->vc_utf && !vc->vc_disp_ctrl) {
- if (is_double_width(c))
- width = 2;
- }
- /* Now try to find out how to display it */
- tc = conv_uni_to_pc(vc, tc);
- if (tc & ~charmask) {
- if (tc == -1 || tc == -2) {
- continue; /* nothing to display */
- }
- /* Glyph not found */
- if ((!(vc->vc_utf && !vc->vc_disp_ctrl) || c < 128) && !(c & ~charmask)) {
- /* In legacy mode use the glyph we get by a 1:1 mapping.
- This would make absolutely no sense with Unicode in mind,
- but do this for ASCII characters since a font may lack
- Unicode mapping info and we don't want to end up with
- having question marks only. */
- tc = c;
- } else {
- /* Display U+FFFD. If it's not found, display an inverse question mark. */
- tc = conv_uni_to_pc(vc, 0xfffd);
- if (tc < 0) {
- inverse = 1;
- tc = conv_uni_to_pc(vc, '?');
- if (tc < 0) tc = '?';
- }
- }
- }
-
- if (!inverse) {
- vc_attr = vc->vc_attr;
- } else {
- /* invert vc_attr */
- if (!vc->vc_can_do_color) {
- vc_attr = (vc->vc_attr) ^ 0x08;
- } else if (vc->vc_hi_font_mask == 0x100) {
- vc_attr = ((vc->vc_attr) & 0x11) | (((vc->vc_attr) & 0xe0) >> 4) | (((vc->vc_attr) & 0x0e) << 4);
- } else {
- vc_attr = ((vc->vc_attr) & 0x88) | (((vc->vc_attr) & 0x70) >> 4) | (((vc->vc_attr) & 0x07) << 4);
- }
- con_flush(vc, draw_from, draw_to, &draw_x);
- }
-
- next_c = c;
- while (1) {
- if (vc->vc_need_wrap || vc->vc_decim)
- con_flush(vc, draw_from, draw_to,
- &draw_x);
- if (vc->vc_need_wrap) {
- cr(vc);
- lf(vc);
- }
- if (vc->vc_decim)
- insert_char(vc, 1);
- vc_uniscr_putc(vc, next_c);
- scr_writew(himask ?
- ((vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
- (vc_attr << 8) + tc,
- (u16 *) vc->vc_pos);
- if (con_should_update(vc) && draw_x < 0) {
- draw_x = vc->vc_x;
- draw_from = vc->vc_pos;
- }
- if (vc->vc_x == vc->vc_cols - 1) {
- vc->vc_need_wrap = vc->vc_decawm;
- draw_to = vc->vc_pos + 2;
- } else {
- vc->vc_x++;
- draw_to = (vc->vc_pos += 2);
- }
-
- if (!--width) break;
-
- tc = conv_uni_to_pc(vc, ' '); /* A space is printed in the second column */
- if (tc < 0) tc = ' ';
- next_c = ' ';
- }
- notify_write(vc, c);
-
- if (inverse)
- con_flush(vc, draw_from, draw_to, &draw_x);
-
- if (rescan) {
- rescan = 0;
- inverse = 0;
- width = 1;
- c = orig;
- goto rescan_last_byte;
- }
+ if (vc_is_control(vc, tc, c)) {
+ con_flush(vc, &draw);
+ do_con_trol(tty, vc, orig);
continue;
}
- con_flush(vc, draw_from, draw_to, &draw_x);
- do_con_trol(tty, vc, orig);
+
+ if (vc_con_write_normal(vc, tc, c, &draw) < 0)
+ continue;
+
+ if (rescan)
+ goto rescan_last_byte;
}
- con_flush(vc, draw_from, draw_to, &draw_x);
+ con_flush(vc, &draw);
vc_uniscr_debug_check(vc);
console_conditional_schedule();
notify_update(vc);
@@ -2972,25 +3062,25 @@ static void vt_console_print(struct console *co, const char *b, unsigned count)
hide_cursor(vc);
start = (ushort *)vc->vc_pos;
- start_x = vc->vc_x;
+ start_x = vc->state.x;
cnt = 0;
while (count--) {
c = *b++;
if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) {
if (cnt && con_is_visible(vc))
- vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, start_x);
+ vc->vc_sw->con_putcs(vc, start, cnt, vc->state.y, start_x);
cnt = 0;
if (c == 8) { /* backspace */
bs(vc);
start = (ushort *)vc->vc_pos;
- start_x = vc->vc_x;
+ start_x = vc->state.x;
continue;
}
if (c != 13)
lf(vc);
cr(vc);
start = (ushort *)vc->vc_pos;
- start_x = vc->vc_x;
+ start_x = vc->state.x;
if (c == 10 || c == 13)
continue;
}
@@ -2998,15 +3088,15 @@ static void vt_console_print(struct console *co, const char *b, unsigned count)
scr_writew((vc->vc_attr << 8) + c, (unsigned short *)vc->vc_pos);
notify_write(vc, c);
cnt++;
- if (vc->vc_x == vc->vc_cols - 1) {
+ if (vc->state.x == vc->vc_cols - 1) {
vc->vc_need_wrap = 1;
} else {
vc->vc_pos += 2;
- vc->vc_x++;
+ vc->state.x++;
}
}
if (cnt && con_is_visible(vc))
- vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, start_x);
+ vc->vc_sw->con_putcs(vc, start, cnt, vc->state.y, start_x);
set_cursor(vc);
notify_update(vc);
@@ -3393,6 +3483,7 @@ static int __init con_init(void)
INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
tty_port_init(&vc->port);
visual_init(vc, currcons, 1);
+ /* Assuming vc->vc_{cols,rows,screenbuf_size} are sane here. */
vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT);
vc_init(vc, vc->vc_rows, vc->vc_cols,
currcons || !vc->vc_sw->con_save_screen);
@@ -3401,7 +3492,7 @@ static int __init con_init(void)
master_display_fg = vc = vc_cons[currcons].d;
set_origin(vc);
save_screen(vc);
- gotoxy(vc, vc->vc_x, vc->vc_y);
+ gotoxy(vc, vc->state.x, vc->state.y);
csi_J(vc, 0);
update_screen(vc);
pr_info("Console: %s %s %dx%d\n",
@@ -4680,8 +4771,8 @@ EXPORT_SYMBOL_GPL(screen_pos);
void getconsxy(struct vc_data *vc, unsigned char *p)
{
/* clamp values if they don't fit */
- p[0] = min(vc->vc_x, 0xFFu);
- p[1] = min(vc->vc_y, 0xFFu);
+ p[0] = min(vc->state.x, 0xFFu);
+ p[1] = min(vc->state.y, 0xFFu);
}
void putconsxy(struct vc_data *vc, unsigned char *p)
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index daf61c28ba76..91c301775047 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -241,136 +241,56 @@ int vt_waitactive(int n)
#define GPLAST 0x3df
#define GPNUM (GPLAST - GPFIRST + 1)
-
-
-static inline int
-do_fontx_ioctl(int cmd, struct consolefontdesc __user *user_cfd, int perm, struct console_font_op *op)
-{
- struct consolefontdesc cfdarg;
- int i;
-
- if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc)))
- return -EFAULT;
-
- switch (cmd) {
- case PIO_FONTX:
- if (!perm)
- return -EPERM;
- op->op = KD_FONT_OP_SET;
- op->flags = KD_FONT_FLAG_OLD;
- op->width = 8;
- op->height = cfdarg.charheight;
- op->charcount = cfdarg.charcount;
- op->data = cfdarg.chardata;
- return con_font_op(vc_cons[fg_console].d, op);
- case GIO_FONTX: {
- op->op = KD_FONT_OP_GET;
- op->flags = KD_FONT_FLAG_OLD;
- op->width = 8;
- op->height = cfdarg.charheight;
- op->charcount = cfdarg.charcount;
- op->data = cfdarg.chardata;
- i = con_font_op(vc_cons[fg_console].d, op);
- if (i)
- return i;
- cfdarg.charheight = op->height;
- cfdarg.charcount = op->charcount;
- if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc)))
- return -EFAULT;
- return 0;
- }
- }
- return -EINVAL;
-}
-
-static inline int
-do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_data *vc)
+/*
+ * currently, setting the mode from KD_TEXT to KD_GRAPHICS doesn't do a whole
+ * lot. i'm not sure if it should do any restoration of modes or what...
+ *
+ * XXX It should at least call into the driver, fbdev's definitely need to
+ * restore their engine state. --BenH
+ */
+static int vt_kdsetmode(struct vc_data *vc, unsigned long mode)
{
- struct unimapdesc tmp;
-
- if (copy_from_user(&tmp, user_ud, sizeof tmp))
- return -EFAULT;
- switch (cmd) {
- case PIO_UNIMAP:
- if (!perm)
- return -EPERM;
- return con_set_unimap(vc, tmp.entry_ct, tmp.entries);
- case GIO_UNIMAP:
- if (!perm && fg_console != vc->vc_num)
- return -EPERM;
- return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp.entries);
+ switch (mode) {
+ case KD_GRAPHICS:
+ break;
+ case KD_TEXT0:
+ case KD_TEXT1:
+ mode = KD_TEXT;
+ fallthrough;
+ case KD_TEXT:
+ break;
+ default:
+ return -EINVAL;
}
- return 0;
-}
-
-/* deallocate a single console, if possible (leave 0) */
-static int vt_disallocate(unsigned int vc_num)
-{
- struct vc_data *vc = NULL;
- int ret = 0;
-
- console_lock();
- if (vt_busy(vc_num))
- ret = -EBUSY;
- else if (vc_num)
- vc = vc_deallocate(vc_num);
- console_unlock();
- if (vc && vc_num >= MIN_NR_CONSOLES)
- tty_port_put(&vc->port);
-
- return ret;
-}
+ /* FIXME: this needs the console lock extending */
+ if (vc->vc_mode == mode)
+ return 0;
-/* deallocate all unused consoles, but leave 0 */
-static void vt_disallocate_all(void)
-{
- struct vc_data *vc[MAX_NR_CONSOLES];
- int i;
+ vc->vc_mode = mode;
+ if (vc->vc_num != fg_console)
+ return 0;
+ /* explicitly blank/unblank the screen if switching modes */
console_lock();
- for (i = 1; i < MAX_NR_CONSOLES; i++)
- if (!vt_busy(i))
- vc[i] = vc_deallocate(i);
- else
- vc[i] = NULL;
+ if (mode == KD_TEXT)
+ do_unblank_screen(1);
+ else
+ do_blank_screen(1);
console_unlock();
- for (i = 1; i < MAX_NR_CONSOLES; i++) {
- if (vc[i] && i >= MIN_NR_CONSOLES)
- tty_port_put(&vc[i]->port);
- }
+ return 0;
}
-
-/*
- * We handle the console-specific ioctl's here. We allow the
- * capability to modify any console, not just the fg_console.
- */
-int vt_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
+static int vt_k_ioctl(struct tty_struct *tty, unsigned int cmd,
+ unsigned long arg, bool perm)
{
struct vc_data *vc = tty->driver_data;
- struct console_font_op op; /* used in multiple places here */
- unsigned int console = vc->vc_num;
- unsigned char ucval;
- unsigned int uival;
void __user *up = (void __user *)arg;
- int i, perm;
- int ret = 0;
+ unsigned int console = vc->vc_num;
+ int ret;
- /*
- * To have permissions to do most of the vt ioctls, we either have
- * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
- */
- perm = 0;
- if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
- perm = 1;
-
switch (cmd) {
- case TIOCLINUX:
- ret = tioclinux(tty, arg);
- break;
case KIOCSOUND:
if (!perm)
return -EPERM;
@@ -390,7 +310,7 @@ int vt_ioctl(struct tty_struct *tty,
return -EPERM;
{
unsigned int ticks, count;
-
+
/*
* Generate the tone for the appropriate number of ticks.
* If the time is zero, turn off sound ourselves.
@@ -407,9 +327,7 @@ int vt_ioctl(struct tty_struct *tty,
/*
* this is naïve.
*/
- ucval = KB_101;
- ret = put_user(ucval, (char __user *)arg);
- break;
+ return put_user(KB_101, (char __user *)arg);
/*
* These cannot be implemented on any machine that implements
@@ -426,84 +344,45 @@ int vt_ioctl(struct tty_struct *tty,
*
* These are locked internally via sys_ioperm
*/
- if (arg < GPFIRST || arg > GPLAST) {
- ret = -EINVAL;
- break;
- }
- ret = ksys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0;
- break;
+ if (arg < GPFIRST || arg > GPLAST)
+ return -EINVAL;
+
+ return ksys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0;
case KDENABIO:
case KDDISABIO:
- ret = ksys_ioperm(GPFIRST, GPNUM,
+ return ksys_ioperm(GPFIRST, GPNUM,
(cmd == KDENABIO)) ? -ENXIO : 0;
- break;
#endif
/* Linux m68k/i386 interface for setting the keyboard delay/repeat rate */
-
+
case KDKBDREP:
{
struct kbd_repeat kbrep;
-
+
if (!capable(CAP_SYS_TTY_CONFIG))
return -EPERM;
- if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) {
- ret = -EFAULT;
- break;
- }
+ if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat)))
+ return -EFAULT;
+
ret = kbd_rate(&kbrep);
if (ret)
- break;
+ return ret;
if (copy_to_user(up, &kbrep, sizeof(struct kbd_repeat)))
- ret = -EFAULT;
+ return -EFAULT;
break;
}
case KDSETMODE:
- /*
- * currently, setting the mode from KD_TEXT to KD_GRAPHICS
- * doesn't do a whole lot. i'm not sure if it should do any
- * restoration of modes or what...
- *
- * XXX It should at least call into the driver, fbdev's definitely
- * need to restore their engine state. --BenH
- */
if (!perm)
return -EPERM;
- switch (arg) {
- case KD_GRAPHICS:
- break;
- case KD_TEXT0:
- case KD_TEXT1:
- arg = KD_TEXT;
- case KD_TEXT:
- break;
- default:
- ret = -EINVAL;
- goto out;
- }
- /* FIXME: this needs the console lock extending */
- if (vc->vc_mode == (unsigned char) arg)
- break;
- vc->vc_mode = (unsigned char) arg;
- if (console != fg_console)
- break;
- /*
- * explicitly blank/unblank the screen if switching modes
- */
- console_lock();
- if (arg == KD_TEXT)
- do_unblank_screen(1);
- else
- do_blank_screen(1);
- console_unlock();
- break;
+
+ return vt_kdsetmode(vc, arg);
case KDGETMODE:
- uival = vc->vc_mode;
- goto setint;
+ return put_user(vc->vc_mode, (int __user *)arg);
case KDMAPDISP:
case KDUNMAPDISP:
@@ -511,51 +390,42 @@ int vt_ioctl(struct tty_struct *tty,
* these work like a combination of mmap and KDENABIO.
* this could be easily finished.
*/
- ret = -EINVAL;
- break;
+ return -EINVAL;
case KDSKBMODE:
if (!perm)
return -EPERM;
ret = vt_do_kdskbmode(console, arg);
- if (ret == 0)
- tty_ldisc_flush(tty);
+ if (ret)
+ return ret;
+ tty_ldisc_flush(tty);
break;
case KDGKBMODE:
- uival = vt_do_kdgkbmode(console);
- ret = put_user(uival, (int __user *)arg);
- break;
+ return put_user(vt_do_kdgkbmode(console), (int __user *)arg);
/* this could be folded into KDSKBMODE, but for compatibility
reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */
case KDSKBMETA:
- ret = vt_do_kdskbmeta(console, arg);
- break;
+ return vt_do_kdskbmeta(console, arg);
case KDGKBMETA:
/* FIXME: should review whether this is worth locking */
- uival = vt_do_kdgkbmeta(console);
- setint:
- ret = put_user(uival, (int __user *)arg);
- break;
+ return put_user(vt_do_kdgkbmeta(console), (int __user *)arg);
case KDGETKEYCODE:
case KDSETKEYCODE:
if(!capable(CAP_SYS_TTY_CONFIG))
perm = 0;
- ret = vt_do_kbkeycode_ioctl(cmd, up, perm);
- break;
+ return vt_do_kbkeycode_ioctl(cmd, up, perm);
case KDGKBENT:
case KDSKBENT:
- ret = vt_do_kdsk_ioctl(cmd, up, perm, console);
- break;
+ return vt_do_kdsk_ioctl(cmd, up, perm, console);
case KDGKBSENT:
case KDSKBSENT:
- ret = vt_do_kdgkb_ioctl(cmd, up, perm);
- break;
+ return vt_do_kdgkb_ioctl(cmd, up, perm);
/* Diacritical processing. Handled in keyboard.c as it has
to operate on the keyboard locks and structures */
@@ -563,8 +433,7 @@ int vt_ioctl(struct tty_struct *tty,
case KDGKBDIACRUC:
case KDSKBDIACR:
case KDSKBDIACRUC:
- ret = vt_do_diacrit(cmd, up, perm);
- break;
+ return vt_do_diacrit(cmd, up, perm);
/* the ioctls below read/set the flags usually shown in the leds */
/* don't use them - they will go away without warning */
@@ -572,8 +441,7 @@ int vt_ioctl(struct tty_struct *tty,
case KDSKBLED:
case KDGETLED:
case KDSETLED:
- ret = vt_do_kdskled(console, cmd, arg, perm);
- break;
+ return vt_do_kdskled(console, cmd, arg, perm);
/*
* A process can indicate its willingness to accept signals
@@ -583,35 +451,416 @@ int vt_ioctl(struct tty_struct *tty,
* See also the kbrequest field of inittab(5).
*/
case KDSIGACCEPT:
- {
if (!perm || !capable(CAP_KILL))
return -EPERM;
if (!valid_signal(arg) || arg < 1 || arg == SIGKILL)
- ret = -EINVAL;
- else {
- spin_lock_irq(&vt_spawn_con.lock);
- put_pid(vt_spawn_con.pid);
- vt_spawn_con.pid = get_pid(task_pid(current));
- vt_spawn_con.sig = arg;
- spin_unlock_irq(&vt_spawn_con.lock);
+ return -EINVAL;
+
+ spin_lock_irq(&vt_spawn_con.lock);
+ put_pid(vt_spawn_con.pid);
+ vt_spawn_con.pid = get_pid(task_pid(current));
+ vt_spawn_con.sig = arg;
+ spin_unlock_irq(&vt_spawn_con.lock);
+ break;
+
+ case KDFONTOP: {
+ struct console_font_op op;
+
+ if (copy_from_user(&op, up, sizeof(op)))
+ return -EFAULT;
+ if (!perm && op.op != KD_FONT_OP_GET)
+ return -EPERM;
+ ret = con_font_op(vc, &op);
+ if (ret)
+ return ret;
+ if (copy_to_user(up, &op, sizeof(op)))
+ return -EFAULT;
+ break;
+ }
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return 0;
+}
+
+static inline int do_fontx_ioctl(int cmd,
+ struct consolefontdesc __user *user_cfd,
+ struct console_font_op *op)
+{
+ struct consolefontdesc cfdarg;
+ int i;
+
+ if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc)))
+ return -EFAULT;
+
+ switch (cmd) {
+ case PIO_FONTX:
+ op->op = KD_FONT_OP_SET;
+ op->flags = KD_FONT_FLAG_OLD;
+ op->width = 8;
+ op->height = cfdarg.charheight;
+ op->charcount = cfdarg.charcount;
+ op->data = cfdarg.chardata;
+ return con_font_op(vc_cons[fg_console].d, op);
+ case GIO_FONTX: {
+ op->op = KD_FONT_OP_GET;
+ op->flags = KD_FONT_FLAG_OLD;
+ op->width = 8;
+ op->height = cfdarg.charheight;
+ op->charcount = cfdarg.charcount;
+ op->data = cfdarg.chardata;
+ i = con_font_op(vc_cons[fg_console].d, op);
+ if (i)
+ return i;
+ cfdarg.charheight = op->height;
+ cfdarg.charcount = op->charcount;
+ if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc)))
+ return -EFAULT;
+ return 0;
}
+ }
+ return -EINVAL;
+}
+
+static int vt_io_fontreset(struct console_font_op *op)
+{
+ int ret;
+
+ if (__is_defined(BROKEN_GRAPHICS_PROGRAMS)) {
+ /*
+ * With BROKEN_GRAPHICS_PROGRAMS defined, the default font is
+ * not saved.
+ */
+ return -ENOSYS;
+ }
+
+ op->op = KD_FONT_OP_SET_DEFAULT;
+ op->data = NULL;
+ ret = con_font_op(vc_cons[fg_console].d, op);
+ if (ret)
+ return ret;
+
+ console_lock();
+ con_set_default_unimap(vc_cons[fg_console].d);
+ console_unlock();
+
+ return 0;
+}
+
+static inline int do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud,
+ struct vc_data *vc)
+{
+ struct unimapdesc tmp;
+
+ if (copy_from_user(&tmp, user_ud, sizeof tmp))
+ return -EFAULT;
+ switch (cmd) {
+ case PIO_UNIMAP:
+ return con_set_unimap(vc, tmp.entry_ct, tmp.entries);
+ case GIO_UNIMAP:
+ if (fg_console != vc->vc_num)
+ return -EPERM;
+ return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct),
+ tmp.entries);
+ }
+ return 0;
+}
+
+static int vt_io_ioctl(struct vc_data *vc, unsigned int cmd, void __user *up,
+ bool perm)
+{
+ struct console_font_op op; /* used in multiple places here */
+
+ switch (cmd) {
+ case PIO_FONT:
+ if (!perm)
+ return -EPERM;
+ op.op = KD_FONT_OP_SET;
+ op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */
+ op.width = 8;
+ op.height = 0;
+ op.charcount = 256;
+ op.data = up;
+ return con_font_op(vc_cons[fg_console].d, &op);
+
+ case GIO_FONT:
+ op.op = KD_FONT_OP_GET;
+ op.flags = KD_FONT_FLAG_OLD;
+ op.width = 8;
+ op.height = 32;
+ op.charcount = 256;
+ op.data = up;
+ return con_font_op(vc_cons[fg_console].d, &op);
+
+ case PIO_CMAP:
+ if (!perm)
+ return -EPERM;
+ return con_set_cmap(up);
+
+ case GIO_CMAP:
+ return con_get_cmap(up);
+
+ case PIO_FONTX:
+ if (!perm)
+ return -EPERM;
+
+ fallthrough;
+ case GIO_FONTX:
+ return do_fontx_ioctl(cmd, up, &op);
+
+ case PIO_FONTRESET:
+ if (!perm)
+ return -EPERM;
+
+ return vt_io_fontreset(&op);
+
+ case PIO_SCRNMAP:
+ if (!perm)
+ return -EPERM;
+ return con_set_trans_old(up);
+
+ case GIO_SCRNMAP:
+ return con_get_trans_old(up);
+
+ case PIO_UNISCRNMAP:
+ if (!perm)
+ return -EPERM;
+ return con_set_trans_new(up);
+
+ case GIO_UNISCRNMAP:
+ return con_get_trans_new(up);
+
+ case PIO_UNIMAPCLR:
+ if (!perm)
+ return -EPERM;
+ con_clear_unimap(vc);
break;
+
+ case PIO_UNIMAP:
+ case GIO_UNIMAP:
+ if (!perm)
+ return -EPERM;
+
+ return do_unimap_ioctl(cmd, up, vc);
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return 0;
+}
+
+static int vt_reldisp(struct vc_data *vc, unsigned int swtch)
+{
+ int newvt, ret;
+
+ if (vc->vt_mode.mode != VT_PROCESS)
+ return -EINVAL;
+
+ /* Switched-to response */
+ if (vc->vt_newvt < 0) {
+ /* If it's just an ACK, ignore it */
+ return swtch == VT_ACKACQ ? 0 : -EINVAL;
+ }
+
+ /* Switching-from response */
+ if (swtch == 0) {
+ /* Switch disallowed, so forget we were trying to do it. */
+ vc->vt_newvt = -1;
+ return 0;
+ }
+
+ /* The current vt has been released, so complete the switch. */
+ newvt = vc->vt_newvt;
+ vc->vt_newvt = -1;
+ ret = vc_allocate(newvt);
+ if (ret)
+ return ret;
+
+ /*
+ * When we actually do the console switch, make sure we are atomic with
+ * respect to other console switches..
+ */
+ complete_change_console(vc_cons[newvt].d);
+
+ return 0;
+}
+
+static int vt_setactivate(struct vt_setactivate __user *sa)
+{
+ struct vt_setactivate vsa;
+ struct vc_data *nvc;
+ int ret;
+
+ if (copy_from_user(&vsa, sa, sizeof(vsa)))
+ return -EFAULT;
+ if (vsa.console == 0 || vsa.console > MAX_NR_CONSOLES)
+ return -ENXIO;
+
+ vsa.console = array_index_nospec(vsa.console, MAX_NR_CONSOLES + 1);
+ vsa.console--;
+ console_lock();
+ ret = vc_allocate(vsa.console);
+ if (ret) {
+ console_unlock();
+ return ret;
+ }
+
+ /*
+ * This is safe providing we don't drop the console sem between
+ * vc_allocate and finishing referencing nvc.
+ */
+ nvc = vc_cons[vsa.console].d;
+ nvc->vt_mode = vsa.mode;
+ nvc->vt_mode.frsig = 0;
+ put_pid(nvc->vt_pid);
+ nvc->vt_pid = get_pid(task_pid(current));
+ console_unlock();
+
+ /* Commence switch and lock */
+ /* Review set_console locks */
+ set_console(vsa.console);
+
+ return 0;
+}
+
+/* deallocate a single console, if possible (leave 0) */
+static int vt_disallocate(unsigned int vc_num)
+{
+ struct vc_data *vc = NULL;
+ int ret = 0;
+
+ console_lock();
+ if (vt_busy(vc_num))
+ ret = -EBUSY;
+ else if (vc_num)
+ vc = vc_deallocate(vc_num);
+ console_unlock();
+
+ if (vc && vc_num >= MIN_NR_CONSOLES)
+ tty_port_put(&vc->port);
+
+ return ret;
+}
+
+/* deallocate all unused consoles, but leave 0 */
+static void vt_disallocate_all(void)
+{
+ struct vc_data *vc[MAX_NR_CONSOLES];
+ int i;
+
+ console_lock();
+ for (i = 1; i < MAX_NR_CONSOLES; i++)
+ if (!vt_busy(i))
+ vc[i] = vc_deallocate(i);
+ else
+ vc[i] = NULL;
+ console_unlock();
+
+ for (i = 1; i < MAX_NR_CONSOLES; i++) {
+ if (vc[i] && i >= MIN_NR_CONSOLES)
+ tty_port_put(&vc[i]->port);
+ }
+}
+
+static int vt_resizex(struct vc_data *vc, struct vt_consize __user *cs)
+{
+ struct vt_consize v;
+ int i;
+
+ if (copy_from_user(&v, cs, sizeof(struct vt_consize)))
+ return -EFAULT;
+
+ /* FIXME: Should check the copies properly */
+ if (!v.v_vlin)
+ v.v_vlin = vc->vc_scan_lines;
+
+ if (v.v_clin) {
+ int rows = v.v_vlin / v.v_clin;
+ if (v.v_rows != rows) {
+ if (v.v_rows) /* Parameters don't add up */
+ return -EINVAL;
+ v.v_rows = rows;
+ }
+ }
+
+ if (v.v_vcol && v.v_ccol) {
+ int cols = v.v_vcol / v.v_ccol;
+ if (v.v_cols != cols) {
+ if (v.v_cols)
+ return -EINVAL;
+ v.v_cols = cols;
+ }
+ }
+
+ if (v.v_clin > 32)
+ return -EINVAL;
+
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ struct vc_data *vcp;
+
+ if (!vc_cons[i].d)
+ continue;
+ console_lock();
+ vcp = vc_cons[i].d;
+ if (vcp) {
+ if (v.v_vlin)
+ vcp->vc_scan_lines = v.v_vlin;
+ if (v.v_clin)
+ vcp->vc_font.height = v.v_clin;
+ vcp->vc_resize_user = 1;
+ vc_resize(vcp, v.v_cols, v.v_rows);
+ }
+ console_unlock();
}
+ return 0;
+}
+
+/*
+ * We handle the console-specific ioctl's here. We allow the
+ * capability to modify any console, not just the fg_console.
+ */
+int vt_ioctl(struct tty_struct *tty,
+ unsigned int cmd, unsigned long arg)
+{
+ struct vc_data *vc = tty->driver_data;
+ void __user *up = (void __user *)arg;
+ int i, perm;
+ int ret;
+
+ /*
+ * To have permissions to do most of the vt ioctls, we either have
+ * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
+ */
+ perm = 0;
+ if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
+ perm = 1;
+
+ ret = vt_k_ioctl(tty, cmd, arg, perm);
+ if (ret != -ENOIOCTLCMD)
+ return ret;
+
+ ret = vt_io_ioctl(vc, cmd, up, perm);
+ if (ret != -ENOIOCTLCMD)
+ return ret;
+
+ switch (cmd) {
+ case TIOCLINUX:
+ return tioclinux(tty, arg);
case VT_SETMODE:
{
struct vt_mode tmp;
if (!perm)
return -EPERM;
- if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) {
- ret = -EFAULT;
- goto out;
- }
- if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS) {
- ret = -EINVAL;
- goto out;
- }
+ if (copy_from_user(&tmp, up, sizeof(struct vt_mode)))
+ return -EFAULT;
+ if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS)
+ return -EINVAL;
+
console_lock();
vc->vt_mode = tmp;
/* the frsig is ignored, so we set it to 0 */
@@ -635,7 +884,7 @@ int vt_ioctl(struct tty_struct *tty,
rc = copy_to_user(up, &tmp, sizeof(struct vt_mode));
if (rc)
- ret = -EFAULT;
+ return -EFAULT;
break;
}
@@ -650,18 +899,16 @@ int vt_ioctl(struct tty_struct *tty,
unsigned short state, mask;
if (put_user(fg_console + 1, &vtstat->v_active))
- ret = -EFAULT;
- else {
- state = 1; /* /dev/tty0 is always open */
- console_lock(); /* required by vt_in_use() */
- for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask;
- ++i, mask <<= 1)
- if (vt_in_use(i))
- state |= mask;
- console_unlock();
- ret = put_user(state, &vtstat->v_state);
- }
- break;
+ return -EFAULT;
+
+ state = 1; /* /dev/tty0 is always open */
+ console_lock(); /* required by vt_in_use() */
+ for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask;
+ ++i, mask <<= 1)
+ if (vt_in_use(i))
+ state |= mask;
+ console_unlock();
+ return put_user(state, &vtstat->v_state);
}
/*
@@ -673,8 +920,8 @@ int vt_ioctl(struct tty_struct *tty,
if (!vt_in_use(i))
break;
console_unlock();
- uival = i < MAX_NR_CONSOLES ? (i+1) : -1;
- goto setint;
+ i = i < MAX_NR_CONSOLES ? (i+1) : -1;
+ return put_user(i, (int __user *)arg);
/*
* ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num,
@@ -685,58 +932,22 @@ int vt_ioctl(struct tty_struct *tty,
if (!perm)
return -EPERM;
if (arg == 0 || arg > MAX_NR_CONSOLES)
- ret = -ENXIO;
- else {
- arg--;
- console_lock();
- ret = vc_allocate(arg);
- console_unlock();
- if (ret)
- break;
- set_console(arg);
- }
+ return -ENXIO;
+
+ arg--;
+ console_lock();
+ ret = vc_allocate(arg);
+ console_unlock();
+ if (ret)
+ return ret;
+ set_console(arg);
break;
case VT_SETACTIVATE:
- {
- struct vt_setactivate vsa;
-
if (!perm)
return -EPERM;
- if (copy_from_user(&vsa, (struct vt_setactivate __user *)arg,
- sizeof(struct vt_setactivate))) {
- ret = -EFAULT;
- goto out;
- }
- if (vsa.console == 0 || vsa.console > MAX_NR_CONSOLES)
- ret = -ENXIO;
- else {
- vsa.console = array_index_nospec(vsa.console,
- MAX_NR_CONSOLES + 1);
- vsa.console--;
- console_lock();
- ret = vc_allocate(vsa.console);
- if (ret == 0) {
- struct vc_data *nvc;
- /* This is safe providing we don't drop the
- console sem between vc_allocate and
- finishing referencing nvc */
- nvc = vc_cons[vsa.console].d;
- nvc->vt_mode = vsa.mode;
- nvc->vt_mode.frsig = 0;
- put_pid(nvc->vt_pid);
- nvc->vt_pid = get_pid(task_pid(current));
- }
- console_unlock();
- if (ret)
- break;
- /* Commence switch and lock */
- /* Review set_console locks */
- set_console(vsa.console);
- }
- break;
- }
+ return vt_setactivate(up);
/*
* wait until the specified VT has been activated
@@ -745,10 +956,8 @@ int vt_ioctl(struct tty_struct *tty,
if (!perm)
return -EPERM;
if (arg == 0 || arg > MAX_NR_CONSOLES)
- ret = -ENXIO;
- else
- ret = vt_waitactive(arg);
- break;
+ return -ENXIO;
+ return vt_waitactive(arg);
/*
* If a vt is under process control, the kernel will not switch to it
@@ -765,258 +974,56 @@ int vt_ioctl(struct tty_struct *tty,
return -EPERM;
console_lock();
- if (vc->vt_mode.mode != VT_PROCESS) {
- console_unlock();
- ret = -EINVAL;
- break;
- }
- /*
- * Switching-from response
- */
- if (vc->vt_newvt >= 0) {
- if (arg == 0)
- /*
- * Switch disallowed, so forget we were trying
- * to do it.
- */
- vc->vt_newvt = -1;
-
- else {
- /*
- * The current vt has been released, so
- * complete the switch.
- */
- int newvt;
- newvt = vc->vt_newvt;
- vc->vt_newvt = -1;
- ret = vc_allocate(newvt);
- if (ret) {
- console_unlock();
- break;
- }
- /*
- * When we actually do the console switch,
- * make sure we are atomic with respect to
- * other console switches..
- */
- complete_change_console(vc_cons[newvt].d);
- }
- } else {
- /*
- * Switched-to response
- */
- /*
- * If it's just an ACK, ignore it
- */
- if (arg != VT_ACKACQ)
- ret = -EINVAL;
- }
+ ret = vt_reldisp(vc, arg);
console_unlock();
- break;
+
+ return ret;
+
/*
* Disallocate memory associated to VT (but leave VT1)
*/
case VT_DISALLOCATE:
- if (arg > MAX_NR_CONSOLES) {
- ret = -ENXIO;
- break;
- }
+ if (arg > MAX_NR_CONSOLES)
+ return -ENXIO;
+
if (arg == 0)
vt_disallocate_all();
else
- ret = vt_disallocate(--arg);
+ return vt_disallocate(--arg);
break;
case VT_RESIZE:
{
struct vt_sizes __user *vtsizes = up;
struct vc_data *vc;
-
ushort ll,cc;
+
if (!perm)
return -EPERM;
if (get_user(ll, &vtsizes->v_rows) ||
get_user(cc, &vtsizes->v_cols))
- ret = -EFAULT;
- else {
- console_lock();
- for (i = 0; i < MAX_NR_CONSOLES; i++) {
- vc = vc_cons[i].d;
-
- if (vc) {
- vc->vc_resize_user = 1;
- /* FIXME: review v tty lock */
- vc_resize(vc_cons[i].d, cc, ll);
- }
- }
- console_unlock();
- }
- break;
- }
-
- case VT_RESIZEX:
- {
- struct vt_consize v;
- if (!perm)
- return -EPERM;
- if (copy_from_user(&v, up, sizeof(struct vt_consize)))
return -EFAULT;
- /* FIXME: Should check the copies properly */
- if (!v.v_vlin)
- v.v_vlin = vc->vc_scan_lines;
- if (v.v_clin) {
- int rows = v.v_vlin/v.v_clin;
- if (v.v_rows != rows) {
- if (v.v_rows) /* Parameters don't add up */
- return -EINVAL;
- v.v_rows = rows;
- }
- }
- if (v.v_vcol && v.v_ccol) {
- int cols = v.v_vcol/v.v_ccol;
- if (v.v_cols != cols) {
- if (v.v_cols)
- return -EINVAL;
- v.v_cols = cols;
- }
- }
-
- if (v.v_clin > 32)
- return -EINVAL;
+ console_lock();
for (i = 0; i < MAX_NR_CONSOLES; i++) {
- struct vc_data *vcp;
-
- if (!vc_cons[i].d)
- continue;
- console_lock();
- vcp = vc_cons[i].d;
- if (vcp) {
- if (v.v_vlin)
- vcp->vc_scan_lines = v.v_vlin;
- if (v.v_clin)
- vcp->vc_font.height = v.v_clin;
- vcp->vc_resize_user = 1;
- vc_resize(vcp, v.v_cols, v.v_rows);
+ vc = vc_cons[i].d;
+
+ if (vc) {
+ vc->vc_resize_user = 1;
+ /* FIXME: review v tty lock */
+ vc_resize(vc_cons[i].d, cc, ll);
}
- console_unlock();
}
- break;
- }
-
- case PIO_FONT: {
- if (!perm)
- return -EPERM;
- op.op = KD_FONT_OP_SET;
- op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */
- op.width = 8;
- op.height = 0;
- op.charcount = 256;
- op.data = up;
- ret = con_font_op(vc_cons[fg_console].d, &op);
- break;
- }
-
- case GIO_FONT: {
- op.op = KD_FONT_OP_GET;
- op.flags = KD_FONT_FLAG_OLD;
- op.width = 8;
- op.height = 32;
- op.charcount = 256;
- op.data = up;
- ret = con_font_op(vc_cons[fg_console].d, &op);
- break;
- }
-
- case PIO_CMAP:
- if (!perm)
- ret = -EPERM;
- else
- ret = con_set_cmap(up);
- break;
-
- case GIO_CMAP:
- ret = con_get_cmap(up);
- break;
-
- case PIO_FONTX:
- case GIO_FONTX:
- ret = do_fontx_ioctl(cmd, up, perm, &op);
- break;
-
- case PIO_FONTRESET:
- {
- if (!perm)
- return -EPERM;
-
-#ifdef BROKEN_GRAPHICS_PROGRAMS
- /* With BROKEN_GRAPHICS_PROGRAMS defined, the default
- font is not saved. */
- ret = -ENOSYS;
- break;
-#else
- {
- op.op = KD_FONT_OP_SET_DEFAULT;
- op.data = NULL;
- ret = con_font_op(vc_cons[fg_console].d, &op);
- if (ret)
- break;
- console_lock();
- con_set_default_unimap(vc_cons[fg_console].d);
console_unlock();
break;
- }
-#endif
}
- case KDFONTOP: {
- if (copy_from_user(&op, up, sizeof(op))) {
- ret = -EFAULT;
- break;
- }
- if (!perm && op.op != KD_FONT_OP_GET)
- return -EPERM;
- ret = con_font_op(vc, &op);
- if (ret)
- break;
- if (copy_to_user(up, &op, sizeof(op)))
- ret = -EFAULT;
- break;
- }
-
- case PIO_SCRNMAP:
- if (!perm)
- ret = -EPERM;
- else
- ret = con_set_trans_old(up);
- break;
-
- case GIO_SCRNMAP:
- ret = con_get_trans_old(up);
- break;
-
- case PIO_UNISCRNMAP:
- if (!perm)
- ret = -EPERM;
- else
- ret = con_set_trans_new(up);
- break;
-
- case GIO_UNISCRNMAP:
- ret = con_get_trans_new(up);
- break;
-
- case PIO_UNIMAPCLR:
+ case VT_RESIZEX:
if (!perm)
return -EPERM;
- con_clear_unimap(vc);
- break;
- case PIO_UNIMAP:
- case GIO_UNIMAP:
- ret = do_unimap_ioctl(cmd, up, perm, vc);
- break;
+ return vt_resizex(vc, up);
case VT_LOCKSWITCH:
if (!capable(CAP_SYS_TTY_CONFIG))
@@ -1029,17 +1036,15 @@ int vt_ioctl(struct tty_struct *tty,
vt_dont_switch = false;
break;
case VT_GETHIFONTMASK:
- ret = put_user(vc->vc_hi_font_mask,
+ return put_user(vc->vc_hi_font_mask,
(unsigned short __user *)arg);
- break;
case VT_WAITEVENT:
- ret = vt_event_wait_ioctl((struct vt_event __user *)arg);
- break;
+ return vt_event_wait_ioctl((struct vt_event __user *)arg);
default:
- ret = -ENOIOCTLCMD;
+ return -ENOIOCTLCMD;
}
-out:
- return ret;
+
+ return 0;
}
void reset_vc(struct vc_data *vc)