summarylogtreecommitdiffstats
path: root/0303-revert-fbcon-remove-soft-scrollback-code.patch
diff options
context:
space:
mode:
Diffstat (limited to '0303-revert-fbcon-remove-soft-scrollback-code.patch')
-rw-r--r--0303-revert-fbcon-remove-soft-scrollback-code.patch500
1 files changed, 500 insertions, 0 deletions
diff --git a/0303-revert-fbcon-remove-soft-scrollback-code.patch b/0303-revert-fbcon-remove-soft-scrollback-code.patch
new file mode 100644
index 000000000000..c11a97198ff2
--- /dev/null
+++ b/0303-revert-fbcon-remove-soft-scrollback-code.patch
@@ -0,0 +1,500 @@
+--- b/drivers/video/fbdev/core/fbcon.c
++++ a/drivers/video/fbdev/core/fbcon.c
+@@ -124,6 +124,12 @@ static int logo_lines;
+ /* logo_shown is an index to vc_cons when >= 0; otherwise follows FBCON_LOGO
+ enums. */
+ static int logo_shown = FBCON_LOGO_CANSHOW;
++/* Software scrollback */
++static int fbcon_softback_size = 32768;
++static unsigned long softback_buf, softback_curr;
++static unsigned long softback_in;
++static unsigned long softback_top, softback_end;
++static int softback_lines;
+ /* console mappings */
+ static unsigned int first_fb_vc;
+ static unsigned int last_fb_vc = MAX_NR_CONSOLES - 1;
+@@ -163,6 +169,8 @@ static int margin_color;
+
+ static const struct consw fb_con;
+
++#define CM_SOFTBACK (8)
++
+ #define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row)
+
+ static int fbcon_set_origin(struct vc_data *);
+@@ -347,6 +355,18 @@ static int get_color(struct vc_data *vc,
+ return color;
+ }
+
++static void fbcon_update_softback(struct vc_data *vc)
++{
++ int l = fbcon_softback_size / vc->vc_size_row;
++
++ if (l > 5)
++ softback_end = softback_buf + l * vc->vc_size_row;
++ else
++ /* Smaller scrollback makes no sense, and 0 would screw
++ the operation totally */
++ softback_top = 0;
++}
++
+ static void fb_flashcursor(struct work_struct *work)
+ {
+ struct fbcon_ops *ops = container_of(work, struct fbcon_ops, cursor_work.work);
+@@ -379,7 +399,7 @@ static void fb_flashcursor(struct work_s
+ c = scr_readw((u16 *) vc->vc_pos);
+ mode = (!ops->cursor_flash || ops->cursor_state.enable) ?
+ CM_ERASE : CM_DRAW;
+- ops->cursor(vc, info, mode, 0, get_color(vc, info, c, 1),
++ ops->cursor(vc, info, mode, softback_lines, get_color(vc, info, c, 1),
+ get_color(vc, info, c, 0));
+ console_unlock();
+
+@@ -419,7 +439,13 @@ static int __init fb_console_setup(char
+ }
+
+ if (!strncmp(options, "scrollback:", 11)) {
+- pr_warn("Ignoring scrollback size option\n");
++ options += 11;
++ if (*options) {
++ fbcon_softback_size = simple_strtoul(options, &options, 0);
++ if (*options == 'k' || *options == 'K') {
++ fbcon_softback_size *= 1024;
++ }
++ }
+ continue;
+ }
+
+@@ -959,6 +985,31 @@ static const char *fbcon_startup(void)
+
+ set_blitting_type(vc, info);
+
++ if (info->fix.type != FB_TYPE_TEXT) {
++ if (fbcon_softback_size) {
++ if (!softback_buf) {
++ softback_buf =
++ (unsigned long)
++ kvmalloc(fbcon_softback_size,
++ GFP_KERNEL);
++ if (!softback_buf) {
++ fbcon_softback_size = 0;
++ softback_top = 0;
++ }
++ }
++ } else {
++ if (softback_buf) {
++ kvfree((void *) softback_buf);
++ softback_buf = 0;
++ softback_top = 0;
++ }
++ }
++ if (softback_buf)
++ softback_in = softback_top = softback_curr =
++ softback_buf;
++ softback_lines = 0;
++ }
++
+ /* Setup default font */
+ if (!p->fontdata && !vc->vc_font.data) {
+ if (!fontname[0] || !(font = find_font(fontname)))
+@@ -1129,6 +1180,9 @@ static void fbcon_init(struct vc_data *v
+ if (logo)
+ fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows);
+
++ if (vc == svc && softback_buf)
++ fbcon_update_softback(vc);
++
+ if (ops->rotate_font && ops->rotate_font(info, vc)) {
+ ops->rotate = FB_ROTATE_UR;
+ set_blitting_type(vc, info);
+@@ -1152,6 +1206,9 @@ static void fbcon_release_all(void)
+ struct fb_info *info;
+ int i, j, mapped;
+
++ kvfree((void *)softback_buf);
++ softback_buf = 0UL;
++
+ fbcon_for_each_registered_fb(i) {
+ mapped = 0;
+ info = fbcon_registered_fb[i];
+@@ -1312,6 +1369,7 @@ static void fbcon_cursor(struct vc_data
+ {
+ struct fb_info *info = fbcon_info_from_console(vc->vc_num);
+ struct fbcon_ops *ops = info->fbcon_par;
++ int y;
+ int c = scr_readw((u16 *) vc->vc_pos);
+
+ ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
+@@ -1325,11 +1383,19 @@ static void fbcon_cursor(struct vc_data
+ fbcon_add_cursor_work(info);
+
+ ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1;
++ if (mode & CM_SOFTBACK) {
++ mode &= ~CM_SOFTBACK;
++ y = softback_lines;
++ } else {
++ if (softback_lines)
++ fbcon_set_origin(vc);
++ y = 0;
++ }
+
+ if (!ops->cursor)
+ return;
+
+- ops->cursor(vc, info, mode, 0, get_color(vc, info, c, 1),
++ ops->cursor(vc, info, mode, y, get_color(vc, info, c, 1),
+ get_color(vc, info, c, 0));
+ }
+
+@@ -1399,6 +1465,8 @@ static void fbcon_set_disp(struct fb_inf
+
+ if (con_is_visible(vc)) {
+ update_screen(vc);
++ if (softback_buf)
++ fbcon_update_softback(vc);
+ }
+ }
+
+@@ -1536,6 +1604,99 @@ static __inline__ void ypan_down_redraw(
+ scrollback_current = 0;
+ }
+
++static void fbcon_redraw_softback(struct vc_data *vc, struct fbcon_display *p,
++ long delta)
++{
++ int count = vc->vc_rows;
++ unsigned short *d, *s;
++ unsigned long n;
++ int line = 0;
++
++ d = (u16 *) softback_curr;
++ if (d == (u16 *) softback_in)
++ d = (u16 *) vc->vc_origin;
++ n = softback_curr + delta * vc->vc_size_row;
++ softback_lines -= delta;
++ if (delta < 0) {
++ if (softback_curr < softback_top && n < softback_buf) {
++ n += softback_end - softback_buf;
++ if (n < softback_top) {
++ softback_lines -=
++ (softback_top - n) / vc->vc_size_row;
++ n = softback_top;
++ }
++ } else if (softback_curr >= softback_top
++ && n < softback_top) {
++ softback_lines -=
++ (softback_top - n) / vc->vc_size_row;
++ n = softback_top;
++ }
++ } else {
++ if (softback_curr > softback_in && n >= softback_end) {
++ n += softback_buf - softback_end;
++ if (n > softback_in) {
++ n = softback_in;
++ softback_lines = 0;
++ }
++ } else if (softback_curr <= softback_in && n > softback_in) {
++ n = softback_in;
++ softback_lines = 0;
++ }
++ }
++ if (n == softback_curr)
++ return;
++ softback_curr = n;
++ s = (u16 *) softback_curr;
++ if (s == (u16 *) 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);
++ do {
++ c = scr_readw(s);
++ if (attr != (c & 0xff00)) {
++ attr = c & 0xff00;
++ if (s > start) {
++ fbcon_putcs(vc, start, s - start,
++ line, x);
++ x += s - start;
++ start = s;
++ }
++ }
++ if (c == scr_readw(d)) {
++ if (s > start) {
++ fbcon_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)
++ fbcon_putcs(vc, start, s - start, line, x);
++ line++;
++ if (d == (u16 *) softback_end)
++ d = (u16 *) softback_buf;
++ if (d == (u16 *) softback_in)
++ d = (u16 *) vc->vc_origin;
++ if (s == (u16 *) softback_end)
++ s = (u16 *) softback_buf;
++ if (s == (u16 *) softback_in)
++ s = (u16 *) vc->vc_origin;
++ }
++}
++
+ static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p,
+ int line, int count, int dy)
+ {
+@@ -1740,6 +1901,31 @@ static void fbcon_bmove(struct vc_data *
+ p->vrows - p->yscroll);
+ }
+
++static inline void fbcon_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 *) softback_in, p, vc->vc_size_row);
++ count--;
++ p = advance_row(p, 1);
++ softback_in += vc->vc_size_row;
++ if (softback_in == softback_end)
++ softback_in = softback_buf;
++ if (softback_in == softback_top) {
++ softback_top += vc->vc_size_row;
++ if (softback_top == softback_end)
++ softback_top = softback_buf;
++ }
++ }
++ softback_curr = softback_in;
++}
++
+ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
+ enum con_scroll dir, unsigned int count)
+ {
+@@ -1762,6 +1948,8 @@ static bool fbcon_scroll(struct vc_data
+ case SM_UP:
+ if (count > vc->vc_rows) /* Maximum realistic size */
+ count = vc->vc_rows;
++ if (softback_top)
++ fbcon_softback_note(vc, t, count);
+ switch (fb_scrollmode(p)) {
+ case SCROLL_MOVE:
+ fbcon_redraw_blit(vc, info, p, t, b - t - count,
+@@ -2076,6 +2264,14 @@ static int fbcon_switch(struct vc_data *
+ info = fbcon_info_from_console(vc->vc_num);
+ ops = info->fbcon_par;
+
++ if (softback_top) {
++ if (softback_lines)
++ fbcon_set_origin(vc);
++ softback_top = softback_curr = softback_in = softback_buf;
++ softback_lines = 0;
++ fbcon_update_softback(vc);
++ }
++
+ if (logo_shown >= 0) {
+ struct vc_data *conp2 = vc_cons[logo_shown].d;
+
+@@ -2406,6 +2602,9 @@ static int fbcon_do_set_font(struct vc_d
+ int resize, ret, old_userfont, old_width, old_height, old_charcount;
+ char *old_data = NULL;
+
++ if (con_is_visible(vc) && softback_lines)
++ fbcon_set_origin(vc);
++
+ resize = (w != vc->vc_font.width) || (h != vc->vc_font.height);
+ if (p->userfont)
+ old_data = vc->vc_font.data;
+@@ -2436,6 +2635,8 @@ static int fbcon_do_set_font(struct vc_d
+ ret = vc_resize(vc, cols, rows);
+ if (ret)
+ goto err_out;
++ if (con_is_visible(vc) && softback_buf)
++ fbcon_update_softback(vc);
+ } else if (con_is_visible(vc)
+ && vc->vc_mode == KD_TEXT) {
+ fbcon_clear_margins(vc, 0);
+@@ -2605,7 +2806,19 @@ static void fbcon_set_palette(struct vc_
+
+ static u16 *fbcon_screen_pos(const struct vc_data *vc, int offset)
+ {
+- return (u16 *) (vc->vc_origin + offset);
++ unsigned long p;
++ int line;
++
++ if (vc->vc_num != fg_console || !softback_lines)
++ return (u16 *) (vc->vc_origin + offset);
++ line = offset / vc->vc_size_row;
++ if (line >= softback_lines)
++ return (u16 *) (vc->vc_origin + offset -
++ softback_lines * vc->vc_size_row);
++ p = softback_curr + offset;
++ if (p >= softback_end)
++ p += softback_buf - softback_end;
++ return (u16 *) p;
+ }
+
+ static unsigned long fbcon_getxy(struct vc_data *vc, unsigned long pos,
+@@ -2619,7 +2832,22 @@ static unsigned long fbcon_getxy(struct
+
+ x = offset % vc->vc_cols;
+ y = offset / vc->vc_cols;
++ if (vc->vc_num == fg_console)
++ y += softback_lines;
++ ret = pos + (vc->vc_cols - x) * 2;
++ } else if (vc->vc_num == fg_console && softback_lines) {
++ unsigned long offset = pos - softback_curr;
++
++ if (pos < softback_curr)
++ offset += softback_end - softback_buf;
++ offset /= 2;
++ x = offset % vc->vc_cols;
++ y = offset / vc->vc_cols;
+ ret = pos + (vc->vc_cols - x) * 2;
++ if (ret == softback_end)
++ ret = softback_buf;
++ if (ret == softback_in)
++ ret = vc->vc_origin;
+ } else {
+ /* Should not happen */
+ x = y = 0;
+@@ -2647,11 +2875,106 @@ static void fbcon_invert_region(struct v
+ a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) |
+ (((a) & 0x0700) << 4);
+ scr_writew(a, p++);
++ if (p == (u16 *) softback_end)
++ p = (u16 *) softback_buf;
++ if (p == (u16 *) softback_in)
++ p = (u16 *) vc->vc_origin;
++ }
++}
++
++static void fbcon_scrolldelta(struct vc_data *vc, int lines)
++{
++ struct fb_info *info = registered_fb[con2fb_map[fg_console]];
++ struct fbcon_ops *ops = info->fbcon_par;
++ struct fbcon_display *disp = &fb_display[fg_console];
++ int offset, limit, scrollback_old;
++
++ if (softback_top) {
++ if (vc->vc_num != fg_console)
++ return;
++ if (vc->vc_mode != KD_TEXT || !lines)
++ return;
++ 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 = softback_in;
++ q = vc->vc_origin +
++ logo_lines * vc->vc_size_row;
++ for (i = 0; i < logo_lines; i++) {
++ if (p == softback_top)
++ break;
++ if (p == softback_buf)
++ p = softback_end;
++ p -= vc->vc_size_row;
++ q -= vc->vc_size_row;
++ scr_memcpyw((u16 *) q, (u16 *) p,
++ vc->vc_size_row);
++ }
++ softback_in = softback_curr = p;
++ update_region(vc, vc->vc_origin,
++ logo_lines * vc->vc_cols);
++ }
++ logo_shown = FBCON_LOGO_CANSHOW;
++ }
++ fbcon_cursor(vc, CM_ERASE | CM_SOFTBACK);
++ fbcon_redraw_softback(vc, disp, lines);
++ fbcon_cursor(vc, CM_DRAW | CM_SOFTBACK);
++ return;
+ }
++
++ if (!scrollback_phys_max)
++ return;
++
++ scrollback_old = scrollback_current;
++ scrollback_current -= lines;
++ if (scrollback_current < 0)
++ scrollback_current = 0;
++ else if (scrollback_current > scrollback_max)
++ scrollback_current = scrollback_max;
++ if (scrollback_current == scrollback_old)
++ return;
++
++ if (fbcon_is_inactive(vc, info))
++ return;
++
++ fbcon_cursor(vc, CM_ERASE);
++
++ offset = disp->yscroll - scrollback_current;
++ limit = disp->vrows;
++ switch (disp->scrollmode) {
++ case SCROLL_WRAP_MOVE:
++ info->var.vmode |= FB_VMODE_YWRAP;
++ break;
++ case SCROLL_PAN_MOVE:
++ case SCROLL_PAN_REDRAW:
++ limit -= vc->vc_rows;
++ info->var.vmode &= ~FB_VMODE_YWRAP;
++ break;
++ }
++ if (offset < 0)
++ offset += limit;
++ else if (offset >= limit)
++ offset -= limit;
++
++ ops->var.xoffset = 0;
++ ops->var.yoffset = offset * vc->vc_font.height;
++ ops->update_start(info);
++
++ if (!scrollback_current)
++ fbcon_cursor(vc, CM_DRAW);
+ }
+
+ static int fbcon_set_origin(struct vc_data *vc)
+ {
++ if (softback_lines)
++ fbcon_scrolldelta(vc, softback_lines);
+ return 0;
+ }
+
+@@ -2715,6 +3038,8 @@ static void fbcon_modechanged(struct fb_
+
+ fbcon_set_palette(vc, color_table);
+ update_screen(vc);
++ if (softback_buf)
++ fbcon_update_softback(vc);
+ }
+ }
+
+@@ -3177,6 +3502,7 @@ 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,
++ .con_scrolldelta = fbcon_scrolldelta,
+ .con_set_origin = fbcon_set_origin,
+ .con_invert_region = fbcon_invert_region,
+ .con_screen_pos = fbcon_screen_pos,