public inbox for gentoo-user@lists.gentoo.org
 help / color / mirror / Atom feed
From: Alan Mackenzie <acm@muc.de>
To: gentoo-user@lists.gentoo.org
Subject: Re: [gentoo-user] Soft scrolling on framebuffer consoles - New version of the patch.
Date: Mon, 12 Dec 2022 18:23:28 +0000	[thread overview]
Message-ID: <Y5dxoIzcioEZjkJ1@ACM> (raw)
In-Reply-To: <YV9Oq/Ql9o99/lNE@ACM>

[-- Attachment #1: Type: text/plain, Size: 1631 bytes --]

Hello, Gentoo.

Here is the latest version of my soft scrolling patch for the gentoo
kernel version 5.15.80.  It will surely work on any reasonably recent
kernel version, and also on future versions.  The new version doesn't
add any new functionality, it just patches the kernel giving rise to
fewer messages from the patch utility.

The purpose of the patch is to enable you to scroll a linux console text
display up and down by half a screen by typing <shift><down> and
<shift><up>.

To use this patch, proceed thusly:

(i) cd /usr/src/linux-5.15.80, or similar.  Get the attached patch file,
  5.15.80-scroll-20221212.diff into this directory.
(ii) patch -p1 < 5.15.80-scroll-20221212.diff.
(iii) Configure the kernel in your usual way.  The extra items added by
  the patch are CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK and
  CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK_SIZE, to be found in make
  menuconfig under Device Drivers/Graphic Support/Console display driver
  support.  The help items for these should explain them adequately.
(iv) Build the kernel.
(v) Put the new kernel into your usual boot manager.
(vi) Reboot and enjoy!

As far as I know this patch should be safe (apart from the mysterious
alleged security problem which caused the soft scrolling to be removed
from the kernel in the first place).  There is certainly nothing
malicious in it.  But if it does break anything for you, you get to keep
the pieces.  But if anything does go wrong, please tell me about it
(preferably here on the list, but by private email if you'd prefer), so
that I can try and fix it.

-- 
Alan Mackenzie (Nuremberg, Germany).


[-- Attachment #2: 5.15.80-scroll.20221212.diff --]
[-- Type: text/plain, Size: 20925 bytes --]

* Unmerged path .config
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index b8f5bc19416d..d7aadca5107d 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -134,6 +134,11 @@ const struct consw *conswitchp;
 #define DEFAULT_BELL_DURATION	(HZ/8)
 #define DEFAULT_CURSOR_BLINK_MS	200
 
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+static unsigned int console_soft_scrollback_size =
+	1024 * CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK_SIZE;
+#endif
+
 struct vc vc_cons [MAX_NR_CONSOLES];
 
 #ifndef VT_SINGLE_DRIVER
@@ -287,7 +292,7 @@ static inline unsigned short *screenpos(const struct vc_data *vc, int offset,
 		bool viewed)
 {
 	unsigned short *p;
-	
+
 	if (!viewed)
 		p = (unsigned short *)(vc->vc_origin + offset);
 	else if (!vc->vc_sw->con_screen_pos)
@@ -616,6 +621,218 @@ static void vc_uniscr_debug_check(struct vc_data *vc)
 	}
 }
 
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+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;
+	}
+	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;
+}
+
+#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;
+
+	if (!vc->vc_softback_lines)
+		vc->vc_char_at_pos = scr_readw((u16 *)vc->vc_pos);
+
+	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;
+	/* 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);
+	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);
+		/* 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->state.y - 1)
+		{
+			c = scr_readw((u16 *)(s + vc->state.x));
+			scr_writew(c, (u16 *)vc->vc_pos);
+			vc->vc_sw->con_putcs
+				(vc, (u16 *)vc->vc_pos, 1, line, vc->state.x);
+		}
+		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;
+	}
+}
+
+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);
+		if (!vc->vc_softback_lines)
+			vc->vc_sw->con_cursor(vc, CM_DRAW /* | CM_SOFTBACK */);
+	}
+}
+
+#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)
@@ -626,6 +843,10 @@ static void con_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
 		nr = b - t - 1;
 	if (b > vc->vc_rows || t >= b || nr < 1)
 		return;
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+	if (dir == SM_UP && vc->vc_softback_top)
+		con_softback_note (vc, t, nr);
+#endif
 	vc_uniscr_scroll(vc, t, b, dir, nr);
 	if (con_is_visible(vc) && vc->vc_sw->con_scroll(vc, t, b, dir, nr))
 		return;
