Hello, John

On Tue, Apr 06, 2021 at 10:13:39 -0400, John Covici wrote:

> On Tue, 06 Apr 2021 09:14:23 -0400,
> Peter Humphrey wrote:

> > On Monday, 5 April 2021 19:13:18 BST Alan Mackenzie wrote:

> > > We'll see how people react to it here, first.

> > You're my hero!

> Would this patch work on 5.4.96 and following?

No, there is a slight difference (two struct fields moved and renamed)
between 5.4 and 5.10.

For 5.4, please use the attached patch instead.  It has been tested on
5.4.80-r1 and 5.4.97.

> -- 
> Your life is like a penny.  You're going to lose it.  The question is:
> How do
> you spend it?

>          John Covici wb2una
>          cov...@ccs.covici.com

-- 
Alan Mackenzie (Nuremberg, Germany).

--- drivers/video/console/Kconfig.orig  2021-03-31 19:14:48.186140856 +0000
+++ drivers/video/console/Kconfig       2021-04-05 13:41:20.967713154 +0000
@@ -79,6 +79,55 @@
        help
          Low-level framebuffer-based console driver.
 
+config FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+       bool "Enable Scrollback Buffer in System RAM"
+       depends on FB=y && FRAMEBUFFER_CONSOLE
+       default y
+       select FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK_PERSISTENT_ENABLE_BY_DEFAULT
+       help
+         This option creates scrollback buffers for each framebuffer console,
+         or one buffer for them all.  These buffers are allocated dynamically
+         during initialisation.
+
+         If you want this feature, say 'Y' here and enter the amount of
+         RAM to allocate for this buffer.  If unsure, say 'N'.
+
+config FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK_SIZE
+       int "Scrollback Buffer Size (in KB)"
+       depends on FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+       range 1 1024
+       default "128"
+       help
+                 Enter the amount of System RAM to allocate for each scrollback
+         buffer of framebuffer consoles in kilobytes.  Each character
+         position on the video takes 2 bytes of storage.  128k will give you
+         approximately 4 240x67 screenfuls of scrollback buffer.
+
+config FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK_PERSISTENT_ENABLE_BY_DEFAULT
+       bool "Persistent Scrollback History for each framebuffer console by 
default"
+       depends on FB=y && FRAMEBUFFER_CONSOLE && 
FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+       default y
+       help
+
+         Note: this option's value N has not (?yet) been implemented (2021-04).
+
+         Say Y here if the scrollback history should persist by default when
+         switching between consoles. Otherwise, the scrollback history will
+         be flushed the first time a scroll-up operation occurs on the new
+         console after the console is switched. STOUGH!!!  FIXME!!! This
+         feature can also be enabled using the boot command line parameter
+         'vgacon.scrollback_persistent=1'.
+
+         This feature might break your tool of choice to flush the scrollback
+         buffer, e.g. clear(1) will work fine but Debian's clear_console(1)
+         will be broken, which might cause security issues.
+         You can use the escape sequence \e[3J instead if this feature is
+         activated.
+
+         Note that a buffer of VGACON_SOFT_SCROLLBACK_SIZE is taken for each
+         created tty device.
+         So if you use a RAM-constrained system, say N here.
+
 config FRAMEBUFFER_CONSOLE_DETECT_PRIMARY
        bool "Map the console to the primary display device"
        depends on FRAMEBUFFER_CONSOLE
--- drivers/tty/vt/vt.orig.c    2020-11-28 17:14:38.523649992 +0000
+++ drivers/tty/vt/vt.c 2021-04-05 14:33:47.743786578 +0000
@@ -142,6 +142,13 @@
 #define DEFAULT_BELL_DURATION  (HZ/8)
 #define DEFAULT_CURSOR_BLINK_MS        200
 
+/* NEW STOUGH, 2021-04-01 */
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+static unsigned int console_soft_scrollback_size =
+       1024 * CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK_SIZE;
+#endif
+/* END OF NEW STOUGH */
+
 struct vc vc_cons [MAX_NR_CONSOLES];
 
 #ifndef VT_SINGLE_DRIVER
@@ -294,7 +301,7 @@
 static inline unsigned short *screenpos(struct vc_data *vc, int offset, int 
viewed)
 {
        unsigned short *p;
-       
+
        if (!viewed)
                p = (unsigned short *)(vc->vc_origin + offset);
        else if (!vc->vc_sw->con_screen_pos)
@@ -623,6 +630,232 @@
        }
 }
 
