aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorAntonino A. Daplas <adaplas@gmail.com>2005-09-09 16:04:39 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-09 16:58:00 -0400
commit3b41dc1a3c7839a765ffa560a5ae07aa5d253cc8 (patch)
tree6cee743cc501593be36191151d391ad5ebfeac5f /drivers/char
parent2cc38ed13f1b0f9d80a2d0acc2916af94922f27e (diff)
[PATCH] console: Fix buffer copy on vc resize
On a vc resize, the contents of the old screen buffer are transferred to the new screenbuffer. If the new screenbuffer is smaller than the old one, only the contents from the bottom are copied to new. If the contents of the old buffer are located at the top, then the contents will not be copied to the new buffer resulting in a blank screen. This bug will happen only if the vc in question is not in the foreground. Doing an fbset -a or con2fbmap will trigger this bug. To fix this problem, base the start of the copy from the location of the current cursor. If the cursor is near the top of the buffer, copy the contents at the top, and if the cursor is near the bottom of the buffer, then copy the contents at the bottom. In the unlikely case where the new row size is greater than 2x smaller than the old one, and the cursor is in the middle, copy 1/2 screenful from the top and bottom of the cursor position. Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/vt.c37
1 files changed, 31 insertions, 6 deletions
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index b8d0c290b0db..1e33cb032e07 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -751,6 +751,7 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
751 unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0; 751 unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0;
752 unsigned int old_cols, old_rows, old_row_size, old_screen_size; 752 unsigned int old_cols, old_rows, old_row_size, old_screen_size;
753 unsigned int new_cols, new_rows, new_row_size, new_screen_size; 753 unsigned int new_cols, new_rows, new_row_size, new_screen_size;
754 unsigned int end;
754 unsigned short *newscreen; 755 unsigned short *newscreen;
755 756
756 WARN_CONSOLE_UNLOCKED(); 757 WARN_CONSOLE_UNLOCKED();
@@ -794,20 +795,44 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
794 old_origin = vc->vc_origin; 795 old_origin = vc->vc_origin;
795 new_origin = (long) newscreen; 796 new_origin = (long) newscreen;
796 new_scr_end = new_origin + new_screen_size; 797 new_scr_end = new_origin + new_screen_size;
797 if (new_rows < old_rows) 798
798 old_origin += (old_rows - new_rows) * old_row_size; 799 if (vc->vc_y > new_rows) {
800 if (old_rows - vc->vc_y < new_rows) {
801 /*
802 * Cursor near the bottom, copy contents from the
803 * bottom of buffer
804 */
805 old_origin += (old_rows - new_rows) * old_row_size;
806 end = vc->vc_scr_end;
807 } else {
808 /*
809 * Cursor is in no man's land, copy 1/2 screenful
810 * from the top and bottom of cursor position
811 */
812 old_origin += (vc->vc_y - new_rows/2) * old_row_size;
813 end = old_origin + new_screen_size;
814 }
815 } else
816 /*
817 * Cursor near the top, copy contents from the top of buffer
818 */
819 end = (old_rows > new_rows) ? old_origin + new_screen_size :
820 vc->vc_scr_end;
799 821
800 update_attr(vc); 822 update_attr(vc);
801 823
802 while (old_origin < vc->vc_scr_end) { 824 while (old_origin < end) {
803 scr_memcpyw((unsigned short *) new_origin, (unsigned short *) old_origin, rlth); 825 scr_memcpyw((unsigned short *) new_origin,
826 (unsigned short *) old_origin, rlth);
804 if (rrem) 827 if (rrem)
805 scr_memsetw((void *)(new_origin + rlth), vc->vc_video_erase_char, rrem); 828 scr_memsetw((void *)(new_origin + rlth),
829 vc->vc_video_erase_char, rrem);
806 old_origin += old_row_size; 830 old_origin += old_row_size;
807 new_origin += new_row_size; 831 new_origin += new_row_size;
808 } 832 }
809 if (new_scr_end > new_origin) 833 if (new_scr_end > new_origin)
810 scr_memsetw((void *)new_origin, vc->vc_video_erase_char, new_scr_end - new_origin); 834 scr_memsetw((void *)new_origin, vc->vc_video_erase_char,
835 new_scr_end - new_origin);
811 if (vc->vc_kmalloced) 836 if (vc->vc_kmalloced)
812 kfree(vc->vc_screenbuf); 837 kfree(vc->vc_screenbuf);
813 vc->vc_screenbuf = newscreen; 838 vc->vc_screenbuf = newscreen;