Merge tag 'tty-6.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
[sfrench/cifs-2.6.git] / drivers / tty / vt / vt.c
index 38a765eadbe2bc81494f1fbd7a63b50b87101f08..9b5b98dfc8b4017289db11d3a42780760cad38fe 100644 (file)
@@ -145,7 +145,7 @@ static void gotoxy(struct vc_data *vc, int new_x, int new_y);
 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 @@ 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 @@ static inline bool con_should_update(const struct vc_data *vc)
        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.. */
@@ -591,18 +593,12 @@ static void con_scroll(struct vc_data *vc, unsigned int top,
 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;
@@ -625,10 +621,6 @@ static void do_update_region(struct vc_data *vc, unsigned long start, int count)
                        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 @@ static void update_attr(struct vc_data *vc)
 /* 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 @@ void complement_pos(struct vc_data *vc, int offset)
            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);
        }
 
@@ -771,15 +763,14 @@ void complement_pos(struct vc_data *vc, int offset)
        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 @@ static void add_softcursor(struct vc_data *vc)
                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)
@@ -841,8 +832,8 @@ 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 @@ static void hide_cursor(struct vc_data *vc)
        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 @@ static void set_cursor(struct vc_data *vc)
                        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 @@ static void flush_scrollback(struct vc_data *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 @@ void redraw_screen(struct vc_data *vc, int is_switch)
        }
 
        if (redraw) {
-               int update;
+               bool update;
                int old_was_color = vc->vc_can_do_color;
 
                set_origin(vc);
@@ -999,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 @@ int vc_allocate(unsigned int currcons)    /* return 0 on success */
        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 @@ 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;
 
@@ -1185,7 +1166,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
                 * 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)
@@ -1208,7 +1189,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
        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);
@@ -1295,34 +1276,35 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
 }
 
 /**
- *     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)
 {
@@ -1330,7 +1312,7 @@ 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 @@ static inline void del(struct vc_data *vc)
        /* 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))
@@ -1540,27 +1529,33 @@ static void csi_J(struct vc_data *vc, int vpar)
        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);
@@ -1569,20 +1564,15 @@ static void csi_K(struct vc_data *vc, int vpar)
                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 @@ static void default_attr(struct vc_data *vc)
 
 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;
@@ -1609,9 +1599,12 @@ static void rgb_from_256(int i, struct rgb *c)
                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 @@ static int vc_t416_color(struct vc_data *vc, int i,
        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)
 {
@@ -1688,33 +1714,33 @@ 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.
                          */
@@ -1722,7 +1748,7 @@ static void csi_m(struct vc_data *vc)
                        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.
                          */
@@ -1730,7 +1756,7 @@ static void csi_m(struct vc_data *vc)
                        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.
                          */
@@ -1738,47 +1764,51 @@ static void csi_m(struct vc_data *vc)
                        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 @@ 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];
@@ -1971,41 +2043,32 @@ static void setterm_command(struct vc_data *vc)
 /* console_lock is held */
 static void csi_at(struct vc_data *vc, unsigned int nr)
 {
-       if (nr > vc->vc_cols - vc->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 @@ static void restore_cur(struct vc_data *vc)
        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)
@@ -2078,10 +2180,10 @@ 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];
 
@@ -2104,36 +2206,54 @@ static void vc_setGx(struct vc_data *vc, unsigned int which, int c)
                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,
@@ -2144,119 +2264,330 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
 
                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) {
@@ -2273,16 +2604,14 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
                } 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;
@@ -2298,182 +2627,44 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
                }
                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 */
@@ -2485,36 +2676,36 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
                        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 @@ static inline int vc_translate_ascii(const struct vc_data *vc, int c)
 
 
 /**
- * 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) {
@@ -2660,14 +2857,7 @@ static int vc_translate_unicode(struct vc_data *vc, int c, bool *rescan)
        } 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 @@ static bool vc_is_control(struct vc_data *vc, int tc, int c)
         * 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;
@@ -2730,17 +2924,17 @@ static bool vc_is_control(struct vc_data *vc, int tc, int c)
         * 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 @@ static int do_con_write(struct tty_struct *tty, const u8 *buf, int count)
        };
        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;
 
@@ -2860,13 +3054,6 @@ static int do_con_write(struct tty_struct *tty, const u8 *buf, int count)
                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? */
@@ -2883,7 +3070,7 @@ static int do_con_write(struct tty_struct *tty, const u8 *buf, int count)
        param.vc = vc;
 
        while (!tty->flow.stopped && count) {
-               int orig = *buf;
+               u8 orig = *buf;
                buf++;
                n++;
                count--;
@@ -2992,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).
  *
@@ -3009,8 +3196,8 @@ struct tty_driver *console_driver;
  * 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 @@ static void vt_console_print(struct console *co, const char *b, unsigned count)
        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 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
 {
        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;
 
@@ -3157,8 +3347,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
        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;
@@ -3171,10 +3360,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
        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
@@ -3190,10 +3376,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
                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);
@@ -3214,7 +3397,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
                 */
                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 @@ static void con_start(struct tty_struct *tty)
 
 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 @@ 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);
@@ -3481,7 +3661,7 @@ static int __init con_init(void)
        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 @@ static int do_bind_con_driver(const struct consw *csw, int first, int last,
                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 @@ static void vtconsole_deinit_device(struct con_driver *con)
  * 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 @@ 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;
@@ -3987,7 +4161,7 @@ int con_debug_enter(struct vc_data *vc)
        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) {
@@ -4017,7 +4191,6 @@ int con_debug_enter(struct vc_data *vc)
                }
        }
 #endif /* CONFIG_KGDB_KDB */
-       return ret;
 }
 EXPORT_SYMBOL_GPL(con_debug_enter);
 
@@ -4026,15 +4199,10 @@ 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;
@@ -4044,8 +4212,7 @@ int con_debug_leave(void)
 
        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 @@ 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 @@ 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);
@@ -4328,7 +4498,8 @@ void do_blank_screen(int entering_gfx)
 
        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 @@ 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 @@ 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 @@ 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);