Merge tag 'tty-6.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 21 Mar 2024 19:44:10 +0000 (12:44 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 21 Mar 2024 19:44:10 +0000 (12:44 -0700)
Pull tty / serial driver updates from Greg KH:
 "Here is the big set of TTY/Serial driver updates and cleanups for
  6.9-rc1. Included in here are:

   - more tty cleanups from Jiri

   - loads of 8250 driver cleanups from Andy

   - max310x driver updates

   - samsung serial driver updates

   - uart_prepare_sysrq_char() updates for many drivers

   - platform driver remove callback void cleanups

   - stm32 driver updates

   - other small tty/serial driver updates

  All of these have been in linux-next for a long time with no reported
  issues"

* tag 'tty-6.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (199 commits)
  dt-bindings: serial: stm32: add power-domains property
  serial: 8250_dw: Replace ACPI device check by a quirk
  serial: Lock console when calling into driver before registration
  serial: 8250_uniphier: Switch to use uart_read_port_properties()
  serial: 8250_tegra: Switch to use uart_read_port_properties()
  serial: 8250_pxa: Switch to use uart_read_port_properties()
  serial: 8250_omap: Switch to use uart_read_port_properties()
  serial: 8250_of: Switch to use uart_read_port_properties()
  serial: 8250_lpc18xx: Switch to use uart_read_port_properties()
  serial: 8250_ingenic: Switch to use uart_read_port_properties()
  serial: 8250_dw: Switch to use uart_read_port_properties()
  serial: 8250_bcm7271: Switch to use uart_read_port_properties()
  serial: 8250_bcm2835aux: Switch to use uart_read_port_properties()
  serial: 8250_aspeed_vuart: Switch to use uart_read_port_properties()
  serial: port: Introduce a common helper to read properties
  serial: core: Add UPIO_UNKNOWN constant for unknown port type
  serial: core: Move struct uart_port::quirks closer to possible values
  serial: sh-sci: Call sci_serial_{in,out}() directly
  serial: core: only stop transmit when HW fifo is empty
  serial: pch: Use uart_prepare_sysrq_char().
  ...

1  2 
drivers/bluetooth/btnxpuart.c
drivers/bluetooth/hci_serdev.c
drivers/mfd/rave-sp.c
drivers/net/ethernet/qualcomm/qca_uart.c
drivers/tty/serial/8250/8250_dw.c
drivers/tty/serial/pmac_zilog.c
drivers/tty/serial/qcom_geni_serial.c
drivers/tty/serial/serial_port.c
drivers/tty/vt/vt.c
drivers/video/fbdev/core/fbcon.c
kernel/printk/printk.c

index 0b93c2ff29e49a10b6fbac2336388bc4ceea1214,056bef5b29191b74cf0b027d131b9d95a95a1913..9d0c7e278114b229f7cc2155e7cc57a2cbfa9c54
@@@ -126,7 -126,6 +126,7 @@@ struct ps_data 
        struct hci_dev *hdev;
        struct work_struct work;
        struct timer_list ps_timer;
 +      struct mutex ps_lock;
  };
  
  struct wakeup_cmd_payload {
@@@ -318,9 -317,6 +318,9 @@@ static void ps_start_timer(struct btnxp
  
        if (psdata->cur_psmode == PS_MODE_ENABLE)
                mod_timer(&psdata->ps_timer, jiffies + msecs_to_jiffies(psdata->h2c_ps_interval));
 +
 +      if (psdata->ps_state == PS_STATE_AWAKE && psdata->ps_cmd == PS_CMD_ENTER_PS)
 +              cancel_work_sync(&psdata->work);
  }
  
  static void ps_cancel_timer(struct btnxpuart_dev *nxpdev)
@@@ -341,7 -337,6 +341,7 @@@ static void ps_control(struct hci_dev *
            !test_bit(BTNXPUART_SERDEV_OPEN, &nxpdev->tx_state))
                return;
  
 +      mutex_lock(&psdata->ps_lock);
        switch (psdata->cur_h2c_wakeupmode) {
        case WAKEUP_METHOD_DTR:
                if (ps_state == PS_STATE_AWAKE)
                        status = serdev_device_break_ctl(nxpdev->serdev, 0);
                else
                        status = serdev_device_break_ctl(nxpdev->serdev, -1);
 +              msleep(20); /* Allow chip to detect UART-break and enter sleep */
                bt_dev_dbg(hdev, "Set UART break: %s, status=%d",
                           str_on_off(ps_state == PS_STATE_SLEEP), status);
                break;
        }
        if (!status)
                psdata->ps_state = ps_state;
 +      mutex_unlock(&psdata->ps_lock);
 +
        if (ps_state == PS_STATE_AWAKE)
                btnxpuart_tx_wakeup(nxpdev);
  }