+/* NEW STOUGH, 2021-03-31 */
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+/* NEW STOUGH, 2021-04-01 */
+static void con_update_softback(struct vc_data *vc)
+{
+       int l = vc->vc_softback_size / vc->vc_size_row;
+       if (l > 5)
+       {
+               vc->vc_softback_end = vc->vc_softback_buf + l * vc->vc_size_row;
+               vc->vc_softback_top = vc->vc_softback_buf; /* STOUGH, 
2021-04-04 */
+       }
+       else
+               /* Smaller scrollback makes no sense, and 0 would screw
+                  the operation totally */
+               vc->vc_softback_top = 0;
+}
+
+static int concon_set_origin(struct vc_data *vc)
+{
+       if (vc->vc_softback_lines)
+               concon_scrolldelta(vc, vc->vc_softback_lines);
+       return 0;
+}
+/* END OF NEW STOUGH */
+
+#define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) 
* vc->vc_size_row)
+
+static void con_redraw_softback(struct vc_data *vc, /* struct display *p, */
+                               long delta)
+{
+       int count = vc->vc_rows;
+       unsigned short *d, *s;
+       unsigned long n;
+       int line = 0;
+
+       /* NEW STOUGH, 2021-04-04 */
+       if (!vc->vc_softback_lines)
+               vc->vc_char_at_pos = scr_readw((u16 *)vc->vc_pos);
+       /* END OF NEW STOUGH */
+
+       d = (u16 *) vc->vc_softback_curr;
+       if (d == (u16 *) vc->vc_softback_in)
+               d = (u16 *) vc->vc_origin;
+       n = vc->vc_softback_curr + delta * vc->vc_size_row;
+       vc->vc_softback_lines -= delta;
+       if (delta < 0) {
+               if (vc->vc_softback_curr < vc->vc_softback_top
+                   && n < vc->vc_softback_buf) {
+                       n += vc->vc_softback_end - vc->vc_softback_buf;
+                       if (n < vc->vc_softback_top) {
+                               vc->vc_softback_lines -=
+                                   (vc->vc_softback_top - n) / vc->vc_size_row;
+                               n = vc->vc_softback_top;
+                       }
+               } else if (vc->vc_softback_curr >= vc->vc_softback_top
+                          && n < vc->vc_softback_top) {
+                       vc->vc_softback_lines -=
+                           (vc->vc_softback_top - n) / vc->vc_size_row;
+                       n = vc->vc_softback_top;
+               }
+       } else {
+               if (vc->vc_softback_curr > vc->vc_softback_in
+                   && n >= vc->vc_softback_end) {
+                       n += vc->vc_softback_buf - vc->vc_softback_end;
+                       if (n > vc->vc_softback_in) {
+                               n = vc->vc_softback_in;
+                               vc->vc_softback_lines = 0;
+                       }
+               } else if (vc->vc_softback_curr <= vc->vc_softback_in
+                          && n > vc->vc_softback_in) {
+                       n = vc->vc_softback_in;
+                       vc->vc_softback_lines = 0;
+               }
+       }
+       if (n == vc->vc_softback_curr)
+               return;
+       vc->vc_softback_curr = n;
+       /* NEW STOUGH, 2021-04-04 */
+       /* If we're not scrolled any more, restore the character to the cursor
+        * position */
+       if (!vc->vc_softback_lines)
+               scr_writew(vc->vc_char_at_pos, (u16 *)vc->vc_pos);
+       /* END OF NEW STOUGH */
+       s = (u16 *) vc->vc_softback_curr;
+       if (s == (u16 *) vc->vc_softback_in)
+               s = (u16 *) vc->vc_origin;
+       while (count--) {
+               unsigned short *start;
+               unsigned short *le;
+               unsigned short c;
+               int x = 0;
+               unsigned short attr = 1;
+
+               start = s;
+               le = advance_row(s, 1);
+               /* NEW STOUGH, 2021-04-04 */
+               /* Temporarily overwrite the character at the cursor position
+                * with the one we actually want to see on the screen.  */
+               if (count == vc->vc_rows - vc->vc_y - 1)
+               {
+                       c = scr_readw((u16 *)(s + vc->vc_x));
+                       scr_writew(c, (u16 *)vc->vc_pos);
+                       vc->vc_sw->con_putcs
+                               (vc, (u16 *)vc->vc_pos, 1, line, vc->vc_x);
+               }
+               /* END OF NEW STOUGH */
+               do {
+                       c = scr_readw(s);
+                       if (attr != (c & 0xff00)) {
+                               attr = c & 0xff00;
+                               if (s > start) {
+                                       vc->vc_sw->con_putcs(
+                                               vc, start, s - start,
+                                               line, x);
+                                       x += s - start;
+                                       start = s;
+                               }
+                       }
+                       if (c == scr_readw(d)) {
+                               if (s > start) {
+                                       vc->vc_sw->con_putcs(
+                                               vc, start, s - start,
+                                               line, x);
+                                       x += s - start + 1;
+                                       start = s + 1;
+                               } else {
+                                       x++;
+                                       start++;
+                               }
+                       }
+                       s++;
+                       d++;
+               } while (s < le);
+               if (s > start)
+                       vc->vc_sw->con_putcs(vc, start, s - start, line, x);
+               line++;
+               if (d == (u16 *) vc->vc_softback_end)
+                       d = (u16 *) vc->vc_softback_buf;
+               if (d == (u16 *) vc->vc_softback_in)
+                       d = (u16 *) vc->vc_origin;
+               if (s == (u16 *) vc->vc_softback_end)
+                       s = (u16 *) vc->vc_softback_buf;
+               if (s == (u16 *) vc->vc_softback_in)
+                       s = (u16 *) vc->vc_origin;
+       }
+}
+/* END OF NEW STOUGH */
+
+/* NEW STOUGH, 2021-04-01 */
+static inline void con_softback_note(struct vc_data *vc, int t,
+                                    int count)
+{
+       unsigned short *p;
+
+       if (vc->vc_num != fg_console)
+               return;
+       p = (unsigned short *) (vc->vc_origin + t * vc->vc_size_row);
+
+       while (count) {
+               scr_memcpyw((u16 *) vc->vc_softback_in, p, vc->vc_size_row);
+               count--;
+               p = advance_row(p, 1);
+               vc->vc_softback_in += vc->vc_size_row;
+               if (vc->vc_softback_in == vc->vc_softback_end)
+                       vc->vc_softback_in = vc->vc_softback_buf;
+               if (vc->vc_softback_in == vc->vc_softback_top) {
+                       vc->vc_softback_top += vc->vc_size_row;
+                       if (vc->vc_softback_top == vc->vc_softback_end)
+                               vc->vc_softback_top = vc->vc_softback_buf;
+               }
+       }
+       vc->vc_softback_curr = vc->vc_softback_in;
+}
+
+void concon_scrolldelta(struct vc_data *vc, int lines)
+{
+       /* struct display *disp = &fb_display[fg_console]; */
+       /* int offset, limit, scrollback_old; */
+
+       if (vc->vc_softback_top) {
+               if (vc->vc_num != fg_console)
+                       return;
+               if (vc->vc_mode != KD_TEXT || !lines)
+                       return;
+#if 0
+               if (logo_shown >= 0) {
+                       struct vc_data *conp2 = vc_cons[logo_shown].d;
+
+                       if (conp2->vc_top == logo_lines
+                           && conp2->vc_bottom == conp2->vc_rows)
+                               conp2->vc_top = 0;
+                       if (logo_shown == vc->vc_num) {
+                               unsigned long p, q;
+                               int i;
+
+                               p = vc->vc_softback_in;
+                               q = vc->vc_origin +
+                                   logo_lines * vc->vc_size_row;
+                               for (i = 0; i < logo_lines; i++) {
+                                       if (p == vc->vc_softback_top)
+                                               break;
+                                       if (p == vc->vc_softback_buf)
+                                               p = vc->vc_softback_end;
+                                       p -= vc->vc_size_row;
+                                       q -= vc->vc_size_row;
+                                       scr_memcpyw((u16 *) q, (u16 *) p,
+                                                   vc->vc_size_row);
+                               }
+                               vc->vc_softback_in = vc->vc_softback_curr = p;
+                               update_region(vc, vc->vc_origin,
+                                             logo_lines * vc->vc_cols);
+                       }
+                       logo_shown = FBCON_LOGO_CANSHOW;
+               }
+#endif
+               vc->vc_sw->con_cursor(vc, CM_ERASE /* | CM_SOFTBACK */);
+               con_redraw_softback(vc, /* disp, */ lines);
+               /* NEW STOUGH, 2021-04-04 */
+               if (!vc->vc_softback_lines)
+                       /* END OF NEW STOUGH */
+                       vc->vc_sw->con_cursor(vc, CM_DRAW /* | CM_SOFTBACK */);
+       }
+}
+
+/* END OF NEW STOUGH */
+#endif  /* CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK */
 
 static void con_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
                enum con_scroll dir, unsigned int nr)
