--- drivers/tty/vt/vt.c +++ drivers/tty/vt/vt.c @@ -348,107 +377,111 @@ void schedule_console_callback(void) * Code to manage unicode-based screen buffers */ -/* - * Our screen buffer is preceded by an array of line pointers so that - * scrolling only implies some pointer shuffling. - */ +#define vc_uniscr_buf_end(vc) (vc->vc_uniscr_buf + vc->vc_uniscr_char_size) -static u32 **vc_uniscr_alloc(unsigned int cols, unsigned int rows) +static int vc_uniscr_alloc(struct vc_data *vc, unsigned int cols, unsigned int rows) { - u32 **uni_lines; - void *p; - unsigned int memsize, i, col_size = cols * sizeof(**uni_lines); - - /* allocate everything in one go */ - memsize = col_size * rows; - memsize += rows * sizeof(*uni_lines); - uni_lines = vzalloc(memsize); - if (!uni_lines) - return NULL; - - /* initial line pointers */ - p = uni_lines + rows; - for (i = 0; i < rows; i++) { - uni_lines[i] = p; - p += col_size; - } + uint32_t *p; + unsigned int new_size; /* In 32-bit characters */ - return uni_lines; -} +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK_GPM + unsigned int num_scrollback_rows; -static void vc_uniscr_free(u32 **uni_lines) -{ - vfree(uni_lines); + num_scrollback_rows = (console_soft_scrollback_size / 2) / cols; + new_size = cols * (num_scrollback_rows + rows + 1); +#else + new_size = cols * (rows + 1); /* 1 row for the circular buffer admin */ +#endif + p = (uint32_t *)vzalloc (sizeof (uint32_t) * new_size); + if (!p) + return -ENOMEM; + vc->vc_uniscr_buf = p; + vc->vc_uniscr_curr = p; + vc->vc_uniscr_char_size = new_size; + memset32(p, ' ', new_size); /* Probably redundant. */ + return 0; } -static void vc_uniscr_set(struct vc_data *vc, u32 **new_uni_lines) +static void vc_uniscr_free(struct vc_data *vc) { - vc_uniscr_free(vc->vc_uni_lines); - vc->vc_uni_lines = new_uni_lines; + kvfree(vc->vc_uniscr_buf); + vc->vc_uniscr_buf = NULL; } static void vc_uniscr_putc(struct vc_data *vc, u32 uc) { - if (vc->vc_uni_lines) - vc->vc_uni_lines[vc->state.y][vc->state.x] = uc; + uint32_t *pos; + + if (vc->vc_uniscr_buf) { + pos = vc->vc_uniscr_curr; + UNISCR_PLUS(pos, vc->state.y * vc->vc_cols + vc->state.x); +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK_GPM + UNISCR_MINUS(pos, vc->vc_cols * (vc->vc_softback_lines + vc->vc_top)); +#endif + *pos = uc; + } } static void vc_uniscr_insert(struct vc_data *vc, unsigned int nr) { - if (vc->vc_uni_lines) { - u32 *ln = vc->vc_uni_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; - memmove(&ln[x + nr], &ln[x], (cols - x - nr) * sizeof(*ln)); + if (vc->vc_uniscr_buf) { + UNISCR_PLUS(ln, y * cols); +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK_GPM + UNISCR_MINUS(ln, vc->vc_cols * (vc->vc_softback_lines + vc->vc_top)); +#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) { - if (vc->vc_uni_lines) { - u32 *ln = vc->vc_uni_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; - memcpy(&ln[x], &ln[x + nr], (cols - x - nr) * sizeof(*ln)); + if (vc->vc_uniscr_buf) { + UNISCR_PLUS(ln, y * cols); +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK_GPM + UNISCR_MINUS(ln, vc->vc_cols * (vc->vc_softback_lines + vc->vc_top)); +#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) { - if (vc->vc_uni_lines) - memset32(&vc->vc_uni_lines[vc->state.y][x], ' ', nr); + if (vc->vc_uniscr_buf) { + uint32_t *ln = vc->vc_uniscr_curr; + + UNISCR_PLUS(ln, vc->state.y * vc->vc_cols); +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK_GPM + UNISCR_MINUS(ln, vc->vc_cols * (vc->vc_softback_lines + vc->vc_top)); +#endif + memset32(&ln[x], ' ', nr); + } } static void vc_uniscr_clear_lines(struct vc_data *vc, unsigned int y, unsigned int nr) { - if (vc->vc_uni_lines) - while (nr--) - memset32(vc->vc_uni_lines[y++], ' ', vc->vc_cols); -} - -/* juggling array rotation algorithm (complexity O(N), size complexity O(1)) */ -static void juggle_array(u32 **array, unsigned int size, unsigned int nr) -{ - unsigned int gcd_idx; - - for (gcd_idx = 0; gcd_idx < gcd(nr, size); gcd_idx++) { - u32 *gcd_idx_val = array[gcd_idx]; - unsigned int dst_idx = gcd_idx; + if (vc->vc_uniscr_buf) { + unsigned int cols = vc->vc_cols; + uint32_t *ln = vc->vc_uniscr_curr; - while (1) { - unsigned int src_idx = (dst_idx + nr) % size; - if (src_idx == gcd_idx) - break; - - array[dst_idx] = array[src_idx]; - dst_idx = src_idx; + UNISCR_PLUS(ln, y * cols); +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK_GPM + UNISCR_MINUS(ln, vc->vc_cols * (vc->vc_softback_lines + vc->vc_top)); +#endif + while (nr--) { + memset32(ln, ' ', cols); + UNISCR_PLUS(ln, cols); } - - array[dst_idx] = gcd_idx_val; } }