Skip to content

Commit 15bdab9

Browse files
adaplasLinus Torvalds
authored andcommitted
[PATCH] vgacon: Add support for soft scrollback
The scrollback buffer of the VGA console is located in VGA RAM. This RAM is fixed in size and is very small. To make the scrollback buffer larger, it must be placed instead in System RAM. This patch adds this feature. The feature and the size of the buffer are made as a kernel config option. Besides consuming kernel memory, this feature will slow down the console by approximately 20%. Signed-off-by: Antonino Daplas <[email protected]> Signed-off-by: Jiri Slaby <[email protected]> Cc: Jindrich Makovicka <[email protected]> Cc: Martin Mares <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 2115aea commit 15bdab9

File tree

2 files changed

+225
-43
lines changed

2 files changed

+225
-43
lines changed

drivers/video/console/Kconfig

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,30 @@ config VGA_CONSOLE
2626
# fi
2727
# fi
2828

29+
config VGACON_SOFT_SCROLLBACK
30+
bool "Enable Scrollback Buffer in System RAM"
31+
depends on VGA_CONSOLE
32+
default n
33+
help
34+
The scrollback buffer of the standard VGA console is located in
35+
the VGA RAM. The size of this RAM is fixed and is quite small.
36+
If you require a larger scrollback buffer, this can be placed in
37+
System RAM which is dynamically allocated during intialization.
38+
Placing the scrollback buffer in System RAM will slightly slow
39+
down the console.
40+
41+
If you want this feature, say 'Y' here and enter the amount of
42+
RAM to allocate for this buffer. If unsure, say 'N'.
43+
44+
config VGACON_SOFT_SCROLLBACK_SIZE
45+
int "Scrollback Buffer Size (in KB)"
46+
depends on VGACON_SOFT_SCROLLBACK
47+
default "64"
48+
help
49+
Enter the amount of System RAM to allocate for the scrollback
50+
buffer. Each 64KB will give you approximately 16 80x25
51+
screenfuls of scrollback buffer
52+
2953
config VIDEO_SELECT
3054
bool "Video mode selection support"
3155
depends on X86 && VGA_CONSOLE

drivers/video/console/vgacon.c

Lines changed: 201 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@ static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity,
9393
static void vgacon_invert_region(struct vc_data *c, u16 * p, int count);
9494
static unsigned long vgacon_uni_pagedir[2];
9595

96-
9796
/* Description of the hardware situation */
9897
static unsigned long vga_vram_base; /* Base of video memory */
9998
static unsigned long vga_vram_end; /* End of video memory */
@@ -161,6 +160,201 @@ static inline void write_vga(unsigned char reg, unsigned int val)
161160
spin_unlock_irqrestore(&vga_lock, flags);
162161
}
163162