@@ -633,6 +866,12 @@
                nr = b - t - 1;
        if (b > vc->vc_rows || t >= b || nr < 1)
                return;
+       /* NEW STOUGH, 2021-04-01 */
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+       if (dir == SM_UP && vc->vc_softback_top)
+               con_softback_note (vc, t, nr);
+#endif
+       /* END OF NEW STOUGH */
        vc_uniscr_scroll(vc, t, b, dir, nr);
        if (con_is_visible(vc) && vc->vc_sw->con_scroll(vc, t, b, dir, nr))
                return;
@@ -648,6 +887,72 @@
        scr_memsetw(clear, vc->vc_video_erase_char, vc->vc_size_row * nr);
 }
 
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+static void do_update_region(struct vc_data *vc, unsigned long start, int 
count)
+{
+       unsigned int xx, yy, offset;
+       u16 *p;
+
+       /* NEW STOUGH, 2021-04-03 */
+       unsigned long origin =
+               (start >= vc->vc_softback_buf && start < vc->vc_softback_end)
+               ? start >= vc->vc_softback_curr
+                 ? vc->vc_softback_curr
+                 : vc->vc_softback_curr
+                   - (vc->vc_softback_end - vc->vc_softback_buf)
+               : vc->vc_origin;
+       /* END OF NEW STOUGH */
+       p = (u16 *) start;
+       /* OLD STOUGH, 2021-04-03 */
+       /* if (!vc->vc_sw->con_getxy) { */
+               /* END OF OLD STOUGH */
+               offset = (start - origin) / 2; /* STOUGH, 2021-04-03 */
+               xx = offset % vc->vc_cols;
+               yy = offset / vc->vc_cols;
+               /* OLD STOUGH, 2021-04-03 */
+       /* } else { */
+       /*      int nxx, nyy; */
+       /*      start = vc->vc_sw->con_getxy(vc, start, &nxx, &nyy); */
+       /*      xx = nxx; yy = nyy; */
+       /* } */
+               /* END OF OLD STOUGH */
+       for(;;) {
+               u16 attrib = scr_readw(p) & 0xff00;
+               int startx = xx;
+               u16 *q = p;
+               while (xx < vc->vc_cols && count) {
+                       if (attrib != (scr_readw(p) & 0xff00)) {
+                               if (p > q)
+                                       vc->vc_sw->con_putcs(vc, q, p-q, yy, 
startx);
+                               startx = xx;
+                               q = p;
+                               attrib = scr_readw(p) & 0xff00;
+                       }
+                       p++;
+                       xx++;
+                       count--;
+               }
+               if (p > q)
+                       vc->vc_sw->con_putcs(vc, q, p-q, yy, startx);
+               /* NEW STOUGH, 2021-04-03 */
+               if (p == (u16 *) vc->vc_softback_end)
+                       p = (u16 *)vc->vc_softback_buf;
+               if (p == (u16 *) vc->vc_softback_in)
+                       p = (u16 *)vc->vc_origin;
+               /* END OF NEW STOUGH */
+               if (!count)
+                       break;
+               xx = 0;
+               yy++;
+               /* OLD STOUGH, 2021-04-03 */
+               /* if (vc->vc_sw->con_getxy) { */
+               /*      p = (u16 *)start; */
+               /*      start = vc->vc_sw->con_getxy(vc, start, NULL, NULL); */
+               /* } */
+               /* END OF OLD STOUGH */
+       }
+}
+#else
 static void do_update_region(struct vc_data *vc, unsigned long start, int 
count)
 {
        unsigned int xx, yy, offset;
@@ -691,6 +996,7 @@
                }
        }
 }
