Soft scrolling on framebuffer consoles – with GPM Handling

M95D1 pts1 comments

[gentoo-user] Soft scrolling on framebuffer consoles - with GPM Handling - for kernel 6.18.12 (etc.) - Alan Mackenziepublic inbox for gentoo-user@lists.gentoo.org<br>help / color / mirror / Atom feedFrom: Alan Mackenzie<br>To: gentoo-user@lists.gentoo.org<br>Subject: [gentoo-user] Soft scrolling on framebuffer consoles - with GPM Handling - for kernel 6.18.12 (etc.)<br>Date: Sun, 22 Feb 2026 21:31:48 +0000 [thread overview]<br>Message-ID: (raw)

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

Hello, Gentoo.

The topic of this post is my kernel patch which enables soft scrolling<br>on Linux tty's with and , and also enables<br>the GPM mouse utility on those scrolled regions.

Attached is a patch which enables this facility in kernel 6.18.12 (and<br>likely future 6.18.n versions, too).

To use the patch:<br>(i) cd /usr/src/linux-6.12.18-gentoo, or similar.<br>(ii) patch -p1 [-- Attachment #2: 6.18.12-GPM.20260222.diff --]<br>[-- Type: text/plain, Size: 56438 bytes --]

--- a/include/linux/console_struct.h 2026-02-22 17:41:32.714679279 +0000<br>+++ b/include/linux/console_struct.h 2026-02-22 15:38:39.132803820 +0000<br>@@ -109,6 +109,17 @@<br>unsigned short *vc_screenbuf; /* In-memory character/attribute buffer */<br>unsigned int vc_screenbuf_size;<br>unsigned char vc_mode; /* KD_TEXT, ... */<br>+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK<br>+ unsigned int vc_softback_size; /* Size in bytes of scrollback buffer. */<br>+ unsigned long vc_softback_buf; /* Address of scrollback buffer. */<br>+ unsigned long vc_softback_end; /* (Just past) end of buffer. */<br>+ unsigned long vc_softback_in; /* Head pointer into circular buffer. */<br>+ unsigned long vc_softback_top; /* Tail pointer into circular buffer. */<br>+ unsigned long vc_softback_curr; /* Pos in vc_screenbuf or vc_softback_buf<br>+ corresponding to visible screen. */<br>+ int vc_softback_lines; /* Number of lines currently scrolled. */<br>+ unsigned short vc_char_at_pos; /* Char at vc_pos when no soft scroll */<br>+#endif<br>/* attributes for all characters on screen */<br>unsigned char vc_attr; /* Current attributes */<br>unsigned char vc_def_color; /* Default colors */<br>@@ -158,10 +169,12 @@<br>struct vc_data **vc_display_fg; /* [!] Ptr to var holding fg console for this display */<br>struct uni_pagedict *uni_pagedict;<br>struct uni_pagedict **uni_pagedict_loc; /* [!] Location of uni_pagedict variable for this console */<br>- u32 **vc_uni_lines; /* unicode screen content */<br>u16 *vc_saved_screen;<br>unsigned int vc_saved_cols;<br>unsigned int vc_saved_rows;<br>+ uint32_t *vc_uniscr_buf; /* Address of unicode screen content */<br>+ unsigned int vc_uniscr_char_size; /* Size of *vc-uniscr_buf in 32-bit chars */<br>+ uint32_t *vc_uniscr_curr; /* Pos of first char of (unscrolled) screen */<br>/* additional information is in vt_kern.h */<br>};

@@ -196,4 +209,22 @@

bool con_is_visible(const struct vc_data *vc);

+/* Macros for wraparound in the uniscr buffer. POS must be a uint32_t pointer<br>+ * variable which is expected to be within the confines of vc->vc_uniscr_buf<br>+ * and vc->vc_uniscr_buf + vc->vc_uniscr_char_size. OFFSET must be a positive<br>+ * distance measured in uint32_t's, which when added to or subtracted from POS<br>+ * won't be too far away from the buffer. */<br>+#define UNISCR_PLUS(pos,offset) \<br>+ do { \<br>+ pos += offset; \<br>+ if (pos >= vc->vc_uniscr_buf + vc->vc_uniscr_char_size) \<br>+ pos -= vc->vc_uniscr_char_size; \<br>+ } while (0)<br>+#define UNISCR_MINUS(pos,offset) \<br>+ do { \<br>+ pos -= offset; \<br>+ if (pos vc_uniscr_buf) \<br>+ pos += vc->vc_uniscr_char_size; \<br>+ } while (0)<br>#endif /* _LINUX_CONSOLE_STRUCT_H */<br>--- a/include/linux/vt_kern.h 2026-02-22 17:41:32.795302219 +0000<br>+++ b/include/linux/vt_kern.h 2026-02-22 15:18:55.382750836 +0000<br>@@ -121,6 +121,9 @@<br>/* vt.c */<br>void vt_event_post(unsigned int event, unsigned int old, unsigned int new);<br>int vt_waitactive(int n);<br>+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK<br>+void concon_scrolldelta(struct vc_data *vc, int lines);<br>+#endif<br>void change_console(struct vc_data *new_vc);<br>void reset_vc(struct vc_data *vc);<br>int do_unbind_con_driver(const struct consw *csw, int first, int last,<br>--- a/drivers/video/fbdev/core/fbcon.c 2026-02-22 17:41:32.545737942 +0000<br>+++ b/drivers/video/fbdev/core/fbcon.c 2026-02-22 15:18:55.380750857 +0000<br>@@ -639,6 +639,28 @@<br>erase,<br>vc->vc_size_row * logo_lines);

+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK_GPM<br>+ {<br>+ uint32_t *s = vc->vc_uniscr_curr, *d = vc->vc_uniscr_curr;<br>+ unsigned int i = vc->vc_rows - logo_lines;<br>+ UNISCR_PLUS(d, vc->vc_rows * vc->vc_cols);<br>+ UNISCR_PLUS(s, (vc->vc_rows - logo_lines) * vc->vc_cols);<br>+ while (i--) {<br>+ UNISCR_MINUS(d, vc->vc_cols);<br>+ UNISCR_MINUS(s, vc->vc_cols);<br>+ memcpy(d, s, vc->vc_cols * sizeof (uint32_t));<br>+ }<br>+ i = logo_lines;<br>+ d = vc->vc_uniscr_curr;<br>+ while (i--) {<br>+ memset32(d, ' ', vc->vc_cols);<br>+ UNISCR_PLUS(d, vc->vc_cols);<br>+ }<br>+ vc->vc_uniscr_curr = d;<br>+ }<br>+#endif<br>if (con_is_visible(vc) && vc->vc_mode == KD_TEXT) {<br>fbcon_clear_margins(vc, 0);<br>update_screen(vc);<br>@@ -1289,6 +1311,25 @@<br>* bitmap stretched into the margin...

unsigned gentoo buffer struct vc_cols linux

Related Articles