@@ -641,6 +862,56 @@ static void con_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
 	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;
+
+	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;
+	p = (u16 *) start;
+		offset = (start - origin) / 2;
+		xx = offset % vc->vc_cols;
+		yy = offset / vc->vc_cols;
+	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);
+		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;
+		if (!count)
+			break;
+		xx = 0;
+		yy++;
+		/* if (vc->vc_sw->con_getxy) { */
+		/* 	p = (u16 *)start; */
+		/* 	start = vc->vc_sw->con_getxy(vc, start, NULL, NULL); */
+		/* } */
+	}
+}
+#else
 static void do_update_region(struct vc_data *vc, unsigned long start, int count)
 {
 	unsigned int xx, yy, offset;
@@ -684,6 +955,7 @@ static void do_update_region(struct vc_data *vc, unsigned long start, int count)
 		}
 	}
 }
+#endif
 
 void update_region(struct vc_data *vc, unsigned long start, int count)
 {
@@ -692,7 +964,10 @@ void update_region(struct vc_data *vc, unsigned long start, int count)
 	if (con_should_update(vc)) {
 		hide_cursor(vc);
 		do_update_region(vc, start, count);
-		set_cursor(vc);
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+		if (!vc->vc_softback_lines)
+#endif
+			set_cursor(vc);
 	}
 }
 
@@ -927,8 +1202,17 @@ static void set_origin(struct vc_data *vc)
 	WARN_CONSOLE_UNLOCKED();
 
 	if (!con_is_visible(vc) ||
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+	    (
+	     !concon_set_origin (vc) &&
+	     (
+#endif
 	    !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;
@@ -1004,7 +1288,6 @@ void redraw_screen(struct vc_data *vc, int is_switch)
 		hide_cursor(old_vc);
 		if (!con_is_visible(old_vc)) {
 			save_screen(old_vc);
-			set_origin(old_vc);
 		}
 		if (tty0dev)
 			sysfs_notify(&tty0dev->kobj, NULL, "active");
@@ -1017,7 +1300,6 @@ void redraw_screen(struct vc_data *vc, int is_switch)
 		int update;
 		int old_was_color = vc->vc_can_do_color;
 
-		set_origin(vc);
 		update = vc->vc_sw->con_switch(vc);
 		set_palette(vc);
 		/*
@@ -1032,9 +1314,19 @@ void redraw_screen(struct vc_data *vc, int is_switch)
 		}
 
 		if (update && vc->vc_mode != KD_GRAPHICS)
-			do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
+			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);
 	}
-	set_cursor(vc);
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+	if (!vc->vc_softback_lines)
+#endif
+		set_cursor(vc);
 	if (is_switch) {
 		vt_set_leds_compute_shiftstate();
 		notify_update(vc);
@@ -1109,15 +1401,68 @@ int vc_allocate(unsigned int currcons)	/* return 0 on success */
 {
 	struct vt_notifier_param param;
 	struct vc_data *vc;
+	unsigned long new_end;
+	unsigned long new_in, new_top;
+	unsigned long in_residue;
+	unsigned short *d;
 	int err;
 
 	WARN_CONSOLE_UNLOCKED();
-
 	if (currcons >= MAX_NR_CONSOLES)
 		return -ENXIO;
 
 	if (vc_cons[currcons].d)
+	{
+#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);
+			}
+		}
+		if (vc->vc_softback_buf
+		    && (vc->vc_softback_end - vc->vc_softback_buf) % vc->vc_size_row) {
+			new_end = vc->vc_softback_buf + vc->vc_softback_size
+				- (vc->vc_softback_size % vc->vc_size_row);
+			new_top = vc->vc_softback_top
+				- (vc->vc_softback_top - vc->vc_softback_buf)
+				% vc->vc_size_row;
+			in_residue = (vc->vc_softback_in - vc->vc_softback_buf)
+				% vc->vc_size_row;
+			new_in = vc->vc_softback_in
+				+ (in_residue ? vc->vc_size_row - in_residue : 0);
+			if (new_in == new_end)
+				new_in = vc->vc_softback_buf;
+			if (new_top == new_in)
+				new_top += vc->vc_size_row;
+			else if ((new_in > new_top
+				  && (new_in - new_top <= vc->vc_size_row)))
+				new_top += 2 * vc->vc_size_row;
+			if (new_top >= new_end)
+				new_top -= (new_end - vc->vc_softback_buf);
+			vc->vc_softback_lines = 0;
+			vc->vc_softback_curr = new_in;
+
+			d = (u16 *)vc->vc_softback_in;
+			vc->vc_softback_end = new_end;
+			vc->vc_softback_in = new_in;
+			vc->vc_softback_top = new_top;
+			while (d != (u16 *)new_in) {
+				scr_writew (0x0020, d); /* How about non-VGA? */
+				if (++d == (u16 *)new_end)
+					d = (u16 *)vc->vc_softback_buf;
+			}
+		}
+#endif
 		return 0;
+	}
 
 	/* due to the granularity of kmalloc, we waste some memory here */
 	/* the alloc is done in two steps, to optimize the common situation
@@ -1157,6 +1502,18 @@ int vc_allocate(unsigned int currcons)	/* return 0 on success */
 	vcs_make_sysfs(currcons);
 	atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, &param);
 
+#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
 	return 0;
 err_free:
 	visual_deinit(vc);
@@ -1646,7 +2003,7 @@ struct rgb { u8 r; u8 g; u8 b; };
 
 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;
@@ -1658,7 +2015,7 @@ static void rgb_from_256(int i, struct rgb *c)
 		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;
 }
 