+#endif
 
 void update_region(struct vc_data *vc, unsigned long start, int count)
 {
@@ -699,7 +1005,12 @@
        if (con_should_update(vc)) {
                hide_cursor(vc);
                do_update_region(vc, start, count);
-               set_cursor(vc);
+               /* NEW STOUGH, 2021-04-04 */
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+               if (!vc->vc_softback_lines)
+#endif
+                       /* END OF NEW STOUGH */
+                       set_cursor(vc);
        }
 }
 
@@ -751,8 +1062,8 @@
 static void update_attr(struct vc_data *vc)
 {
        vc->vc_attr = build_attr(vc, vc->vc_color, vc->vc_intensity,
-                     vc->vc_blink, vc->vc_underline,
-                     vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic);
+                     vc->vc_blink, vc->vc_underline,
+                     vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic);
        vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, 
vc->vc_blink, 0, vc->vc_decscnm, 0) << 8) | ' ';
 }
 
@@ -922,8 +1233,19 @@
        WARN_CONSOLE_UNLOCKED();
 
        if (!con_is_visible(vc) ||
+           /* NEW STOUGH, 2021-04-01 */
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+           (
+            !concon_set_origin (vc) &&
+            (
+#endif
+           /* END OF NEW STOUGH */
            !vc->vc_sw->con_set_origin ||
-           !vc->vc_sw->con_set_origin(vc))
+           !vc->vc_sw->con_set_origin(vc)
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+                    ))
+#endif
+                                         )
                vc->vc_origin = (unsigned long)vc->vc_screenbuf;
        vc->vc_visible_origin = vc->vc_origin;
        vc->vc_scr_end = vc->vc_origin + vc->vc_screenbuf_size;
