tty vt: Fix line garbage in virtual console on command line edition

On some machines using a specific hardware for console screen output,
the update of the pixel frame buffer does not work correctly when
using command line edition. This may be due to a memory cache bug
in the machine on which the problem has been found, but an other
solution is possible.

This patch proposes to avoid touching directly the pixel frame buffer
and to rebuild each character using the standard putc() function
on command line edition.

The resulting code is smaller and not obviously slower (no read
access to the pixel frame buffer).

Tested on a Cubox (ARM Marvell Dove 88AP510 SoC).

Signed-off-by: Jean-François Moine <moinejf@free.fr>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Jean-François Moine 2012-09-06 19:24:13 +02:00 committed by Greg Kroah-Hartman
parent 7b6031a7bc
commit 81732c3b2f
1 changed files with 17 additions and 61 deletions

View File

@ -537,45 +537,27 @@ void complement_pos(struct vc_data *vc, int offset)
static void insert_char(struct vc_data *vc, unsigned int nr)
{
unsigned short *p, *q = (unsigned short *)vc->vc_pos;
unsigned short *p = (unsigned short *) vc->vc_pos;
p = q + vc->vc_cols - nr - vc->vc_x;
while (--p >= q)
scr_writew(scr_readw(p), p + nr);
scr_memsetw(q, vc->vc_video_erase_char, nr * 2);
scr_memmovew(p + nr, p, vc->vc_cols - vc->vc_x);
scr_memsetw(p, vc->vc_video_erase_char, nr * 2);
vc->vc_need_wrap = 0;
if (DO_UPDATE(vc)) {
unsigned short oldattr = vc->vc_attr;
vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x, vc->vc_y, vc->vc_x + nr, 1,
vc->vc_cols - vc->vc_x - nr);
vc->vc_attr = vc->vc_video_erase_char >> 8;
while (nr--)
vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y, vc->vc_x + nr);
vc->vc_attr = oldattr;
}
if (DO_UPDATE(vc))
do_update_region(vc, (unsigned long) p,
(vc->vc_cols - vc->vc_x) / 2 + 1);
}
static void delete_char(struct vc_data *vc, unsigned int nr)
{
unsigned int i = vc->vc_x;
unsigned short *p = (unsigned short *)vc->vc_pos;
unsigned short *p = (unsigned short *) vc->vc_pos;
while (++i <= vc->vc_cols - nr) {
scr_writew(scr_readw(p+nr), p);
p++;
}
scr_memsetw(p, vc->vc_video_erase_char, nr * 2);
scr_memcpyw(p, p + nr, vc->vc_cols - vc->vc_x - nr);
scr_memsetw(p + vc->vc_cols - vc->vc_x - nr, vc->vc_video_erase_char,
nr * 2);
vc->vc_need_wrap = 0;
if (DO_UPDATE(vc)) {
unsigned short oldattr = vc->vc_attr;
vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x + nr, vc->vc_y, vc->vc_x, 1,
vc->vc_cols - vc->vc_x - nr);
vc->vc_attr = vc->vc_video_erase_char >> 8;
while (nr--)
vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y,
vc->vc_cols - 1 - nr);
vc->vc_attr = oldattr;
}
if (DO_UPDATE(vc))
do_update_region(vc, (unsigned long) p,
(vc->vc_cols - vc->vc_x) / 2);
}
static int softcursor_original;
@ -1172,45 +1154,26 @@ static void csi_J(struct vc_data *vc, int vpar)
case 0: /* erase from cursor to end of display */
count = (vc->vc_scr_end - vc->vc_pos) >> 1;
start = (unsigned short *)vc->vc_pos;
if (DO_UPDATE(vc)) {
/* do in two stages */
vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1,
vc->vc_cols - vc->vc_x);
vc->vc_sw->con_clear(vc, vc->vc_y + 1, 0,
vc->vc_rows - vc->vc_y - 1,
vc->vc_cols);
}
break;
case 1: /* erase from start to cursor */
count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1;
start = (unsigned short *)vc->vc_origin;
if (DO_UPDATE(vc)) {
/* do in two stages */
vc->vc_sw->con_clear(vc, 0, 0, vc->vc_y,
vc->vc_cols);
vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
vc->vc_x + 1);
}
break;
case 3: /* erase scroll-back buffer (and whole display) */
scr_memsetw(vc->vc_screenbuf, vc->vc_video_erase_char,
vc->vc_screenbuf_size >> 1);
set_origin(vc);
if (CON_IS_VISIBLE(vc))
update_screen(vc);
/* fall through */
case 2: /* erase whole display */
count = vc->vc_cols * vc->vc_rows;
start = (unsigned short *)vc->vc_origin;
if (DO_UPDATE(vc))
vc->vc_sw->con_clear(vc, 0, 0,
vc->vc_rows,
vc->vc_cols);
break;
default:
return;
}
scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
if (DO_UPDATE(vc))
do_update_region(vc, (unsigned long) start, count);
vc->vc_need_wrap = 0;
}
@ -1223,29 +1186,22 @@ static void csi_K(struct vc_data *vc, int vpar)
case 0: /* erase from cursor to end of line */
count = vc->vc_cols - vc->vc_x;
start = (unsigned short *)vc->vc_pos;
if (DO_UPDATE(vc))
vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1,
vc->vc_cols - vc->vc_x);
break;
case 1: /* erase from start of line to cursor */
start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1));
count = vc->vc_x + 1;
if (DO_UPDATE(vc))
vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
vc->vc_x + 1);
break;
case 2: /* erase whole line */
start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1));
count = vc->vc_cols;
if (DO_UPDATE(vc))
vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
vc->vc_cols);
break;
default:
return;
}
scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
vc->vc_need_wrap = 0;
if (DO_UPDATE(vc))
do_update_region(vc, (unsigned long) start, count);
}
static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar positions */