163+
static inline void vga_set_mem_top(struct vc_data *c)
164+
{
165+
write_vga(12, (c->vc_visible_origin - vga_vram_base) / 2);
166+
}
167+
168+
#ifdef CONFIG_VGACON_SOFT_SCROLLBACK
169+
#include <linux/bootmem.h>
170+
/* software scrollback */
171+
static void *vgacon_scrollback;
172+
static int vgacon_scrollback_tail;
173+
static int vgacon_scrollback_size;
174+
static int vgacon_scrollback_rows;
175+
static int vgacon_scrollback_cnt;
176+
static int vgacon_scrollback_cur;
177+
static int vgacon_scrollback_save;
178+
static int vgacon_scrollback_restore;
179+
180+
static void vgacon_scrollback_init(int pitch)
181+
{
182+
int rows = CONFIG_VGACON_SOFT_SCROLLBACK_SIZE * 1024/pitch;
183+
184+
if (vgacon_scrollback) {
185+
vgacon_scrollback_cnt = 0;
186+
vgacon_scrollback_tail = 0;
187+
vgacon_scrollback_cur = 0;
188+
vgacon_scrollback_rows = rows - 1;
189+
vgacon_scrollback_size = rows * pitch;
190+
}
191+
}
192+
193+
static void __init vgacon_scrollback_startup(void)
194+
{
195+
vgacon_scrollback = alloc_bootmem(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE
196+
* 1024);
197+
vgacon_scrollback_init(vga_video_num_columns * 2);
198+
}
199+
200+
static void vgacon_scrollback_update(struct vc_data *c, int t, int count)
201+
{
202+
void *p;
203+
204+
if (!vgacon_scrollback_size || c->vc_num != fg_console)
205+
return;
206+
207+
p = (void *) (c->vc_origin + t * c->vc_size_row);
208+
209+
while (count--) {
210+
scr_memcpyw(vgacon_scrollback + vgacon_scrollback_tail,
211+
p, c->vc_size_row);
212+
vgacon_scrollback_cnt++;
213+
p += c->vc_size_row;
214+
vgacon_scrollback_tail += c->vc_size_row;
215+
216+
if (vgacon_scrollback_tail >= vgacon_scrollback_size)
217+
vgacon_scrollback_tail = 0;
218+
219+
if (vgacon_scrollback_cnt > vgacon_scrollback_rows)
220+
vgacon_scrollback_cnt = vgacon_scrollback_rows;
221+
222+
vgacon_scrollback_cur = vgacon_scrollback_cnt;
223+
}
224+
}
225+
226+
static void vgacon_restore_screen(struct vc_data *c)
227+
{
228+
vgacon_scrollback_save = 0;
229+
230+
if (!vga_is_gfx && !vgacon_scrollback_restore) {
231+
scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf,
232+
c->vc_screenbuf_size > vga_vram_size ?
233+
vga_vram_size : c->vc_screenbuf_size);
234+
vgacon_scrollback_restore = 1;
235+
vgacon_scrollback_cur = vgacon_scrollback_cnt;
236+
}
237+
}
238+
239+
static int vgacon_scrolldelta(struct vc_data *c, int lines)
240+
{
241+
int start, end, count, soff, diff;
242+
void *d, *s;
243+
244+
if (!lines) {
245+
c->vc_visible_origin = c->vc_origin;
246+
vga_set_mem_top(c);
247+
return 1;
248+
}
249+
250+
if (!vgacon_scrollback)
251+
return 1;
252+
253+
if (!vgacon_scrollback_save) {
254+
vgacon_cursor(c, CM_ERASE);
255+
vgacon_save_screen(c);
256+
vgacon_scrollback_save = 1;
257+
}
258+
259+
vgacon_scrollback_restore = 0;
260+
start = vgacon_scrollback_cur + lines;
261+
end = start + abs(lines);
262+
263+
if (start < 0)
264+
start = 0;
265+
266+
if (start > vgacon_scrollback_cnt)
267+
start = vgacon_scrollback_cnt;
268+
269+
if (end < 0)
270+
end = 0;
271+
272+
if (end > vgacon_scrollback_cnt)
273+
end = vgacon_scrollback_cnt;
274+
275+
vgacon_scrollback_cur = start;
276+
count = end - start;
277+
soff = vgacon_scrollback_tail - ((vgacon_scrollback_cnt - end) *
278+
c->vc_size_row);
279+
soff -= count * c->vc_size_row;
280+
281+
if (soff < 0)
282+
soff += vgacon_scrollback_size;
283+
284+
count = vgacon_scrollback_cnt - start;
285+
286+
if (count > c->vc_rows)
287+
count = c->vc_rows;
288+
289+
diff = c->vc_rows - count;
290+
291+
d = (void *) c->vc_origin;
292+
s = (void *) c->vc_screenbuf;
293+
294+
while (count--) {
295+
scr_memcpyw(d, vgacon_scrollback + soff, c->vc_size_row);
296+
d += c->vc_size_row;
297+
soff += c->vc_size_row;
298+
299+
if (soff >= vgacon_scrollback_size)
300+
soff = 0;
301+
}
302+
303+
if (diff == c->vc_rows) {
304+
vgacon_cursor(c, CM_MOVE);
305+
} else {
306+
while (diff--) {
307+
scr_memcpyw(d, s, c->vc_size_row);
308+
d += c->vc_size_row;
309+
s += c->vc_size_row;
310+
}
311+
}
312+
313+
return 1;
314+
}
315+
#else
316+
#define vgacon_scrollback_startup(...) do { } while (0)
317+
#define vgacon_scrollback_init(...) do { } while (0)
318+
#define vgacon_scrollback_update(...) do { } while (0)
319+
320+
static void vgacon_restore_screen(struct vc_data *c)
321+
{
322+
if (c->vc_origin != c->vc_visible_origin)
323+
vgacon_scrolldelta(c, 0);
324+
}
325+
326+
static int vgacon_scrolldelta(struct vc_data *c, int lines)
327+
{
328+
if (!lines) /* Turn scrollback off */
329+
c->vc_visible_origin = c->vc_origin;
330+
else {
331+
int margin = c->vc_size_row * 4;
332+
int ul, we, p, st;
333+
334+
if (vga_rolled_over >
335+
(c->vc_scr_end - vga_vram_base) + margin) {
336+
ul = c->vc_scr_end - vga_vram_base;
337+
we = vga_rolled_over + c->vc_size_row;
338+
} else {
339+
ul = 0;
340+
we = vga_vram_size;
341+
}
342+
p = (c->vc_visible_origin - vga_vram_base - ul + we) % we +
343+
lines * c->vc_size_row;
344+
st = (c->vc_origin - vga_vram_base - ul + we) % we;
345+
if (st < 2 * margin)
346+
margin = 0;
347+
if (p < margin)
348+
p = 0;
349+
if (p > st - margin)
350+
p = st;
351+
c->vc_visible_origin = vga_vram_base + (p + ul) % we;
352+
}
353+
vga_set_mem_top(c);
354+
return 1;
355+
}
356+
#endif /* CONFIG_VGACON_SOFT_SCROLLBACK */
357+
164358
static const char __init *vgacon_startup(void)
165359
{
166360
const char *display_desc = NULL;
@@ -330,7 +524,7 @@ static const char __init *vgacon_startup(void)
330524

331525
vgacon_xres = ORIG_VIDEO_COLS * VGA_FONTWIDTH;
332526
vgacon_yres = vga_scan_lines;
333-
527+
vgacon_scrollback_startup();
334528
return display_desc;
335529
}
336530