@@ -998,7 +1320,9 @@
                hide_cursor(old_vc);
                if (!con_is_visible(old_vc)) {
                        save_screen(old_vc);
-                       set_origin(old_vc);
+                       /* OLD STOUGH, 2021-04-02 */
+                       /* set_origin(old_vc); */
+                       /* END OF OLD STOUGH */
                }
                if (tty0dev)
                        sysfs_notify(&tty0dev->kobj, NULL, "active");
@@ -1011,7 +1335,9 @@
                int update;
                int old_was_color = vc->vc_can_do_color;
 
-               set_origin(vc);
+               /* OLD STOUGH, 2021-04-02 */
+               /* set_origin(vc); */
+               /* END OF OLD STOUGH */
                update = vc->vc_sw->con_switch(vc);
                set_palette(vc);
                /*
@@ -1026,9 +1352,25 @@
                }
 
                if (update && vc->vc_mode != KD_GRAPHICS)
-                       do_update_region(vc, vc->vc_origin, 
vc->vc_screenbuf_size / 2);
-       }
-       set_cursor(vc);
+                       /* OLD STOUGH, 2021-04-03 */
+                       /* do_update_region(vc, vc->vc_origin, 
vc->vc_screenbuf_size / 2); */
+                       /* NEW STOUGH, 2021-04-03 */
+                       do_update_region(vc,
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+                                        vc->vc_softback_lines
+                                        ? vc->vc_softback_curr
+                                        :
+#endif
+                                          vc->vc_origin,
+                                        vc->vc_screenbuf_size / 2);
+                       /* END OF NEW STOUGH */
+       }
+       /* NEW STOUGH, 2021-04-04 */
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+       if (!vc->vc_softback_lines)
+#endif
+               /* END OF NEW STOUGH */
+               set_cursor(vc);
        if (is_switch) {
                set_leds();
                compute_shiftstate();
@@ -1107,12 +1449,32 @@
        int err;
 
        WARN_CONSOLE_UNLOCKED();
-
        if (currcons >= MAX_NR_CONSOLES)
                return -ENXIO;
 
        if (vc_cons[currcons].d)
+               /* NEW STOUGH, 2021-04-05 */
+       {
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+               vc = vc_cons[currcons].d;
+               if (!vc->vc_softback_size) {
+                       /* vc was partially initialized by __init. */
+                       vc->vc_softback_size = console_soft_scrollback_size;
+                       vc->vc_softback_buf =
+                               (unsigned long)kzalloc(vc->vc_softback_size, 
GFP_KERNEL);
+                       if (vc->vc_softback_buf) {
+                               vc->vc_softback_in = vc->vc_softback_top =
+                                       vc->vc_softback_curr = 
vc->vc_softback_buf;
+                               vc->vc_softback_lines = 0;
+                               con_update_softback(vc);
+                       }
+               }
+#endif
+               /* END OF NEW STOUGH */
                return 0;
+               /* NEW STOUGH, 2021-04-05 */
+       }
+       /* END OF NEW STOUGH */
 
        /* due to the granularity of kmalloc, we waste some memory here */
        /* the alloc is done in two steps, to optimize the common situation
@@ -1152,6 +1514,20 @@
        vcs_make_sysfs(currcons);
        atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, &param);
 
+       /* NEW STOUGH, 2021-04-01 */
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+       vc->vc_softback_size = console_soft_scrollback_size;
+       err = -ENOMEM;
+       vc->vc_softback_buf =
+               (unsigned long)kzalloc(vc->vc_softback_size, GFP_KERNEL);
+       if (!vc->vc_softback_buf)
+               goto err_free;
+       vc->vc_softback_in = vc->vc_softback_top = vc->vc_softback_curr =
+               vc->vc_softback_buf;
+       vc->vc_softback_lines = 0;
+       con_update_softback(vc);
+#endif
+       /* END OF NEW STOUGH */
        return 0;
 err_free:
        visual_deinit(vc);
@@ -1627,7 +2003,7 @@
 
 static void rgb_from_256(int i, struct rgb *c)
 {
-       if (i < 8) {            /* Standard colours. */
+       if (i < 8) {        /* Standard colours. */
                c->r = i&1 ? 0xaa : 0x00;
                c->g = i&2 ? 0xaa : 0x00;
                c->b = i&4 ? 0xaa : 0x00;
@@ -1639,7 +2015,7 @@
                c->r = (i - 16) / 36 * 85 / 2;
                c->g = (i - 16) / 6 % 6 * 85 / 2;
                c->b = (i - 16) % 6 * 85 / 2;
-       } else                  /* Grayscale ramp. */
+       } else            /* Grayscale ramp. */
                c->r = c->g = c->b = i * 10 - 2312;
 }
 
@@ -2629,6 +3005,14 @@
 
        param.vc = vc;
 
+       /* NEW STOUGH, 2021-04-03 */
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+       /* Undo any soft scrolling - <Alt><Fn> and <Shift><PgUp/Down> do
+          not pass through this function.  */
+       concon_set_origin (vc);
+#endif
+       /* END OF NEW STOUGH */
+
        while (!tty->stopped && count) {
                int orig = *buf;
                c = orig;
@@ -2722,17 +3106,17 @@
                                        &param) == NOTIFY_STOP)
                        continue;
 