@@@ -399,25 -391,17 +399,25 @@@ static void ps_setup(struct hci_dev *hd
  
        psdata->hdev = hdev;
        INIT_WORK(&psdata->work, ps_work_func);
 +      mutex_init(&psdata->ps_lock);
        timer_setup(&psdata->ps_timer, ps_timeout_func, 0);
  }
  
 -static void ps_wakeup(struct btnxpuart_dev *nxpdev)
 +static bool ps_wakeup(struct btnxpuart_dev *nxpdev)
  {
        struct ps_data *psdata = &nxpdev->psdata;
 +      u8 ps_state;
 +
 +      mutex_lock(&psdata->ps_lock);
 +      ps_state = psdata->ps_state;
 +      mutex_unlock(&psdata->ps_lock);
  
 -      if (psdata->ps_state != PS_STATE_AWAKE) {
 +      if (ps_state != PS_STATE_AWAKE) {
                psdata->ps_cmd = PS_CMD_EXIT_PS;
                schedule_work(&psdata->work);
 +              return true;
        }
 +      return false;
  }
  
  static int send_ps_cmd(struct hci_dev *hdev, void *data)
@@@ -1187,6 -1171,7 +1187,6 @@@ static struct sk_buff *nxp_dequeue(voi
  {
        struct btnxpuart_dev *nxpdev = (struct btnxpuart_dev *)data;
  
 -      ps_wakeup(nxpdev);
        ps_start_timer(nxpdev);
        return skb_dequeue(&nxpdev->txq);
  }
@@@ -1201,9 -1186,6 +1201,9 @@@ static void btnxpuart_tx_work(struct wo
        struct sk_buff *skb;
        int len;
  
 +      if (ps_wakeup(nxpdev))
 +              return;
 +
        while ((skb = nxp_dequeue(nxpdev))) {
                len = serdev_device_write_buf(serdev, skb->data, skb->len);
                hdev->stat.byte_tx += len;
@@@ -1252,9 -1234,6 +1252,9 @@@ static int btnxpuart_close(struct hci_d
  
        ps_wakeup(nxpdev);
        serdev_device_close(nxpdev->serdev);
 +      skb_queue_purge(&nxpdev->txq);
 +      kfree_skb(nxpdev->rx_skb);
 +      nxpdev->rx_skb = NULL;
        clear_bit(BTNXPUART_SERDEV_OPEN, &nxpdev->tx_state);
        return 0;
  }
@@@ -1285,8 -1264,8 +1285,8 @@@ static const struct h4_recv_pkt nxp_rec
        { NXP_RECV_FW_REQ_V3,   .recv = nxp_recv_fw_req_v3 },
  };
  
- static ssize_t btnxpuart_receive_buf(struct serdev_device *serdev,
-                                    const u8 *data, size_t count)
+ static size_t btnxpuart_receive_buf(struct serdev_device *serdev,
+                                   const u8 *data, size_t count)
  {
        struct btnxpuart_dev *nxpdev = serdev_device_get_drvdata(serdev);
  
index 214fff876eae50e8ef88b7a4df44a3c76fdff240,a3c3beb2806d08762077ba73f617f199616e5a4a..85c0d9b68f5f76f5274f2ba049c9eaa949274381
@@@ -271,8 -271,8 +271,8 @@@ static void hci_uart_write_wakeup(struc
   *
   * Return: number of processed bytes
   */
- static ssize_t hci_uart_receive_buf(struct serdev_device *serdev,
-                                   const u8 *data, size_t count)
+ static size_t hci_uart_receive_buf(struct serdev_device *serdev,
+                                  const u8 *data, size_t count)
  {
        struct hci_uart *hu = serdev_device_get_drvdata(serdev);
  
@@@ -300,9 -300,8 +300,9 @@@ static const struct serdev_device_ops h
        .write_wakeup = hci_uart_write_wakeup,
  };
  
 -int hci_uart_register_device(struct hci_uart *hu,
 -                           const struct hci_uart_proto *p)
 +int hci_uart_register_device_priv(struct hci_uart *hu,
 +                           const struct hci_uart_proto *p,
 +                           int sizeof_priv)
  {
        int err;
        struct hci_dev *hdev;
        set_bit(HCI_UART_PROTO_READY, &hu->flags);
  
        /* Initialize and register HCI device */
 -      hdev = hci_alloc_dev();
 +      hdev = hci_alloc_dev_priv(sizeof_priv);
        if (!hdev) {
                BT_ERR("Can't allocate HCI device");
                err = -ENOMEM;
@@@ -395,7 -394,7 +395,7 @@@ err_rwsem
        percpu_free_rwsem(&hu->proto_lock);
        return err;
  }
 -EXPORT_SYMBOL_GPL(hci_uart_register_device);
 +EXPORT_SYMBOL_GPL(hci_uart_register_device_priv);
  
  void hci_uart_unregister_device(struct hci_uart *hu)
  {
diff --combined drivers/mfd/rave-sp.c
index ea5fbcbbe4a56f8a7ba9dd3e57a87c54b97db56d,62a6613fb07005917c1f00b214b107e9148f7319..ef326d6d566e691603cd20604b863c6de091a246
@@@ -358,7 -358,7 +358,7 @@@ int rave_sp_exec(struct rave_sp *sp
  
        ackid       = atomic_inc_return(&sp->ackid);
        reply.ackid = ackid;
 -      reply.code  = rave_sp_reply_code((u8)command),
 +      reply.code  = rave_sp_reply_code((u8)command);
  
        mutex_lock(&sp->bus_lock);
  
@@@ -471,8 -471,8 +471,8 @@@ static void rave_sp_receive_frame(struc
                rave_sp_receive_reply(sp, data, length);
  }
  
- static ssize_t rave_sp_receive_buf(struct serdev_device *serdev,
-                                  const u8 *buf, size_t size)
+ static size_t rave_sp_receive_buf(struct serdev_device *serdev,
+                                 const u8 *buf, size_t size)
  {
        struct device *dev = &serdev->dev;
        struct rave_sp *sp = dev_get_drvdata(dev);
index 321fd8d00730410bc53c9c2e8d8f1fec30947dab,20f50bde82acde677e6d837da3d10fce999ef4e9..37efb1ea9fcd9ca91067b98b2e2310e9d8881545
@@@ -1,7 -1,20 +1,7 @@@
 +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
  /*
   *   Copyright (c) 2011, 2012, Qualcomm Atheros Communications Inc.
   *   Copyright (c) 2017, I2SE GmbH
 - *
 - *   Permission to use, copy, modify, and/or distribute this software
 - *   for any purpose with or without fee is hereby granted, provided
 - *   that the above copyright notice and this permission notice appear
 - *   in all copies.
 - *
 - *   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
 - *   WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
 - *   WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
 - *   THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
 - *   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 - *   LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
 - *   NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 - *   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   */
  
  /*   This module implements the Qualcomm Atheros UART protocol for
@@@ -45,7 -58,7 +45,7 @@@ struct qcauart 
        unsigned char *tx_buffer;
  };
  
- static ssize_t
+ static size_t
  qca_tty_receive(struct serdev_device *serdev, const u8 *data, size_t count)
  {
        struct qcauart *qca = serdev_device_get_drvdata(serdev);
@@@ -397,6 -410,6 +397,6 @@@ module_serdev_device_driver(qca_uart_dr
  
  MODULE_DESCRIPTION("Qualcomm Atheros QCA7000 UART Driver");
  MODULE_AUTHOR("Qualcomm Atheros Communications");
 -MODULE_AUTHOR("Stefan Wahren <stefan.wahren@i2se.com>");
 +MODULE_AUTHOR("Stefan Wahren <wahrenst@gmx.net>");
  MODULE_LICENSE("Dual BSD/GPL");
  MODULE_VERSION(QCAUART_DRV_VERSION);
index c1d43f040c43abc517c4ef6b48a5423e936e97f2,1300c92b8702a3237459190d9027f12319581b25..a3acbf0f5da1beff6724e839fa14a0a990a15576
@@@ -9,7 -9,6 +9,6 @@@
   * LCR is written whilst busy.  If it is, then a busy detect interrupt is
   * raised, the LCR needs to be rewritten and the uart status register read.
   */
- #include <linux/acpi.h>
  #include <linux/clk.h>
  #include <linux/delay.h>
  #include <linux/device.h>
@@@ -17,7 -16,6 +16,6 @@@
  #include <linux/mod_devicetable.h>
  #include <linux/module.h>
  #include <linux/notifier.h>
- #include <linux/of.h>
  #include <linux/platform_device.h>
  #include <linux/pm_runtime.h>
  #include <linux/property.h>
@@@ -56,6 -54,7 +54,7 @@@
  #define DW_UART_QUIRK_ARMADA_38X      BIT(1)
  #define DW_UART_QUIRK_SKIP_SET_RATE   BIT(2)
  #define DW_UART_QUIRK_IS_DMA_FC               BIT(3)
+ #define DW_UART_QUIRK_APMC0D08                BIT(4)
  
  static inline struct dw8250_data *clk_to_dw8250_data(struct notifier_block *nb)
  {
@@@ -357,9 -356,9 +356,9 @@@ static void dw8250_set_termios(struct u
        long rate;
        int ret;
  
 -      clk_disable_unprepare(d->clk);
        rate = clk_round_rate(d->clk, newrate);
 -      if (rate > 0) {
 +      if (rate > 0 && p->uartclk != rate) {
 +              clk_disable_unprepare(d->clk);
                /*
                 * Note that any clock-notifer worker will block in
                 * serial8250_update_uartclk() until we are done.
                ret = clk_set_rate(d->clk, newrate);
                if (!ret)
                        p->uartclk = rate;
 +              clk_prepare_enable(d->clk);
        }
 -      clk_prepare_enable(d->clk);
  
        dw8250_do_set_termios(p, termios, old);
  }
@@@ -445,44 -444,29 +444,29 @@@ static void dw8250_prepare_rx_dma(struc
  
  static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
  {
-       struct device_node *np = p->dev->of_node;
+       unsigned int quirks = data->pdata ? data->pdata->quirks : 0;
  
-       if (np) {
-               unsigned int quirks = data->pdata->quirks;
-               int id;
-               /* get index of serial line, if found in DT aliases */
-               id = of_alias_get_id(np, "serial");
-               if (id >= 0)
-                       p->line = id;
  #ifdef CONFIG_64BIT
-               if (quirks & DW_UART_QUIRK_OCTEON) {
-                       p->serial_in = dw8250_serial_inq;
-                       p->serial_out = dw8250_serial_outq;
-                       p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
-                       p->type = PORT_OCTEON;
-                       data->skip_autocfg = true;
-               }
+       if (quirks & DW_UART_QUIRK_OCTEON) {
+               p->serial_in = dw8250_serial_inq;
+               p->serial_out = dw8250_serial_outq;
+               p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
+               p->type = PORT_OCTEON;
+               data->skip_autocfg = true;
+       }
  #endif
  
-               if (of_device_is_big_endian(np)) {
-                       p->iotype = UPIO_MEM32BE;
-                       p->serial_in = dw8250_serial_in32be;
-                       p->serial_out = dw8250_serial_out32be;
-               }
-               if (quirks & DW_UART_QUIRK_ARMADA_38X)
-                       p->serial_out = dw8250_serial_out38x;
-               if (quirks & DW_UART_QUIRK_SKIP_SET_RATE)
-                       p->set_termios = dw8250_do_set_termios;
-               if (quirks & DW_UART_QUIRK_IS_DMA_FC) {
-                       data->data.dma.txconf.device_fc = 1;
-                       data->data.dma.rxconf.device_fc = 1;
-                       data->data.dma.prepare_tx_dma = dw8250_prepare_tx_dma;
-                       data->data.dma.prepare_rx_dma = dw8250_prepare_rx_dma;
-               }
-       } else if (acpi_dev_present("APMC0D08", NULL, -1)) {
+       if (quirks & DW_UART_QUIRK_ARMADA_38X)
+               p->serial_out = dw8250_serial_out38x;
+       if (quirks & DW_UART_QUIRK_SKIP_SET_RATE)
+               p->set_termios = dw8250_do_set_termios;
+       if (quirks & DW_UART_QUIRK_IS_DMA_FC) {
+               data->data.dma.txconf.device_fc = 1;
+               data->data.dma.rxconf.device_fc = 1;
+               data->data.dma.prepare_tx_dma = dw8250_prepare_tx_dma;
+               data->data.dma.prepare_rx_dma = dw8250_prepare_rx_dma;
+       }
+       if (quirks & DW_UART_QUIRK_APMC0D08) {
                p->iotype = UPIO_MEM32;
                p->regshift = 2;
                p->serial_in = dw8250_serial_in32;
@@@ -510,39 -494,21 +494,21 @@@ static int dw8250_probe(struct platform
        struct device *dev = &pdev->dev;
        struct dw8250_data *data;
        struct resource *regs;
-       int irq;
        int err;
-       u32 val;
  
        regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!regs)
                return dev_err_probe(dev, -EINVAL, "no registers defined\n");
  
-       irq = platform_get_irq_optional(pdev, 0);
-       /* no interrupt -> fall back to polling */
-       if (irq == -ENXIO)
-               irq = 0;
-       if (irq < 0)
-               return irq;
        spin_lock_init(&p->lock);
-       p->mapbase      = regs->start;
-       p->irq          = irq;
        p->handle_irq   = dw8250_handle_irq;
        p->pm           = dw8250_do_pm;
        p->type         = PORT_8250;
-       p->flags        = UPF_SHARE_IRQ | UPF_FIXED_PORT;
+       p->flags        = UPF_FIXED_PORT;
        p->dev          = dev;
-       p->iotype       = UPIO_MEM;
-       p->serial_in    = dw8250_serial_in;
-       p->serial_out   = dw8250_serial_out;
        p->set_ldisc    = dw8250_set_ldisc;
        p->set_termios  = dw8250_set_termios;
  
-       p->membase = devm_ioremap(dev, regs->start, resource_size(regs));
-       if (!p->membase)
-               return -ENOMEM;
        data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
        data->uart_16550_compatible = device_property_read_bool(dev,
                                                "snps,uart-16550-compatible");
  
-       err = device_property_read_u32(dev, "reg-shift", &val);
-       if (!err)
-               p->regshift = val;
+       p->mapbase = regs->start;
+       p->mapsize = resource_size(regs);
  
-       err = device_property_read_u32(dev, "reg-io-width", &val);
-       if (!err && val == 4) {
-               p->iotype = UPIO_MEM32;
+       p->membase = devm_ioremap(dev, p->mapbase, p->mapsize);
+       if (!p->membase)
+               return -ENOMEM;
+       err = uart_read_port_properties(p);
+       /* no interrupt -> fall back to polling */
+       if (err == -ENXIO)
+               err = 0;
+       if (err)
+               return err;
+       switch (p->iotype) {
+       case UPIO_MEM:
+               p->serial_in = dw8250_serial_in;
+               p->serial_out = dw8250_serial_out;
+               break;
+       case UPIO_MEM32:
                p->serial_in = dw8250_serial_in32;
                p->serial_out = dw8250_serial_out32;
+               break;
+       case UPIO_MEM32BE:
+               p->serial_in = dw8250_serial_in32be;
+               p->serial_out = dw8250_serial_out32be;
+               break;
+       default:
+               return -ENODEV;
        }
  
        if (device_property_read_bool(dev, "dcd-override")) {
                data->msr_mask_off |= UART_MSR_TERI;
        }
  
-       /* Always ask for fixed clock rate from a property. */
-       device_property_read_u32(dev, "clock-frequency", &p->uartclk);
        /* If there is separate baudclk, get the rate from it. */
        data->clk = devm_clk_get_optional_enabled(dev, "baudclk");
        if (data->clk == NULL)
                data->clk = devm_clk_get_optional_enabled(dev, NULL);
        if (IS_ERR(data->clk))
-               return PTR_ERR(data->clk);
+               return dev_err_probe(dev, PTR_ERR(data->clk),
+                                    "failed to get baudclk\n");
  
        INIT_WORK(&data->clk_work, dw8250_clk_work_cb);
        data->clk_notifier.notifier_call = dw8250_clk_notifier_cb;
@@@ -762,13 -746,18 +746,18 @@@ static const struct of_device_id dw8250
  };
  MODULE_DEVICE_TABLE(of, dw8250_of_match);
  
+ static const struct dw8250_platform_data dw8250_apmc0d08 = {
+       .usr_reg = DW_UART_USR,
+       .quirks = DW_UART_QUIRK_APMC0D08,
+ };
  static const struct acpi_device_id dw8250_acpi_match[] = {
        { "80860F0A", (kernel_ulong_t)&dw8250_dw_apb },
        { "8086228A", (kernel_ulong_t)&dw8250_dw_apb },
        { "AMD0020", (kernel_ulong_t)&dw8250_dw_apb },
        { "AMDI0020", (kernel_ulong_t)&dw8250_dw_apb },
        { "AMDI0022", (kernel_ulong_t)&dw8250_dw_apb },
-       { "APMC0D08", (kernel_ulong_t)&dw8250_dw_apb},
+       { "APMC0D08", (kernel_ulong_t)&dw8250_apmc0d08 },
        { "BRCM2032", (kernel_ulong_t)&dw8250_dw_apb },
        { "HISI0031", (kernel_ulong_t)&dw8250_dw_apb },
        { "INT33C4", (kernel_ulong_t)&dw8250_dw_apb },
index 732d821db4f805d539e732367b9ef9df1afb7cc9,05b5b3b456ac831cd8954f53134b536dd27fe106..05d97e89511e698bee73698edd0a98a58893bb7b
@@@ -1507,12 -1507,12 +1507,12 @@@ static int pmz_attach(struct macio_dev 
   * That one should not be called, macio isn't really a hotswap device,
   * we don't expect one of those serial ports to go away...
   */
 -static int pmz_detach(struct macio_dev *mdev)
 +static void pmz_detach(struct macio_dev *mdev)
  {
        struct uart_pmac_port   *uap = dev_get_drvdata(&mdev->ofdev.dev);
        
        if (!uap)
 -              return -ENODEV;
 +              return;
  
        uart_remove_one_port(&pmz_uart_reg, &uap->port);
  
        dev_set_drvdata(&mdev->ofdev.dev, NULL);
        uap->dev = NULL;
        uap->port.dev = NULL;
 -      
 -      return 0;
  }
  
 -
  static int pmz_suspend(struct macio_dev *mdev, pm_message_t pm_state)
  {
        struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev);
@@@ -1714,18 -1717,13 +1714,13 @@@ static int __init pmz_attach(struct pla
        return uart_add_one_port(&pmz_uart_reg, &uap->port);
  }
  
- static int __exit pmz_detach(struct platform_device *pdev)
+ static void __exit pmz_detach(struct platform_device *pdev)
  {
        struct uart_pmac_port *uap = platform_get_drvdata(pdev);
  
-       if (!uap)
-               return -ENODEV;
        uart_remove_one_port(&pmz_uart_reg, &uap->port);
  
        uap->port.dev = NULL;
-       return 0;
  }
  
  #endif /* !CONFIG_PPC_PMAC */
@@@ -1794,7 -1792,7 +1789,7 @@@ static struct macio_driver pmz_driver 
  #else
  
  static struct platform_driver pmz_driver = {
-       .remove         = __exit_p(pmz_detach),
+       .remove_new     = __exit_p(pmz_detach),
        .driver         = {
                .name           = "scc",
        },
index 99e08737f293c6868e56d2de80f31bf0e3345ca3,fdc75bb26c6933c3acf8d2144a7e74ebfac61a60..f9f7ac1a10df3d668d41506075359c7601b12185
@@@ -488,18 -488,16 +488,16 @@@ static void qcom_geni_serial_console_wr
  
        geni_status = readl(uport->membase + SE_GENI_STATUS);
  
-       /* Cancel the current write to log the fault */
        if (!locked) {
-               geni_se_cancel_m_cmd(&port->se);
-               if (!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
-                                               M_CMD_CANCEL_EN, true)) {
-                       geni_se_abort_m_cmd(&port->se);
-                       qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
-                                                       M_CMD_ABORT_EN, true);
-                       writel(M_CMD_ABORT_EN, uport->membase +
-                                                       SE_GENI_M_IRQ_CLEAR);
-               }
-               writel(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
+               /*
+                * We can only get here if an oops is in progress then we were
+                * unable to get the lock. This means we can't safely access
+                * our state variables like tx_remaining. About the best we
+                * can do is wait for the FIFO to be empty before we start our
+                * transfer, so we'll do that.
+                */
+               qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
+                                         M_TX_FIFO_NOT_EMPTY_EN, false);
        } else if ((geni_status & M_GENI_CMD_ACTIVE) && !port->tx_remaining) {
                /*
                 * It seems we can't interrupt existing transfers if all data
  
        __qcom_geni_serial_console_write(uport, s, count);
  
-       if (port->tx_remaining)
-               qcom_geni_serial_setup_tx(uport, port->tx_remaining);
  
-       if (locked)
+       if (locked) {
+               if (port->tx_remaining)
+                       qcom_geni_serial_setup_tx(uport, port->tx_remaining);
                uart_port_unlock_irqrestore(uport, flags);
+       }
  }
  
  static void handle_rx_console(struct uart_port *uport, u32 bytes, bool drop)
@@@ -851,21 -850,19 +850,21 @@@ static void qcom_geni_serial_stop_tx(st
  }
  
  static void qcom_geni_serial_send_chunk_fifo(struct uart_port *uport,
 -                                           unsigned int remaining)
 +                                           unsigned int chunk)
  {
        struct qcom_geni_serial_port *port = to_dev_port(uport);
        struct circ_buf *xmit = &uport->state->xmit;
 -      unsigned int tx_bytes;
 +      unsigned int tx_bytes, c, remaining = chunk;
        u8 buf[BYTES_PER_FIFO_WORD];
  
        while (remaining) {
                memset(buf, 0, sizeof(buf));
                tx_bytes = min(remaining, BYTES_PER_FIFO_WORD);
  
 -              memcpy(buf, &xmit->buf[xmit->tail], tx_bytes);
 -              uart_xmit_advance(uport, tx_bytes);
 +              for (c = 0; c < tx_bytes ; c++) {
 +                      buf[c] = xmit->buf[xmit->tail];
 +                      uart_xmit_advance(uport, 1);
 +              }
  
                iowrite32_rep(uport->membase + SE_GENI_TX_FIFOn, buf, 1);
  
index 72b6f4f326e2b04953875062f8ebc6e56f324e45,6779a008e67aadaf1d567d8aea75caa3d1adf3cb..22b9eeb23e68adb2cfd949ff20c18816bb78b1cb
@@@ -8,7 -8,10 +8,10 @@@
  
  #include <linux/device.h>
  #include <linux/module.h>
+ #include <linux/of.h>
+ #include <linux/platform_device.h>
  #include <linux/pm_runtime.h>
+ #include <linux/property.h>
  #include <linux/serial_core.h>
  #include <linux/spinlock.h>
  
@@@ -46,31 -49,8 +49,31 @@@ out
        return 0;
  }
  
 +static int serial_port_runtime_suspend(struct device *dev)
 +{
 +      struct serial_port_device *port_dev = to_serial_base_port_device(dev);
 +      struct uart_port *port = port_dev->port;
 +      unsigned long flags;
 +      bool busy;
 +
 +      if (port->flags & UPF_DEAD)
 +              return 0;
 +
 +      uart_port_lock_irqsave(port, &flags);
 +      busy = __serial_port_busy(port);
 +      if (busy)
 +              port->ops->start_tx(port);
 +      uart_port_unlock_irqrestore(port, flags);
 +
 +      if (busy)
 +              pm_runtime_mark_last_busy(dev);
 +
 +      return busy ? -EBUSY : 0;
 +}
 +
  static DEFINE_RUNTIME_DEV_PM_OPS(serial_port_pm,
 -                               NULL, serial_port_runtime_resume, NULL);
 +                               serial_port_runtime_suspend,
 +                               serial_port_runtime_resume, NULL);
  
  static int serial_port_probe(struct device *dev)
  {
@@@ -105,6 -85,148 +108,148 @@@ void uart_remove_one_port(struct uart_d
  }
  EXPORT_SYMBOL(uart_remove_one_port);
  
+ /**
+  * __uart_read_properties - read firmware properties of the given UART port
+  * @port: corresponding port
+  * @use_defaults: apply defaults (when %true) or validate the values (when %false)
+  *
+  * The following device properties are supported:
+  *   - clock-frequency (optional)
+  *   - fifo-size (optional)
+  *   - no-loopback-test (optional)
+  *   - reg-shift (defaults may apply)
+  *   - reg-offset (value may be validated)
+  *   - reg-io-width (defaults may apply or value may be validated)
+  *   - interrupts (OF only)
+  *   - serial [alias ID] (OF only)
+  *
+  * If the port->dev is of struct platform_device type the interrupt line
+  * will be retrieved via platform_get_irq() call against that device.
+  * Otherwise it will be assigned by fwnode_irq_get() call. In both cases
+  * the index 0 of the resource is used.
+  *
+  * The caller is responsible to initialize the following fields of the @port
+  *   ->dev (must be valid)
+  *   ->flags
+  *   ->mapbase
+  *   ->mapsize
+  *   ->regshift (if @use_defaults is false)
+  * before calling this function. Alternatively the above mentioned fields
+  * may be zeroed, in such case the only ones, that have associated properties
+  * found, will be set to the respective values.
+  *
+  * If no error happened, the ->irq, ->mapbase, ->mapsize will be altered.
+  * The ->iotype is always altered.
+  *
+  * When @use_defaults is true and the respective property is not found
+  * the following values will be applied:
+  *   ->regshift = 0
+  * In this case IRQ must be provided, otherwise an error will be returned.
+  *
+  * When @use_defaults is false and the respective property is found
+  * the following values will be validated:
+  *   - reg-io-width (->iotype)
+  *   - reg-offset (->mapsize against ->mapbase)
+  *
+  * Returns: 0 on success or negative errno on failure
+  */
+ static int __uart_read_properties(struct uart_port *port, bool use_defaults)
+ {
+       struct device *dev = port->dev;
+       u32 value;
+       int ret;
+       /* Read optional UART functional clock frequency */
+       device_property_read_u32(dev, "clock-frequency", &port->uartclk);
+       /* Read the registers alignment (default: 8-bit) */
+       ret = device_property_read_u32(dev, "reg-shift", &value);
+       if (ret)
+               port->regshift = use_defaults ? 0 : port->regshift;
+       else
+               port->regshift = value;
+       /* Read the registers I/O access type (default: MMIO 8-bit) */
+       ret = device_property_read_u32(dev, "reg-io-width", &value);
+       if (ret) {
+               port->iotype = UPIO_MEM;
+       } else {
+               switch (value) {
+               case 1:
+                       port->iotype = UPIO_MEM;
+                       break;
+               case 2:
+                       port->iotype = UPIO_MEM16;
+                       break;
+               case 4:
+                       port->iotype = device_is_big_endian(dev) ? UPIO_MEM32BE : UPIO_MEM32;
+                       break;
+               default:
+                       if (!use_defaults) {
+                               dev_err(dev, "Unsupported reg-io-width (%u)\n", value);
+                               return -EINVAL;
+                       }
+                       port->iotype = UPIO_UNKNOWN;
+                       break;
+               }
+       }
+       /* Read the address mapping base offset (default: no offset) */
+       ret = device_property_read_u32(dev, "reg-offset", &value);
+       if (ret)
+               value = 0;
+       /* Check for shifted address mapping overflow */
+       if (!use_defaults && port->mapsize < value) {
+               dev_err(dev, "reg-offset %u exceeds region size %pa\n", value, &port->mapsize);
+               return -EINVAL;
+       }
+       port->mapbase += value;
+       port->mapsize -= value;
+       /* Read optional FIFO size */
+       device_property_read_u32(dev, "fifo-size", &port->fifosize);
+       if (device_property_read_bool(dev, "no-loopback-test"))
+               port->flags |= UPF_SKIP_TEST;
+       /* Get index of serial line, if found in DT aliases */
+       ret = of_alias_get_id(dev_of_node(dev), "serial");
+       if (ret >= 0)
+               port->line = ret;
+       if (dev_is_platform(dev))
+               ret = platform_get_irq(to_platform_device(dev), 0);
+       else
+               ret = fwnode_irq_get(dev_fwnode(dev), 0);
+       if (ret == -EPROBE_DEFER)
+               return ret;
+       if (ret > 0)
+               port->irq = ret;
+       else if (use_defaults)
+               /* By default IRQ support is mandatory */
+               return ret;
+       else
+               port->irq = 0;
+       port->flags |= UPF_SHARE_IRQ;
+       return 0;
+ }
+ int uart_read_port_properties(struct uart_port *port)
+ {
+       return __uart_read_properties(port, true);
+ }
+ EXPORT_SYMBOL_GPL(uart_read_port_properties);
+ int uart_read_and_validate_port_properties(struct uart_port *port)
+ {
+       return __uart_read_properties(port, false);
+ }
+ EXPORT_SYMBOL_GPL(uart_read_and_validate_port_properties);
  static struct device_driver serial_port_driver = {
        .name = "port",
        .suppress_bind_attrs = true,
diff --combined drivers/tty/vt/vt.c
index 38a765eadbe2bc81494f1fbd7a63b50b87101f08,4342c47285fe88364145b81fe5efac8dbd3ccbc4..9b5b98dfc8b4017289db11d3a42780760cad38fe
@@@ -145,7 -145,7 +145,7 @@@ static void gotoxy(struct vc_data *vc, 
  static void save_cur(struct vc_data *vc);
  static void reset_terminal(struct vc_data *vc, int do_clear);
  static void con_flush_chars(struct tty_struct *tty);
- static int set_vesa_blanking(char __user *p);
+ static int set_vesa_blanking(u8 __user *mode);
  static void set_cursor(struct vc_data *vc);
  static void hide_cursor(struct vc_data *vc);
  static void console_callback(struct work_struct *ignored);
@@@ -175,7 -175,7 +175,7 @@@ int do_poke_blanked_console
  int console_blanked;
  EXPORT_SYMBOL(console_blanked);
  
- static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */
+ static enum vesa_blank_mode vesa_blank_mode;
  static int vesa_off_interval;
  static int blankinterval;
  core_param(consoleblank, blankinterval, int, 0444);
@@@ -286,18 -286,20 +286,20 @@@ static inline bool con_should_update(co
        return con_is_visible(vc) && !console_blanked;
  }
  
- static inline unsigned short *screenpos(const struct vc_data *vc, int offset,
-               bool viewed)
+ static inline u16 *screenpos(const struct vc_data *vc, unsigned int offset,
+                            bool viewed)
  {
-       unsigned short *p;
-       
-       if (!viewed)
-               p = (unsigned short *)(vc->vc_origin + offset);
-       else if (!vc->vc_sw->con_screen_pos)
-               p = (unsigned short *)(vc->vc_visible_origin + offset);
+       unsigned long origin = viewed ? vc->vc_visible_origin : vc->vc_origin;
+       return (u16 *)(origin + offset);
+ }
+ static void con_putc(struct vc_data *vc, u16 ca, unsigned int y, unsigned int x)
+ {
+       if (vc->vc_sw->con_putc)
+               vc->vc_sw->con_putc(vc, ca, y, x);
        else
-               p = vc->vc_sw->con_screen_pos(vc, offset);
-       return p;
+               vc->vc_sw->con_putcs(vc, &ca, 1, y, x);
  }
  
  /* Called  from the keyboard irq path.. */
@@@ -381,7 -383,7 +383,7 @@@ static void vc_uniscr_delete(struct vc_
                u32 *ln = vc->vc_uni_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));
 +              memmove(&ln[x], &ln[x + nr], (cols - x - nr) * sizeof(*ln));
                memset32(&ln[cols - nr], ' ', nr);
        }
  }
@@@ -591,18 -593,12 +593,12 @@@ static void con_scroll(struct vc_data *
  static void do_update_region(struct vc_data *vc, unsigned long start, int count)
  {
        unsigned int xx, yy, offset;
-       u16 *p;
+       u16 *p = (u16 *)start;
+       offset = (start - vc->vc_origin) / 2;
+       xx = offset % vc->vc_cols;
+       yy = offset / vc->vc_cols;
  
-       p = (u16 *) start;
-       if (!vc->vc_sw->con_getxy) {
-               offset = (start - vc->vc_origin) / 2;
-               xx = offset % vc->vc_cols;
-               yy = offset / vc->vc_cols;
-       } else {
-               int nxx, nyy;
-               start = vc->vc_sw->con_getxy(vc, start, &nxx, &nyy);
-               xx = nxx; yy = nyy;
-       }
        for(;;) {
                u16 attrib = scr_readw(p) & 0xff00;
                int startx = xx;
                        break;
                xx = 0;
                yy++;
-               if (vc->vc_sw->con_getxy) {
-                       p = (u16 *)start;
-                       start = vc->vc_sw->con_getxy(vc, start, NULL, NULL);
-               }
        }
  }
  
@@@ -703,7 -695,7 +695,7 @@@ static void update_attr(struct vc_data 
  /* Note: inverting the screen twice should revert to the original state */
  void invert_screen(struct vc_data *vc, int offset, int count, bool viewed)
  {
-       unsigned short *p;
+       u16 *p;
  
        WARN_CONSOLE_UNLOCKED();
  
@@@ -762,7 -754,7 +754,7 @@@ void complement_pos(struct vc_data *vc
            old_offset < vc->vc_screenbuf_size) {
                scr_writew(old, screenpos(vc, old_offset, true));
                if (con_should_update(vc))
-                       vc->vc_sw->con_putc(vc, old, oldy, oldx);
+                       con_putc(vc, old, oldy, oldx);
                notify_update(vc);
        }
  
        if (offset != -1 && offset >= 0 &&
            offset < vc->vc_screenbuf_size) {
                unsigned short new;
-               unsigned short *p;
-               p = screenpos(vc, offset, true);
+               u16 *p = screenpos(vc, offset, true);
                old = scr_readw(p);
                new = old ^ vc->vc_complement_mask;
                scr_writew(new, p);
                if (con_should_update(vc)) {
                        oldx = (offset >> 1) % vc->vc_cols;
                        oldy = (offset >> 1) / vc->vc_cols;
-                       vc->vc_sw->con_putc(vc, new, oldy, oldx);
+                       con_putc(vc, new, oldy, oldx);
                }
                notify_update(vc);
        }
@@@ -833,7 -824,7 +824,7 @@@ static void add_softcursor(struct vc_da
                i ^= CUR_FG;
        scr_writew(i, (u16 *)vc->vc_pos);
        if (con_should_update(vc))
-               vc->vc_sw->con_putc(vc, i, vc->state.y, vc->state.x);
+               con_putc(vc, i, vc->state.y, vc->state.x);
  }
  
  static void hide_softcursor(struct vc_data *vc)
        if (softcursor_original != -1) {
                scr_writew(softcursor_original, (u16 *)vc->vc_pos);
                if (con_should_update(vc))
-                       vc->vc_sw->con_putc(vc, softcursor_original,
-                                       vc->state.y, vc->state.x);
+                       con_putc(vc, softcursor_original, vc->state.y,
+                                vc->state.x);
                softcursor_original = -1;
        }
  }
@@@ -852,7 -843,7 +843,7 @@@ static void hide_cursor(struct vc_data 
        if (vc_is_sel(vc))
                clear_selection();
  
-       vc->vc_sw->con_cursor(vc, CM_ERASE);
+       vc->vc_sw->con_cursor(vc, false);
        hide_softcursor(vc);
  }
  
@@@ -865,7 -856,7 +856,7 @@@ static void set_cursor(struct vc_data *
                        clear_selection();
                add_softcursor(vc);
                if (CUR_SIZE(vc->vc_cursor_type) != CUR_NONE)
-                       vc->vc_sw->con_cursor(vc, CM_DRAW);
+                       vc->vc_sw->con_cursor(vc, true);
        } else
                hide_cursor(vc);
  }
@@@ -897,21 -888,18 +888,18 @@@ static void flush_scrollback(struct vc_
        WARN_CONSOLE_UNLOCKED();
  
        set_origin(vc);
-       if (vc->vc_sw->con_flush_scrollback) {
-               vc->vc_sw->con_flush_scrollback(vc);
-       } else if (con_is_visible(vc)) {
-               /*
-                * When no con_flush_scrollback method is provided then the
-                * legacy way for flushing the scrollback buffer is to use
-                * a side effect of the con_switch method. We do it only on
-                * the foreground console as background consoles have no
-                * scrollback buffers in that case and we obviously don't
-                * want to switch to them.
-                */
-               hide_cursor(vc);
-               vc->vc_sw->con_switch(vc);
-               set_cursor(vc);
-       }
+       if (!con_is_visible(vc))
+               return;
+       /*
+        * The legacy way for flushing the scrollback buffer is to use a side
+        * effect of the con_switch method. We do it only on the foreground
+        * console as background consoles have no scrollback buffers in that
+        * case and we obviously don't want to switch to them.
+        */
+       hide_cursor(vc);
+       vc->vc_sw->con_switch(vc);
+       set_cursor(vc);
  }
  
  /*
@@@ -962,7 -950,7 +950,7 @@@ void redraw_screen(struct vc_data *vc, 
        }
  
        if (redraw) {
-               int update;
+               bool update;
                int old_was_color = vc->vc_can_do_color;
  
                set_origin(vc);
@@@ -999,7 -987,7 +987,7 @@@ int vc_cons_allocated(unsigned int i
        return (i < MAX_NR_CONSOLES && vc_cons[i].d);
  }
  
- static void visual_init(struct vc_data *vc, int num, int init)
+ static void visual_init(struct vc_data *vc, int num, bool init)
  {
        /* ++Geert: vc->vc_sw->con_init determines console size */
        if (vc->vc_sw)
@@@ -1083,7 -1071,7 +1071,7 @@@ int vc_allocate(unsigned int currcons)  
        vc->port.ops = &vc_port_ops;
        INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
  
-       visual_init(vc, currcons, 1);
+       visual_init(vc, currcons, true);
  
        if (!*vc->uni_pagedict_loc)
                con_set_default_unimap(vc);
@@@ -1115,51 -1103,44 +1103,44 @@@ err_free
  }
  
  static inline int resize_screen(struct vc_data *vc, int width, int height,
-                               int user)
+                               bool from_user)
  {
        /* Resizes the resolution of the display adapater */
        int err = 0;
  
        if (vc->vc_sw->con_resize)
-               err = vc->vc_sw->con_resize(vc, width, height, user);
+               err = vc->vc_sw->con_resize(vc, width, height, from_user);
  
        return err;
  }
  
  /**
-  *    vc_do_resize    -       resizing method for the tty
-  *    @tty: tty being resized
-  *    @vc: virtual console private data
-  *    @cols: columns
-  *    @lines: lines
+  * vc_do_resize - resizing method for the tty
+  * @tty: tty being resized
+  * @vc: virtual console private data
+  * @cols: columns
+  * @lines: lines
+  * @from_user: invoked by a user?
   *
-  *    Resize a virtual console, clipping according to the actual constraints.
-  *    If the caller passes a tty structure then update the termios winsize
-  *    information and perform any necessary signal handling.
+  * Resize a virtual console, clipping according to the actual constraints. If
+  * the caller passes a tty structure then update the termios winsize
+  * information and perform any necessary signal handling.
   *
-  *    Caller must hold the console semaphore. Takes the termios rwsem and
-  *    ctrl.lock of the tty IFF a tty is passed.
+  * Locking: Caller must hold the console semaphore. Takes the termios rwsem and
+  * ctrl.lock of the tty IFF a tty is passed.
   */
  static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
-                               unsigned int cols, unsigned int lines)
+                       unsigned int cols, unsigned int lines, bool from_user)
  {
        unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0;
        unsigned long end;
        unsigned int old_rows, old_row_size, first_copied_row;
        unsigned int new_cols, new_rows, new_row_size, new_screen_size;
-       unsigned int user;
        unsigned short *oldscreen, *newscreen;
        u32 **new_uniscr = NULL;
  
        WARN_CONSOLE_UNLOCKED();
  
-       if (!vc)
-               return -ENXIO;
-       user = vc->vc_resize_user;
-       vc->vc_resize_user = 0;
        if (cols > VC_MAXCOL || lines > VC_MAXROW)
                return -EINVAL;
  
                 * to deal with possible errors from the code below, we call
                 * the resize_screen here as well.
                 */
-               return resize_screen(vc, new_cols, new_rows, user);
+               return resize_screen(vc, new_cols, new_rows, from_user);
        }
  
        if (new_screen_size > KMALLOC_MAX_SIZE || !new_screen_size)
        old_rows = vc->vc_rows;
        old_row_size = vc->vc_size_row;
  
-       err = resize_screen(vc, new_cols, new_rows, user);
+       err = resize_screen(vc, new_cols, new_rows, from_user);
        if (err) {
                kfree(newscreen);
                vc_uniscr_free(new_uniscr);
  }
  
  /**
-  *    vc_resize               -       resize a VT
-  *    @vc: virtual console
-  *    @cols: columns
-  *    @rows: rows
+  * __vc_resize - resize a VT
+  * @vc: virtual console
+  * @cols: columns
+  * @rows: rows
+  * @from_user: invoked by a user?
+  *
+  * Resize a virtual console as seen from the console end of things. We use the
+  * common vc_do_resize() method to update the structures.
   *
-  *    Resize a virtual console as seen from the console end of things. We
-  *    use the common vc_do_resize methods to update the structures. The
-  *    caller must hold the console sem to protect console internals and
-  *    vc->port.tty
+  * Locking: The caller must hold the console sem to protect console internals
+  * and @vc->port.tty.
   */
int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows)
+ int __vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows,
              bool from_user)
  {
-       return vc_do_resize(vc->port.tty, vc, cols, rows);
+       return vc_do_resize(vc->port.tty, vc, cols, rows, from_user);
  }
- EXPORT_SYMBOL(vc_resize);
+ EXPORT_SYMBOL(__vc_resize);
  
  /**
-  *    vt_resize               -       resize a VT
-  *    @tty: tty to resize
-  *    @ws: winsize attributes
+  * vt_resize - resize a VT
+  * @tty: tty to resize
+  * @ws: winsize attributes
   *
-  *    Resize a virtual terminal. This is called by the tty layer as we
-  *    register our own handler for resizing. The mutual helper does all
-  *    the actual work.
+  * Resize a virtual terminal. This is called by the tty layer as we register
+  * our own handler for resizing. The mutual helper does all the actual work.
   *
-  *    Takes the console sem and the called methods then take the tty
-  *    termios_rwsem and the tty ctrl.lock in that order.
+  * Locking: Takes the console sem and the called methods then take the tty
+  * termios_rwsem and the tty ctrl.lock in that order.
   */
  static int vt_resize(struct tty_struct *tty, struct winsize *ws)
  {
        int ret;
  
        console_lock();
-       ret = vc_do_resize(tty, vc, ws->ws_col, ws->ws_row);
+       ret = vc_do_resize(tty, vc, ws->ws_col, ws->ws_row, false);
        console_unlock();
        return ret;
  }
@@@ -1503,36 -1485,43 +1485,43 @@@ static inline void del(struct vc_data *
        /* ignored */
  }
  
- static void csi_J(struct vc_data *vc, int vpar)
+ enum CSI_J {
+       CSI_J_CURSOR_TO_END     = 0,
+       CSI_J_START_TO_CURSOR   = 1,
+       CSI_J_VISIBLE           = 2,
+       CSI_J_FULL              = 3,
+ };
+ static void csi_J(struct vc_data *vc, enum CSI_J vpar)
  {
+       unsigned short *start;
        unsigned int count;
-       unsigned short * start;
  
        switch (vpar) {
-               case 0: /* erase from cursor to end of display */
-                       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->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;
-               case 3: /* include scrollback */
-                       flush_scrollback(vc);
-                       fallthrough;
-               case 2: /* erase whole display */
-                       vc_uniscr_clear_lines(vc, 0, vc->vc_rows);
-                       count = vc->vc_cols * vc->vc_rows;
-                       start = (unsigned short *)vc->vc_origin;
-                       break;
-               default:
-                       return;
+       case CSI_J_CURSOR_TO_END:
+               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 CSI_J_START_TO_CURSOR:
+               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;
+       case CSI_J_FULL:
+               flush_scrollback(vc);
+               fallthrough;
+       case CSI_J_VISIBLE:
+               vc_uniscr_clear_lines(vc, 0, vc->vc_rows);
+               count = vc->vc_cols * vc->vc_rows;
+               start = (unsigned short *)vc->vc_origin;
+               break;
+       default:
+               return;
        }
        scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
        if (con_should_update(vc))
        vc->vc_need_wrap = 0;
  }
  
- static void csi_K(struct vc_data *vc, int vpar)
+ enum {
+       CSI_K_CURSOR_TO_LINEEND         = 0,
+       CSI_K_LINESTART_TO_CURSOR       = 1,
+       CSI_K_LINE                      = 2,
+ };
+ static void csi_K(struct vc_data *vc)
  {
        unsigned int count;
        unsigned short *start = (unsigned short *)vc->vc_pos;
        int offset;
  
-       switch (vpar) {
-               case 0: /* erase from cursor to end of line */
-                       offset = 0;
-                       count = vc->vc_cols - vc->state.x;
-                       break;
-               case 1: /* erase from start of line to cursor */
-                       offset = -vc->state.x;
-                       count = vc->state.x + 1;
-                       break;
-               case 2: /* erase whole line */
-                       offset = -vc->state.x;
-                       count = vc->vc_cols;
-                       break;
-               default:
-                       return;
+       switch (vc->vc_par[0]) {
+       case CSI_K_CURSOR_TO_LINEEND:
+               offset = 0;
+               count = vc->vc_cols - vc->state.x;
+               break;
+       case CSI_K_LINESTART_TO_CURSOR:
+               offset = -vc->state.x;
+               count = vc->state.x + 1;
+               break;
+       case CSI_K_LINE:
+               offset = -vc->state.x;
+               count = vc->vc_cols;
+               break;
+       default:
+               return;
        }
        vc_uniscr_clear_line(vc, vc->state.x + offset, count);
        scr_memsetw(start + offset, vc->vc_video_erase_char, 2 * count);
                do_update_region(vc, (unsigned long)(start + offset), count);
  }
  
- /* erase the following vpar positions */
- static void csi_X(struct vc_data *vc, unsigned int vpar)
+ /* erase the following count positions */
+ static void csi_X(struct vc_data *vc)
  {                                       /* not vt100? */
-       unsigned int count;
-       if (!vpar)
-               vpar++;
-       count = min(vpar, vc->vc_cols - vc->state.x);
+       unsigned int count = clamp(vc->vc_par[0], 1, 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->state.y, vc->state.x, 1, count);
+               vc->vc_sw->con_clear(vc, vc->state.y, vc->state.x, count);
        vc->vc_need_wrap = 0;
  }
  
@@@ -1598,7 -1588,7 +1588,7 @@@ static void default_attr(struct vc_dat
  
  struct rgb { u8 r; u8 g; u8 b; };
  
- static void rgb_from_256(int i, struct rgb *c)
+ static void rgb_from_256(unsigned int i, struct rgb *c)
  {
        if (i < 8) {            /* Standard colours. */
                c->r = i&1 ? 0xaa : 0x00;
                c->g = i&2 ? 0xff : 0x55;
                c->b = i&4 ? 0xff : 0x55;
        } else if (i < 232) {   /* 6x6x6 colour cube. */
-               c->r = (i - 16) / 36 * 85 / 2;
-               c->g = (i - 16) / 6 % 6 * 85 / 2;
-               c->b = (i - 16) % 6 * 85 / 2;
+               i -= 16;
+               c->b = i % 6 * 255 / 6;
+               i /= 6;
+               c->g = i % 6 * 255 / 6;
+               i /= 6;
+               c->r = i     * 255 / 6;
        } else                  /* Grayscale ramp. */
                c->r = c->g = c->b = i * 10 - 2312;
  }
@@@ -1681,6 -1674,39 +1674,39 @@@ static int vc_t416_color(struct vc_dat
        return i;
  }
  
+ enum {
+       CSI_m_DEFAULT                   = 0,
+       CSI_m_BOLD                      = 1,
+       CSI_m_HALF_BRIGHT               = 2,
+       CSI_m_ITALIC                    = 3,
+       CSI_m_UNDERLINE                 = 4,
+       CSI_m_BLINK                     = 5,
+       CSI_m_REVERSE                   = 7,
+       CSI_m_PRI_FONT                  = 10,
+       CSI_m_ALT_FONT1                 = 11,
+       CSI_m_ALT_FONT2                 = 12,
+       CSI_m_DOUBLE_UNDERLINE          = 21,
+       CSI_m_NORMAL_INTENSITY          = 22,
+       CSI_m_NO_ITALIC                 = 23,
+       CSI_m_NO_UNDERLINE              = 24,
+       CSI_m_NO_BLINK                  = 25,
+       CSI_m_NO_REVERSE                = 27,
+       CSI_m_FG_COLOR_BEG              = 30,
+       CSI_m_FG_COLOR_END              = 37,
+       CSI_m_FG_COLOR                  = 38,
+       CSI_m_DEFAULT_FG_COLOR          = 39,
+       CSI_m_BG_COLOR_BEG              = 40,
+       CSI_m_BG_COLOR_END              = 47,
+       CSI_m_BG_COLOR                  = 48,
+       CSI_m_DEFAULT_BG_COLOR          = 49,
+       CSI_m_BRIGHT_FG_COLOR_BEG       = 90,
+       CSI_m_BRIGHT_FG_COLOR_END       = 97,
+       CSI_m_BRIGHT_FG_COLOR_OFF       = CSI_m_BRIGHT_FG_COLOR_BEG - CSI_m_FG_COLOR_BEG,
+       CSI_m_BRIGHT_BG_COLOR_BEG       = 100,
+       CSI_m_BRIGHT_BG_COLOR_END       = 107,
+       CSI_m_BRIGHT_BG_COLOR_OFF       = CSI_m_BRIGHT_BG_COLOR_BEG - CSI_m_BG_COLOR_BEG,
+ };
  /* console_lock is held */
  static void csi_m(struct vc_data *vc)
  {
  
        for (i = 0; i <= vc->vc_npar; i++)
                switch (vc->vc_par[i]) {
-               case 0: /* all attributes off */
+               case CSI_m_DEFAULT:     /* all attributes off */
                        default_attr(vc);
                        break;
-               case 1:
+               case CSI_m_BOLD:
                        vc->state.intensity = VCI_BOLD;
                        break;
-               case 2:
+               case CSI_m_HALF_BRIGHT:
                        vc->state.intensity = VCI_HALF_BRIGHT;
                        break;
-               case 3:
+               case CSI_m_ITALIC:
                        vc->state.italic = true;
                        break;
-               case 21:
+               case CSI_m_DOUBLE_UNDERLINE:
                        /*
                         * No console drivers support double underline, so
                         * convert it to a single underline.
                         */
-               case 4:
+               case CSI_m_UNDERLINE:
                        vc->state.underline = true;
                        break;
-               case 5:
+               case CSI_m_BLINK:
                        vc->state.blink = true;
                        break;
-               case 7:
+               case CSI_m_REVERSE:
                        vc->state.reverse = true;
                        break;
-               case 10: /* ANSI X3.64-1979 (SCO-ish?)
+               case CSI_m_PRI_FONT: /* 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_disp_ctrl = 0;
                        vc->vc_toggle_meta = 0;
                        break;
-               case 11: /* ANSI X3.64-1979 (SCO-ish?)
+               case CSI_m_ALT_FONT1: /* ANSI X3.64-1979 (SCO-ish?)
                          * Select first alternate font, lets chars < 32 be
                          * displayed as ROM chars.
                          */
                        vc->vc_disp_ctrl = 1;
                        vc->vc_toggle_meta = 0;
                        break;
-               case 12: /* ANSI X3.64-1979 (SCO-ish?)
+               case CSI_m_ALT_FONT2: /* ANSI X3.64-1979 (SCO-ish?)
                          * Select second alternate font, toggle high bit
                          * before displaying as ROM char.
                          */
                        vc->vc_disp_ctrl = 1;
                        vc->vc_toggle_meta = 1;
                        break;
-               case 22:
+               case CSI_m_NORMAL_INTENSITY:
                        vc->state.intensity = VCI_NORMAL;
                        break;
-               case 23:
+               case CSI_m_NO_ITALIC:
                        vc->state.italic = false;
                        break;
-               case 24:
+               case CSI_m_NO_UNDERLINE:
                        vc->state.underline = false;
                        break;
-               case 25:
+               case CSI_m_NO_BLINK:
                        vc->state.blink = false;
                        break;
-               case 27:
+               case CSI_m_NO_REVERSE:
                        vc->state.reverse = false;
                        break;
-               case 38:
+               case CSI_m_FG_COLOR:
                        i = vc_t416_color(vc, i, rgb_foreground);
                        break;
-               case 48:
+               case CSI_m_BG_COLOR:
                        i = vc_t416_color(vc, i, rgb_background);
                        break;
-               case 39:
+               case CSI_m_DEFAULT_FG_COLOR:
                        vc->state.color = (vc->vc_def_color & 0x0f) |
                                (vc->state.color & 0xf0);
                        break;
-               case 49:
+               case CSI_m_DEFAULT_BG_COLOR:
                        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->state.intensity = VCI_BOLD;
-                               vc->vc_par[i] -= 60;
-                       }
-                       if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37)
-                               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->state.color = (color_table[vc->vc_par[i] - 40] << 4)
-                                       | (vc->state.color & 0x0f);
+               case CSI_m_BRIGHT_FG_COLOR_BEG ... CSI_m_BRIGHT_FG_COLOR_END:
+                       vc->state.intensity = VCI_BOLD;
+                       vc->vc_par[i] -= CSI_m_BRIGHT_FG_COLOR_OFF;
+                       fallthrough;
+               case CSI_m_FG_COLOR_BEG ... CSI_m_FG_COLOR_END:
+                       vc->vc_par[i] -= CSI_m_FG_COLOR_BEG;
+                       vc->state.color = color_table[vc->vc_par[i]] |
+                               (vc->state.color & 0xf0);
+                       break;
+               case CSI_m_BRIGHT_BG_COLOR_BEG ... CSI_m_BRIGHT_BG_COLOR_END:
+                       vc->vc_par[i] -= CSI_m_BRIGHT_BG_COLOR_OFF;
+                       fallthrough;
+               case CSI_m_BG_COLOR_BEG ... CSI_m_BG_COLOR_END:
+                       vc->vc_par[i] -= CSI_m_BG_COLOR_BEG;
+                       vc->state.color = (color_table[vc->vc_par[i]] << 4) |
+                               (vc->state.color & 0x0f);
                        break;
                }
        update_attr(vc);
@@@ -1832,133 -1862,175 +1862,175 @@@ int mouse_reporting(void
        return vc_cons[fg_console].d->vc_report_mouse;
  }
  
+ enum {
+       CSI_DEC_hl_CURSOR_KEYS  = 1,    /* CKM: cursor keys send ^[Ox/^[[x */
+       CSI_DEC_hl_132_COLUMNS  = 3,    /* COLM: 80/132 mode switch */
+       CSI_DEC_hl_REVERSE_VIDEO = 5,   /* SCNM */
+       CSI_DEC_hl_ORIGIN_MODE  = 6,    /* OM: origin relative/absolute */
+       CSI_DEC_hl_AUTOWRAP     = 7,    /* AWM */
+       CSI_DEC_hl_AUTOREPEAT   = 8,    /* ARM */
+       CSI_DEC_hl_MOUSE_X10    = 9,
+       CSI_DEC_hl_SHOW_CURSOR  = 25,   /* TCEM */
+       CSI_DEC_hl_MOUSE_VT200  = 1000,
+ };
  /* console_lock is held */
- static void set_mode(struct vc_data *vc, int on_off)
+ static void csi_DEC_hl(struct vc_data *vc, bool on_off)
  {
-       int i;
+       unsigned int i;
  
        for (i = 0; i <= vc->vc_npar; i++)
-               if (vc->vc_priv == EPdec) {
-                       switch(vc->vc_par[i]) { /* DEC private modes set/reset */
-                       case 1:                 /* Cursor keys send ^[Ox/^[[x */
-                               if (on_off)
-                                       set_kbd(vc, decckm);
-                               else
-                                       clr_kbd(vc, decckm);
-                               break;
-                       case 3: /* 80/132 mode switch unimplemented */
+               switch (vc->vc_par[i]) {
+               case CSI_DEC_hl_CURSOR_KEYS:
+                       if (on_off)
+                               set_kbd(vc, decckm);
+                       else
+                               clr_kbd(vc, decckm);
+                       break;
+               case CSI_DEC_hl_132_COLUMNS:    /* unimplemented */
  #if 0
-                               vc_resize(deccolm ? 132 : 80, vc->vc_rows);
-                               /* this alone does not suffice; some user mode
-                                  utility has to change the hardware regs */
+                       vc_resize(deccolm ? 132 : 80, vc->vc_rows);
+                       /* this alone does not suffice; some user mode
+                          utility has to change the hardware regs */
  #endif
-                               break;
-                       case 5:                 /* Inverted screen on/off */
-                               if (vc->vc_decscnm != on_off) {
-                                       vc->vc_decscnm = on_off;
-                                       invert_screen(vc, 0,
-                                                       vc->vc_screenbuf_size,
-                                                       false);
-                                       update_attr(vc);
-                               }
-                               break;
-                       case 6:                 /* Origin relative/absolute */
-                               vc->vc_decom = on_off;
-                               gotoxay(vc, 0, 0);
-                               break;
-                       case 7:                 /* Autowrap on/off */
-                               vc->vc_decawm = on_off;
-                               break;
-                       case 8:                 /* Autorepeat on/off */
-                               if (on_off)
-                                       set_kbd(vc, decarm);
-                               else
-                                       clr_kbd(vc, decarm);
-                               break;
-                       case 9:
-                               vc->vc_report_mouse = on_off ? 1 : 0;
-                               break;
-                       case 25:                /* Cursor on/off */
-                               vc->vc_deccm = on_off;
-                               break;
-                       case 1000:
-                               vc->vc_report_mouse = on_off ? 2 : 0;
-                               break;
-                       }
-               } else {
-                       switch(vc->vc_par[i]) { /* ANSI modes set/reset */
-                       case 3:                 /* Monitor (display ctrls) */
-                               vc->vc_disp_ctrl = on_off;
-                               break;
-                       case 4:                 /* Insert Mode on/off */
-                               vc->vc_decim = on_off;
-                               break;
-                       case 20:                /* Lf, Enter == CrLf/Lf */
-                               if (on_off)
-                                       set_kbd(vc, lnm);
-                               else
-                                       clr_kbd(vc, lnm);
-                               break;
+                       break;
+               case CSI_DEC_hl_REVERSE_VIDEO:
+                       if (vc->vc_decscnm != on_off) {
+                               vc->vc_decscnm = on_off;
+                               invert_screen(vc, 0, vc->vc_screenbuf_size,
+                                             false);
+                               update_attr(vc);
                        }
+                       break;
+               case CSI_DEC_hl_ORIGIN_MODE:
+                       vc->vc_decom = on_off;
+                       gotoxay(vc, 0, 0);
+                       break;
+               case CSI_DEC_hl_AUTOWRAP:
+                       vc->vc_decawm = on_off;
+                       break;
+               case CSI_DEC_hl_AUTOREPEAT:
+                       if (on_off)
+                               set_kbd(vc, decarm);
+                       else
+                               clr_kbd(vc, decarm);
+                       break;
+               case CSI_DEC_hl_MOUSE_X10:
+                       vc->vc_report_mouse = on_off ? 1 : 0;
+                       break;
+               case CSI_DEC_hl_SHOW_CURSOR:
+                       vc->vc_deccm = on_off;
+                       break;
+               case CSI_DEC_hl_MOUSE_VT200:
+                       vc->vc_report_mouse = on_off ? 2 : 0;
+                       break;
                }
  }
  
+ enum {
+       CSI_hl_DISPLAY_CTRL     = 3,    /* handle ansi control chars */
+       CSI_hl_INSERT           = 4,    /* IRM: insert/replace */
+       CSI_hl_AUTO_NL          = 20,   /* LNM: Enter == CrLf/Lf */
+ };
  /* console_lock is held */
- static void setterm_command(struct vc_data *vc)
+ static void csi_hl(struct vc_data *vc, bool on_off)
+ {
+       unsigned int i;
+       for (i = 0; i <= vc->vc_npar; i++)
+               switch (vc->vc_par[i]) {        /* ANSI modes set/reset */
+               case CSI_hl_DISPLAY_CTRL:
+                       vc->vc_disp_ctrl = on_off;
+                       break;
+               case CSI_hl_INSERT:
+                       vc->vc_decim = on_off;
+                       break;
+               case CSI_hl_AUTO_NL:
+                       if (on_off)
+                               set_kbd(vc, lnm);
+                       else
+                               clr_kbd(vc, lnm);
+                       break;
+               }
+ }
+ enum CSI_right_square_bracket {
+       CSI_RSB_COLOR_FOR_UNDERLINE             = 1,
+       CSI_RSB_COLOR_FOR_HALF_BRIGHT           = 2,
+       CSI_RSB_MAKE_CUR_COLOR_DEFAULT          = 8,
+       CSI_RSB_BLANKING_INTERVAL               = 9,
+       CSI_RSB_BELL_FREQUENCY                  = 10,
+       CSI_RSB_BELL_DURATION                   = 11,
+       CSI_RSB_BRING_CONSOLE_TO_FRONT          = 12,
+       CSI_RSB_UNBLANK                         = 13,
+       CSI_RSB_VESA_OFF_INTERVAL               = 14,
+       CSI_RSB_BRING_PREV_CONSOLE_TO_FRONT     = 15,
+       CSI_RSB_CURSOR_BLINK_INTERVAL           = 16,
+ };
+ /*
+  * csi_RSB - csi+] (Right Square Bracket) handler
+  *
+  * These are linux console private sequences.
+  *
+  * console_lock is held
+  */
+ static void csi_RSB(struct vc_data *vc)
  {
        switch (vc->vc_par[0]) {
-       case 1: /* set color for underline mode */
+       case CSI_RSB_COLOR_FOR_UNDERLINE:
                if (vc->vc_can_do_color && vc->vc_par[1] < 16) {
                        vc->vc_ulcolor = color_table[vc->vc_par[1]];
                        if (vc->state.underline)
                                update_attr(vc);
                }
                break;
-       case 2: /* set color for half intensity mode */
+       case CSI_RSB_COLOR_FOR_HALF_BRIGHT:
                if (vc->vc_can_do_color && vc->vc_par[1] < 16) {
                        vc->vc_halfcolor = color_table[vc->vc_par[1]];
                        if (vc->state.intensity == VCI_HALF_BRIGHT)
                                update_attr(vc);
                }
                break;
-       case 8: /* store colors as defaults */
+       case CSI_RSB_MAKE_CUR_COLOR_DEFAULT:
                vc->vc_def_color = vc->vc_attr;
                if (vc->vc_hi_font_mask == 0x100)
                        vc->vc_def_color >>= 1;
                default_attr(vc);
                update_attr(vc);
                break;
-       case 9: /* set blanking interval */
+       case CSI_RSB_BLANKING_INTERVAL:
                blankinterval = min(vc->vc_par[1], 60U) * 60;
                poke_blanked_console();
                break;
-       case 10: /* set bell frequency in Hz */
+       case CSI_RSB_BELL_FREQUENCY:
                if (vc->vc_npar >= 1)
                        vc->vc_bell_pitch = vc->vc_par[1];
                else
                        vc->vc_bell_pitch = DEFAULT_BELL_PITCH;
                break;
-       case 11: /* set bell duration in msec */
+       case CSI_RSB_BELL_DURATION:
                if (vc->vc_npar >= 1)
                        vc->vc_bell_duration = (vc->vc_par[1] < 2000) ?
                                msecs_to_jiffies(vc->vc_par[1]) : 0;
                else
                        vc->vc_bell_duration = DEFAULT_BELL_DURATION;
                break;
-       case 12: /* bring specified console to the front */
+       case CSI_RSB_BRING_CONSOLE_TO_FRONT:
                if (vc->vc_par[1] >= 1 && vc_cons_allocated(vc->vc_par[1] - 1))
                        set_console(vc->vc_par[1] - 1);
                break;
-       case 13: /* unblank the screen */
+       case CSI_RSB_UNBLANK:
                poke_blanked_console();
                break;
-       case 14: /* set vesa powerdown interval */
+       case CSI_RSB_VESA_OFF_INTERVAL:
                vesa_off_interval = min(vc->vc_par[1], 60U) * 60 * HZ;
                break;
-       case 15: /* activate the previous console */
+       case CSI_RSB_BRING_PREV_CONSOLE_TO_FRONT:
                set_console(last_console);
                break;
-       case 16: /* set cursor blink duration in msec */
+       case CSI_RSB_CURSOR_BLINK_INTERVAL:
                if (vc->vc_npar >= 1 && vc->vc_par[1] >= 50 &&
                                vc->vc_par[1] <= USHRT_MAX)
                        vc->vc_cur_blink_ms = vc->vc_par[1];
  /* console_lock is held */
  static void csi_at(struct vc_data *vc, unsigned int nr)
  {
-       if (nr > vc->vc_cols - vc->state.x)
-               nr = vc->vc_cols - vc->state.x;
-       else if (!nr)
-               nr = 1;
+       nr = clamp(nr, 1, vc->vc_cols - vc->state.x);
        insert_char(vc, nr);
  }
  
  /* console_lock is held */
- static void csi_L(struct vc_data *vc, unsigned int nr)
+ static void csi_L(struct vc_data *vc)
  {
-       if (nr > vc->vc_rows - vc->state.y)
-               nr = vc->vc_rows - vc->state.y;
-       else if (!nr)
-               nr = 1;
+       unsigned int nr = clamp(vc->vc_par[0], 1, vc->vc_rows - vc->state.y);
        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)
+ static void csi_P(struct vc_data *vc)
  {
-       if (nr > vc->vc_cols - vc->state.x)
-               nr = vc->vc_cols - vc->state.x;
-       else if (!nr)
-               nr = 1;
+       unsigned int nr = clamp(vc->vc_par[0], 1, vc->vc_cols - vc->state.x);
        delete_char(vc, nr);
  }
  
  /* console_lock is held */
- static void csi_M(struct vc_data *vc, unsigned int nr)
+ static void csi_M(struct vc_data *vc)
  {
-       if (nr > vc->vc_rows - vc->state.y)
-               nr = vc->vc_rows - vc->state.y;
-       else if (!nr)
-               nr=1;
+       unsigned int nr = clamp(vc->vc_par[0], 1, vc->vc_rows - vc->state.y);
        con_scroll(vc, vc->state.y, vc->vc_bottom, SM_UP, nr);
        vc->vc_need_wrap = 0;
  }
@@@ -2028,9 -2091,48 +2091,48 @@@ static void restore_cur(struct vc_data 
        vc->vc_need_wrap = 0;
  }
  
- enum { ESnormal, ESesc, ESsquare, ESgetpars, ESfunckey,
-       EShash, ESsetG0, ESsetG1, ESpercent, EScsiignore, ESnonstd,
-       ESpalette, ESosc, ESapc, ESpm, ESdcs };
+ /**
+  * enum vc_ctl_state - control characters state of a vt
+  *
+  * @ESnormal:         initial state, no control characters parsed
+  * @ESesc:            ESC parsed
+  * @ESsquare:         CSI parsed -- modifiers/parameters/ctrl chars expected
+  * @ESgetpars:                CSI parsed -- parameters/ctrl chars expected
+  * @ESfunckey:                CSI [ parsed
+  * @EShash:           ESC # parsed
+  * @ESsetG0:          ESC ( parsed
+  * @ESsetG1:          ESC ) parsed
+  * @ESpercent:                ESC % parsed
+  * @EScsiignore:      CSI [0x20-0x3f] parsed
+  * @ESnonstd:         OSC parsed
+  * @ESpalette:                OSC P parsed
+  * @ESosc:            OSC [0-9] parsed
+  * @ESANSI_first:     first state for ignoring ansi control sequences
+  * @ESapc:            ESC _ parsed
+  * @ESpm:             ESC ^ parsed
+  * @ESdcs:            ESC P parsed
+  * @ESANSI_last:      last state for ignoring ansi control sequences
+  */
+ enum vc_ctl_state {
+       ESnormal,
+       ESesc,
+       ESsquare,
+       ESgetpars,
+       ESfunckey,
+       EShash,
+       ESsetG0,
+       ESsetG1,
+       ESpercent,
+       EScsiignore,
+       ESnonstd,
+       ESpalette,
+       ESosc,
+       ESANSI_first = ESosc,
+       ESapc,
+       ESpm,
+       ESdcs,
+       ESANSI_last = ESdcs,
+ };
  
  /* console_lock is held (except via vc_init()) */
  static void reset_terminal(struct vc_data *vc, int do_clear)
        gotoxy(vc, 0, 0);
        save_cur(vc);
        if (do_clear)
-           csi_J(vc, 2);
+           csi_J(vc, CSI_J_VISIBLE);
  }
  
- static void vc_setGx(struct vc_data *vc, unsigned int which, int c)
+ static void vc_setGx(struct vc_data *vc, unsigned int which, u8 c)
  {
        unsigned char *charset = &vc->state.Gx_charset[which];
  
                vc->vc_translate = set_translate(*charset, vc);
  }
  
- /* is this state an ANSI control string? */
- static bool ansi_control_string(unsigned int state)
+ static bool ansi_control_string(enum vc_ctl_state state)
  {
-       if (state == ESosc || state == ESapc || state == ESpm || state == ESdcs)
-               return true;
-       return false;
+       return state >= ESANSI_first && state <= ESANSI_last;
  }
  
- /* console_lock is held */
- static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
+ enum {
+       ASCII_NULL              = 0,
+       ASCII_BELL              = 7,
+       ASCII_BACKSPACE         = 8,
+       ASCII_IGNORE_FIRST      = ASCII_BACKSPACE,
+       ASCII_HTAB              = 9,
+       ASCII_LINEFEED          = 10,
+       ASCII_VTAB              = 11,
+       ASCII_FORMFEED          = 12,
+       ASCII_CAR_RET           = 13,
+       ASCII_IGNORE_LAST       = ASCII_CAR_RET,
+       ASCII_SHIFTOUT          = 14,
+       ASCII_SHIFTIN           = 15,
+       ASCII_CANCEL            = 24,
+       ASCII_SUBSTITUTE        = 26,
+       ASCII_ESCAPE            = 27,
+       ASCII_CSI_IGNORE_FIRST  = ' ', /* 0x2x, 0x3a and 0x3c - 0x3f */
+       ASCII_CSI_IGNORE_LAST   = '?',
+       ASCII_DEL               = 127,
+       ASCII_EXT_CSI           = 128 + ASCII_ESCAPE,
+ };
+ /*
+  * Handle ascii characters in control sequences and change states accordingly.
+  * E.g. ESC sets the state of vc to ESesc.
+  *
+  * Returns: true if @c handled.
+  */
+ static bool handle_ascii(struct tty_struct *tty, struct vc_data *vc, u8 c)
  {
-       /*
-        *  Control characters can be used in the _middle_
-        *  of an escape sequence, aside from ANSI control strings.
-        */
-       if (ansi_control_string(vc->vc_state) && c >= 8 && c <= 13)
-               return;
        switch (c) {
-       case 0:
-               return;
-       case 7:
+       case ASCII_NULL:
+               return true;
+       case ASCII_BELL:
                if (ansi_control_string(vc->vc_state))
                        vc->vc_state = ESnormal;
                else if (vc->vc_bell_duration)
                        kd_mksound(vc->vc_bell_pitch, vc->vc_bell_duration);
-               return;
-       case 8:
+               return true;
+       case ASCII_BACKSPACE:
                bs(vc);
-               return;
-       case 9:
+               return true;
+       case ASCII_HTAB:
                vc->vc_pos -= (vc->state.x << 1);
  
                vc->state.x = find_next_bit(vc->vc_tab_stop,
  
                vc->vc_pos += (vc->state.x << 1);
                notify_write(vc, '\t');
-               return;
-       case 10: case 11: case 12:
+               return true;
+       case ASCII_LINEFEED:
+       case ASCII_VTAB:
+       case ASCII_FORMFEED:
                lf(vc);
                if (!is_kbd(vc, lnm))
-                       return;
+                       return true;
                fallthrough;
-       case 13:
+       case ASCII_CAR_RET:
                cr(vc);
-               return;
-       case 14:
+               return true;
+       case ASCII_SHIFTOUT:
                vc->state.charset = 1;
                vc->vc_translate = set_translate(vc->state.Gx_charset[1], vc);
                vc->vc_disp_ctrl = 1;
-               return;
-       case 15:
+               return true;
+       case ASCII_SHIFTIN:
                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:
+               return true;
+       case ASCII_CANCEL:
+       case ASCII_SUBSTITUTE:
                vc->vc_state = ESnormal;
-               return;
-       case 27:
+               return true;
+       case ASCII_ESCAPE:
                vc->vc_state = ESesc;
-               return;
-       case 127:
+               return true;
+       case ASCII_DEL:
                del(vc);
-               return;
-       case 128+27:
+               return true;
+       case ASCII_EXT_CSI:
                vc->vc_state = ESsquare;
-               return;
+               return true;
        }
-       switch(vc->vc_state) {
-       case ESesc:
-               vc->vc_state = ESnormal;
-               switch (c) {
-               case '[':
-                       vc->vc_state = ESsquare;
-                       return;
-               case ']':
-                       vc->vc_state = ESnonstd;
-                       return;
-               case '_':
-                       vc->vc_state = ESapc;
-                       return;
-               case '^':
-                       vc->vc_state = ESpm;
-                       return;
-               case '%':
-                       vc->vc_state = ESpercent;
-                       return;
-               case 'E':
-                       cr(vc);
-                       lf(vc);
-                       return;
-               case 'M':
-                       ri(vc);
-                       return;
-               case 'D':
-                       lf(vc);
-                       return;
-               case 'H':
-                       if (vc->state.x < VC_TABSTOPS_COUNT)
-                               set_bit(vc->state.x, vc->vc_tab_stop);
-                       return;
-               case 'P':
-                       vc->vc_state = ESdcs;
-                       return;
-               case 'Z':
+       return false;
+ }
+ /*
+  * Handle a character (@c) following an ESC (when @vc is in the ESesc state).
+  * E.g. previous ESC with @c == '[' here yields the ESsquare state (that is:
+  * CSI).
+  */
+ static void handle_esc(struct tty_struct *tty, struct vc_data *vc, u8 c)
+ {
+       vc->vc_state = ESnormal;
+       switch (c) {
+       case '[':
+               vc->vc_state = ESsquare;
+               break;
+       case ']':
+               vc->vc_state = ESnonstd;
+               break;
+       case '_':
+               vc->vc_state = ESapc;
+               break;
+       case '^':
+               vc->vc_state = ESpm;
+               break;
+       case '%':
+               vc->vc_state = ESpercent;
+               break;
+       case 'E':
+               cr(vc);
+               lf(vc);
+               break;
+       case 'M':
+               ri(vc);
+               break;
+       case 'D':
+               lf(vc);
+               break;
+       case 'H':
+               if (vc->state.x < VC_TABSTOPS_COUNT)
+                       set_bit(vc->state.x, vc->vc_tab_stop);
+               break;
+       case 'P':
+               vc->vc_state = ESdcs;
+               break;
+       case 'Z':
+               respond_ID(tty);
+               break;
+       case '7':
+               save_cur(vc);
+               break;
+       case '8':
+               restore_cur(vc);
+               break;
+       case '(':
+               vc->vc_state = ESsetG0;
+               break;
+       case ')':
+               vc->vc_state = ESsetG1;
+               break;
+       case '#':
+               vc->vc_state = EShash;
+               break;
+       case 'c':
+               reset_terminal(vc, 1);
+               break;
+       case '>':  /* Numeric keypad */
+               clr_kbd(vc, kbdapplic);
+               break;
+       case '=':  /* Appl. keypad */
+               set_kbd(vc, kbdapplic);
+               break;
+       }
+ }
+ /*
+  * Handle special DEC control sequences ("ESC [ ? parameters char"). Parameters
+  * are in @vc->vc_par and the char is in @c here.
+  */
+ static void csi_DEC(struct tty_struct *tty, struct vc_data *vc, u8 c)
+ {
+       switch (c) {
+       case 'h':
+               csi_DEC_hl(vc, true);
+               break;
+       case 'l':
+               csi_DEC_hl(vc, false);
+               break;
+       case 'c':
+               if (vc->vc_par[0])
+                       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;
+               break;
+       case 'm':
+               clear_selection();
+               if (vc->vc_par[0])
+                       vc->vc_complement_mask = vc->vc_par[0] << 8 | vc->vc_par[1];
+               else
+                       vc->vc_complement_mask = vc->vc_s_complement_mask;
+               break;
+       case 'n':
+               if (vc->vc_par[0] == 5)
+                       status_report(tty);
+               else if (vc->vc_par[0] == 6)
+                       cursor_report(vc, tty);
+               break;
+       }
+ }
+ /*
+  * Handle Control Sequence Introducer control characters. That is
+  * "ESC [ parameters char". Parameters are in @vc->vc_par and the char is in
+  * @c here.
+  */
+ static void csi_ECMA(struct tty_struct *tty, struct vc_data *vc, u8 c)
+ {
+       switch (c) {
+       case 'G':
+       case '`':
+               if (vc->vc_par[0])
+                       vc->vc_par[0]--;
+               gotoxy(vc, vc->vc_par[0], vc->state.y);
+               break;
+       case 'A':
+               if (!vc->vc_par[0])
+                       vc->vc_par[0]++;
+               gotoxy(vc, vc->state.x, vc->state.y - vc->vc_par[0]);
+               break;
+       case 'B':
+       case 'e':
+               if (!vc->vc_par[0])
+                       vc->vc_par[0]++;
+               gotoxy(vc, vc->state.x, vc->state.y + vc->vc_par[0]);
+               break;
+       case 'C':
+       case 'a':
+               if (!vc->vc_par[0])
+                       vc->vc_par[0]++;
+               gotoxy(vc, vc->state.x + vc->vc_par[0], vc->state.y);
+               break;
+       case 'D':
+               if (!vc->vc_par[0])
+                       vc->vc_par[0]++;
+               gotoxy(vc, vc->state.x - vc->vc_par[0], vc->state.y);
+               break;
+       case 'E':
+               if (!vc->vc_par[0])
+                       vc->vc_par[0]++;
+               gotoxy(vc, 0, vc->state.y + vc->vc_par[0]);
+               break;
+       case 'F':
+               if (!vc->vc_par[0])
+                       vc->vc_par[0]++;
+               gotoxy(vc, 0, vc->state.y - vc->vc_par[0]);
+               break;
+       case 'd':
+               if (vc->vc_par[0])
+                       vc->vc_par[0]--;
+               gotoxay(vc, vc->state.x ,vc->vc_par[0]);
+               break;
+       case 'H':
+       case 'f':
+               if (vc->vc_par[0])
+                       vc->vc_par[0]--;
+               if (vc->vc_par[1])
+                       vc->vc_par[1]--;
+               gotoxay(vc, vc->vc_par[1], vc->vc_par[0]);
+               break;
+       case 'J':
+               csi_J(vc, vc->vc_par[0]);
+               break;
+       case 'K':
+               csi_K(vc);
+               break;
+       case 'L':
+               csi_L(vc);
+               break;
+       case 'M':
+               csi_M(vc);
+               break;
+       case 'P':
+               csi_P(vc);
+               break;
+       case 'c':
+               if (!vc->vc_par[0])
                        respond_ID(tty);
-                       return;
-               case '7':
-                       save_cur(vc);
-                       return;
-               case '8':
-                       restore_cur(vc);
-                       return;
-               case '(':
-                       vc->vc_state = ESsetG0;
-                       return;
-               case ')':
-                       vc->vc_state = ESsetG1;
-                       return;
-               case '#':
-                       vc->vc_state = EShash;
-                       return;
-               case 'c':
-                       reset_terminal(vc, 1);
-                       return;
-               case '>':  /* Numeric keypad */
-                       clr_kbd(vc, kbdapplic);
-                       return;
-               case '=':  /* Appl. keypad */
-                       set_kbd(vc, kbdapplic);
-                       return;
+               break;
+       case 'g':
+               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);
+               break;
+       case 'h':
+               csi_hl(vc, true);
+               break;
+       case 'l':
+               csi_hl(vc, false);
+               break;
+       case 'm':
+               csi_m(vc);
+               break;
+       case 'n':
+               if (vc->vc_par[0] == 5)
+                       status_report(tty);
+               else if (vc->vc_par[0] == 6)
+                       cursor_report(vc, tty);
+               break;
+       case 'q': /* DECLL - but only 3 leds */
+               /* map 0,1,2,3 to 0,1,2,4 */
+               if (vc->vc_par[0] < 4)
+                       vt_set_led_state(vc->vc_num,
+                                   (vc->vc_par[0] < 3) ? vc->vc_par[0] : 4);
+               break;
+       case 'r':
+               if (!vc->vc_par[0])
+                       vc->vc_par[0]++;
+               if (!vc->vc_par[1])
+                       vc->vc_par[1] = vc->vc_rows;
+               /* Minimum allowed region is 2 lines */
+               if (vc->vc_par[0] < vc->vc_par[1] &&
+                   vc->vc_par[1] <= vc->vc_rows) {
+                       vc->vc_top = vc->vc_par[0] - 1;
+                       vc->vc_bottom = vc->vc_par[1];
+                       gotoxay(vc, 0, 0);
                }
+               break;
+       case 's':
+               save_cur(vc);
+               break;
+       case 'u':
+               restore_cur(vc);
+               break;
+       case 'X':
+               csi_X(vc);
+               break;
+       case '@':
+               csi_at(vc, vc->vc_par[0]);
+               break;
+       case ']':
+               csi_RSB(vc);
+               break;
+       }
+ }
+ static void vc_reset_params(struct vc_data *vc)
+ {
+       memset(vc->vc_par, 0, sizeof(vc->vc_par));
+       vc->vc_npar = 0;
+ }
+ /* console_lock is held */
+ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, u8 c)
+ {
+       /*
+        *  Control characters can be used in the _middle_
+        *  of an escape sequence, aside from ANSI control strings.
+        */
+       if (ansi_control_string(vc->vc_state) && c >= ASCII_IGNORE_FIRST &&
+           c <= ASCII_IGNORE_LAST)
+               return;
+       if (handle_ascii(tty, vc, c))
+               return;
+       switch(vc->vc_state) {
+       case ESesc:     /* ESC */
+               handle_esc(tty, vc, c);
                return;
-       case ESnonstd:
-               if (c=='P') {   /* palette escape sequence */
-                       for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++)
-                               vc->vc_par[vc->vc_npar] = 0;
-                       vc->vc_npar = 0;
+       case ESnonstd:  /* ESC ] aka OSC */
+               switch (c) {
+               case 'P': /* palette escape sequence */
+                       vc_reset_params(vc);
                        vc->vc_state = ESpalette;
                        return;
-               } else if (c=='R') {   /* reset palette */
+               case 'R': /* reset palette */
                        reset_palette(vc);
-                       vc->vc_state = ESnormal;
-               } else if (c>='0' && c<='9')
+                       break;
+               case '0' ... '9':
                        vc->vc_state = ESosc;
-               else
-                       vc->vc_state = ESnormal;
+                       return;
+               }
+               vc->vc_state = ESnormal;
                return;
-       case ESpalette:
+       case ESpalette: /* ESC ] P aka OSC P */
                if (isxdigit(c)) {
                        vc->vc_par[vc->vc_npar++] = hex_to_bin(c);
                        if (vc->vc_npar == 7) {
                } else
                        vc->vc_state = ESnormal;
                return;
-       case ESsquare:
-               for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++)
-                       vc->vc_par[vc->vc_npar] = 0;
-               vc->vc_npar = 0;
+       case ESsquare:  /* ESC [ aka CSI, parameters or modifiers expected */
+               vc_reset_params(vc);
                vc->vc_state = ESgetpars;
-               if (c == '[') { /* Function key */
-                       vc->vc_state=ESfunckey;
-                       return;
-               }
                switch (c) {
+               case '[': /* Function key */
+                       vc->vc_state = ESfunckey;
+                       return;
                case '?':
                        vc->vc_priv = EPdec;
                        return;
                }
                vc->vc_priv = EPecma;
                fallthrough;
-       case ESgetpars:
-               if (c == ';' && vc->vc_npar < NPAR - 1) {
-                       vc->vc_npar++;
-                       return;
-               } else if (c>='0' && c<='9') {
+       case ESgetpars: /* ESC [ aka CSI, parameters expected */
+               switch (c) {
+               case ';':
+                       if (vc->vc_npar < NPAR - 1) {
+                               vc->vc_npar++;
+                               return;
+                       }
+                       break;
+               case '0' ... '9':
                        vc->vc_par[vc->vc_npar] *= 10;
                        vc->vc_par[vc->vc_npar] += c - '0';
                        return;
                }
-               if (c >= 0x20 && c <= 0x3f) { /* 0x2x, 0x3a and 0x3c - 0x3f */
+               if (c >= ASCII_CSI_IGNORE_FIRST && c <= ASCII_CSI_IGNORE_LAST) {
                        vc->vc_state = EScsiignore;
                        return;
                }
+               /* parameters done, handle the control char @c */
                vc->vc_state = ESnormal;
-               switch(c) {
-               case 'h':
-                       if (vc->vc_priv <= EPdec)
-                               set_mode(vc, 1);
-                       return;
-               case 'l':
-                       if (vc->vc_priv <= EPdec)
-                               set_mode(vc, 0);
-                       return;
-               case 'c':
-                       if (vc->vc_priv == EPdec) {
-                               if (vc->vc_par[0])
-                                       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;
-                       }
-                       break;
-               case 'm':
-                       if (vc->vc_priv == EPdec) {
-                               clear_selection();
-                               if (vc->vc_par[0])
-                                       vc->vc_complement_mask = vc->vc_par[0] << 8 | vc->vc_par[1];
-                               else
-                                       vc->vc_complement_mask = vc->vc_s_complement_mask;
-                               return;
-                       }
-                       break;
-               case 'n':
-                       if (vc->vc_priv == EPecma) {
-                               if (vc->vc_par[0] == 5)
-                                       status_report(tty);
-                               else if (vc->vc_par[0] == 6)
-                                       cursor_report(vc, tty);
-                       }
-                       return;
-               }
-               if (vc->vc_priv != EPecma) {
-                       vc->vc_priv = EPecma;
-                       return;
-               }
-               switch(c) {
-               case 'G': case '`':
-                       if (vc->vc_par[0])
-                               vc->vc_par[0]--;
-                       gotoxy(vc, vc->vc_par[0], vc->state.y);
-                       return;
-               case 'A':
-                       if (!vc->vc_par[0])
-                               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->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->state.x + vc->vc_par[0], vc->state.y);
-                       return;
-               case 'D':
-                       if (!vc->vc_par[0])
-                               vc->vc_par[0]++;
-                       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->state.y + vc->vc_par[0]);
-                       return;
-               case 'F':
-                       if (!vc->vc_par[0])
-                               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->state.x ,vc->vc_par[0]);
-                       return;
-               case 'H': case 'f':
-                       if (vc->vc_par[0])
-                               vc->vc_par[0]--;
-                       if (vc->vc_par[1])
-                               vc->vc_par[1]--;
-                       gotoxay(vc, vc->vc_par[1], vc->vc_par[0]);
-                       return;
-               case 'J':
-                       csi_J(vc, vc->vc_par[0]);
-                       return;
-               case 'K':
-                       csi_K(vc, vc->vc_par[0]);
-                       return;
-               case 'L':
-                       csi_L(vc, vc->vc_par[0]);
-                       return;
-               case 'M':
-                       csi_M(vc, vc->vc_par[0]);
-                       return;
-               case 'P':
-                       csi_P(vc, vc->vc_par[0]);
-                       return;
-               case 'c':
-                       if (!vc->vc_par[0])
-                               respond_ID(tty);
-                       return;
-               case 'g':
-                       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);
-                       return;
-               case 'q': /* DECLL - but only 3 leds */
-                       /* map 0,1,2,3 to 0,1,2,4 */
-                       if (vc->vc_par[0] < 4)
-                               vt_set_led_state(vc->vc_num,
-                                           (vc->vc_par[0] < 3) ? vc->vc_par[0] : 4);
-                       return;
-               case 'r':
-                       if (!vc->vc_par[0])
-                               vc->vc_par[0]++;
-                       if (!vc->vc_par[1])
-                               vc->vc_par[1] = vc->vc_rows;
-                       /* Minimum allowed region is 2 lines */
-                       if (vc->vc_par[0] < vc->vc_par[1] &&
-                           vc->vc_par[1] <= vc->vc_rows) {
-                               vc->vc_top = vc->vc_par[0] - 1;
-                               vc->vc_bottom = vc->vc_par[1];
-                               gotoxay(vc, 0, 0);
-                       }
-                       return;
-               case 's':
-                       save_cur(vc);
-                       return;
-               case 'u':
-                       restore_cur(vc);
-                       return;
-               case 'X':
-                       csi_X(vc, vc->vc_par[0]);
+               switch (vc->vc_priv) {
+               case EPdec:
+                       csi_DEC(tty, vc, c);
                        return;
-               case '@':
-                       csi_at(vc, vc->vc_par[0]);
+               case EPecma:
+                       csi_ECMA(tty, vc, c);
                        return;
-               case ']': /* setterm functions */
-                       setterm_command(vc);
+               default:
                        return;
                }
-               return;
        case EScsiignore:
-               if (c >= 20 && c <= 0x3f)
+               if (c >= ASCII_CSI_IGNORE_FIRST && c <= ASCII_CSI_IGNORE_LAST)
                        return;
                vc->vc_state = ESnormal;
                return;
-       case ESpercent:
+       case ESpercent: /* ESC % */
                vc->vc_state = ESnormal;
                switch (c) {
                case '@':  /* defined in ISO 2022 */
                        return;
                }
                return;
-       case ESfunckey:
+       case ESfunckey: /* ESC [ [ aka CSI [ */
                vc->vc_state = ESnormal;
                return;
-       case EShash:
+       case EShash:    /* ESC # */
                vc->vc_state = ESnormal;
                if (c == '8') {
                        /* DEC screen alignment test. kludge :-) */
                        vc->vc_video_erase_char =
                                (vc->vc_video_erase_char & 0xff00) | 'E';
-                       csi_J(vc, 2);
+                       csi_J(vc, CSI_J_VISIBLE);
                        vc->vc_video_erase_char =
                                (vc->vc_video_erase_char & 0xff00) | ' ';
                        do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
                }
                return;
-       case ESsetG0:
+       case ESsetG0:   /* ESC ( */
                vc_setGx(vc, 0, c);
                vc->vc_state = ESnormal;
                return;
-       case ESsetG1:
+       case ESsetG1:   /* ESC ) */
                vc_setGx(vc, 1, c);
                vc->vc_state = ESnormal;
                return;
-       case ESapc:
+       case ESapc:     /* ESC _ */
                return;
-       case ESosc:
+       case ESosc:     /* ESC ] [0-9] aka OSC [0-9] */
                return;
-       case ESpm:
+       case ESpm:      /* ESC ^ */
                return;
-       case ESdcs:
+       case ESdcs:     /* ESC P */
                return;
        default:
                vc->vc_state = ESnormal;
@@@ -2588,33 -2779,39 +2779,39 @@@ static inline int vc_translate_ascii(co
  
  
  /**
-  * vc_sanitize_unicode - Replace invalid Unicode code points with U+FFFD
-  * @c: the received character, or U+FFFD for invalid sequences.
+  * vc_sanitize_unicode - Replace invalid Unicode code points with ``U+FFFD``
+  * @c: the received code point
   */
  static inline int vc_sanitize_unicode(const int c)
  {
-       if ((c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff)
+       if (c >= 0xd800 && c <= 0xdfff)
                return 0xfffd;
  
        return c;
  }
  
  /**
-  * vc_translate_unicode - Combine UTF-8 into Unicode in @vc_utf_char
+  * vc_translate_unicode - Combine UTF-8 into Unicode in &vc_data.vc_utf_char
   * @vc: virtual console
-  * @c: character to translate
-  * @rescan: we return true if we need more (continuation) data
+  * @c: UTF-8 byte to translate
+  * @rescan: set to true iff @c wasn't consumed here and needs to be re-processed
+  *
+  * * &vc_data.vc_utf_char is the being-constructed Unicode code point.
+  * * &vc_data.vc_utf_count is the number of continuation bytes still expected to
+  *   arrive.
+  * * &vc_data.vc_npar is the number of continuation bytes arrived so far.
   *
-  * @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.
+  * Return:
+  * * %-1 - Input OK so far, @c consumed, further bytes expected.
+  * * %0xFFFD - Possibility 1: input invalid, @c may have been consumed (see
+  *             desc. of @rescan). Possibility 2: input OK, @c consumed,
+  *             ``U+FFFD`` is the resulting code point. ``U+FFFD`` is valid,
+  *             ``REPLACEMENT CHARACTER``.
+  * * otherwise - Input OK, @c consumed, resulting code point returned.
   */
  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
-       };
+       static const u32 utf8_length_changes[] = {0x7f, 0x7ff, 0xffff, 0x10ffff};
  
        /* Continuation byte received */
        if ((c & 0xc0) == 0x80) {
        } 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;
        }
  
@@@ -2711,9 -2901,13 +2901,13 @@@ static bool vc_is_control(struct vc_dat
         * 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;
+       static const u32 CTRL_ACTION = BIT(ASCII_NULL) |
+               GENMASK(ASCII_SHIFTIN, ASCII_BELL) | BIT(ASCII_CANCEL) |
+               BIT(ASCII_SUBSTITUTE) | BIT(ASCII_ESCAPE);
        /* Cannot be overridden by disp_ctrl */
-       static const u32 CTRL_ALWAYS = 0x0800f501;
+       static const u32 CTRL_ALWAYS = BIT(ASCII_NULL) | BIT(ASCII_BACKSPACE) |
+               BIT(ASCII_LINEFEED) | BIT(ASCII_SHIFTIN) | BIT(ASCII_SHIFTOUT) |
+               BIT(ASCII_CAR_RET) | BIT(ASCII_FORMFEED) | BIT(ASCII_ESCAPE);
  
        if (vc->vc_state != ESnormal)
                return true;
         * useless without them; to display an arbitrary font position use the
         * direct-to-font zone in UTF-8 mode.
         */
-       if (c < 32) {
+       if (c < BITS_PER_TYPE(CTRL_ALWAYS)) {
                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)
+       if (c == ASCII_DEL && !vc->vc_disp_ctrl)
                return true;
  
-       if (c == 128 + 27)
+       if (c == ASCII_EXT_CSI)
                return true;
  
        return false;
@@@ -2852,7 -3046,7 +3046,7 @@@ static int do_con_write(struct tty_stru
        };
        int c, tc, n = 0;
        unsigned int currcons;
-       struct vc_data *vc;
+       struct vc_data *vc = tty->driver_data;
        struct vt_notifier_param param;
        bool rescan;
  
                return count;
  
        console_lock();
-       vc = tty->driver_data;
-       if (vc == NULL) {
-               pr_err("vt: argh, driver_data is NULL !\n");
-               console_unlock();
-               return 0;
-       }
        currcons = vc->vc_num;
        if (!vc_cons_allocated(currcons)) {
                /* could this happen? */
        param.vc = vc;
  
        while (!tty->flow.stopped && count) {
-               int orig = *buf;
+               u8 orig = *buf;
                buf++;
                n++;
                count--;
@@@ -2992,16 -3179,16 +3179,16 @@@ struct tty_driver *console_driver
  #ifdef CONFIG_VT_CONSOLE
  
  /**
-  * vt_kmsg_redirect() - Sets/gets the kernel message console
-  * @new:      The new virtual terminal number or -1 if the console should stay
-  *            unchanged
+  * vt_kmsg_redirect() - sets/gets the kernel message console
+  * @new: the new virtual terminal number or -1 if the console should stay
+  *    unchanged
   *
   * By default, the kernel messages are always printed on the current virtual
   * console. However, the user may modify that default with the
-  * TIOCL_SETKMSGREDIRECT ioctl call.
+  * %TIOCL_SETKMSGREDIRECT ioctl call.
   *
   * This function sets the kernel message console to be @new. It returns the old
-  * virtual console number. The virtual terminal number 0 (both as parameter and
+  * virtual console number. The virtual terminal number %0 (both as parameter and
   * return value) means no redirection (i.e. always printed on the currently
   * active console).
   *
   * value is not modified. You may use the macro vt_get_kmsg_redirect() in that
   * case to make the code more understandable.
   *
-  * When the kernel is compiled without CONFIG_VT_CONSOLE, this function ignores
-  * the parameter and always returns 0.
+  * When the kernel is compiled without %CONFIG_VT_CONSOLE, this function ignores
+  * the parameter and always returns %0.
   */
  int vt_kmsg_redirect(int new)
  {
@@@ -3065,22 -3252,23 +3252,23 @@@ static void vt_console_print(struct con
        cnt = 0;
        while (count--) {
                c = *b++;
-               if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) {
+               if (c == ASCII_LINEFEED || c == ASCII_CAR_RET ||
+                   c == ASCII_BACKSPACE || vc->vc_need_wrap) {
                        if (cnt && con_is_visible(vc))
                                vc->vc_sw->con_putcs(vc, start, cnt, vc->state.y, start_x);
                        cnt = 0;
-                       if (c == 8) {           /* backspace */
+                       if (c == ASCII_BACKSPACE) {
                                bs(vc);
                                start = (ushort *)vc->vc_pos;
                                start_x = vc->state.x;
                                continue;
                        }
-                       if (c != 13)
+                       if (c != ASCII_CAR_RET)
                                lf(vc);
                        cr(vc);
                        start = (ushort *)vc->vc_pos;
                        start_x = vc->state.x;
-                       if (c == 10 || c == 13)
+                       if (c == ASCII_LINEFEED || c == ASCII_CAR_RET)
                                continue;
                }
                vc_uniscr_putc(vc, c);
@@@ -3144,6 -3332,8 +3332,8 @@@ int tioclinux(struct tty_struct *tty, u
  {
        char type, data;
        char __user *p = (char __user *)arg;
+       void __user *param_aligned32 = (u32 __user *)arg + 1;
+       void __user *param = (void __user *)arg + 1;
        int lines;
        int ret;
  
        case TIOCL_SETSEL:
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
-               return set_selection_user((struct tiocl_selection
-                                        __user *)(p+1), tty);
+               return set_selection_user(param, tty);
        case TIOCL_PASTESEL:
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
        case TIOCL_SELLOADLUT:
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
-               console_lock();
-               ret = sel_loadlut(p);
-               console_unlock();
-               break;
+               return sel_loadlut(param_aligned32);
        case TIOCL_GETSHIFTSTATE:
                /*
                 * Make it possible to react to Shift+Mousebutton. Note that
                console_unlock();
                return put_user(data, p);
        case TIOCL_SETVESABLANK:
-               console_lock();
-               ret = set_vesa_blanking(p);
-               console_unlock();
-               break;
+               return set_vesa_blanking(param);
        case TIOCL_GETKMSGREDIRECT:
                data = vt_get_kmsg_redirect();
                return put_user(data, p);
                 */
                return fg_console;
        case TIOCL_SCROLLCONSOLE:
-               if (get_user(lines, (s32 __user *)(p+4)))
+               if (get_user(lines, (s32 __user *)param_aligned32))
                        return -EFAULT;
  
                /*
@@@ -3312,16 -3495,13 +3495,13 @@@ static void con_start(struct tty_struc
  
  static void con_flush_chars(struct tty_struct *tty)
  {
-       struct vc_data *vc;
+       struct vc_data *vc = tty->driver_data;
  
        if (in_interrupt())     /* from flush_to_ldisc */
                return;
  
-       /* if we race with con_close(), vt may be null */
        console_lock();
-       vc = tty->driver_data;
-       if (vc)
-               set_cursor(vc);
+       set_cursor(vc);
        console_unlock();
  }
  
@@@ -3471,7 -3651,7 +3651,7 @@@ static int __init con_init(void
                vc_cons[currcons].d = vc = kzalloc(sizeof(struct vc_data), GFP_NOWAIT);
                INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
                tty_port_init(&vc->port);
-               visual_init(vc, currcons, 1);
+               visual_init(vc, currcons, true);
                /* Assuming vc->vc_{cols,rows,screenbuf_size} are sane here. */
                vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT);
                vc_init(vc, currcons || !vc->vc_sw->con_save_screen);
        set_origin(vc);
        save_screen(vc);
        gotoxy(vc, vc->state.x, vc->state.y);
-       csi_J(vc, 0);
+       csi_J(vc, CSI_J_CURSOR_TO_END);
        update_screen(vc);
        pr_info("Console: %s %s %dx%d\n",
                vc->vc_can_do_color ? "colour" : "mono",
@@@ -3640,7 -3820,7 +3820,7 @@@ static int do_bind_con_driver(const str
                old_was_color = vc->vc_can_do_color;
                vc->vc_sw->con_deinit(vc);
                vc->vc_origin = (unsigned long)vc->vc_screenbuf;
-               visual_init(vc, i, 0);
+               visual_init(vc, i, false);
                set_origin(vc);
                update_attr(vc);
  
@@@ -3930,7 -4110,7 +4110,7 @@@ static void vtconsole_deinit_device(str
   * RETURNS: zero if unbound, nonzero if bound
   *
   * Drivers can call this and if zero, they should release
-  * all resources allocated on con_startup()
+  * all resources allocated on &consw.con_startup()
   */
  int con_is_bound(const struct consw *csw)
  {
@@@ -3970,15 -4150,9 +4150,9 @@@ EXPORT_SYMBOL(con_is_visible)
   * Called when the console is taken over by the kernel debugger, this
   * function needs to save the current console state, then put the console
   * into a state suitable for the kernel debugger.
-  *
-  * RETURNS:
-  * Zero on success, nonzero if a failure occurred when trying to prepare
-  * the console for the debugger.
   */
int con_debug_enter(struct vc_data *vc)
void con_debug_enter(struct vc_data *vc)
  {
-       int ret = 0;
        saved_fg_console = fg_console;
        saved_last_console = last_console;
        saved_want_console = want_console;
        vc->vc_mode = KD_TEXT;
        console_blanked = 0;
        if (vc->vc_sw->con_debug_enter)
-               ret = vc->vc_sw->con_debug_enter(vc);
+               vc->vc_sw->con_debug_enter(vc);
  #ifdef CONFIG_KGDB_KDB
        /* Set the initial LINES variable if it is not already set */
        if (vc->vc_rows < 999) {
                }
        }
  #endif /* CONFIG_KGDB_KDB */
-       return ret;
  }
  EXPORT_SYMBOL_GPL(con_debug_enter);
  
   *
   * Restore the console state to what it was before the kernel debugger
   * was invoked.
-  *
-  * RETURNS:
-  * Zero on success, nonzero if a failure occurred when trying to restore
-  * the console.
   */
int con_debug_leave(void)
void con_debug_leave(void)
  {
        struct vc_data *vc;
-       int ret = 0;
  
        fg_console = saved_fg_console;
        last_console = saved_last_console;
  
        vc = vc_cons[fg_console].d;
        if (vc->vc_sw->con_debug_leave)
-               ret = vc->vc_sw->con_debug_leave(vc);
-       return ret;
+               vc->vc_sw->con_debug_leave(vc);
  }
  EXPORT_SYMBOL_GPL(con_debug_leave);
  
@@@ -4275,14 -4442,17 +4442,17 @@@ postcore_initcall(vtconsole_class_init)
   *    Screen blanking
   */
  
- static int set_vesa_blanking(char __user *p)
+ static int set_vesa_blanking(u8 __user *mode_user)
  {
-       unsigned int mode;
+       u8 mode;
  
-       if (get_user(mode, p + 1))
+       if (get_user(mode, mode_user))
                return -EFAULT;
  
-       vesa_blank_mode = (mode < 4) ? mode : 0;
+       console_lock();
+       vesa_blank_mode = (mode <= VESA_BLANK_MAX) ? mode : VESA_NO_BLANKING;
+       console_unlock();
        return 0;
  }
  
@@@ -4307,7 -4477,7 +4477,7 @@@ void do_blank_screen(int entering_gfx
        if (entering_gfx) {
                hide_cursor(vc);
                save_screen(vc);
-               vc->vc_sw->con_blank(vc, -1, 1);
+               vc->vc_sw->con_blank(vc, VESA_VSYNC_SUSPEND, 1);
                console_blanked = fg_console + 1;
                blank_state = blank_off;
                set_origin(vc);
  
        save_screen(vc);
        /* In case we need to reset origin, blanking hook returns 1 */
-       i = vc->vc_sw->con_blank(vc, vesa_off_interval ? 1 : (vesa_blank_mode + 1), 0);
+       i = vc->vc_sw->con_blank(vc, vesa_off_interval ? VESA_VSYNC_SUSPEND :
+                                (vesa_blank_mode + 1), 0);
        console_blanked = fg_console + 1;
        if (i)
                set_origin(vc);
@@@ -4379,7 -4550,7 +4550,7 @@@ void do_unblank_screen(int leaving_gfx
        }
  
        console_blanked = 0;
-       if (vc->vc_sw->con_blank(vc, 0, leaving_gfx))
+       if (vc->vc_sw->con_blank(vc, VESA_NO_BLANKING, leaving_gfx))
                /* Low-level driver cannot restore -> do it ourselves */
                update_screen(vc);
        if (console_blank_hook)
@@@ -4584,7 -4755,7 +4755,7 @@@ out
        return rc;
  }
  
- static int con_font_set(struct vc_data *vc, struct console_font_op *op)
+ static int con_font_set(struct vc_data *vc, const struct console_font_op *op)
  {
        struct console_font font;
        int rc = -EINVAL;
@@@ -4748,43 -4919,3 +4919,3 @@@ void vcs_scr_updated(struct vc_data *vc
  {
        notify_update(vc);
  }
- void vc_scrolldelta_helper(struct vc_data *c, int lines,
-               unsigned int rolled_over, void *base, unsigned int size)
- {
-       unsigned long ubase = (unsigned long)base;
-       ptrdiff_t scr_end = (void *)c->vc_scr_end - base;
-       ptrdiff_t vorigin = (void *)c->vc_visible_origin - base;
-       ptrdiff_t origin = (void *)c->vc_origin - base;
-       int margin = c->vc_size_row * 4;
-       int from, wrap, from_off, avail;
-       /* Turn scrollback off */
-       if (!lines) {
-               c->vc_visible_origin = c->vc_origin;
-               return;
-       }
-       /* Do we have already enough to allow jumping from 0 to the end? */
-       if (rolled_over > scr_end + margin) {
-               from = scr_end;
-               wrap = rolled_over + c->vc_size_row;
-       } else {
-               from = 0;
-               wrap = size;
-       }
-       from_off = (vorigin - from + wrap) % wrap + lines * c->vc_size_row;
-       avail = (origin - from + wrap) % wrap;
-       /* Only a little piece would be left? Show all incl. the piece! */
-       if (avail < 2 * margin)
-               margin = 0;
-       if (from_off < margin)
-               from_off = 0;
-       if (from_off > avail - margin)
-               from_off = avail;
-       c->vc_visible_origin = ubase + (from + from_off) % wrap;
- }
- EXPORT_SYMBOL_GPL(vc_scrolldelta_helper);
index 46823c2e2ba1207e327607fa0ca0c757bc0968aa,17a9fc80b4e4f02139aa9527fdcda32c37fc7e77..98d0e2dbcd2f362ff8ea0f3e098f4ec54345ad8d
@@@ -351,7 -351,7 +351,7 @@@ static void fb_flashcursor(struct work_
        struct fb_info *info;
        struct vc_data *vc = NULL;
        int c;
-       int mode;
+       bool enable;
        int ret;
  
        /* FIXME: we should sort out the unbind locking instead */
        }
  
        c = scr_readw((u16 *) vc->vc_pos);
-       mode = (!ops->cursor_flash || ops->cursor_state.enable) ?
-               CM_ERASE : CM_DRAW;
-       ops->cursor(vc, info, mode, get_color(vc, info, c, 1),
+       enable = ops->cursor_flash && !ops->cursor_state.enable;
+       ops->cursor(vc, info, enable, get_color(vc, info, c, 1),
                    get_color(vc, info, c, 0));
        console_unlock();
  
@@@ -920,7 -919,7 +919,7 @@@ static void display_to_var(struct fb_va
  
  static const char *fbcon_startup(void)
  {
-       const char *display_desc = "frame buffer device";
+       static const char display_desc[] = "frame buffer device";
        struct fbcon_display *p = &fb_display[fg_console];
        struct vc_data *vc = vc_cons[fg_console].d;
        const struct font_desc *font = NULL;
        return display_desc;
  }
  
- static void fbcon_init(struct vc_data *vc, int init)
+ static void fbcon_init(struct vc_data *vc, bool init)
  {
        struct fb_info *info;
        struct fbcon_ops *ops;
@@@ -1234,8 -1233,8 +1233,8 @@@ finished
   *  restriction is simplicity & efficiency at the moment.
   */
  
- static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height,
-                       int width)
+ static void __fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
+                         unsigned int height, unsigned int width)
  {
        struct fb_info *info = fbcon_info_from_console(vc->vc_num);
        struct fbcon_ops *ops = info->fbcon_par;
                ops->clear(vc, info, real_y(p, sy), sx, height, width);
  }
  
- static void fbcon_putcs(struct vc_data *vc, const unsigned short *s,
-                       int count, int ypos, int xpos)
+ static void fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
+                       unsigned int width)
+ {
+       __fbcon_clear(vc, sy, sx, 1, width);
+ }
+ static void fbcon_putcs(struct vc_data *vc, const u16 *s, unsigned int count,
+                       unsigned int ypos, unsigned int xpos)
  {
        struct fb_info *info = fbcon_info_from_console(vc->vc_num);
        struct fbcon_display *p = &fb_display[vc->vc_num];
                           get_color(vc, info, scr_readw(s), 0));
  }
  
- static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos)
- {
-       unsigned short chr;
-       scr_writew(c, &chr);
-       fbcon_putcs(vc, &chr, 1, ypos, xpos);
- }
  static void fbcon_clear_margins(struct vc_data *vc, int bottom_only)
  {
        struct fb_info *info = fbcon_info_from_console(vc->vc_num);
                ops->clear_margins(vc, info, margin_color, bottom_only);
  }
  
- static void fbcon_cursor(struct vc_data *vc, int mode)
+ static void fbcon_cursor(struct vc_data *vc, bool enable)
  {
        struct fb_info *info = fbcon_info_from_console(vc->vc_num);
        struct fbcon_ops *ops = info->fbcon_par;
        else
                fbcon_add_cursor_work(info);
  
-       ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1;
+       ops->cursor_flash = enable;
  
        if (!ops->cursor)
                return;
  
-       ops->cursor(vc, info, mode, get_color(vc, info, c, 1),
+       ops->cursor(vc, info, enable, get_color(vc, info, c, 1),
                    get_color(vc, info, c, 0));
  }
  
@@@ -1743,7 -1740,7 +1740,7 @@@ static bool fbcon_scroll(struct vc_dat
        if (fbcon_is_inactive(vc, info))
                return true;
  
-       fbcon_cursor(vc, CM_ERASE);
+       fbcon_cursor(vc, false);
  
        /*
         * ++Geert: Only use ywrap/ypan if the console is in text mode
                case SCROLL_MOVE:
                        fbcon_redraw_blit(vc, info, p, t, b - t - count,
                                     count);
-                       fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+                       __fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
                        scr_memsetw((unsigned short *) (vc->vc_origin +
                                                        vc->vc_size_row *
                                                        (b - count)),
                                            b - t - count, vc->vc_cols);
                        else
                                goto redraw_up;
-                       fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+                       __fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
                        break;
  
                case SCROLL_PAN_REDRAW:
                                                          vc->vc_rows - b, b);
                        } else
                                fbcon_redraw_move(vc, p, t + count, b - t - count, t);
-                       fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+                       __fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
                        break;
  
                case SCROLL_PAN_MOVE:
                                            b - t - count, vc->vc_cols);
                        else
                                goto redraw_up;
-                       fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+                       __fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
                        break;
  
                case SCROLL_REDRAW:
                      redraw_up:
                        fbcon_redraw(vc, t, b - t - count,
                                     count * vc->vc_cols);
-                       fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+                       __fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
                        scr_memsetw((unsigned short *) (vc->vc_origin +
                                                        vc->vc_size_row *
                                                        (b - count)),
                case SCROLL_MOVE:
                        fbcon_redraw_blit(vc, info, p, b - 1, b - t - count,
                                     -count);
-                       fbcon_clear(vc, t, 0, count, vc->vc_cols);
+                       __fbcon_clear(vc, t, 0, count, vc->vc_cols);
                        scr_memsetw((unsigned short *) (vc->vc_origin +
                                                        vc->vc_size_row *
                                                        t),
                                            b - t - count, vc->vc_cols);
                        else
                                goto redraw_down;
-                       fbcon_clear(vc, t, 0, count, vc->vc_cols);
+                       __fbcon_clear(vc, t, 0, count, vc->vc_cols);
                        break;
  
                case SCROLL_PAN_MOVE:
                                            b - t - count, vc->vc_cols);
                        else
                                goto redraw_down;
-                       fbcon_clear(vc, t, 0, count, vc->vc_cols);
+                       __fbcon_clear(vc, t, 0, count, vc->vc_cols);
                        break;
  
                case SCROLL_PAN_REDRAW:
                                        fbcon_redraw_move(vc, p, count, t, 0);
                        } else
                                fbcon_redraw_move(vc, p, t, b - t - count, t + count);
-                       fbcon_clear(vc, t, 0, count, vc->vc_cols);
+                       __fbcon_clear(vc, t, 0, count, vc->vc_cols);
                        break;
  
                case SCROLL_REDRAW:
                      redraw_down:
                        fbcon_redraw(vc, b - 1, b - t - count,
                                     -count * vc->vc_cols);
-                       fbcon_clear(vc, t, 0, count, vc->vc_cols);
+                       __fbcon_clear(vc, t, 0, count, vc->vc_cols);
                        scr_memsetw((unsigned short *) (vc->vc_origin +
                                                        vc->vc_size_row *
                                                        t),
@@@ -1995,7 -1992,7 +1992,7 @@@ static void updatescrollmode(struct fbc
  #define CALC_FONTSZ(h, p, c) ((h) * (p) * (c)) /* size = height * pitch * charcount */
  
  static int fbcon_resize(struct vc_data *vc, unsigned int width,
-                       unsigned int height, unsigned int user)
+                       unsigned int height, bool from_user)
  {
        struct fb_info *info = fbcon_info_from_console(vc->vc_num);
        struct fbcon_ops *ops = info->fbcon_par;
        return 0;
  }
  
- static int fbcon_switch(struct vc_data *vc)
+ static bool fbcon_switch(struct vc_data *vc)
  {
        struct fb_info *info, *old_info = NULL;
        struct fbcon_ops *ops;
                              vc->vc_origin + vc->vc_size_row * vc->vc_top,
                              vc->vc_size_row * (vc->vc_bottom -
                                                 vc->vc_top) / 2);
-               return 0;
+               return false;
        }
-       return 1;
+       return true;
  }
  
  static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info,
  
                oldc = vc->vc_video_erase_char;
                vc->vc_video_erase_char &= charmask;
-               fbcon_clear(vc, 0, 0, vc->vc_rows, vc->vc_cols);
+               __fbcon_clear(vc, 0, 0, vc->vc_rows, vc->vc_cols);
                vc->vc_video_erase_char = oldc;
        }
  }
  
- static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
+ static bool fbcon_blank(struct vc_data *vc, enum vesa_blank_mode blank,
+                       bool mode_switch)
  {
        struct fb_info *info = fbcon_info_from_console(vc->vc_num);
        struct fbcon_ops *ops = info->fbcon_par;
        if (!fbcon_is_inactive(vc, info)) {
                if (ops->blank_state != blank) {
                        ops->blank_state = blank;
-                       fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW);
+                       fbcon_cursor(vc, !blank);
                        ops->cursor_flash = (!blank);
  
                        if (fb_blank(info, blank))
        else
                fbcon_add_cursor_work(info);
  
-       return 0;
+       return false;
  }
  
- static int fbcon_debug_enter(struct vc_data *vc)
+ static void fbcon_debug_enter(struct vc_data *vc)
  {
        struct fb_info *info = fbcon_info_from_console(vc->vc_num);
        struct fbcon_ops *ops = info->fbcon_par;
        if (info->fbops->fb_debug_enter)
                info->fbops->fb_debug_enter(info);
        fbcon_set_palette(vc, color_table);
-       return 0;
  }
  
- static int fbcon_debug_leave(struct vc_data *vc)
+ static void fbcon_debug_leave(struct vc_data *vc)
  {
        struct fb_info *info = fbcon_info_from_console(vc->vc_num);
        struct fbcon_ops *ops = info->fbcon_par;
        ops->graphics = ops->save_graphics;
        if (info->fbops->fb_debug_leave)
                info->fbops->fb_debug_leave(info);
-       return 0;
  }
  
  static int fbcon_get_font(struct vc_data *vc, struct console_font *font, unsigned int vpitch)
@@@ -2399,9 -2395,11 +2395,9 @@@ static int fbcon_do_set_font(struct vc_
        struct fbcon_ops *ops = info->fbcon_par;
        struct fbcon_display *p = &fb_display[vc->vc_num];
        int resize, ret, old_userfont, old_width, old_height, old_charcount;
 -      char *old_data = NULL;
 +      u8 *old_data = vc->vc_font.data;
  
        resize = (w != vc->vc_font.width) || (h != vc->vc_font.height);
 -      if (p->userfont)
 -              old_data = vc->vc_font.data;
        vc->vc_font.data = (void *)(p->fontdata = data);
        old_userfont = p->userfont;
        if ((p->userfont = userfont))
                update_screen(vc);
        }
  
 -      if (old_data && (--REFCOUNT(old_data) == 0))
 +      if (old_userfont && (--REFCOUNT(old_data) == 0))
                kfree(old_data - FONT_EXTRA_WORDS * sizeof(int));
        return 0;
  
  err_out:
        p->fontdata = old_data;
 -      vc->vc_font.data = (void *)old_data;
 +      vc->vc_font.data = old_data;
  
        if (userfont) {
                p->userfont = old_userfont;
   *  but lets not assume that, since charcount of 512 is small for unicode support.
   */
  
- static int fbcon_set_font(struct vc_data *vc, struct console_font *font,
+ static int fbcon_set_font(struct vc_data *vc, const struct console_font *font,
                          unsigned int vpitch, unsigned int flags)
  {
        struct fb_info *info = fbcon_info_from_console(vc->vc_num);
        return fbcon_do_set_font(vc, font->width, font->height, charcount, new_data, 1);
  }
  
- static int fbcon_set_def_font(struct vc_data *vc, struct console_font *font, char *name)
+ static int fbcon_set_def_font(struct vc_data *vc, struct console_font *font,
+                             const char *name)
  {
        struct fb_info *info = fbcon_info_from_console(vc->vc_num);
        const struct font_desc *f;
@@@ -2593,35 -2592,6 +2590,6 @@@ static void fbcon_set_palette(struct vc
        fb_set_cmap(&palette_cmap, info);
  }
  
- static u16 *fbcon_screen_pos(const struct vc_data *vc, int offset)
- {
-       return (u16 *) (vc->vc_origin + offset);
- }
- static unsigned long fbcon_getxy(struct vc_data *vc, unsigned long pos,
-                                int *px, int *py)
- {
-       unsigned long ret;
-       int x, y;
-       if (pos >= vc->vc_origin && pos < vc->vc_scr_end) {
-               unsigned long offset = (pos - vc->vc_origin) / 2;
-               x = offset % vc->vc_cols;
-               y = offset / vc->vc_cols;
-               ret = pos + (vc->vc_cols - x) * 2;
-       } else {
-               /* Should not happen */
-               x = y = 0;
-               ret = vc->vc_origin;
-       }
-       if (px)
-               *px = x;
-       if (py)
-               *py = y;
-       return ret;
- }
  /* As we might be inside of softback, we may work with non-contiguous buffer,
     that's why we have to use a separate routine. */
  static void fbcon_invert_region(struct vc_data *vc, u16 * p, int cnt)
@@@ -2650,7 -2620,7 +2618,7 @@@ void fbcon_suspended(struct fb_info *in
        vc = vc_cons[ops->currcon].d;
  
        /* Clear cursor, restore saved data */
-       fbcon_cursor(vc, CM_ERASE);
+       fbcon_cursor(vc, false);
  }
  
  void fbcon_resumed(struct fb_info *info)
@@@ -3152,7 -3122,6 +3120,6 @@@ static const struct consw fb_con = 
        .con_init               = fbcon_init,
        .con_deinit             = fbcon_deinit,
        .con_clear              = fbcon_clear,
-       .con_putc               = fbcon_putc,
        .con_putcs              = fbcon_putcs,
        .con_cursor             = fbcon_cursor,
        .con_scroll             = fbcon_scroll,
        .con_font_default       = fbcon_set_def_font,
        .con_set_palette        = fbcon_set_palette,
        .con_invert_region      = fbcon_invert_region,
-       .con_screen_pos         = fbcon_screen_pos,
-       .con_getxy              = fbcon_getxy,
        .con_resize             = fbcon_resize,
        .con_debug_enter        = fbcon_debug_enter,
        .con_debug_leave        = fbcon_debug_leave,
diff --combined kernel/printk/printk.c
index a000bef511772b4a10613d16c5ea135686f90033,89f2aa2e1172f2222f5b82b2ec773b5ce2573710..ca5146006b94c6742ac770323aaf123688d65572
@@@ -34,7 -34,7 +34,7 @@@
  #include <linux/security.h>
  #include <linux/memblock.h>
  #include <linux/syscalls.h>
 -#include <linux/crash_core.h>
 +#include <linux/vmcore_info.h>
  #include <linux/ratelimit.h>
  #include <linux/kmsg_dump.h>
  #include <linux/syslog.h>
@@@ -347,29 -347,6 +347,29 @@@ static bool panic_in_progress(void
        return unlikely(atomic_read(&panic_cpu) != PANIC_CPU_INVALID);
  }
  
 +/* Return true if a panic is in progress on the current CPU. */
 +bool this_cpu_in_panic(void)
 +{
 +      /*
 +       * We can use raw_smp_processor_id() here because it is impossible for
 +       * the task to be migrated to the panic_cpu, or away from it. If
 +       * panic_cpu has already been set, and we're not currently executing on
 +       * that CPU, then we never will be.
 +       */
 +      return unlikely(atomic_read(&panic_cpu) == raw_smp_processor_id());
 +}
 +
 +/*
 + * Return true if a panic is in progress on a remote CPU.
 + *
 + * On true, the local CPU should immediately release any printing resources
 + * that may be needed by the panic CPU.
 + */
 +bool other_cpu_in_panic(void)
 +{
 +      return (panic_in_progress() && !this_cpu_in_panic());
 +}
 +
  /*
   * This is used for debugging the mess that is the VT code by
   * keeping track if we have the console semaphore held. It's
@@@ -462,6 -439,12 +462,6 @@@ static int console_msg_format = MSG_FOR
  static DEFINE_MUTEX(syslog_lock);
  
  #ifdef CONFIG_PRINTK
 -/*
 - * During panic, heavy printk by other CPUs can delay the
 - * panic and risk deadlock on console resources.
 - */
 -static int __read_mostly suppress_panic_printk;
 -
  DECLARE_WAIT_QUEUE_HEAD(log_wait);
  /* All 3 protected by @syslog_lock. */
  /* the next printk record to read by syslog(READ) or /proc/kmsg */
@@@ -615,6 -598,17 +615,6 @@@ static int check_syslog_permissions(in
        if (syslog_action_restricted(type)) {
                if (capable(CAP_SYSLOG))
                        goto ok;
 -              /*
 -               * For historical reasons, accept CAP_SYS_ADMIN too, with
 -               * a warning.
 -               */
 -              if (capable(CAP_SYS_ADMIN)) {
 -                      pr_warn_once("%s (%d): Attempt to access syslog with "
 -                                   "CAP_SYS_ADMIN but no CAP_SYSLOG "
 -                                   "(deprecated).\n",
 -                               current->comm, task_pid_nr(current));
 -                      goto ok;
 -              }
                return -EPERM;
        }
  ok:
@@@ -957,7 -951,7 +957,7 @@@ const struct file_operations kmsg_fops 
        .release = devkmsg_release,
  };
  
 -#ifdef CONFIG_CRASH_CORE
 +#ifdef CONFIG_VMCORE_INFO
  /*
   * This appends the listed symbols to /proc/vmcore
   *
@@@ -1852,23 -1846,10 +1852,23 @@@ static bool console_waiter
   */
  static void console_lock_spinning_enable(void)
  {
 +      /*
 +       * Do not use spinning in panic(). The panic CPU wants to keep the lock.
 +       * Non-panic CPUs abandon the flush anyway.
 +       *
 +       * Just keep the lockdep annotation. The panic-CPU should avoid
 +       * taking console_owner_lock because it might cause a deadlock.
 +       * This looks like the easiest way how to prevent false lockdep
 +       * reports without handling races a lockless way.
 +       */
 +      if (panic_in_progress())
 +              goto lockdep;
 +
        raw_spin_lock(&console_owner_lock);
        console_owner = current;
        raw_spin_unlock(&console_owner_lock);
  
 +lockdep:
        /* The waiter may spin on us after setting console_owner */
        spin_acquire(&console_owner_dep_map, 0, 0, _THIS_IP_);
  }
@@@ -1893,22 -1874,6 +1893,22 @@@ static int console_lock_spinning_disabl
  {
        int waiter;
  
 +      /*
 +       * Ignore spinning waiters during panic() because they might get stopped
 +       * or blocked at any time,
 +       *
 +       * It is safe because nobody is allowed to start spinning during panic
 +       * in the first place. If there has been a waiter then non panic CPUs
 +       * might stay spinning. They would get stopped anyway. The panic context
 +       * will never start spinning and an interrupted spin on panic CPU will
 +       * never continue.
 +       */
 +      if (panic_in_progress()) {
 +              /* Keep lockdep happy. */
 +              spin_release(&console_owner_dep_map, _THIS_IP_);
 +              return 0;
 +      }
 +
        raw_spin_lock(&console_owner_lock);
        waiter = READ_ONCE(console_waiter);
        console_owner = NULL;
@@@ -2305,12 -2270,8 +2305,12 @@@ asmlinkage int vprintk_emit(int facilit
        if (unlikely(suppress_printk))
                return 0;
  
 -      if (unlikely(suppress_panic_printk) &&
 -          atomic_read(&panic_cpu) != raw_smp_processor_id())
 +      /*
 +       * The messages on the panic CPU are the most important. If
 +       * non-panic CPUs are generating any messages, they will be
 +       * silently dropped.
 +       */
 +      if (other_cpu_in_panic())
                return 0;
  
        if (level == LOGLEVEL_SCHED) {
@@@ -2640,6 -2601,26 +2640,6 @@@ static int console_cpu_notify(unsigned 
        return 0;
  }
  
 -/*
 - * Return true if a panic is in progress on a remote CPU.
 - *
 - * On true, the local CPU should immediately release any printing resources
 - * that may be needed by the panic CPU.
 - */
 -bool other_cpu_in_panic(void)
 -{
 -      if (!panic_in_progress())
 -              return false;
 -
 -      /*
 -       * We can use raw_smp_processor_id() here because it is impossible for
 -       * the task to be migrated to the panic_cpu, or away from it. If
 -       * panic_cpu has already been set, and we're not currently executing on
 -       * that CPU, then we never will be.
 -       */
 -      return atomic_read(&panic_cpu) != raw_smp_processor_id();
 -}
 -
  /**
   * console_lock - block the console subsystem from printing
   *
@@@ -2795,6 -2776,8 +2795,6 @@@ void console_prepend_dropped(struct pri
  bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
                             bool is_extended, bool may_suppress)
  {
 -      static int panic_console_dropped;
 -
        struct printk_buffers *pbufs = pmsg->pbufs;
        const size_t scratchbuf_sz = sizeof(pbufs->scratchbuf);
        const size_t outbuf_sz = sizeof(pbufs->outbuf);
        pmsg->seq = r.info->seq;
        pmsg->dropped = r.info->seq - seq;
  
 -      /*
 -       * Check for dropped messages in panic here so that printk
 -       * suppression can occur as early as possible if necessary.
 -       */
 -      if (pmsg->dropped &&
 -          panic_in_progress() &&
 -          panic_console_dropped++ > 10) {
 -              suppress_panic_printk = 1;
 -              pr_warn_once("Too many dropped messages. Suppress messages on non-panic CPUs to prevent livelock.\n");
 -      }
 -
        /* Skip record that has level above the console loglevel. */
        if (may_suppress && suppress_message_printing(r.info->level))
                goto out;
@@@ -3269,6 -3263,21 +3269,21 @@@ static int __init keep_bootcon_setup(ch
  
  early_param("keep_bootcon", keep_bootcon_setup);
  
+ static int console_call_setup(struct console *newcon, char *options)
+ {
+       int err;
+       if (!newcon->setup)
+               return 0;
+       /* Synchronize with possible boot console. */
+       console_lock();
+       err = newcon->setup(newcon, options);
+       console_unlock();
+       return err;
+ }
  /*
   * This is called by register_console() to try to match
   * the newly registered console with any of the ones selected
@@@ -3304,8 -3313,8 +3319,8 @@@ static int try_enable_preferred_console
                        if (_braille_register_console(newcon, c))
                                return 0;
  
-                       if (newcon->setup &&
-                           (err = newcon->setup(newcon, c->options)) != 0)
+                       err = console_call_setup(newcon, c->options);
+                       if (err)
                                return err;
                }
                newcon->flags |= CON_ENABLED;
@@@ -3331,7 -3340,7 +3346,7 @@@ static void try_enable_default_console(
        if (newcon->index < 0)
                newcon->index = 0;
  
-       if (newcon->setup && newcon->setup(newcon, NULL) != 0)
+       if (console_call_setup(newcon, NULL) != 0)
                return;
  
        newcon->flags |= CON_ENABLED;
@@@ -3767,7 -3776,7 +3782,7 @@@ static bool __pr_flush(struct console *
  
        might_sleep();
  
 -      seq = prb_next_seq(prb);
 +      seq = prb_next_reserve_seq(prb);
  
        /* Flush the consoles so that records up to @seq are printed. */
        console_lock();