@@ -357,11 +551,6 @@ static void vgacon_init(struct vc_data *c, int init)
357551
con_set_default_unimap(c);
358552
}
359553

360-
static inline void vga_set_mem_top(struct vc_data *c)
361-
{
362-
write_vga(12, (c->vc_visible_origin - vga_vram_base) / 2);
363-
}
364-
365554
static void vgacon_deinit(struct vc_data *c)
366555
{
367556
/* When closing the last console, reset video origin */
@@ -455,8 +644,8 @@ static void vgacon_set_cursor_size(int xpos, int from, int to)
455644

456645
static void vgacon_cursor(struct vc_data *c, int mode)
457646
{
458-
if (c->vc_origin != c->vc_visible_origin)
459-
vgacon_scrolldelta(c, 0);
647+
vgacon_restore_screen(c);
648+
460649
switch (mode) {
461650
case CM_ERASE:
462651
write_vga(14, (c->vc_pos - vga_vram_base) / 2);
@@ -606,6 +795,7 @@ static int vgacon_switch(struct vc_data *c)
606795
vgacon_doresize(c, c->vc_cols, c->vc_rows);
607796
}
608797

798+
vgacon_scrollback_init(c->vc_size_row);
609799
return 0; /* Redrawing not needed */
610800
}
611801

@@ -1073,37 +1263,6 @@ static int vgacon_resize(struct vc_data *c, unsigned int width,
10731263
return 0;
10741264
}
10751265

1076-
static int vgacon_scrolldelta(struct vc_data *c, int lines)
1077-
{
1078-
if (!lines) /* Turn scrollback off */
1079-
c->vc_visible_origin = c->vc_origin;
1080-
else {
1081-
int margin = c->vc_size_row * 4;
1082-
int ul, we, p, st;
1083-
1084-
if (vga_rolled_over >
1085-
(c->vc_scr_end - vga_vram_base) + margin) {
1086-
ul = c->vc_scr_end - vga_vram_base;
1087-
we = vga_rolled_over + c->vc_size_row;
1088-
} else {
1089-
ul = 0;
1090-
we = vga_vram_size;
1091-
}
1092-
p = (c->vc_visible_origin - vga_vram_base - ul + we) % we +
1093-
lines * c->vc_size_row;
1094-
st = (c->vc_origin - vga_vram_base - ul + we) % we;
1095-
if (st < 2 * margin)
1096-
margin = 0;
1097-
if (p < margin)
1098-
p = 0;
1099-
if (p > st - margin)
1100-
p = st;
1101-
c->vc_visible_origin = vga_vram_base + (p + ul) % we;
1102-
}
1103-
vga_set_mem_top(c);
1104-
return 1;
1105-
}
1106-
11071266
static int vgacon_set_origin(struct vc_data *c)
11081267
{
11091268
if (vga_is_gfx || /* We don't play origin tricks in graphic modes */
@@ -1146,15 +1305,14 @@ static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
11461305
if (t || b != c->vc_rows || vga_is_gfx)
11471306
return 0;
11481307

1149-
if (c->vc_origin != c->vc_visible_origin)
1150-
vgacon_scrolldelta(c, 0);
1151-
11521308
if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2)
11531309
return 0;
11541310

1311+
vgacon_restore_screen(c);
11551312
oldo = c->vc_origin;
11561313
delta = lines * c->vc_size_row;
11571314
if (dir == SM_UP) {
1315+
vgacon_scrollback_update(c, t, lines);
11581316
if (c->vc_scr_end + delta >= vga_vram_end) {
11591317
scr_memcpyw((u16 *) vga_vram_base,
11601318
(u16 *) (oldo + delta),

0 commit comments

Comments
 (0)