-                /* If the original code was a control character we
-                 * only allow a glyph to be displayed if the code is
-                 * not normally used (such as for cursor movement) or
-                 * if the disp_ctrl mode has been explicitly enabled.
-                 * Certain characters (as given by the CTRL_ALWAYS
-                 * bitmap) are always displayed as control characters,
-                 * as the console would be pretty useless without
-                 * them; to display an arbitrary font position use the
-                 * direct-to-font zone in UTF-8 mode.
-                 */
-                ok = tc && (c >= 32 ||
+               /* If the original code was a control character we
+                * only allow a glyph to be displayed if the code is
+                * not normally used (such as for cursor movement) or
+                * if the disp_ctrl mode has been explicitly enabled.
+                * Certain characters (as given by the CTRL_ALWAYS
+                * bitmap) are always displayed as control characters,
+                * as the console would be pretty useless without
+                * them; to display an arbitrary font position use the
+                * direct-to-font zone in UTF-8 mode.
+                */
+               ok = tc && (c >= 32 ||
                            !(vc->vc_disp_ctrl ? (CTRL_ALWAYS >> c) & 1 :
                                  vc->vc_utf || ((CTRL_ACTION >> c) & 1)))
                        && (c != 127 || vc->vc_disp_ctrl)
@@ -3018,7 +3402,12 @@
        }
        if (cnt && con_is_visible(vc))
                vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, start_x);
