diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index d7aadca5107d..c453c6031098 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -291,6 +291,28 @@ static inline bool con_should_update(const struct vc_data *vc) static inline unsigned short *screenpos(const struct vc_data *vc, int offset, bool viewed) { +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK + unsigned long softback_pos, scrolled_expanse; + + if (vc->vc_softback_curr == vc->vc_origin) + return (unsigned short *)(vc->vc_origin + offset); + else { + scrolled_expanse = vc->vc_softback_in - vc->vc_softback_curr; + if (scrolled_expanse < 0) + scrolled_expanse += vc->vc_softback_end + - vc->vc_softback_buf; + if (offset >= scrolled_expanse) + return (unsigned short *)(vc->vc_origin + + (offset - scrolled_expanse)); + else { + softback_pos = vc->vc_softback_curr + offset; + if (softback_pos >= vc->vc_softback_end) + softback_pos -= vc->vc_softback_end + - vc->vc_softback_buf; + } + } + return (unsigned short *)softback_pos; +#else unsigned short *p; if (!viewed) @@ -300,6 +322,7 @@ static inline unsigned short *screenpos(const struct vc_data *vc, int offset, else p = vc->vc_sw->con_screen_pos(vc, offset); return p; +#endif } /* Called from the keyboard irq path.. */ @@ -321,101 +344,106 @@ void schedule_console_callback(void) * Code to manage unicode-based screen buffers */ -#ifdef NO_VC_UNI_SCREEN -/* this disables and optimizes related code away at compile time */ -#define get_vc_uniscr(vc) NULL -#else -#define get_vc_uniscr(vc) vc->vc_uni_screen -#endif - #define VC_UNI_SCREEN_DEBUG 0 typedef uint32_t char32_t; -/* - * Our screen buffer is preceded by an array of line pointers so that - * scrolling only implies some pointer shuffling. - */ -struct uni_screen { - char32_t *lines[0]; -}; +#define vc_uniscr_buf_end(vc) vc->vc_uniscr_buf + vc->vc_uniscr_char_size -static struct uni_screen *vc_uniscr_alloc(unsigned int cols, unsigned int rows) +static int vc_uniscr_alloc(struct vc_data *vc, unsigned int cols, unsigned int rows) { - struct uni_screen *uniscr; - void *p; - unsigned int memsize, i; + uint32_t *p; - /* allocate everything in one go */ - memsize = cols * rows * sizeof(char32_t); - memsize += rows * sizeof(char32_t *); - p = vzalloc(memsize); +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK_GPM + vc->vc_uniscr_char_size = + cols * rows + + ((vc->vc_softback_end - vc->vc_softback_buf) / 2); +#else + vc->vc_uniscr_char_size = cols * (rows + 1); /* 1 row for the circular buffer admin */ +#endif + p = (uint32_t *)vzalloc (sizeof (uint32_t) * vc->vc_uniscr_char_size); + vc->vc_uniscr_buf = p; if (!p) - return NULL; - - /* initial line pointers */ - uniscr = p; - p = uniscr->lines + rows; - for (i = 0; i < rows; i++) { - uniscr->lines[i] = p; - p += cols * sizeof(char32_t); - } - return uniscr; -} - -static void vc_uniscr_free(struct uni_screen *uniscr) -{ - vfree(uniscr); + return -ENOMEM; + vc->vc_uniscr_curr = p; + return 0; } -static void vc_uniscr_set(struct vc_data *vc, struct uni_screen *new_uniscr) +static void vc_uniscr_free(struct vc_data *vc) { - vc_uniscr_free(vc->vc_uni_screen); - vc->vc_uni_screen = new_uniscr; + kfree(vc->vc_uniscr_buf); + vc->vc_uniscr_buf = NULL; } static void vc_uniscr_putc(struct vc_data *vc, char32_t uc) { - struct uni_screen *uniscr = get_vc_uniscr(vc); - - if (uniscr) - uniscr->lines[vc->state.y][vc->state.x] = uc; + uint32_t *pos; + + if (vc->vc_uniscr_buf) { + pos = vc->vc_uniscr_curr + + vc->state.y * vc->vc_cols + + vc->state.x; + if (pos >= vc_uniscr_buf_end(vc)) + pos -= vc->vc_uniscr_char_size; +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK_GPM + pos -= vc->vc_softback_lines * vc->vc_cols; + if (pos < vc->vc_uniscr_buf) + pos += vc->vc_uniscr_char_size; +#endif + *pos = uc; + } } static void vc_uniscr_insert(struct vc_data *vc, unsigned int nr) { - struct uni_screen *uniscr = get_vc_uniscr(vc); - - if (uniscr) { - char32_t *ln = uniscr->lines[vc->state.y]; - unsigned int x = vc->state.x, cols = vc->vc_cols; + unsigned int x = vc->state.x, y = vc->state.y, cols = vc->vc_cols; + uint32_t *ln = vc->vc_uniscr_curr + y * cols; - memmove(&ln[x + nr], &ln[x], (cols - x - nr) * sizeof(*ln)); + if (vc->vc_uniscr_buf) { + if (ln >= vc_uniscr_buf_end(vc)) + ln -= vc->vc_uniscr_char_size; +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK_GPM + ln -= vc->vc_softback_lines * vc->vc_cols; + if (ln < vc->vc_uniscr_buf) + ln += vc->vc_uniscr_char_size; +#endif + memmove(&ln[x + nr], &ln[x], (cols - x - nr) * sizeof(uint32_t)); memset32(&ln[x], ' ', nr); } } static void vc_uniscr_delete(struct vc_data *vc, unsigned int nr) { - struct uni_screen *uniscr = get_vc_uniscr(vc); - - if (uniscr) { - char32_t *ln = uniscr->lines[vc->state.y]; - unsigned int x = vc->state.x, cols = vc->vc_cols; + unsigned int x = vc->state.x, y = vc->state.y, cols = vc->vc_cols; + uint32_t *ln = vc->vc_uniscr_curr + y * cols; - memcpy(&ln[x], &ln[x + nr], (cols - x - nr) * sizeof(*ln)); + if (vc->vc_uniscr_buf) { + if (ln >= vc_uniscr_buf_end(vc)) + ln -= vc->vc_uniscr_char_size; +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK_GPM + ln -= vc->vc_softback_lines * vc->vc_cols; + if (ln < vc->vc_uniscr_buf) + ln += vc->vc_uniscr_char_size; +#endif + memcpy(&ln[x], &ln[x + nr], (cols - x - nr) * sizeof(uint32_t)); memset32(&ln[cols - nr], ' ', nr); } } +/* FIXME!!! We need to check that NR never goes beyond the current line end. !!! */ static void vc_uniscr_clear_line(struct vc_data *vc, unsigned int x, unsigned int nr) { - struct uni_screen *uniscr = get_vc_uniscr(vc); - - if (uniscr) { - char32_t *ln = uniscr->lines[vc->state.y]; + if (vc->vc_uniscr_buf) { + uint32_t *ln = vc->vc_uniscr_curr + vc->state.y * vc->vc_cols; + if (ln >= vc_uniscr_buf_end(vc)) + ln -= vc->vc_uniscr_char_size; +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK_GPM + ln -= vc->vc_softback_lines * vc->vc_cols; + if (ln < vc->vc_uniscr_buf) + ln += vc->vc_uniscr_char_size; +#endif memset32(&ln[x], ' ', nr); } } @@ -423,77 +451,72 @@ static void vc_uniscr_clear_line(struct vc_data *vc, unsigned int x, static void vc_uniscr_clear_lines(struct vc_data *vc, unsigned int y, unsigned int nr) { - struct uni_screen *uniscr = get_vc_uniscr(vc); - - if (uniscr) { + if (vc->vc_uniscr_buf) { unsigned int cols = vc->vc_cols; - - while (nr--) - memset32(uniscr->lines[y++], ' ', cols); + uint32_t *ln = vc->vc_uniscr_curr + y * cols; + + /* if (ln >= vc_uniscr_buf_end(vc)) /\* We probably don't need this FIXME!!! STOUGH!!! *\/ */ + /* ln -= vc->vc_uniscr_char_size; */ /* Commented out 2022-12-29. STOUGH!!! */ +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK_GPM + ln -= vc->vc_softback_lines * cols; + if (ln < vc->vc_uniscr_buf) + ln += vc->vc_uniscr_char_size; +#endif + while (nr--) { + if (ln >= vc_uniscr_buf_end(vc)) + ln -= vc->vc_uniscr_char_size; + memset32(ln, ' ', cols); + ln += cols; + } } } static void vc_uniscr_scroll(struct vc_data *vc, unsigned int t, unsigned int b, enum con_scroll dir, unsigned int nr) { - struct uni_screen *uniscr = get_vc_uniscr(vc); - - if (uniscr) { - unsigned int i, j, k, sz, d, clear; - - sz = b - t; - clear = b - nr; - d = nr; - if (dir == SM_DOWN) { - clear = t; - d = sz - nr; - } - for (i = 0; i < gcd(d, sz); i++) { - char32_t *tmp = uniscr->lines[t + i]; - j = i; - while (1) { - k = j + d; - if (k >= sz) - k -= sz; - if (k == i) - break; - uniscr->lines[t + j] = uniscr->lines[t + k]; - j = k; + if (vc->vc_uniscr_buf) { + unsigned int cols = vc->vc_cols; + unsigned int sz, /* number of rows being scrolled */ + d, /* number of rows needing blanking */ + clear; /* The number of the topmost row needing blanking. */ + uint32_t *dest, *src; + unsigned int i; + + if (dir == SM_UP && t == 0 && b == vc->vc_rows) { + vc->vc_uniscr_curr += nr * cols; + if (vc->vc_uniscr_curr >= vc_uniscr_buf_end(vc)) + vc->vc_uniscr_curr -= vc->vc_uniscr_char_size; + d = nr; + clear = vc->vc_rows - nr; + } else if (dir == SM_DOWN && t == 0 && b == vc->vc_rows - nr) { + vc->vc_uniscr_curr -= nr * cols; + if (vc->vc_uniscr_curr < vc->vc_uniscr_buf) + vc->vc_uniscr_curr += vc->vc_uniscr_char_size; + d = 0; + } else { + sz = b - t; + src = vc->vc_uniscr_curr + t * cols; + if (dir == SM_UP) { + dest = vc->vc_uniscr_curr - nr * cols; + clear = b - nr; + d = nr; + } else { + dest = vc->vc_uniscr_curr + nr * cols; + clear = t; + d = sz - nr; + } + i = nr; + while (i--) { + if (dest >= vc_uniscr_buf_end(vc)) + dest -= vc->vc_uniscr_char_size; + if (src >= vc_uniscr_buf_end(vc)) + src -= vc->vc_uniscr_char_size; + dest += cols; + src += cols; } - uniscr->lines[t + j] = tmp; } - vc_uniscr_clear_lines(vc, clear, nr); - } -} - -static void vc_uniscr_copy_area(struct uni_screen *dst, - unsigned int dst_cols, - unsigned int dst_rows, - struct uni_screen *src, - unsigned int src_cols, - unsigned int src_top_row, - unsigned int src_bot_row) -{ - unsigned int dst_row = 0; - - if (!dst) - return; - - while (src_top_row < src_bot_row) { - char32_t *src_line = src->lines[src_top_row]; - char32_t *dst_line = dst->lines[dst_row]; - - memcpy(dst_line, src_line, src_cols * sizeof(char32_t)); - if (dst_cols - src_cols) - memset32(dst_line + src_cols, ' ', dst_cols - src_cols); - src_top_row++; - dst_row++; - } - while (dst_row < dst_rows) { - char32_t *dst_line = dst->lines[dst_row]; - - memset32(dst_line, ' ', dst_cols); - dst_row++; + if (d) + vc_uniscr_clear_lines(vc, clear, nr); } } @@ -505,7 +528,6 @@ static void vc_uniscr_copy_area(struct uni_screen *dst, */ int vc_uniscr_check(struct vc_data *vc) { - struct uni_screen *uniscr; unsigned short *p; int x, y, mask; @@ -517,11 +539,10 @@ int vc_uniscr_check(struct vc_data *vc) if (!vc->vc_utf) return -ENODATA; - if (vc->vc_uni_screen) + if (vc->vc_uniscr_buf) return 0; - uniscr = vc_uniscr_alloc(vc->vc_cols, vc->vc_rows); - if (!uniscr) + if (vc_uniscr_alloc (vc, vc->vc_cols, vc->vc_rows)) return -ENOMEM; /* @@ -533,14 +554,15 @@ int vc_uniscr_check(struct vc_data *vc) p = (unsigned short *)vc->vc_origin; mask = vc->vc_hi_font_mask | 0xff; for (y = 0; y < vc->vc_rows; y++) { - char32_t *line = uniscr->lines[y]; + uint32_t *line = vc->vc_uniscr_curr + y * vc->vc_cols; + if (line >= vc_uniscr_buf_end(vc)) + line -= vc->vc_uniscr_char_size; for (x = 0; x < vc->vc_cols; x++) { u16 glyph = scr_readw(p++) & mask; line[x] = inverse_translate(vc, glyph, true); } } - vc->vc_uni_screen = uniscr; return 0; } @@ -552,12 +574,26 @@ int vc_uniscr_check(struct vc_data *vc) void vc_uniscr_copy_line(const struct vc_data *vc, void *dest, bool viewed, unsigned int row, unsigned int col, unsigned int nr) { - struct uni_screen *uniscr = get_vc_uniscr(vc); +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK + uint32_t *pos; /* Position in the unicode buffer of col/row */ +#else int offset = row * vc->vc_size_row + col * 2; - unsigned long pos; + unsigned long pos; /* Position in the main screen buffer of col/row */ +#endif - BUG_ON(!uniscr); + BUG_ON(!vc->vc_uniscr_buf); +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK + pos = (vc->vc_uniscr_curr + row * vc->vc_cols + col); + if (pos >= vc_uniscr_buf_end(vc)) + pos -= vc->vc_uniscr_char_size; +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK_GPM + pos -= vc->vc_softback_lines * vc->vc_cols; + if (pos < vc->vc_uniscr_buf) + pos += vc->vc_uniscr_char_size; +#endif + memcpy(dest, pos, nr * sizeof(uint32_t)); +#else pos = (unsigned long)screenpos(vc, offset, viewed); if (pos >= vc->vc_origin && pos < vc->vc_scr_end) { /* @@ -567,58 +603,57 @@ void vc_uniscr_copy_line(const struct vc_data *vc, void *dest, bool viewed, */ row = (pos - vc->vc_origin) / vc->vc_size_row; col = ((pos - vc->vc_origin) % vc->vc_size_row) / 2; - memcpy(dest, &uniscr->lines[row][col], nr * sizeof(char32_t)); + memcpy(dest, + (void *)(vc->vc_uniscr_curr + row * vc->vc_cols + col), + nr); } else { /* - * Scrollback is active. For now let's simply backtranslate - * the screen glyphs until the unicode screen buffer does - * synchronize with console display drivers for a scrollback - * buffer of its own. + * Scrollback is active. So hoik the unicode characters out + * of the unicode circular buffer. */ - u16 *p = (u16 *)pos; - int mask = vc->vc_hi_font_mask | 0xff; - char32_t *uni_buf = dest; - while (nr--) { - u16 glyph = scr_readw(p++) & mask; - *uni_buf++ = inverse_translate(vc, glyph, true); - } + /* CAN'T HAPPEN!!! (Hah hah!) */ } +#endif } /* this is for validation and debugging only */ static void vc_uniscr_debug_check(struct vc_data *vc) { - struct uni_screen *uniscr = get_vc_uniscr(vc); - unsigned short *p; - int x, y, mask; +#ifndef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK + /* struct uni_screen *uniscr = get_vc_uniscr(vc); */ + /* unsigned short *p; */ + /* int x, y, mask; */ +#endif - if (!VC_UNI_SCREEN_DEBUG || !uniscr) + if (!VC_UNI_SCREEN_DEBUG || !vc->vc_uniscr_buf) return; WARN_CONSOLE_UNLOCKED(); +#ifndef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK /* * Make sure our unicode screen translates into the same glyphs * as the actual screen. This is brutal indeed. */ - p = (unsigned short *)vc->vc_origin; - mask = vc->vc_hi_font_mask | 0xff; - for (y = 0; y < vc->vc_rows; y++) { - char32_t *line = uniscr->lines[y]; - for (x = 0; x < vc->vc_cols; x++) { - u16 glyph = scr_readw(p++) & mask; - char32_t uc = line[x]; - int tc = conv_uni_to_pc(vc, uc); - if (tc == -4) - tc = conv_uni_to_pc(vc, 0xfffd); - if (tc == -4) - tc = conv_uni_to_pc(vc, '?'); - if (tc != glyph) - pr_err_ratelimited( - "%s: mismatch at %d,%d: glyph=%#x tc=%#x\n", - __func__, x, y, glyph, tc); - } - } + /* p = (unsigned short *)vc->vc_origin; */ + /* mask = vc->vc_hi_font_mask | 0xff; */ + /* for (y = 0; y < vc->vc_rows; y++) { */ + /* char32_t *line = uniscr->lines[y]; */ + /* for (x = 0; x < vc->vc_cols; x++) { */ + /* u16 glyph = scr_readw(p++) & mask; */ + /* char32_t uc = line[x]; */ + /* int tc = conv_uni_to_pc(vc, uc); */ + /* if (tc == -4) */ + /* tc = conv_uni_to_pc(vc, 0xfffd); */ + /* if (tc == -4) */ + /* tc = conv_uni_to_pc(vc, '?'); */ + /* if (tc != glyph) */ + /* pr_err_ratelimited( */ + /* "%s: mismatch at %d,%d: glyph=%#x tc=%#x\n", */ + /* __func__, x, y, glyph, tc); */ + /* } */ + /* } */ +#endif } #ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK @@ -874,11 +909,12 @@ static void do_update_region(struct vc_data *vc, unsigned long start, int count) ? vc->vc_softback_curr : vc->vc_softback_curr - (vc->vc_softback_end - vc->vc_softback_buf) - : vc->vc_origin; + : vc->vc_origin - vc->vc_softback_lines * vc->vc_size_row; p = (u16 *) start; - offset = (start - origin) / 2; - xx = offset % vc->vc_cols; - yy = offset / vc->vc_cols; + offset = (start - origin) / 2; + xx = offset % vc->vc_cols; + yy = offset / vc->vc_cols; + for(;;) { u16 attrib = scr_readw(p) & 0xff00; int startx = xx; @@ -905,10 +941,6 @@ static void do_update_region(struct vc_data *vc, unsigned long start, int 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 @@ -1028,51 +1060,68 @@ static void update_attr(struct vc_data *vc) } /* Note: inverting the screen twice should revert to the original state */ +/* OFFSET is the offset in bytes (not 16-bit characters), COUNT is a byte + * count (not a character count). */ void invert_screen(struct vc_data *vc, int offset, int count, bool viewed) { unsigned short *p; + int row_offset, bytes_left_in_row; + int row_count; WARN_CONSOLE_UNLOCKED(); count /= 2; - p = screenpos(vc, offset, viewed); - if (vc->vc_sw->con_invert_region) { - vc->vc_sw->con_invert_region(vc, p, count); - } else { - u16 *q = p; - int cnt = count; - u16 a; - - if (!vc->vc_can_do_color) { - while (cnt--) { - a = scr_readw(q); - a ^= 0x0800; - scr_writew(a, q); - q++; - } - } else if (vc->vc_hi_font_mask == 0x100) { - while (cnt--) { - a = scr_readw(q); - a = (a & 0x11ff) | - ((a & 0xe000) >> 4) | - ((a & 0x0e00) << 4); - scr_writew(a, q); - q++; - } + row_offset = offset; + bytes_left_in_row = vc->vc_size_row - (row_offset % vc->vc_size_row); + row_count = (count < bytes_left_in_row / 2) + ? count + : bytes_left_in_row / 2; + + while (count) { + p = screenpos(vc, row_offset, viewed); + if (vc->vc_sw->con_invert_region) { + vc->vc_sw->con_invert_region(vc, p, row_count); } else { - while (cnt--) { - a = scr_readw(q); - a = (a & 0x88ff) | - ((a & 0x7000) >> 4) | - ((a & 0x0700) << 4); - scr_writew(a, q); - q++; + u16 *q = p; + int cnt = row_count; + u16 a; + + if (!vc->vc_can_do_color) { + while (cnt--) { + a = scr_readw(q); + a ^= 0x0800; + scr_writew(a, q); + q++; + } + } else if (vc->vc_hi_font_mask == 0x100) { + while (cnt--) { + a = scr_readw(q); + a = (a & 0x11ff) | + ((a & 0xe000) >> 4) | + ((a & 0x0e00) << 4); + scr_writew(a, q); + q++; + } + } else { + while (cnt--) { + a = scr_readw(q); + a = (a & 0x88ff) | + ((a & 0x7000) >> 4) | + ((a & 0x0700) << 4); + scr_writew(a, q); + q++; + } } } - } - if (con_should_update(vc)) - do_update_region(vc, (unsigned long) p, count); + if (con_should_update(vc)) + do_update_region(vc, (unsigned long) p, row_count); + row_offset += 2 * row_count; + count -= row_count; + row_count = (count >= vc->vc_cols) + ? vc->vc_cols + : count; + } notify_update(vc); } @@ -1273,7 +1322,6 @@ void redraw_screen(struct vc_data *vc, int is_switch) if (!vc) { /* strange ... */ - /* printk("redraw_screen: tty %d not allocated ??\n", new_console+1); */ return; } @@ -1401,11 +1449,13 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */ { struct vt_notifier_param param; struct vc_data *vc; + int err; +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK unsigned long new_end; unsigned long new_in, new_top; unsigned long in_residue; unsigned short *d; - int err; +#endif WARN_CONSOLE_UNLOCKED(); if (currcons >= MAX_NR_CONSOLES) @@ -1425,6 +1475,7 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */ vc->vc_softback_curr = vc->vc_softback_buf; vc->vc_softback_lines = 0; con_update_softback(vc); + vc_uniscr_alloc(vc, vc->vc_cols, vc->vc_rows); } } if (vc->vc_softback_buf @@ -1513,6 +1564,7 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */ vc->vc_softback_buf; vc->vc_softback_lines = 0; con_update_softback(vc); + vc_uniscr_alloc(vc, vc->vc_cols, vc->vc_rows); #endif return 0; err_free: @@ -1534,6 +1586,68 @@ static inline int resize_screen(struct vc_data *vc, int width, int height, return err; } +static int vc_copy_uniscr_to_new_area (struct vc_data *vc, + unsigned int new_rows, + unsigned int new_cols) +{ + unsigned int old_rows = vc->vc_rows, old_cols = vc->vc_cols; + uint32_t *old_uniscr_curr = vc->vc_uniscr_curr, + *old_uniscr_buf = vc->vc_uniscr_buf; + unsigned int old_uniscr_char_size = vc->vc_uniscr_char_size; + unsigned int new_lines; + uint32_t *dest, *src; + int res; + +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK_GPM + unsigned int new_uniscr_rows; + unsigned int old_lines; + long tmp; + + tmp = vc->vc_softback_curr - vc->vc_softback_top; + if (tmp < 0) + tmp += vc->vc_softback_end - vc->vc_softback_buf; + old_lines = tmp / vc->vc_size_row + old_rows; + + if ((res = vc_uniscr_alloc(vc, new_cols, new_rows)) != 0) + return res; + + new_uniscr_rows = (vc->vc_softback_end - vc->vc_softback_buf) + / vc->vc_size_row + + new_rows; /* STOUGH, Added, 2022-12-28 */ + new_lines = min(old_lines, new_uniscr_rows); + dest = vc->vc_uniscr_curr - (new_lines - new_rows) * new_cols; + if (dest < vc->vc_uniscr_buf) + dest += vc->vc_uniscr_char_size; + src = old_uniscr_curr - (old_lines - old_rows) * old_cols; + if (src < old_uniscr_buf) + src += old_uniscr_char_size; +#else + if ((res = vc_uniscr_alloc(vc, new_cols, new_rows)) != 0) + return res; + + new_lines = min(old_rows, new_rows); + dest = vc->vc_uniscr_curr; + src = old_uniscr_curr; +#endif + if (old_uniscr_buf) { + while (new_lines--) { + memcpy(dest, src, old_cols * sizeof(uint32_t)); + if (new_cols > old_cols) + memset32(dest + old_cols, ' ', + new_cols - old_cols); + dest += new_cols; + if (dest >= vc->vc_uniscr_buf + + vc->vc_uniscr_char_size) + dest -= vc->vc_uniscr_char_size; + src += old_cols; + if (src >= old_uniscr_buf + old_uniscr_char_size) + src -= old_uniscr_char_size; + } + kfree(old_uniscr_buf); + } + return 0; +} + /** * vc_do_resize - resizing method for the tty * @tty: tty being resized @@ -1558,7 +1672,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, unsigned int new_cols, new_rows, new_row_size, new_screen_size; unsigned int user; unsigned short *oldscreen, *newscreen; - struct uni_screen *new_uniscr = NULL; + uint32_t *old_uniscr = vc->vc_uniscr_buf; WARN_CONSOLE_UNLOCKED(); @@ -1602,14 +1716,6 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, if (!newscreen) return -ENOMEM; - if (get_vc_uniscr(vc)) { - new_uniscr = vc_uniscr_alloc(new_cols, new_rows); - if (!new_uniscr) { - kfree(newscreen); - return -ENOMEM; - } - } - if (vc_is_sel(vc)) clear_selection(); @@ -1619,10 +1725,14 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, err = resize_screen(vc, new_cols, new_rows, user); if (err) { kfree(newscreen); - vc_uniscr_free(new_uniscr); + vc_uniscr_free(vc); + vc->vc_uniscr_buf = old_uniscr; return err; } + if ((err = vc_copy_uniscr_to_new_area(vc, new_rows, new_cols)) != 0) + return err; + vc->vc_rows = new_rows; vc->vc_cols = new_cols; vc->vc_size_row = new_row_size; @@ -1653,11 +1763,6 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, first_copied_row = 0; end = old_origin + old_row_size * min(old_rows, new_rows); - vc_uniscr_copy_area(new_uniscr, new_cols, new_rows, - get_vc_uniscr(vc), rlth/2, first_copied_row, - min(old_rows, new_rows)); - vc_uniscr_set(vc, new_uniscr); - update_attr(vc); while (old_origin < end) { @@ -1757,8 +1862,8 @@ struct vc_data *vc_deallocate(unsigned int currcons) visual_deinit(vc); con_free_unimap(vc); put_pid(vc->vt_pid); - vc_uniscr_set(vc, NULL); kfree(vc->vc_screenbuf); + vc->vc_uniscr_buf = NULL; vc_cons[currcons].d = NULL; } return vc; @@ -3457,11 +3562,8 @@ static void vt_console_print(struct console *co, const char *b, unsigned count) if (kmsg_console && vc_cons_allocated(kmsg_console - 1)) vc = vc_cons[kmsg_console - 1].d; - if (!vc_cons_allocated(fg_console)) { - /* impossible */ - /* printk("vt_console_print: tty %d not allocated ??\n", currcons+1); */ + if (!vc_cons_allocated(fg_console)) goto quit; - } if (vc->vc_mode != KD_TEXT) goto quit; @@ -3758,6 +3860,10 @@ static int con_install(struct tty_driver *driver, struct tty_struct *tty) #ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK con_update_softback(vc); + if (!vc->vc_uniscr_buf) + ret = vc_uniscr_alloc(vc, vc->vc_cols, vc->vc_rows); + if (ret) + goto unlock; #endif /* Still being freed */ @@ -5119,10 +5225,19 @@ EXPORT_SYMBOL_GPL(screen_glyph); u32 screen_glyph_unicode(const struct vc_data *vc, int n) { - struct uni_screen *uniscr = get_vc_uniscr(vc); + int y = n / vc->vc_cols, x = n % vc->vc_cols; + uint32_t *ln = vc->vc_uniscr_curr + y * vc->vc_cols; - if (uniscr) - return uniscr->lines[n / vc->vc_cols][n % vc->vc_cols]; + if (vc->vc_uniscr_curr) { + if (ln >= vc_uniscr_buf_end(vc)) + ln -= vc->vc_uniscr_char_size; +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK_GPM + ln -= vc->vc_softback_lines * vc->vc_cols; + if (ln < vc->vc_uniscr_buf) + ln += vc->vc_uniscr_char_size; +#endif + return ln[x]; + } return inverse_translate(vc, screen_glyph(vc, n * 2), 1); } EXPORT_SYMBOL_GPL(screen_glyph_unicode); diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index 4a343877d70c..1abba103d7da 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -121,6 +121,21 @@ config FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK_SIZE position on the video takes 2 bytes of storage. 128kB will give you approximately four 240x67 screenfuls of scrollback buffer. +config FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK_GPM + bool "Enable a working GPM for scrolled back scrollback buffer in System RAM" + depends on FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK + default y + help + This option buffers up Unicode characters corresponding to the glyphs + displayed by the scrollback buffer. This enables the GPM mouse driver + (or similar) to copy characters from a scrolled back buffer. + + A buffer is created for each framebuffer console, this buffer being + approximately twice as big as the buffer size specified in + FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK_SIZE. + + If unsure, say 'Y'. + config FRAMEBUFFER_CONSOLE_DETECT_PRIMARY bool "Map the console to the primary display device" depends on FRAMEBUFFER_CONSOLE diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h index acc277e73e32..1d5d944ffaa7 100644 --- a/include/linux/console_struct.h +++ b/include/linux/console_struct.h @@ -170,7 +170,9 @@ struct vc_data { struct vc_data **vc_display_fg; /* [!] Ptr to var holding fg console for this display */ struct uni_pagedir *vc_uni_pagedir; struct uni_pagedir **vc_uni_pagedir_loc; /* [!] Location of uni_pagedir variable for this console */ - struct uni_screen *vc_uni_screen; /* unicode screen content */ + uint32_t *vc_uniscr_buf; /* Address of unicode screen content */ + uint32_t vc_uniscr_char_size; /* Size of *vc-uniscr_buf in 32-bit chars */ + uint32_t *vc_uniscr_curr; /* Pos of first char on (currently scrolled) screen */ /* additional information is in vt_kern.h */ };