summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/tty/vt/vc_screen.c3
-rw-r--r--drivers/tty/vt/vt.c31
-rw-r--r--include/linux/selection.h2
3 files changed, 32 insertions, 4 deletions
diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c
index 9c44252e52a3..2384ea85ffaf 100644
--- a/drivers/tty/vt/vc_screen.c
+++ b/drivers/tty/vt/vc_screen.c
@@ -311,7 +311,8 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
do {
if (nr > this_round/4)
nr = this_round/4;
- vc_uniscr_copy_line(vc, con_buf0, row, col, nr);
+ vc_uniscr_copy_line(vc, con_buf0, viewed,
+ row, col, nr);
con_buf0 += nr * 4;
this_round -= nr * 4;
row++;
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 062ce6be7957..2d14bb195d98 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -533,13 +533,40 @@ int vc_uniscr_check(struct vc_data *vc)
* This must be preceded by a successful call to vc_uniscr_check() once
* the console lock has been taken.
*/
-void vc_uniscr_copy_line(struct vc_data *vc, void *dest,
+void vc_uniscr_copy_line(struct vc_data *vc, void *dest, int viewed,
unsigned int row, unsigned int col, unsigned int nr)
{
struct uni_screen *uniscr = get_vc_uniscr(vc);
+ int offset = row * vc->vc_size_row + col * 2;
+ unsigned long pos;
BUG_ON(!uniscr);
- memcpy(dest, &uniscr->lines[row][col], nr * sizeof(char32_t));
+
+ pos = (unsigned long)screenpos(vc, offset, viewed);
+ if (pos >= vc->vc_origin && pos < vc->vc_scr_end) {
+ /*
+ * Desired position falls in the main screen buffer.
+ * However the actual row/col might be different if
+ * scrollback is active.
+ */
+ 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));
+ } 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.
+ */
+ 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);
+ }
+ }
}
diff --git a/include/linux/selection.h b/include/linux/selection.h
index 2b34df9f1e26..067d2e99c79f 100644
--- a/include/linux/selection.h
+++ b/include/linux/selection.h
@@ -43,7 +43,7 @@ extern void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org);
extern void vcs_scr_updated(struct vc_data *vc);
extern int vc_uniscr_check(struct vc_data *vc);
-extern void vc_uniscr_copy_line(struct vc_data *vc, void *dest,
+extern void vc_uniscr_copy_line(struct vc_data *vc, void *dest, int viewed,
unsigned int row, unsigned int col,
unsigned int nr);