-       set_cursor(vc);
+       /* NEW STOUGH, 2021-04-04 */
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+       if (!vc->vc_softback_lines)
+#endif
+               /* END OF NEW STOUGH */
+               set_cursor(vc);
        notify_update(vc);
 
 quit:
@@ -3246,7 +3635,13 @@
        /* if we race with con_close(), vt may be null */
        console_lock();
        vc = tty->driver_data;
-       if (vc)
+       if (vc
+           /* NEW STOUGH, 2021-04-04 */
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+           && !vc->vc_softback_lines
+#endif
+           /* END OF NEW STOUGH */
+             )
                set_cursor(vc);
        console_unlock();
 }
@@ -3267,6 +3662,12 @@
 
        vc = vc_cons[currcons].d;
 
+       /* NEW STOUGH, 2021-04-04 */
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+       con_update_softback(vc);
+#endif
+       /* END OF NEW STOUGH */
+
        /* Still being freed */
        if (vc->port.tty) {
                ret = -ERESTARTSYS;
@@ -3322,7 +3723,7 @@
        tty_port_put(&vc->port);
 }
 
-static int default_color           = 7; /* white */
+static int default_color          = 7; /* white */
 static int default_italic_color    = 2; // green (ASCII)
 static int default_underline_color = 3; // cyan (ASCII)
 module_param_named(color, default_color, int, S_IRUGO | S_IWUSR);
@@ -4024,7 +4425,7 @@
                        con_driver->desc = desc;
                        con_driver->node = i;
                        con_driver->flag = CON_DRIVER_FLAG_MODULE |
