1 # --- T2-COPYRIGHT-NOTE-BEGIN ---
2 # T2 SDE: package/*/linux/restore-con-scrollback.patch
3 # Copyright (C) 2024 The T2 SDE Project
5 # This Copyright note is generated by scripts/Create-CopyPatch,
6 # more information can be found in the files COPYING and README.
8 # This patch file is dual-licensed. It is available under the license the
9 # patched project is licensed under, as long as it is an OpenSource license
10 # as defined at http://www.opensource.org/ (e.g. BSD, X11) or under the terms
11 # of the GNU General Public License version 2 as used by the T2 SDE.
12 # --- T2-COPYRIGHT-NOTE-END ---
14 f441aa3b441306e35e8fcbec5ac13c68b5f48245
15 7cf01c92addb73c3055ff0fc596441c80ce82113
16 42822fabfc24f4fc8d5404d9359fa17a0bcfcea8
17 af757ca6b274bc3db025617a7f8960166734cf9e fbcon: remove fbcon_getxy()
18 d62808ba9ebca537607678207d2deb25d949d923 fbcon: remove consw::con_screen_pos()
20 # 174657478cd8425288aeabf93b964b9387e096fa maybe
22 03b89a08484a88fb9e0604cab2b3eb0c2f265c74
23 6ceed69cde8fe4a78fe50d62d7a88a5c1eed4709 A
24 0ae798fd96f8c28850e09d22d3f0d455071ed8eb vgacon: drop unused vga_init_done
25 973c096f6a85e5b5f2a295126ba6928d9a6afd45 vgacon: remove software scrollback support
27 1a336c934623b011c289a298aff3b7fdefb3f876
28 bcd375f7f71f7106c97516bf5395149954ef8810
30 4f59617065592c446cd8450e9e6bac229cbc1383 tty: vt: make consw::con_font_default()'s name const
31 fd0f631fffa87f1c26045c3c88c0c4a7706d14de tty: vt: make font of consw::con_font_set() const
32 a292e3fc94cb9795bbba4ddac075a9055cd58a5e tty: vt: remove CM_* constants
33 bfeb28539d1f61829232883ced0986569218c4de fbcon: remove no-op fbcon_set_origin()
34 06a0df4d1b8b13b551668e47b11fd7629033b7df fbcon: remove now unusued 'softback_lines' cursor() argument
35 50145474f6ef4a9c19205b173da6264a644c7489 fbcon: remove soft scrollback code
37 diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
38 index bc31db6ef7d2..6cadef33fa83 100644
39 --- a/drivers/video/console/Kconfig
40 +++ b/drivers/video/console/Kconfig
41 @@ -84,8 +84,7 @@ config FRAMEBUFFER_CONSOLE
42 config FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
43 bool "Enable legacy fbcon hardware acceleration code"
44 depends on FRAMEBUFFER_CONSOLE
49 This option enables the fbcon (framebuffer text-based) hardware
50 acceleration for graphics drivers which were written for the fbdev
51 diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
52 index 96842ce817af..ac2383746483 100644
53 --- a/drivers/tty/vt/vt.c
54 +++ b/drivers/tty/vt/vt.c
55 @@ -289,9 +289,15 @@ static inline bool con_should_update(const struct vc_data *vc)
56 static inline u16 *screenpos(const struct vc_data *vc, unsigned int offset,
59 - unsigned long origin = viewed ? vc->vc_visible_origin : vc->vc_origin;
62 - return (u16 *)(origin + offset);
64 + p = (unsigned short *)(vc->vc_origin + offset);
65 + else if (!vc->vc_sw->con_screen_pos)
66 + p = (unsigned short *)(vc->vc_visible_origin + offset);
68 + p = vc->vc_sw->con_screen_pos(vc, offset);
72 static void con_putc(struct vc_data *vc, u16 ca, unsigned int y, unsigned int x)
73 @@ -593,12 +599,18 @@ static void con_scroll(struct vc_data *vc, unsigned int top,
74 static void do_update_region(struct vc_data *vc, unsigned long start, int count)
76 unsigned int xx, yy, offset;
77 - u16 *p = (u16 *)start;
79 - offset = (start - vc->vc_origin) / 2;
80 - xx = offset % vc->vc_cols;
81 - yy = offset / vc->vc_cols;
85 + if (!vc->vc_sw->con_getxy) {
86 + offset = (start - vc->vc_origin) / 2;
87 + xx = offset % vc->vc_cols;
88 + yy = offset / vc->vc_cols;
91 + start = vc->vc_sw->con_getxy(vc, start, &nxx, &nyy);
95 u16 attrib = scr_readw(p) & 0xff00;
97 @@ -621,6 +633,10 @@ static void do_update_region(struct vc_data *vc, unsigned long start, int count)
101 + if (vc->vc_sw->con_getxy) {
103 + start = vc->vc_sw->con_getxy(vc, start, NULL, NULL);
108 @@ -843,7 +859,7 @@ static void hide_cursor(struct vc_data *vc)
112 - vc->vc_sw->con_cursor(vc, false);
113 + vc->vc_sw->con_cursor(vc, CM_ERASE);
117 @@ -856,7 +872,7 @@ static void set_cursor(struct vc_data *vc)
120 if (CUR_SIZE(vc->vc_cursor_type) != CUR_NONE)
121 - vc->vc_sw->con_cursor(vc, true);
122 + vc->vc_sw->con_cursor(vc, CM_DRAW);
126 diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
127 index bc31db6ef7d2..82201ed06a36 100644
128 --- a/drivers/video/console/Kconfig
129 +++ b/drivers/video/console/Kconfig
130 @@ -23,6 +23,31 @@ config VGA_CONSOLE
134 +config VGACON_SOFT_SCROLLBACK
135 + bool "Enable Scrollback Buffer in System RAM"
136 + depends on VGA_CONSOLE
139 + The scrollback buffer of the standard VGA console is located in
140 + the VGA RAM. The size of this RAM is fixed and is quite small.
141 + If you require a larger scrollback buffer, this can be placed in
142 + System RAM which is dynamically allocated during initialization.
143 + Placing the scrollback buffer in System RAM will slightly slow
146 + If you want this feature, say 'Y' here and enter the amount of
147 + RAM to allocate for this buffer. If unsure, say 'N'.
149 +config VGACON_SOFT_SCROLLBACK_SIZE
150 + int "Scrollback Buffer Size (in KB)"
151 + depends on VGACON_SOFT_SCROLLBACK
155 + Enter the amount of System RAM to allocate for scrollback
156 + buffers of VGA consoles. Each 64KB will give you approximately
157 + 16 80x25 screenfuls of scrollback buffer.
160 depends on !M68K && !PARISC && ISA
161 tristate "MDA text console (dual-headed)"
162 diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c
163 index 139049368fdc..95109b6bb651 100644
164 --- a/drivers/video/console/dummycon.c
165 +++ b/drivers/video/console/dummycon.c
166 @@ -115,7 +115,7 @@ static void dummycon_init(struct vc_data *vc, bool init)
167 static void dummycon_deinit(struct vc_data *vc) { }
168 static void dummycon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
169 unsigned int width) { }
170 -static void dummycon_cursor(struct vc_data *vc, bool enable) { }
171 +static void dummycon_cursor(struct vc_data *vc, int mode) { }
173 static bool dummycon_scroll(struct vc_data *vc, unsigned int top,
174 unsigned int bottom, enum con_scroll dir,
175 diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c
176 index d52cd99cd18b..47e7529338ad 100644
177 --- a/drivers/video/console/mdacon.c
178 +++ b/drivers/video/console/mdacon.c
179 @@ -471,9 +471,9 @@ static bool mdacon_blank(struct vc_data *c, enum vesa_blank_mode blank,
183 -static void mdacon_cursor(struct vc_data *c, bool enable)
184 +static void mdacon_cursor(struct vc_data *c, int mode)
187 + if (mode == CM_ERASE) {
188 mda_set_cursor(mda_vram_len - 1);
191 diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c
192 index 242415366074..4daf31a635a8 100644
193 --- a/drivers/video/console/newport_con.c
194 +++ b/drivers/video/console/newport_con.c
195 @@ -438,14 +438,14 @@ static void newport_putcs(struct vc_data *vc, const u16 *s,
199 -static void newport_cursor(struct vc_data *vc, bool enable)
200 +static void newport_cursor(struct vc_data *vc, int mode)
205 treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
208 + if (mode == CM_ERASE) {
209 newport_vc2_set(npregs, VC2_IREG_CONTROL,
210 (treg & ~(VC2_CTRL_ECDISP)));
212 diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c
213 index f1f3ee8e5e8a..2619e7499013 100644
214 --- a/drivers/video/console/sticon.c
215 +++ b/drivers/video/console/sticon.c
216 @@ -86,7 +86,7 @@ static void sticon_putcs(struct vc_data *conp, const u16 *s, unsigned int count,
220 -static void sticon_cursor(struct vc_data *conp, bool enable)
221 +static void sticon_cursor(struct vc_data *conp, int mode)
225 @@ -95,7 +95,7 @@ static void sticon_cursor(struct vc_data *conp, bool enable)
228 car1 = conp->vc_screenbuf[conp->state.x + conp->state.y * conp->vc_cols];
230 + if (mode == CM_ERASE) {
231 sti_putc(sticon_sti, car1, conp->state.y, conp->state.x,
232 font_data[conp->vc_num]);
234 @@ -121,7 +121,7 @@ static bool sticon_scroll(struct vc_data *conp, unsigned int t,
238 - sticon_cursor(conp, false);
239 + sticon_cursor(conp, CM_ERASE);
243 @@ -246,8 +246,7 @@ static int sticon_set_font(struct vc_data *vc, const struct console_font *op,
247 -static int sticon_font_default(struct vc_data *vc, struct console_font *op,
249 +static int sticon_font_default(struct vc_data *vc, struct console_font *op, const char *name)
251 sticon_set_def_font(vc->vc_num);
253 diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
254 index 37bd18730fe0..e0f44b77f882 100644
255 --- a/drivers/video/console/vgacon.c
256 +++ b/drivers/video/console/vgacon.c
257 @@ -65,12 +65,18 @@ static struct vgastate vgastate;
258 * Interface used by the world
261 -static bool vgacon_set_origin(struct vc_data *c);
262 +static const char *vgacon_startup(void);
263 +static void vgacon_cursor(struct vc_data *c, int mode);
264 +static int vgacon_set_origin(struct vc_data *c);
265 +static void vgacon_save_screen(struct vc_data *c);
266 +static void vgacon_scrollback_switch(int vc_num);
267 +static void vgacon_scrolldelta(struct vc_data *c, int lines);
269 static struct uni_pagedict *vgacon_uni_pagedir;
270 static int vgacon_refcount;
272 /* Description of the hardware situation */
273 +static bool vga_init_done;
274 static unsigned long vga_vram_base __read_mostly; /* Base of video memory */
275 static unsigned long vga_vram_end __read_mostly; /* End of video memory */
276 static unsigned int vga_vram_size __read_mostly; /* Size of video memory */
277 @@ -136,6 +140,204 @@ static inline void vga_set_mem_top(struct vc_data *c)
278 write_vga(12, (c->vc_visible_origin - vga_vram_base) / 2);
281 +#ifdef CONFIG_VGACON_SOFT_SCROLLBACK
282 +/* software scrollback */
283 +struct vgacon_scrollback_info {
294 +static struct vgacon_scrollback_info *vgacon_scrollback_cur;
295 +static struct vgacon_scrollback_info vgacon_scrollbacks[1];
297 +static void vgacon_scrollback_reset(int vc_num, size_t reset_size)
299 + struct vgacon_scrollback_info *scrollback = &vgacon_scrollbacks[vc_num];
301 + if (scrollback->data && reset_size > 0)
302 + memset(scrollback->data, 0, reset_size);
304 + scrollback->cnt = 0;
305 + scrollback->tail = 0;
306 + scrollback->cur = 0;
309 +static void vgacon_scrollback_init(int vc_num)
311 + int pitch = vga_video_num_columns * 2;
312 + size_t size = CONFIG_VGACON_SOFT_SCROLLBACK_SIZE * 1024;
313 + int rows = size / pitch;
316 + data = kmalloc_array(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE, 1024,
319 + vgacon_scrollbacks[vc_num].data = data;
320 + vgacon_scrollback_cur = &vgacon_scrollbacks[vc_num];
322 + vgacon_scrollback_cur->rows = rows - 1;
323 + vgacon_scrollback_cur->size = rows * pitch;
325 + vgacon_scrollback_reset(vc_num, size);
328 +static void vgacon_scrollback_switch(int vc_num)
332 + if (!vgacon_scrollbacks[vc_num].data) {
333 + vgacon_scrollback_init(vc_num);
335 + size_t size = CONFIG_VGACON_SOFT_SCROLLBACK_SIZE * 1024;
337 + vgacon_scrollback_reset(vc_num, size);
341 +static void vgacon_scrollback_startup(void)
343 + vgacon_scrollback_cur = &vgacon_scrollbacks[0];
344 + vgacon_scrollback_init(0);
347 +static void vgacon_scrollback_update(struct vc_data *c, int t, int count)
351 + if (!vgacon_scrollback_cur->data || !vgacon_scrollback_cur->size ||
352 + c->vc_num != fg_console)
355 + p = (void *) (c->vc_origin + t * c->vc_size_row);
358 + if ((vgacon_scrollback_cur->tail + c->vc_size_row) >
359 + vgacon_scrollback_cur->size)
360 + vgacon_scrollback_cur->tail = 0;
362 + scr_memcpyw(vgacon_scrollback_cur->data +
363 + vgacon_scrollback_cur->tail,
364 + p, c->vc_size_row);
366 + vgacon_scrollback_cur->cnt++;
367 + p += c->vc_size_row;
368 + vgacon_scrollback_cur->tail += c->vc_size_row;
370 + if (vgacon_scrollback_cur->tail >= vgacon_scrollback_cur->size)
371 + vgacon_scrollback_cur->tail = 0;
373 + if (vgacon_scrollback_cur->cnt > vgacon_scrollback_cur->rows)
374 + vgacon_scrollback_cur->cnt = vgacon_scrollback_cur->rows;
376 + vgacon_scrollback_cur->cur = vgacon_scrollback_cur->cnt;
380 +static void vgacon_restore_screen(struct vc_data *c)
382 + c->vc_origin = c->vc_visible_origin;
383 + vgacon_scrollback_cur->save = 0;
385 + if (!vga_is_gfx && !vgacon_scrollback_cur->restore) {
386 + scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf,
387 + c->vc_screenbuf_size > vga_vram_size ?
388 + vga_vram_size : c->vc_screenbuf_size);
389 + vgacon_scrollback_cur->restore = 1;
390 + vgacon_scrollback_cur->cur = vgacon_scrollback_cur->cnt;
394 +static void vgacon_scrolldelta(struct vc_data *c, int lines)
396 + int start, end, count, soff;
399 + vgacon_restore_screen(c);
403 + if (!vgacon_scrollback_cur->data)
406 + if (!vgacon_scrollback_cur->save) {
407 + vgacon_cursor(c, CM_ERASE);
408 + vgacon_save_screen(c);
409 + c->vc_origin = (unsigned long)c->vc_screenbuf;
410 + vgacon_scrollback_cur->save = 1;
413 + vgacon_scrollback_cur->restore = 0;
414 + start = vgacon_scrollback_cur->cur + lines;
415 + end = start + abs(lines);
420 + if (start > vgacon_scrollback_cur->cnt)
421 + start = vgacon_scrollback_cur->cnt;
426 + if (end > vgacon_scrollback_cur->cnt)
427 + end = vgacon_scrollback_cur->cnt;
429 + vgacon_scrollback_cur->cur = start;
430 + count = end - start;
431 + soff = vgacon_scrollback_cur->tail -
432 + ((vgacon_scrollback_cur->cnt - end) * c->vc_size_row);
433 + soff -= count * c->vc_size_row;
436 + soff += vgacon_scrollback_cur->size;
438 + count = vgacon_scrollback_cur->cnt - start;
440 + if (count > c->vc_rows)
441 + count = c->vc_rows;
446 + int diff = c->vc_rows - count;
447 + void *d = (void *) c->vc_visible_origin;
448 + void *s = (void *) c->vc_screenbuf;
450 + count *= c->vc_size_row;
451 + /* how much memory to end of buffer left? */
452 + copysize = min(count, vgacon_scrollback_cur->size - soff);
453 + scr_memcpyw(d, vgacon_scrollback_cur->data + soff, copysize);
458 + scr_memcpyw(d, vgacon_scrollback_cur->data, count);
463 + scr_memcpyw(d, s, diff * c->vc_size_row);
465 + vgacon_cursor(c, CM_MOVE);
469 +#define vgacon_scrollback_startup(...) do { } while (0)
470 +#define vgacon_scrollback_init(...) do { } while (0)
471 +#define vgacon_scrollback_update(...) do { } while (0)
473 +static void vgacon_restore_screen(struct vc_data *c)
475 + if (c->vc_origin != c->vc_visible_origin)
476 + vgacon_scrolldelta(c, 0);
479 static void vgacon_scrolldelta(struct vc_data *c, int lines)
481 unsigned long scr_end = c->vc_scr_end - vga_vram_base;
482 @@ -175,11 +377,7 @@ static void vgacon_scrolldelta(struct vc_data *c, int lines)
486 -static void vgacon_restore_screen(struct vc_data *c)
488 - if (c->vc_origin != c->vc_visible_origin)
489 - vgacon_scrolldelta(c, 0);
491 +#endif /* CONFIG_VGACON_SOFT_SCROLLBACK */
493 static const char *vgacon_startup(void)
495 @@ -364,6 +562,11 @@ static const char *vgacon_startup(void)
496 vgacon_xres = vga_si->orig_video_cols * VGA_FONTWIDTH;
497 vgacon_yres = vga_scan_lines;
499 + if (!vga_init_done) {
500 + vgacon_scrollback_startup();
501 + vga_init_done = true;
507 @@ -503,7 +706,7 @@ static void vgacon_set_cursor_size(int from, int to)
508 raw_spin_unlock_irqrestore(&vga_lock, flags);
511 -static void vgacon_cursor(struct vc_data *c, bool enable)
512 +static void vgacon_cursor(struct vc_data *c, int mode)
514 unsigned int c_height;
516 @@ -516,7 +719,7 @@ static void vgacon_cursor(struct vc_data *c, bool enable)
518 write_vga(14, (c->vc_pos - vga_vram_base) / 2);
521 + if (mode == CM_ERASE) {
522 if (vga_video_type >= VIDEO_TYPE_VGAC)
523 vgacon_set_cursor_size(31, 30);
525 @@ -643,6 +846,7 @@ static bool vgacon_switch(struct vc_data *c)
526 vgacon_doresize(c, c->vc_cols, c->vc_rows);
529 + vgacon_scrollback_switch(c->vc_num);
530 return false; /* Redrawing not needed */
533 @@ -1030,7 +1234,7 @@ static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight)
534 /* void size to cause regs to be rewritten */
535 cursor_size_lastfrom = 0;
536 cursor_size_lastto = 0;
537 - c->vc_sw->con_cursor(c, true);
538 + c->vc_sw->con_cursor(c, CM_DRAW);
540 c->vc_font.height = c->vc_cell_height = fontheight;
541 vc_resize(c, 0, rows); /* Adjust console size */
542 @@ -1100,15 +1304,15 @@ static int vgacon_resize(struct vc_data *c, unsigned int width,
546 -static bool vgacon_set_origin(struct vc_data *c)
547 +static int vgacon_set_origin(struct vc_data *c)
549 if (vga_is_gfx || /* We don't play origin tricks in graphic modes */
550 (console_blanked && !vga_palette_blanked)) /* Nor we write to blanked screens */
553 c->vc_origin = c->vc_visible_origin = vga_vram_base;
560 static void vgacon_save_screen(struct vc_data *c)
561 @@ -1149,6 +1353,7 @@ static bool vgacon_scroll(struct vc_data *c, unsigned int t, unsigned int b,
563 delta = lines * c->vc_size_row;
565 + vgacon_scrollback_update(c, t, lines);
566 if (c->vc_scr_end + delta >= vga_vram_end) {
567 scr_memcpyw((u16 *) vga_vram_base,
568 (u16 *) (oldo + delta),
569 diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c
570 index 3ff1b2a8659e..9bf7d56e0d20 100644
571 --- a/drivers/video/fbdev/core/bitblit.c
572 +++ b/drivers/video/fbdev/core/bitblit.c
573 @@ -233,8 +233,8 @@ static void bit_clear_margins(struct vc_data *vc, struct fb_info *info,
577 -static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
579 +static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode,
580 + int softback_lines, int fg, int bg)
582 struct fb_cursor cursor;
583 struct fbcon_ops *ops = info->fbcon_par;
584 @@ -250,6 +250,15 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
585 if (!vc->vc_font.data)
588 + if (softback_lines) {
589 + if (y + softback_lines >= vc->vc_rows) {
591 + ops->cursor_flash = 0;
594 + y += softback_lines;
597 c = scr_readw((u16 *) vc->vc_pos);
598 attribute = get_attribute(info, c);
599 src = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height));
600 @@ -348,7 +357,7 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
604 - ops->cursor_state.enable = enable && !use_sw;
605 + ops->cursor_state.enable = (mode != CM_ERASE) && !use_sw;
607 cursor.image.data = src;
608 cursor.image.fg_color = ops->cursor_state.image.fg_color;
609 diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
610 index e8b4e8c119b5..e6818f5fa629 100644
611 --- a/drivers/video/fbdev/core/fbcon.c
612 +++ b/drivers/video/fbdev/core/fbcon.c
613 @@ -126,6 +126,12 @@ static int logo_lines;
614 /* logo_shown is an index to vc_cons when >= 0; otherwise follows FBCON_LOGO
616 static int logo_shown = FBCON_LOGO_CANSHOW;
617 +/* Software scrollback */
618 +static int fbcon_softback_size = 0x10000;
619 +static unsigned long softback_buf, softback_curr;
620 +static unsigned long softback_in;
621 +static unsigned long softback_top, softback_end;
622 +static int softback_lines;
623 /* console mappings */
624 static unsigned int first_fb_vc;
625 static unsigned int last_fb_vc = MAX_NR_CONSOLES - 1;
626 @@ -165,8 +171,12 @@ static int margin_color;
628 static const struct consw fb_con;
630 +#define CM_SOFTBACK (8)
632 #define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row)
634 +static int fbcon_set_origin(struct vc_data *);
636 static int fbcon_cursor_noblink;
638 #define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1)
639 @@ -359,13 +369,25 @@ static int get_color(struct vc_data *vc, struct fb_info *info,
643 +static void fbcon_update_softback(struct vc_data *vc)
645 + int l = fbcon_softback_size / vc->vc_size_row;
648 + softback_end = softback_buf + l * vc->vc_size_row;
650 + /* Smaller scrollback makes no sense, and 0 would screw
651 + the operation totally */
655 static void fb_flashcursor(struct work_struct *work)
657 struct fbcon_ops *ops = container_of(work, struct fbcon_ops, cursor_work.work);
658 struct fb_info *info;
659 struct vc_data *vc = NULL;
665 /* FIXME: we should sort out the unbind locking instead */
666 @@ -389,8 +411,9 @@ static void fb_flashcursor(struct work_struct *work)
669 c = scr_readw((u16 *) vc->vc_pos);
670 - enable = ops->cursor_flash && !ops->cursor_state.enable;
671 - ops->cursor(vc, info, enable, get_color(vc, info, c, 1),
672 + mode = (!ops->cursor_flash || ops->cursor_state.enable) ?
673 + CM_ERASE : CM_DRAW;
674 + ops->cursor(vc, info, mode, softback_lines, get_color(vc, info, c, 1),
675 get_color(vc, info, c, 0));
678 @@ -430,7 +453,13 @@ static int __init fb_console_setup(char *this_opt)
681 if (!strncmp(options, "scrollback:", 11)) {
682 - pr_warn("Ignoring scrollback size option\n");
685 + fbcon_softback_size = simple_strtoul(options, &options, 0);
686 + if (*options == 'k' || *options == 'K') {
687 + fbcon_softback_size *= 1024;
693 @@ -977,6 +1006,31 @@ static const char *fbcon_startup(void)
695 set_blitting_type(vc, info);
697 + if (info->fix.type != FB_TYPE_TEXT) {
698 + if (fbcon_softback_size) {
699 + if (!softback_buf) {
702 + kvmalloc(fbcon_softback_size,
704 + if (!softback_buf) {
705 + fbcon_softback_size = 0;
710 + if (softback_buf) {
711 + kvfree((void *) softback_buf);
717 + softback_in = softback_top = softback_curr =
719 + softback_lines = 0;
722 /* Setup default font */
724 if (!fontname[0] || !(font = find_font(fontname)))
725 @@ -1145,6 +1199,9 @@ static void fbcon_init(struct vc_data *vc, bool init)
727 fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows);
729 + if (vc == svc && softback_buf)
730 + fbcon_update_softback(vc);
732 if (ops->rotate_font && ops->rotate_font(info, vc)) {
733 ops->rotate = FB_ROTATE_UR;
734 set_blitting_type(vc, info);
735 @@ -1319,10 +1376,11 @@ static void fbcon_clear_margins(struct vc_data *vc, int bottom_only)
736 ops->clear_margins(vc, info, margin_color, bottom_only);
739 -static void fbcon_cursor(struct vc_data *vc, bool enable)
740 +static void fbcon_cursor(struct vc_data *vc, int mode)
742 struct fb_info *info = fbcon_info_from_console(vc->vc_num);
743 struct fbcon_ops *ops = info->fbcon_par;
745 int c = scr_readw((u16 *) vc->vc_pos);
747 ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
748 @@ -1335,12 +1393,21 @@ static void fbcon_cursor(struct vc_data *vc, bool enable)
750 fbcon_add_cursor_work(info);
752 - ops->cursor_flash = enable;
753 + ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1;
758 - ops->cursor(vc, info, enable, get_color(vc, info, c, 1),
759 + if (mode & CM_SOFTBACK) {
760 + mode &= ~CM_SOFTBACK;
761 + y = softback_lines;
763 + if (softback_lines)
764 + fbcon_set_origin(vc);
768 + ops->cursor(vc, info, mode, y, get_color(vc, info, c, 1),
769 get_color(vc, info, c, 0));
772 @@ -1410,6 +1477,8 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
774 if (con_is_visible(vc)) {
777 + fbcon_update_softback(vc);
781 @@ -1547,6 +1616,99 @@ static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count)
782 scrollback_current = 0;
785 +static void fbcon_redraw_softback(struct vc_data *vc, struct fbcon_display *p,
788 + int count = vc->vc_rows;
789 + unsigned short *d, *s;
793 + d = (u16 *) softback_curr;
794 + if (d == (u16 *) softback_in)
795 + d = (u16 *) vc->vc_origin;
796 + n = softback_curr + delta * vc->vc_size_row;
797 + softback_lines -= delta;
799 + if (softback_curr < softback_top && n < softback_buf) {
800 + n += softback_end - softback_buf;
801 + if (n < softback_top) {
803 + (softback_top - n) / vc->vc_size_row;
806 + } else if (softback_curr >= softback_top
807 + && n < softback_top) {
809 + (softback_top - n) / vc->vc_size_row;
813 + if (softback_curr > softback_in && n >= softback_end) {
814 + n += softback_buf - softback_end;
815 + if (n > softback_in) {
817 + softback_lines = 0;
819 + } else if (softback_curr <= softback_in && n > softback_in) {
821 + softback_lines = 0;
824 + if (n == softback_curr)
827 + s = (u16 *) softback_curr;
828 + if (s == (u16 *) softback_in)
829 + s = (u16 *) vc->vc_origin;
831 + unsigned short *start;
832 + unsigned short *le;
835 + unsigned short attr = 1;
838 + le = advance_row(s, 1);
841 + if (attr != (c & 0xff00)) {
844 + fbcon_putcs(vc, start, s - start,
850 + if (c == scr_readw(d)) {
852 + fbcon_putcs(vc, start, s - start,
854 + x += s - start + 1;
865 + fbcon_putcs(vc, start, s - start, line, x);
867 + if (d == (u16 *) softback_end)
868 + d = (u16 *) softback_buf;
869 + if (d == (u16 *) softback_in)
870 + d = (u16 *) vc->vc_origin;
871 + if (s == (u16 *) softback_end)
872 + s = (u16 *) softback_buf;
873 + if (s == (u16 *) softback_in)
874 + s = (u16 *) vc->vc_origin;
878 static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p,
879 int line, int count, int dy)
881 @@ -1750,6 +1912,31 @@ static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx,
882 p->vrows - p->yscroll);
885 +static inline void fbcon_softback_note(struct vc_data *vc, int t,
890 + if (vc->vc_num != fg_console)
892 + p = (unsigned short *) (vc->vc_origin + t * vc->vc_size_row);
895 + scr_memcpyw((u16 *) softback_in, p, vc->vc_size_row);
897 + p = advance_row(p, 1);
898 + softback_in += vc->vc_size_row;
899 + if (softback_in == softback_end)
900 + softback_in = softback_buf;
901 + if (softback_in == softback_top) {
902 + softback_top += vc->vc_size_row;
903 + if (softback_top == softback_end)
904 + softback_top = softback_buf;
907 + softback_curr = softback_in;
910 static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
911 enum con_scroll dir, unsigned int count)
913 @@ -1760,7 +1947,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
914 if (fbcon_is_inactive(vc, info))
917 - fbcon_cursor(vc, false);
918 + fbcon_cursor(vc, CM_ERASE);
921 * ++Geert: Only use ywrap/ypan if the console is in text mode
922 @@ -1772,6 +1959,8 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
924 if (count > vc->vc_rows) /* Maximum realistic size */
927 + fbcon_softback_note(vc, t, count);
928 switch (fb_scrollmode(p)) {
930 fbcon_redraw_blit(vc, info, p, t, b - t - count,
931 @@ -2086,6 +2275,14 @@ static bool fbcon_switch(struct vc_data *vc)
932 info = fbcon_info_from_console(vc->vc_num);
933 ops = info->fbcon_par;
935 + if (softback_top) {
936 + if (softback_lines)
937 + fbcon_set_origin(vc);
938 + softback_top = softback_curr = softback_in = softback_buf;
939 + softback_lines = 0;
940 + fbcon_update_softback(vc);
943 if (logo_shown >= 0) {
944 struct vc_data *conp2 = vc_cons[logo_shown].d;
946 @@ -2240,7 +2437,7 @@ static bool fbcon_blank(struct vc_data *vc, enum vesa_blank_mode blank,
947 if (!fbcon_is_inactive(vc, info)) {
948 if (ops->blank_state != blank) {
949 ops->blank_state = blank;
950 - fbcon_cursor(vc, !blank);
951 + fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW);
952 ops->cursor_flash = (!blank);
954 if (fb_blank(info, blank))
955 @@ -2417,6 +2614,9 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
956 int resize, ret, old_userfont, old_width, old_height, old_charcount;
957 u8 *old_data = vc->vc_font.data;
959 + if (con_is_visible(vc) && softback_lines)
960 + fbcon_set_origin(vc);
962 resize = (w != vc->vc_font.width) || (h != vc->vc_font.height);
963 vc->vc_font.data = (void *)(p->fontdata = data);
964 old_userfont = p->userfont;
965 @@ -2445,6 +2645,8 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
966 ret = vc_resize(vc, cols, rows);
969 + if (con_is_visible(vc) && softback_buf)
970 + fbcon_update_softback(vc);
971 } else if (con_is_visible(vc)
972 && vc->vc_mode == KD_TEXT) {
973 fbcon_clear_margins(vc, 0);
974 @@ -2610,6 +2811,62 @@ static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table)
975 fb_set_cmap(&palette_cmap, info);
978 +static u16 *fbcon_screen_pos(const struct vc_data *vc, int offset)
983 + if (vc->vc_num != fg_console || !softback_lines)
984 + return (u16 *) (vc->vc_origin + offset);
985 + line = offset / vc->vc_size_row;
986 + if (line >= softback_lines)
987 + return (u16 *) (vc->vc_origin + offset -
988 + softback_lines * vc->vc_size_row);
989 + p = softback_curr + offset;
990 + if (p >= softback_end)
991 + p += softback_buf - softback_end;
995 +static unsigned long fbcon_getxy(struct vc_data *vc, unsigned long pos,
1001 + if (pos >= vc->vc_origin && pos < vc->vc_scr_end) {
1002 + unsigned long offset = (pos - vc->vc_origin) / 2;
1004 + x = offset % vc->vc_cols;
1005 + y = offset / vc->vc_cols;
1006 + if (vc->vc_num == fg_console)
1007 + y += softback_lines;
1008 + ret = pos + (vc->vc_cols - x) * 2;
1009 + } else if (vc->vc_num == fg_console && softback_lines) {
1010 + unsigned long offset = pos - softback_curr;
1012 + if (pos < softback_curr)
1013 + offset += softback_end - softback_buf;
1015 + x = offset % vc->vc_cols;
1016 + y = offset / vc->vc_cols;
1017 + ret = pos + (vc->vc_cols - x) * 2;
1018 + if (ret == softback_end)
1019 + ret = softback_buf;
1020 + if (ret == softback_in)
1021 + ret = vc->vc_origin;
1023 + /* Should not happen */
1025 + ret = vc->vc_origin;
1034 /* As we might be inside of softback, we may work with non-contiguous buffer,
1035 that's why we have to use a separate routine. */
1036 static void fbcon_invert_region(struct vc_data *vc, u16 * p, int cnt)
1037 @@ -2625,7 +2882,107 @@ static void fbcon_invert_region(struct vc_data *vc, u16 * p, int cnt)
1038 a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) |
1039 (((a) & 0x0700) << 4);
1041 + if (p == (u16 *) softback_end)
1042 + p = (u16 *) softback_buf;
1043 + if (p == (u16 *) softback_in)
1044 + p = (u16 *) vc->vc_origin;
1048 +static void fbcon_scrolldelta(struct vc_data *vc, int lines)
1050 + struct fb_info *info = registered_fb[con2fb_map[fg_console]];
1051 + struct fbcon_ops *ops = info->fbcon_par;
1052 + struct fbcon_display *disp = &fb_display[fg_console];
1053 + int offset, limit, scrollback_old;
1055 + if (softback_top) {
1056 + if (vc->vc_num != fg_console)
1058 + if (vc->vc_mode != KD_TEXT || !lines)
1060 + if (logo_shown >= 0) {
1061 + struct vc_data *conp2 = vc_cons[logo_shown].d;
1063 + if (conp2->vc_top == logo_lines
1064 + && conp2->vc_bottom == conp2->vc_rows)
1065 + conp2->vc_top = 0;
1066 + if (logo_shown == vc->vc_num) {
1067 + unsigned long p, q;
1071 + q = vc->vc_origin +
1072 + logo_lines * vc->vc_size_row;
1073 + for (i = 0; i < logo_lines; i++) {
1074 + if (p == softback_top)
1076 + if (p == softback_buf)
1078 + p -= vc->vc_size_row;
1079 + q -= vc->vc_size_row;
1080 + scr_memcpyw((u16 *) q, (u16 *) p,
1083 + softback_in = softback_curr = p;
1084 + update_region(vc, vc->vc_origin,
1085 + logo_lines * vc->vc_cols);
1087 + logo_shown = FBCON_LOGO_CANSHOW;
1089 + fbcon_cursor(vc, CM_ERASE | CM_SOFTBACK);
1090 + fbcon_redraw_softback(vc, disp, lines);
1091 + fbcon_cursor(vc, CM_DRAW | CM_SOFTBACK);
1095 + if (!scrollback_phys_max)
1098 + scrollback_old = scrollback_current;
1099 + scrollback_current -= lines;
1100 + if (scrollback_current < 0)
1101 + scrollback_current = 0;
1102 + else if (scrollback_current > scrollback_max)
1103 + scrollback_current = scrollback_max;
1104 + if (scrollback_current == scrollback_old)
1107 + if (fbcon_is_inactive(vc, info))
1110 + fbcon_cursor(vc, CM_ERASE);
1112 + offset = disp->yscroll - scrollback_current;
1113 + limit = disp->vrows;
1114 + switch (disp->scrollmode) {
1115 + case SCROLL_WRAP_MOVE:
1116 + info->var.vmode |= FB_VMODE_YWRAP;
1118 + case SCROLL_PAN_MOVE:
1119 + case SCROLL_PAN_REDRAW:
1120 + limit -= vc->vc_rows;
1121 + info->var.vmode &= ~FB_VMODE_YWRAP;
1126 + else if (offset >= limit)
1129 + ops->var.xoffset = 0;
1130 + ops->var.yoffset = offset * vc->vc_font.height;
1131 + ops->update_start(info);
1133 + if (!scrollback_current)
1134 + fbcon_cursor(vc, CM_DRAW);
1137 +static int fbcon_set_origin(struct vc_data *vc)
1139 + if (softback_lines)
1140 + fbcon_scrolldelta(vc, softback_lines);
1144 void fbcon_suspended(struct fb_info *info)
1145 @@ -2638,7 +2995,7 @@ void fbcon_suspended(struct fb_info *info)
1146 vc = vc_cons[ops->currcon].d;
1148 /* Clear cursor, restore saved data */
1149 - fbcon_cursor(vc, false);
1150 + fbcon_cursor(vc, CM_ERASE);
1153 void fbcon_resumed(struct fb_info *info)
1154 @@ -2688,6 +3045,8 @@ static void fbcon_modechanged(struct fb_info *info)
1156 fbcon_set_palette(vc, color_table);
1159 + fbcon_update_softback(vc);
1163 @@ -3151,7 +3510,11 @@ static const struct consw fb_con = {
1164 .con_font_get = fbcon_get_font,
1165 .con_font_default = fbcon_set_def_font,
1166 .con_set_palette = fbcon_set_palette,
1167 + .con_scrolldelta = fbcon_scrolldelta,
1168 + .con_set_origin = fbcon_set_origin,
1169 .con_invert_region = fbcon_invert_region,
1170 + .con_screen_pos = fbcon_screen_pos,
1171 + .con_getxy = fbcon_getxy,
1172 .con_resize = fbcon_resize,
1173 .con_debug_enter = fbcon_debug_enter,
1174 .con_debug_leave = fbcon_debug_leave,
1175 @@ -3412,6 +3775,9 @@ void __exit fb_console_exit(void)
1176 fbcon_deinit_device();
1177 device_destroy(fb_class, MKDEV(0, 0));
1179 + kvfree((void *)softback_buf);
1180 + softback_buf = 0UL;
1182 do_unregister_con_driver(&fb_con);
1185 diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h
1186 index df70ea5ec5b3..53e376798094 100644
1187 --- a/drivers/video/fbdev/core/fbcon.h
1188 +++ b/drivers/video/fbdev/core/fbcon.h
1189 @@ -61,8 +61,8 @@ struct fbcon_ops {
1191 void (*clear_margins)(struct vc_data *vc, struct fb_info *info,
1192 int color, int bottom_only);
1193 - void (*cursor)(struct vc_data *vc, struct fb_info *info,
1194 - bool enable, int fg, int bg);
1195 + void (*cursor)(struct vc_data *vc, struct fb_info *info, int mode,
1196 + int softback_lines, int fg, int bg);
1197 int (*update_start)(struct fb_info *info);
1198 int (*rotate_font)(struct fb_info *info, struct vc_data *vc);
1199 struct fb_var_screeninfo var; /* copy of the current fb_var_screeninfo */
1200 diff --git a/drivers/video/fbdev/core/fbcon_ccw.c b/drivers/video/fbdev/core/fbcon_ccw.c
1201 index f9b794ff7d39..91562cd2a2c9 100644
1202 --- a/drivers/video/fbdev/core/fbcon_ccw.c
1203 +++ b/drivers/video/fbdev/core/fbcon_ccw.c
1204 @@ -218,8 +218,8 @@ static void ccw_clear_margins(struct vc_data *vc, struct fb_info *info,
1208 -static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
1210 +static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
1211 + int softback_lines, int fg, int bg)
1213 struct fb_cursor cursor;
1214 struct fbcon_ops *ops = info->fbcon_par;
1215 @@ -236,6 +236,15 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
1219 + if (softback_lines) {
1220 + if (y + softback_lines >= vc->vc_rows) {
1222 + ops->cursor_flash = 0;
1225 + y += softback_lines;
1228 c = scr_readw((u16 *) vc->vc_pos);
1229 attribute = get_attribute(info, c);
1230 src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
1231 @@ -349,7 +358,7 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
1235 - ops->cursor_state.enable = enable && !use_sw;
1236 + ops->cursor_state.enable = (mode != CM_ERASE) && !use_sw;
1238 cursor.image.data = src;
1239 cursor.image.fg_color = ops->cursor_state.image.fg_color;
1240 diff --git a/drivers/video/fbdev/core/fbcon_cw.c b/drivers/video/fbdev/core/fbcon_cw.c
1241 index 903f6fc174e1..bd8e05e2e4bb 100644
1242 --- a/drivers/video/fbdev/core/fbcon_cw.c
1243 +++ b/drivers/video/fbdev/core/fbcon_cw.c
1244 @@ -201,8 +201,8 @@ static void cw_clear_margins(struct vc_data *vc, struct fb_info *info,
1248 -static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
1250 +static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
1251 + int softback_lines, int fg, int bg)
1253 struct fb_cursor cursor;
1254 struct fbcon_ops *ops = info->fbcon_par;
1255 @@ -219,6 +219,15 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
1259 + if (softback_lines) {
1260 + if (y + softback_lines >= vc->vc_rows) {
1262 + ops->cursor_flash = 0;
1265 + y += softback_lines;
1268 c = scr_readw((u16 *) vc->vc_pos);
1269 attribute = get_attribute(info, c);
1270 src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
1271 @@ -332,7 +341,7 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
1275 - ops->cursor_state.enable = enable && !use_sw;
1276 + ops->cursor_state.enable = (mode != CM_ERASE) && !use_sw;
1278 cursor.image.data = src;
1279 cursor.image.fg_color = ops->cursor_state.image.fg_color;
1280 diff --git a/drivers/video/fbdev/core/fbcon_ud.c b/drivers/video/fbdev/core/fbcon_ud.c
1281 index 594331936fd3..6474970928a2 100644
1282 --- a/drivers/video/fbdev/core/fbcon_ud.c
1283 +++ b/drivers/video/fbdev/core/fbcon_ud.c
1284 @@ -248,8 +248,8 @@ static void ud_clear_margins(struct vc_data *vc, struct fb_info *info,
1288 -static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
1290 +static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode,
1291 + int softback_lines, int fg, int bg)
1293 struct fb_cursor cursor;
1294 struct fbcon_ops *ops = info->fbcon_par;
1295 @@ -267,6 +267,15 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
1299 + if (softback_lines) {
1300 + if (y + softback_lines >= vc->vc_rows) {
1302 + ops->cursor_flash = 0;
1305 + y += softback_lines;
1308 c = scr_readw((u16 *) vc->vc_pos);
1309 attribute = get_attribute(info, c);
1310 src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.height));
1311 @@ -372,7 +381,7 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
1315 - ops->cursor_state.enable = enable && !use_sw;
1316 + ops->cursor_state.enable = (mode != CM_ERASE) && !use_sw;
1318 cursor.image.data = src;
1319 cursor.image.fg_color = ops->cursor_state.image.fg_color;
1320 diff --git a/drivers/video/fbdev/core/tileblit.c b/drivers/video/fbdev/core/tileblit.c
1321 index eff7ec4da167..16b844ef416c 100644
1322 --- a/drivers/video/fbdev/core/tileblit.c
1323 +++ b/drivers/video/fbdev/core/tileblit.c
1324 @@ -79,15 +79,15 @@ static void tile_clear_margins(struct vc_data *vc, struct fb_info *info,
1328 -static void tile_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
1330 +static void tile_cursor(struct vc_data *vc, struct fb_info *info, int mode,
1331 + int softback_lines, int fg, int bg)
1333 struct fb_tilecursor cursor;
1334 int use_sw = vc->vc_cursor_type & CUR_SW;
1336 cursor.sx = vc->state.x;
1337 cursor.sy = vc->state.y;
1338 - cursor.mode = enable && !use_sw;
1339 + cursor.mode = (mode == CM_ERASE || use_sw) ? 0 : 1;
1343 diff --git a/include/linux/console.h b/include/linux/console.h
1344 index eba367bf605d..97888956d028 100644
1345 --- a/include/linux/console.h
1346 +++ b/include/linux/console.h
1347 @@ -48,7 +48,6 @@ enum vc_intensity;
1348 * @con_putc: emit one character with attributes @ca to [@x, @y] on @vc.
1349 * (optional -- @con_putcs would be called instead)
1350 * @con_putcs: emit @count characters with attributes @s to [@x, @y] on @vc.
1351 - * @con_cursor: enable/disable cursor depending on @enable
1352 * @con_scroll: move lines from @top to @bottom in direction @dir by @lines.
1353 * Return true if no generic handling should be done.
1354 * Invoked by csi_M and printing to the console.
1355 @@ -97,7 +96,7 @@ struct consw {
1356 void (*con_putcs)(struct vc_data *vc, const u16 *s,
1357 unsigned int count, unsigned int ypos,
1359 - void (*con_cursor)(struct vc_data *vc, bool enable);
1360 + void (*con_cursor)(struct vc_data *vc, int mode);
1361 bool (*con_scroll)(struct vc_data *vc, unsigned int top,
1362 unsigned int bottom, enum con_scroll dir,
1363 unsigned int lines);
1364 @@ -107,12 +96,15 @@ struct consw {
1365 void (*con_set_palette)(struct vc_data *vc,
1366 const unsigned char *table);
1367 void (*con_scrolldelta)(struct vc_data *vc, int lines);
1368 - bool (*con_set_origin)(struct vc_data *vc);
1369 + int (*con_set_origin)(struct vc_data *vc);
1370 void (*con_save_screen)(struct vc_data *vc);
1371 u8 (*con_build_attr)(struct vc_data *vc, u8 color,
1372 enum vc_intensity intensity,
1373 bool blink, bool underline, bool reverse, bool italic);
1374 void (*con_invert_region)(struct vc_data *vc, u16 *p, int count);
1375 + u16 *(*con_screen_pos)(const struct vc_data *vc, int offset);
1376 + unsigned long (*con_getxy)(struct vc_data *vc, unsigned long position,
1377 + int *px, int *py);
1378 void (*con_debug_enter)(struct vc_data *vc);
1379 void (*con_debug_leave)(struct vc_data *vc);
1381 @@ -151,6 +152,11 @@ static inline void con_debug_enter(struct vc_data *vc) { }
1382 static inline void con_debug_leave(void) { }
1386 +#define CM_DRAW (1)
1387 +#define CM_ERASE (2)
1388 +#define CM_MOVE (3)
1391 * The interface for a console, or any other device that wants to capture
1392 * console messages (printer driver?)