@@ -2928,6 +3285,12 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
 
 	param.vc = vc;
 
+#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
+
 	while (!tty->flow.stopped && count) {
 		int orig = *buf;
 		buf++;
@@ -3143,7 +3506,11 @@ static void vt_console_print(struct console *co, const char *b, unsigned count)
 	}
 	if (cnt && con_is_visible(vc))
 		vc->vc_sw->con_putcs(vc, start, cnt, vc->state.y, start_x);
-	set_cursor(vc);
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+	if (!vc->vc_softback_lines)
+#endif
+		set_cursor(vc);
+
 	notify_update(vc);
 
 quit:
@@ -3364,7 +3731,11 @@ static void con_flush_chars(struct tty_struct *tty)
 	/* if we race with con_close(), vt may be null */
 	console_lock();
 	vc = tty->driver_data;
-	if (vc)
+	if (vc
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+	    && !vc->vc_softback_lines
+#endif
+	      )
 		set_cursor(vc);
 	console_unlock();
 }
@@ -3385,6 +3756,10 @@ static int con_install(struct tty_driver *driver, struct tty_struct *tty)
 
 	vc = vc_cons[currcons].d;
 
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+	con_update_softback(vc);
+#endif
+
 	/* Still being freed */
 	if (vc->port.tty) {
 		ret = -ERESTARTSYS;
@@ -3440,7 +3815,7 @@ static void con_cleanup(struct tty_struct *tty)
 	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);
@@ -4140,7 +4515,7 @@ static int do_register_con_driver(const struct consw *csw, int first, int last)
 			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;
@@ -4441,7 +4816,10 @@ void do_unblank_screen(int leaving_gfx)
 	if (console_blank_hook)
 		console_blank_hook(0);
 	set_palette(vc);
-	set_cursor(vc);
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+	if (!vc->vc_softback_lines)
+#endif
+		set_cursor(vc);
 	vt_event_post(VT_EVENT_UNBLANK, vc->vc_num, vc->vc_num);
 }
 EXPORT_SYMBOL(do_unblank_screen);
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index fcc46380e7c9..4a343877d70c 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -98,6 +98,29 @@ config FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
 
 	  If unsure, select n.
 
