aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/vt
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/vt')
-rw-r--r--drivers/tty/vt/vc_screen.c48
-rw-r--r--drivers/tty/vt/vt.c127
2 files changed, 107 insertions, 68 deletions
diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c
index 2384ea85ffaf..160f46115aaa 100644
--- a/drivers/tty/vt/vc_screen.c
+++ b/drivers/tty/vt/vc_screen.c
@@ -80,7 +80,7 @@
struct vcs_poll_data {
struct notifier_block notifier;
unsigned int cons_num;
- bool seen_last_update;
+ int event;
wait_queue_head_t waitq;
struct fasync_struct *fasync;
};
@@ -93,9 +93,18 @@ vcs_notifier(struct notifier_block *nb, unsigned long code, void *_param)
struct vcs_poll_data *poll =
container_of(nb, struct vcs_poll_data, notifier);
int currcons = poll->cons_num;
-
- if (code != VT_UPDATE)
+ int fa_band;
+
+ switch (code) {
+ case VT_UPDATE:
+ fa_band = POLL_PRI;
+ break;
+ case VT_DEALLOCATE:
+ fa_band = POLL_HUP;
+ break;
+ default:
return NOTIFY_DONE;
+ }
if (currcons == 0)
currcons = fg_console;
@@ -104,9 +113,9 @@ vcs_notifier(struct notifier_block *nb, unsigned long code, void *_param)
if (currcons != vc->vc_num)
return NOTIFY_DONE;
- poll->seen_last_update = false;
+ poll->event = code;
wake_up_interruptible(&poll->waitq);
- kill_fasync(&poll->fasync, SIGIO, POLL_IN);
+ kill_fasync(&poll->fasync, SIGIO, fa_band);
return NOTIFY_OK;
}
@@ -131,6 +140,15 @@ vcs_poll_data_get(struct file *file)
poll->cons_num = console(file_inode(file));
init_waitqueue_head(&poll->waitq);
poll->notifier.notifier_call = vcs_notifier;
+ /*
+ * In order not to lose any update event, we must pretend one might
+ * have occurred before we have a chance to register our notifier.
+ * This is also how user space has come to detect which kernels
+ * support POLLPRI on /dev/vcs* devices i.e. using poll() with
+ * POLLPRI and a zero timeout.
+ */
+ poll->event = VT_UPDATE;
+
if (register_vt_notifier(&poll->notifier) != 0) {
kfree(poll);
return NULL;
@@ -261,7 +279,7 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
poll = file->private_data;
if (count && poll)
- poll->seen_last_update = true;
+ poll->event = 0;
read = 0;
ret = 0;
while (count) {
@@ -335,8 +353,9 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
if (p < HEADER_SIZE) {
size_t tmp_count;
- con_buf0[0] = (char)vc->vc_rows;
- con_buf0[1] = (char)vc->vc_cols;
+ /* clamp header values if they don't fit */
+ con_buf0[0] = min(vc->vc_rows, 0xFFu);
+ con_buf0[1] = min(vc->vc_cols, 0xFFu);
getconsxy(vc, con_buf0 + 2);
con_buf_start += p;
@@ -615,12 +634,21 @@ static __poll_t
vcs_poll(struct file *file, poll_table *wait)
{
struct vcs_poll_data *poll = vcs_poll_data_get(file);
- __poll_t ret = DEFAULT_POLLMASK|EPOLLERR|EPOLLPRI;
+ __poll_t ret = DEFAULT_POLLMASK|EPOLLERR;
if (poll) {
poll_wait(file, &poll->waitq, wait);
- if (poll->seen_last_update)
+ switch (poll->event) {
+ case VT_UPDATE:
+ ret = DEFAULT_POLLMASK|EPOLLPRI;
+ break;
+ case VT_DEALLOCATE:
+ ret = DEFAULT_POLLMASK|EPOLLHUP|EPOLLERR;
+ break;
+ case 0:
ret = DEFAULT_POLLMASK;
+ break;
+ }
}
return ret;
}
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 41ec8e5010f3..d34984aa646d 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -935,8 +935,11 @@ static void flush_scrollback(struct vc_data *vc)
{
WARN_CONSOLE_UNLOCKED();
+ set_origin(vc);
if (vc->vc_sw->con_flush_scrollback)
vc->vc_sw->con_flush_scrollback(vc);
+ else
+ vc->vc_sw->con_switch(vc);
}
/*
@@ -1272,6 +1275,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
if (con_is_visible(vc))
update_screen(vc);
vt_event_post(VT_EVENT_RESIZE, vc->vc_num, vc->vc_num);
+ notify_update(vc);
return err;
}
@@ -1341,6 +1345,8 @@ struct vc_data *vc_deallocate(unsigned int currcons)
* VT102 emulator
*/
+enum { EPecma = 0, EPdec, EPeq, EPgt, EPlt};
+
#define set_kbd(vc, x) vt_set_kbd_mode_bit((vc)->vc_num, (x))
#define clr_kbd(vc, x) vt_clr_kbd_mode_bit((vc)->vc_num, (x))
#define is_kbd(vc, x) vt_get_kbd_mode_bit((vc)->vc_num, (x))
@@ -1502,8 +1508,10 @@ static void csi_J(struct vc_data *vc, int vpar)
count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1;
start = (unsigned short *)vc->vc_origin;
break;
+ case 3: /* include scrollback */
+ flush_scrollback(vc);
+ /* fallthrough */
case 2: /* erase whole display */
- case 3: /* (and scrollback buffer later) */
vc_uniscr_clear_lines(vc, 0, vc->vc_rows);
count = vc->vc_cols * vc->vc_rows;
start = (unsigned short *)vc->vc_origin;
@@ -1512,13 +1520,7 @@ static void csi_J(struct vc_data *vc, int vpar)
return;
}
scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
- if (vpar == 3) {
- set_origin(vc);
- flush_scrollback(vc);
- if (con_is_visible(vc))
- update_screen(vc);
- } else if (con_should_update(vc))
- do_update_region(vc, (unsigned long) start, count);
+ update_region(vc, (unsigned long) start, count);
vc->vc_need_wrap = 0;
}
@@ -1627,9 +1629,9 @@ static void rgb_background(struct vc_data *vc, const struct rgb *c)
/*
* ITU T.416 Higher colour modes. They break the usual properties of SGR codes
- * and thus need to be detected and ignored by hand. Strictly speaking, that
- * standard also wants : rather than ; as separators, contrary to ECMA-48, but
- * no one produces such codes and almost no one accepts them.
+ * and thus need to be detected and ignored by hand. That standard also
+ * wants : rather than ; as separators but sequences containing : are currently
+ * completely ignored by the parser.
*
* Subcommands 3 (CMY) and 4 (CMYK) are so insane there's no point in
* supporting them.
@@ -1814,7 +1816,7 @@ static void set_mode(struct vc_data *vc, int on_off)
int i;
for (i = 0; i <= vc->vc_npar; i++)
- if (vc->vc_ques) {
+ if (vc->vc_priv == EPdec) {
switch(vc->vc_par[i]) { /* DEC private modes set/reset */
case 1: /* Cursor keys send ^[Ox/^[[x */
if (on_off)
@@ -2021,7 +2023,7 @@ static void restore_cur(struct vc_data *vc)
}
enum { ESnormal, ESesc, ESsquare, ESgetpars, ESfunckey,
- EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
+ EShash, ESsetG0, ESsetG1, ESpercent, EScsiignore, ESnonstd,
ESpalette, ESosc };
/* console_lock is held (except via vc_init()) */
@@ -2030,7 +2032,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear)
vc->vc_top = 0;
vc->vc_bottom = vc->vc_rows;
vc->vc_state = ESnormal;
- vc->vc_ques = 0;
+ vc->vc_priv = EPecma;
vc->vc_translate = set_translate(LAT1_MAP, vc);
vc->vc_G0_charset = LAT1_MAP;
vc->vc_G1_charset = GRAF_MAP;
@@ -2111,6 +2113,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
lf(vc);
if (!is_kbd(vc, lnm))
return;
+ /* fall through */
case 13:
cr(vc);
return;
@@ -2233,9 +2236,22 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
vc->vc_state=ESfunckey;
return;
}
- vc->vc_ques = (c == '?');
- if (vc->vc_ques)
+ switch (c) {
+ case '?':
+ vc->vc_priv = EPdec;
return;
+ case '>':
+ vc->vc_priv = EPgt;
+ return;
+ case '=':
+ vc->vc_priv = EPeq;
+ return;
+ case '<':
+ vc->vc_priv = EPlt;
+ return;
+ }
+ vc->vc_priv = EPecma;
+ /* fall through */
case ESgetpars:
if (c == ';' && vc->vc_npar < NPAR - 1) {
vc->vc_npar++;
@@ -2245,16 +2261,22 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
vc->vc_par[vc->vc_npar] += c - '0';
return;
}
+ if (c >= 0x20 && c <= 0x3f) { /* 0x2x, 0x3a and 0x3c - 0x3f */
+ vc->vc_state = EScsiignore;
+ return;
+ }
vc->vc_state = ESnormal;
switch(c) {
case 'h':
- set_mode(vc, 1);
+ if (vc->vc_priv <= EPdec)
+ set_mode(vc, 1);
return;
case 'l':
- set_mode(vc, 0);
+ if (vc->vc_priv <= EPdec)
+ set_mode(vc, 0);
return;
case 'c':
- if (vc->vc_ques) {
+ if (vc->vc_priv == EPdec) {
if (vc->vc_par[0])
vc->vc_cursor_type = vc->vc_par[0] | (vc->vc_par[1] << 8) | (vc->vc_par[2] << 16);
else
@@ -2263,7 +2285,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
}
break;
case 'm':
- if (vc->vc_ques) {
+ if (vc->vc_priv == EPdec) {
clear_selection();
if (vc->vc_par[0])
vc->vc_complement_mask = vc->vc_par[0] << 8 | vc->vc_par[1];
@@ -2273,7 +2295,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
}
break;
case 'n':
- if (!vc->vc_ques) {
+ if (vc->vc_priv == EPecma) {
if (vc->vc_par[0] == 5)
status_report(tty);
else if (vc->vc_par[0] == 6)
@@ -2281,8 +2303,8 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
}
return;
}
- if (vc->vc_ques) {
- vc->vc_ques = 0;
+ if (vc->vc_priv != EPecma) {
+ vc->vc_priv = EPecma;
return;
}
switch(c) {
@@ -2405,6 +2427,11 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
return;
}
return;
+ case EScsiignore:
+ if (c >= 20 && c <= 0x3f)
+ return;
+ vc->vc_state = ESnormal;
+ return;
case ESpercent:
vc->vc_state = ESnormal;
switch (c) {
@@ -2764,8 +2791,8 @@ rescan_last_byte:
con_flush(vc, draw_from, draw_to, &draw_x);
vc_uniscr_debug_check(vc);
console_conditional_schedule();
- console_unlock();
notify_update(vc);
+ console_unlock();
return n;
}
@@ -2884,8 +2911,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count)
unsigned char c;
static DEFINE_SPINLOCK(printing_lock);
const ushort *start;
- ushort cnt = 0;
- ushort myx;
+ ushort start_x, cnt;
int kmsg_console;
/* console busy or not yet initialized */
@@ -2898,10 +2924,6 @@ 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;
- /* read `x' only after setting currcons properly (otherwise
- the `x' macro will read the x of the foreground console). */
- myx = vc->vc_x;
-
if (!vc_cons_allocated(fg_console)) {
/* impossible */
/* printk("vt_console_print: tty %d not allocated ??\n", currcons+1); */
@@ -2916,53 +2938,41 @@ static void vt_console_print(struct console *co, const char *b, unsigned count)
hide_cursor(vc);
start = (ushort *)vc->vc_pos;
-
- /* Contrived structure to try to emulate original need_wrap behaviour
- * Problems caused when we have need_wrap set on '\n' character */
+ start_x = vc->vc_x;
+ cnt = 0;
while (count--) {
c = *b++;
if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) {
- if (cnt > 0) {
- if (con_is_visible(vc))
- vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x);
- vc->vc_x += cnt;
- if (vc->vc_need_wrap)
- vc->vc_x--;
- cnt = 0;
- }
+ if (cnt && con_is_visible(vc))
+ vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, start_x);
+ cnt = 0;
if (c == 8) { /* backspace */
bs(vc);
start = (ushort *)vc->vc_pos;
- myx = vc->vc_x;
+ start_x = vc->vc_x;
continue;
}
if (c != 13)
lf(vc);
cr(vc);
start = (ushort *)vc->vc_pos;
- myx = vc->vc_x;
+ start_x = vc->vc_x;
if (c == 10 || c == 13)
continue;
}
+ vc_uniscr_putc(vc, c);
scr_writew((vc->vc_attr << 8) + c, (unsigned short *)vc->vc_pos);
notify_write(vc, c);
cnt++;
- if (myx == vc->vc_cols - 1) {
- vc->vc_need_wrap = 1;
- continue;
- }
- vc->vc_pos += 2;
- myx++;
- }
- if (cnt > 0) {
- if (con_is_visible(vc))
- vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x);
- vc->vc_x += cnt;
- if (vc->vc_x == vc->vc_cols) {
- vc->vc_x--;
+ if (vc->vc_x == vc->vc_cols - 1) {
vc->vc_need_wrap = 1;
+ } else {
+ vc->vc_pos += 2;
+ vc->vc_x++;
}
}
+ if (cnt && con_is_visible(vc))
+ vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, start_x);
set_cursor(vc);
notify_update(vc);
@@ -4607,8 +4617,9 @@ EXPORT_SYMBOL_GPL(screen_pos);
void getconsxy(struct vc_data *vc, unsigned char *p)
{
- p[0] = vc->vc_x;
- p[1] = vc->vc_y;
+ /* clamp values if they don't fit */
+ p[0] = min(vc->vc_x, 0xFFu);
+ p[1] = min(vc->vc_y, 0xFFu);
}
void putconsxy(struct vc_data *vc, unsigned char *p)