-                                          CON_DRIVER_FLAG_INIT;
+                                          CON_DRIVER_FLAG_INIT;
                        con_driver->first = first;
                        con_driver->last = last;
                        retval = 0;
@@ -4325,7 +4726,12 @@
        if (console_blank_hook)
                console_blank_hook(0);
        set_palette(vc);
-       set_cursor(vc);
+       /* NEW STOUGH, 2021-04-04 */
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+       if (!vc->vc_softback_lines)
+#endif
+               /* END OF NEW STOUGH */
+               set_cursor(vc);
        vt_event_post(VT_EVENT_UNBLANK, vc->vc_num, vc->vc_num);
 }
 EXPORT_SYMBOL(do_unblank_screen);
--- include/linux/console_struct.h.orig 2021-04-02 19:55:52.696177657 +0000
+++ include/linux/console_struct.h      2021-04-05 14:39:24.531805027 +0000
@@ -70,6 +70,21 @@
        unsigned short  *vc_screenbuf;          /* In-memory 
character/attribute buffer */
        unsigned int    vc_screenbuf_size;
        unsigned char   vc_mode;                /* KD_TEXT, ... */
+       /* NEW STOUGH, 2021-03-31 */
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+       unsigned int    vc_softback_size;       /* Size in bytes of scrollback 
buffer. */
+       unsigned long   vc_softback_buf;        /* Address of scrollback 
buffer. */
+       unsigned long   vc_softback_end;        /* (Just past) end of buffer. */
+       unsigned long   vc_softback_in;         /* Head pointer into circular 
buffer. */
+       unsigned long   vc_softback_top;        /* Tail pointer into circular 
buffer. */
+       unsigned long   vc_softback_curr;       /* Pos in vc_screenbuf or 
vc_softback_buf
+                                                  corresponding to visible 
screen. */
+       int             vc_softback_lines;      /* Number of lines currently 
scrolled. */
+       /* NEW STOUGH, 2021-04-04 */
+       unsigned short  vc_char_at_pos;         /* Char at vc_pos when no soft 
scroll */
+       /* END OF NEW STOUGH. */
+#endif
+       /* END OF NEW STOUGH */
        /* attributes for all characters on screen */
        unsigned char   vc_attr;                /* Current attributes */
        unsigned char   vc_def_color;           /* Default colors */
--- drivers/video/fbdev/core/fbcon.c.orig       2021-04-02 19:58:46.332168089 
+0000
+++ drivers/video/fbdev/core/fbcon.c    2021-04-05 14:41:32.128812016 +0000
@@ -3115,6 +3115,11 @@
        .con_font_default       = fbcon_set_def_font,
        .con_font_copy          = fbcon_copy_font,
        .con_set_palette        = fbcon_set_palette,
+       /* NEW STOUGH, 2021-04-01 */
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+       .con_scrolldelta        = concon_scrolldelta,
+#endif
+       /* END OF NEW STOUGH */
        .con_set_origin         = fbcon_set_origin,
        .con_invert_region      = fbcon_invert_region,
        .con_screen_pos         = fbcon_screen_pos,
--- include/linux/vt_kern.h.orig        2021-04-02 20:01:19.552159645 +0000
+++ include/linux/vt_kern.h     2021-04-01 17:31:45.125471834 +0000
@@ -129,6 +129,11 @@
 /* vt.c */
 void vt_event_post(unsigned int event, unsigned int old, unsigned int new);
 int vt_waitactive(int n);
+/* NEW STOUGH, 2021-04-01 */
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+void concon_scrolldelta(struct vc_data *vc, int lines);
+#endif
+/* END OF NEW STOUGH */
 void change_console(struct vc_data *new_vc);
 void reset_vc(struct vc_data *vc);
 extern int do_unbind_con_driver(const struct consw *csw, int first, int last,

Reply via email to