+config FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+	bool "Enable Scrollback Buffer in System RAM"
+	depends on FB=y && FRAMEBUFFER_CONSOLE
+	default y
+	help
+	  This option creates a scrollback buffer for each framebuffer console.
+          These buffers are allocated dynamically during initialisation.
+
+	  If you want this feature, say 'Y' here and enter in
+          FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK_SIZE the amount of RAM to
+          allocate for each 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 in kilobytes to allocate for the
+          scrollback buffer of each framebuffer console.  Each character
+	  position on the video takes 2 bytes of storage.  128kB will give you
+	  approximately four 240x67 screenfuls of scrollback buffer.
+
 config FRAMEBUFFER_CONSOLE_DETECT_PRIMARY
        bool "Map the console to the primary display device"
        depends on FRAMEBUFFER_CONSOLE
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index e035a63bbe5b..a4fab71c5853 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -3152,6 +3152,9 @@ static const struct consw fb_con = {
 	.con_font_get 		= fbcon_get_font,
 	.con_font_default	= fbcon_set_def_font,
 	.con_set_palette 	= fbcon_set_palette,
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+	.con_scrolldelta	= concon_scrolldelta,
+#endif
 	.con_invert_region 	= fbcon_invert_region,
 	.con_screen_pos 	= fbcon_screen_pos,
 	.con_getxy 		= fbcon_getxy,
diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h
index d5b9c8d40c18..acc277e73e32 100644
--- a/include/linux/console_struct.h
+++ b/include/linux/console_struct.h
@@ -110,6 +110,17 @@ struct vc_data {
 	unsigned short	*vc_screenbuf;		/* In-memory character/attribute buffer */
 	unsigned int	vc_screenbuf_size;
 	unsigned char	vc_mode;		/* KD_TEXT, ... */
+#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. */
+	unsigned short  vc_char_at_pos;		/* Char at vc_pos when no soft scroll */
+#endif
 	/* attributes for all characters on screen */
 	unsigned char	vc_attr;		/* Current attributes */
 	unsigned char	vc_def_color;		/* Default colors */
diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h
index b5ab452fca5b..1a11c9868f8e 100644
--- a/include/linux/vt_kern.h
+++ b/include/linux/vt_kern.h
@@ -115,6 +115,9 @@ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
 /* vt.c */
 void vt_event_post(unsigned int event, unsigned int old, unsigned int new);
 int vt_waitactive(int n);
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK
+void concon_scrolldelta(struct vc_data *vc, int lines);
+#endif
 void change_console(struct vc_data *new_vc);
 void reset_vc(struct vc_data *vc);
 int do_unbind_con_driver(const struct consw *csw, int first, int last,

  parent reply	other threads:[~2022-12-12 18:23 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-10-07 19:46 [gentoo-user] Soft scrolling on framebuffer consoles - New versions of the patches Alan Mackenzie
2021-10-08  7:37 ` Peter Humphrey
2022-12-12 18:23 ` Alan Mackenzie [this message]
2022-12-12 19:29   ` [gentoo-user] Soft scrolling on framebuffer consoles - New version of the patch Mike Civil
2022-12-12 19:43     ` Alan Mackenzie
2022-12-13  3:44   ` Peter Humphrey
2022-12-14 10:53     ` Alan Mackenzie
2022-12-29 19:50       ` [gentoo-user] Soft scrolling on framebuffer consoles - New version of the patch - with GPM handling Alan Mackenzie
2022-12-31  9:42         ` Peter Humphrey
2022-12-31 14:08           ` Alan Mackenzie
2022-12-31 15:47             ` Peter Humphrey
2022-12-31 16:13               ` Alan Mackenzie
2022-12-31 21:49                 ` David Rosenbaum
2023-01-01 15:13                 ` Alan Mackenzie
2023-01-01 15:38                   ` Peter Humphrey
2023-01-26 20:28                   ` Alan Mackenzie
2023-01-27 12:24                     ` Peter Humphrey
2023-01-27 22:31                       ` Alan Mackenzie
2023-01-28 14:41                         ` Peter Humphrey
2023-02-03 18:56                           ` [gentoo-user] Soft scrolling on framebuffer consoles - New (?final) " Alan Mackenzie
2023-10-04 13:16                             ` [gentoo-user] Soft scrolling on framebuffer consoles - with GPM handling - version of the patch for kernel 6.3 onwards Alan Mackenzie
2023-10-04 14:41                               ` Peter Humphrey
2023-10-04 17:08                               ` Jorge Almeida
2023-10-04 18:59                                 ` Alan Mackenzie
2023-10-04 19:02                                   ` Jorge Almeida
2024-01-24 10:00                             ` Alan Mackenzie
2024-01-24 12:20                               ` [gentoo-user] Soft scrolling on framebuffer consoles - with GPM handling - version of the patch for kernel 6.6 [was 6.3] onwards Alan Mackenzie
2024-03-11 10:47                                 ` Peter Humphrey
2024-04-04  8:05                                   ` [gentoo-user] Soft scrolling on framebuffer consoles - with GPM handling - version of the patch for kernel 6.8.1 onwards Alan Mackenzie
2024-01-24 14:08                               ` [gentoo-user] Soft scrolling on framebuffer consoles - with GPM handling - version of the patch for kernel 6.3 onwards Peter Humphrey
2023-09-09 15:21                           ` [gentoo-user] Soft scrolling on framebuffer consoles - New version of the patch - with GPM handling David Rosenbaum

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=Y5dxoIzcioEZjkJ1@ACM \
    --to=acm@muc.de \
    --cc=gentoo-user@lists.gentoo.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox