aboutsummaryrefslogtreecommitdiff
path: root/drivers/tty/vt
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/vt')
-rw-r--r--drivers/tty/vt/Makefile4
-rw-r--r--drivers/tty/vt/consolemap.c57
-rw-r--r--drivers/tty/vt/keyboard.c46
-rw-r--r--drivers/tty/vt/selection.c8
-rw-r--r--drivers/tty/vt/vc_screen.c31
-rw-r--r--drivers/tty/vt/vt.c301
-rw-r--r--drivers/tty/vt/vt_ioctl.c64
7 files changed, 274 insertions, 237 deletions
diff --git a/drivers/tty/vt/Makefile b/drivers/tty/vt/Makefile
index 14a51c9960d..17ae94cb29f 100644
--- a/drivers/tty/vt/Makefile
+++ b/drivers/tty/vt/Makefile
@@ -27,8 +27,6 @@ $(obj)/defkeymap.o: $(obj)/defkeymap.c
ifdef GENERATE_KEYMAP
$(obj)/defkeymap.c: $(obj)/%.c: $(src)/%.map
- loadkeys --mktable $< > $@.tmp
- sed -e 's/^static *//' $@.tmp > $@
- rm $@.tmp
+ loadkeys --mktable $< > $@
endif
diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c
index 248381b3072..610b720d3b9 100644
--- a/drivers/tty/vt/consolemap.c
+++ b/drivers/tty/vt/consolemap.c
@@ -179,7 +179,6 @@ struct uni_pagedir {
unsigned long sum;
unsigned char *inverse_translations[4];
u16 *inverse_trans_unicode;
- int readonly;
};
static struct uni_pagedir *dflt;
@@ -194,8 +193,7 @@ static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int
q = p->inverse_translations[i];
if (!q) {
- q = p->inverse_translations[i] = (unsigned char *)
- kmalloc(MAX_GLYPH, GFP_KERNEL);
+ q = p->inverse_translations[i] = kmalloc(MAX_GLYPH, GFP_KERNEL);
if (!q) return;
}
memset(q, 0, MAX_GLYPH);
@@ -263,7 +261,7 @@ u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode)
int m;
if (glyph < 0 || glyph >= MAX_GLYPH)
return 0;
- else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc))
+ else if (!(p = *conp->vc_uni_pagedir_loc))
return glyph;
else if (use_unicode) {
if (!p->inverse_trans_unicode)
@@ -288,7 +286,7 @@ static void update_user_maps(void)
for (i = 0; i < MAX_NR_CONSOLES; i++) {
if (!vc_cons_allocated(i))
continue;
- p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
+ p = *vc_cons[i].d->vc_uni_pagedir_loc;
if (p && p != q) {
set_inverse_transl(vc_cons[i].d, p, USER_MAP);
set_inverse_trans_unicode(vc_cons[i].d, p);
@@ -419,10 +417,10 @@ void con_free_unimap(struct vc_data *vc)
{
struct uni_pagedir *p;
- p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+ p = *vc->vc_uni_pagedir_loc;
if (!p)
return;
- *vc->vc_uni_pagedir_loc = 0;
+ *vc->vc_uni_pagedir_loc = NULL;
if (--p->refcount)
return;
con_release_unimap(p);
@@ -437,7 +435,7 @@ static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
for (i = 0; i < MAX_NR_CONSOLES; i++) {
if (!vc_cons_allocated(i))
continue;
- q = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
+ q = *vc_cons[i].d->vc_uni_pagedir_loc;
if (!q || q == p || q->sum != p->sum)
continue;
for (j = 0; j < 32; j++) {
@@ -460,7 +458,7 @@ static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
}
if (j == 32) {
q->refcount++;
- *conp->vc_uni_pagedir_loc = (unsigned long)q;
+ *conp->vc_uni_pagedir_loc = q;
con_release_unimap(p);
kfree(p);
return 1;
@@ -501,10 +499,7 @@ static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
{
struct uni_pagedir *p, *q;
- p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
- if (p && p->readonly)
- return -EIO;
-
+ p = *vc->vc_uni_pagedir_loc;
if (!p || --p->refcount) {
q = kzalloc(sizeof(*p), GFP_KERNEL);
if (!q) {
@@ -513,7 +508,7 @@ static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
return -ENOMEM;
}
q->refcount=1;
- *vc->vc_uni_pagedir_loc = (unsigned long)q;
+ *vc->vc_uni_pagedir_loc = q;
} else {
if (p == dflt) dflt = NULL;
p->refcount++;
@@ -537,19 +532,13 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
int err = 0, err1, i;
struct uni_pagedir *p, *q;
+ if (!ct)
+ return 0;
+
console_lock();
/* Save original vc_unipagdir_loc in case we allocate a new one */
- p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
- if (p->readonly) {
- console_unlock();
- return -EIO;
- }
-
- if (!ct) {
- console_unlock();
- return 0;
- }
+ p = *vc->vc_uni_pagedir_loc;
if (p->refcount > 1) {
int j, k;
@@ -565,7 +554,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
* Since refcount was > 1, con_clear_unimap() allocated a
* a new uni_pagedir for this vc. Re: p != q
*/
- q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+ q = *vc->vc_uni_pagedir_loc;
/*
* uni_pgdir is a 32*32*64 table with rows allocated
@@ -587,7 +576,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
err1 = con_insert_unipair(q, l, p2[k]);
if (err1) {
p->refcount++;
- *vc->vc_uni_pagedir_loc = (unsigned long)p;
+ *vc->vc_uni_pagedir_loc = p;
con_release_unimap(q);
kfree(q);
console_unlock();
@@ -656,12 +645,12 @@ int con_set_default_unimap(struct vc_data *vc)
struct uni_pagedir *p;
if (dflt) {
- p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+ p = *vc->vc_uni_pagedir_loc;
if (p == dflt)
return 0;
dflt->refcount++;
- *vc->vc_uni_pagedir_loc = (unsigned long)dflt;
+ *vc->vc_uni_pagedir_loc = dflt;
if (p && !--p->refcount) {
con_release_unimap(p);
kfree(p);
@@ -675,7 +664,7 @@ int con_set_default_unimap(struct vc_data *vc)
if (err)
return err;
- p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+ p = *vc->vc_uni_pagedir_loc;
q = dfont_unitable;
for (i = 0; i < 256; i++)
@@ -686,7 +675,7 @@ int con_set_default_unimap(struct vc_data *vc)
}
if (con_unify_unimap(vc, p)) {
- dflt = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+ dflt = *vc->vc_uni_pagedir_loc;
return err;
}
@@ -714,9 +703,9 @@ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
if (*dst_vc->vc_uni_pagedir_loc == *src_vc->vc_uni_pagedir_loc)
return 0;
con_free_unimap(dst_vc);
- q = (struct uni_pagedir *)*src_vc->vc_uni_pagedir_loc;
+ q = *src_vc->vc_uni_pagedir_loc;
q->refcount++;
- *dst_vc->vc_uni_pagedir_loc = (long)q;
+ *dst_vc->vc_uni_pagedir_loc = q;
return 0;
}
EXPORT_SYMBOL(con_copy_unimap);
@@ -738,7 +727,7 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni
ect = 0;
if (*vc->vc_uni_pagedir_loc) {
- p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+ p = *vc->vc_uni_pagedir_loc;
for (i = 0; i < 32; i++)
if ((p1 = p->uni_pgdir[i]))
for (j = 0; j < 32; j++)
@@ -811,7 +800,7 @@ conv_uni_to_pc(struct vc_data *conp, long ucs)
if (!*conp->vc_uni_pagedir_loc)
return -3;
- p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+ p = *conp->vc_uni_pagedir_loc;
if ((p1 = p->uni_pgdir[ucs >> 11]) &&
(p2 = p1[(ucs >> 6) & 0x1f]) &&
(h = p2[ucs & 0x3f]) < MAX_GLYPH)
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 681765baef6..d0e3a449770 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -132,12 +132,6 @@ static int shift_state = 0;
static unsigned char ledstate = 0xff; /* undefined */
static unsigned char ledioctl;
-static struct ledptr {
- unsigned int *addr;
- unsigned int mask;
- unsigned char valid:1;
-} ledptrs[3];
-
/*
* Notifier list for console keyboard events
*/
@@ -307,26 +301,17 @@ int kbd_rate(struct kbd_repeat *rep)
*/
static void put_queue(struct vc_data *vc, int ch)
{
- struct tty_struct *tty = vc->port.tty;
-
- if (tty) {
- tty_insert_flip_char(tty, ch, 0);
- tty_schedule_flip(tty);
- }
+ tty_insert_flip_char(&vc->port, ch, 0);
+ tty_schedule_flip(&vc->port);
}
static void puts_queue(struct vc_data *vc, char *cp)
{
- struct tty_struct *tty = vc->port.tty;
-
- if (!tty)
- return;
-
while (*cp) {
- tty_insert_flip_char(tty, *cp, 0);
+ tty_insert_flip_char(&vc->port, *cp, 0);
cp++;
}
- tty_schedule_flip(tty);
+ tty_schedule_flip(&vc->port);
}
static void applkey(struct vc_data *vc, int key, char mode)
@@ -582,12 +567,8 @@ static void fn_inc_console(struct vc_data *vc)
static void fn_send_intr(struct vc_data *vc)
{
- struct tty_struct *tty = vc->port.tty;
-
- if (!tty)
- return;
- tty_insert_flip_char(tty, 0, TTY_BREAK);
- tty_schedule_flip(tty);
+ tty_insert_flip_char(&vc->port, 0, TTY_BREAK);
+ tty_schedule_flip(&vc->port);
}
static void fn_scroll_forw(struct vc_data *vc)
@@ -1007,24 +988,11 @@ void setledstate(struct kbd_struct *kbd, unsigned int led)
static inline unsigned char getleds(void)
{
struct kbd_struct *kbd = kbd_table + fg_console;
- unsigned char leds;
- int i;
if (kbd->ledmode == LED_SHOW_IOCTL)
return ledioctl;
- leds = kbd->ledflagstate;
-
- if (kbd->ledmode == LED_SHOW_MEM) {
- for (i = 0; i < 3; i++)
- if (ledptrs[i].valid) {
- if (*ledptrs[i].addr & ledptrs[i].mask)
- leds |= (1 << i);
- else
- leds &= ~(1 << i);
- }
- }
- return leds;
+ return kbd->ledflagstate;
}
static int kbd_update_leds_helper(struct input_handle *handle, void *data)
diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c
index 60b7b692605..ea27804d87a 100644
--- a/drivers/tty/vt/selection.c
+++ b/drivers/tty/vt/selection.c
@@ -24,6 +24,7 @@
#include <linux/selection.h>
#include <linux/tiocl.h>
#include <linux/console.h>
+#include <linux/tty_flip.h>
/* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */
#define isspace(c) ((c) == ' ')
@@ -346,8 +347,8 @@ int paste_selection(struct tty_struct *tty)
console_unlock();
ld = tty_ldisc_ref_wait(tty);
+ tty_buffer_lock_exclusive(&vc->port);
- /* FIXME: this is completely unsafe */
add_wait_queue(&vc->paste_wait, &wait);
while (sel_buffer && sel_buffer_lth > pasted) {
set_current_state(TASK_INTERRUPTIBLE);
@@ -356,13 +357,14 @@ int paste_selection(struct tty_struct *tty)
continue;
}
count = sel_buffer_lth - pasted;
- count = min(count, tty->receive_room);
- ld->ops->receive_buf(tty, sel_buffer + pasted, NULL, count);
+ count = tty_ldisc_receive_buf(ld, sel_buffer + pasted, NULL,
+ count);
pasted += count;
}
remove_wait_queue(&vc->paste_wait, &wait);
__set_current_state(TASK_RUNNING);
+ tty_buffer_unlock_exclusive(&vc->port);
tty_ldisc_deref(ld);
return 0;
}
diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c
index fa7268a93c0..14a2b5f11bc 100644
--- a/drivers/tty/vt/vc_screen.c
+++ b/drivers/tty/vt/vc_screen.c
@@ -93,7 +93,7 @@ vcs_poll_data_free(struct vcs_poll_data *poll)
static struct vcs_poll_data *
vcs_poll_data_get(struct file *file)
{
- struct vcs_poll_data *poll = file->private_data;
+ struct vcs_poll_data *poll = file->private_data, *kill = NULL;
if (poll)
return poll;
@@ -101,7 +101,7 @@ vcs_poll_data_get(struct file *file)
poll = kzalloc(sizeof(*poll), GFP_KERNEL);
if (!poll)
return NULL;
- poll->cons_num = iminor(file->f_path.dentry->d_inode) & 127;
+ poll->cons_num = iminor(file_inode(file)) & 127;
init_waitqueue_head(&poll->waitq);
poll->notifier.notifier_call = vcs_notifier;
if (register_vt_notifier(&poll->notifier) != 0) {
@@ -122,10 +122,12 @@ vcs_poll_data_get(struct file *file)
file->private_data = poll;
} else {
/* someone else raced ahead of us */
- vcs_poll_data_free(poll);
+ kill = poll;
poll = file->private_data;
}
spin_unlock(&file->f_lock);
+ if (kill)
+ vcs_poll_data_free(kill);
return poll;
}
@@ -182,33 +184,18 @@ static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
int size;
console_lock();
- size = vcs_size(file->f_path.dentry->d_inode);
+ size = vcs_size(file_inode(file));
console_unlock();
if (size < 0)
return size;
- switch (orig) {
- default:
- return -EINVAL;
- case 2:
- offset += size;
- break;
- case 1:
- offset += file->f_pos;
- case 0:
- break;
- }
- if (offset < 0 || offset > size) {
- return -EINVAL;
- }
- file->f_pos = offset;
- return file->f_pos;
+ return fixed_size_llseek(file, offset, orig, size);
}
static ssize_t
vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
- struct inode *inode = file->f_path.dentry->d_inode;
+ struct inode *inode = file_inode(file);
unsigned int currcons = iminor(inode);
struct vc_data *vc;
struct vcs_poll_data *poll;
@@ -386,7 +373,7 @@ unlock_out:
static ssize_t
vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
- struct inode *inode = file->f_path.dentry->d_inode;
+ struct inode *inode = file_inode(file);
unsigned int currcons = iminor(inode);
struct vc_data *vc;
long pos;
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 8fd89687d06..b33b00b386d 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -539,7 +539,7 @@ static void insert_char(struct vc_data *vc, unsigned int nr)
{
unsigned short *p = (unsigned short *) vc->vc_pos;
- scr_memmovew(p + nr, p, (vc->vc_cols - vc->vc_x) * 2);
+ scr_memmovew(p + nr, p, (vc->vc_cols - vc->vc_x - nr) * 2);
scr_memsetw(p, vc->vc_video_erase_char, nr * 2);
vc->vc_need_wrap = 0;
if (DO_UPDATE(vc))
@@ -638,7 +638,7 @@ static inline void save_screen(struct vc_data *vc)
* Redrawing of screen
*/
-static void clear_buffer_attributes(struct vc_data *vc)
+void clear_buffer_attributes(struct vc_data *vc)
{
unsigned short *p = (unsigned short *)vc->vc_origin;
int count = vc->vc_screenbuf_size / 2;
@@ -735,7 +735,7 @@ static void visual_init(struct vc_data *vc, int num, int init)
vc->vc_num = num;
vc->vc_display_fg = &master_display_fg;
vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir;
- vc->vc_uni_pagedir = 0;
+ vc->vc_uni_pagedir = NULL;
vc->vc_hi_font_mask = 0;
vc->vc_complement_mask = 0;
vc->vc_can_do_color = 0;
@@ -779,7 +779,6 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */
con_set_default_unimap(vc);
vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
if (!vc->vc_screenbuf) {
- tty_port_destroy(&vc->port);
kfree(vc);
vc_cons[currcons].d = NULL;
return -ENOMEM;
@@ -829,7 +828,7 @@ static inline int resize_screen(struct vc_data *vc, int width, int height,
* If the caller passes a tty structure then update the termios winsize
* information and perform any necessary signal handling.
*
- * Caller must hold the console semaphore. Takes the termios mutex and
+ * Caller must hold the console semaphore. Takes the termios rwsem and
* ctrl_lock of the tty IFF a tty is passed.
*/
@@ -973,7 +972,7 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows)
* the actual work.
*
* Takes the console sem and the called methods then take the tty
- * termios_mutex and the tty ctrl_lock in that order.
+ * termios_rwsem and the tty ctrl_lock in that order.
*/
static int vt_resize(struct tty_struct *tty, struct winsize *ws)
{
@@ -986,26 +985,25 @@ static int vt_resize(struct tty_struct *tty, struct winsize *ws)
return ret;
}
-void vc_deallocate(unsigned int currcons)
+struct vc_data *vc_deallocate(unsigned int currcons)
{
+ struct vc_data *vc = NULL;
+
WARN_CONSOLE_UNLOCKED();
if (vc_cons_allocated(currcons)) {
- struct vc_data *vc = vc_cons[currcons].d;
- struct vt_notifier_param param = { .vc = vc };
+ struct vt_notifier_param param;
+ param.vc = vc = vc_cons[currcons].d;
atomic_notifier_call_chain(&vt_notifier_list, VT_DEALLOCATE, &param);
vcs_remove_sysfs(currcons);
vc->vc_sw->con_deinit(vc);
put_pid(vc->vt_pid);
module_put(vc->vc_sw->owner);
kfree(vc->vc_screenbuf);
- if (currcons >= MIN_NR_CONSOLES) {
- tty_port_destroy(&vc->port);
- kfree(vc);
- }
vc_cons[currcons].d = NULL;
}
+ return vc;
}
/*
@@ -1166,6 +1164,8 @@ static void csi_J(struct vc_data *vc, int vpar)
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;
@@ -1231,6 +1231,52 @@ static void default_attr(struct vc_data *vc)
vc->vc_color = vc->vc_def_color;
}
+struct rgb { u8 r; u8 g; u8 b; };
+
+struct rgb rgb_from_256(int i)
+{
+ struct rgb c;
+ if (i < 8) { /* Standard colours. */
+ c.r = i&1 ? 0xaa : 0x00;
+ c.g = i&2 ? 0xaa : 0x00;
+ c.b = i&4 ? 0xaa : 0x00;
+ } else if (i < 16) {
+ c.r = i&1 ? 0xff : 0x55;
+ c.g = i&2 ? 0xff : 0x55;
+ c.b = i&4 ? 0xff : 0x55;
+ } else if (i < 232) { /* 6x6x6 colour cube. */
+ c.r = (i - 16) / 36 * 85 / 2;
+ c.g = (i - 16) / 6 % 6 * 85 / 2;
+ c.b = (i - 16) % 6 * 85 / 2;
+ } else /* Grayscale ramp. */
+ c.r = c.g = c.b = i * 10 - 2312;
+ return c;
+}
+
+static void rgb_foreground(struct vc_data *vc, struct rgb c)
+{
+ u8 hue, max = c.r;
+ if (c.g > max)
+ max = c.g;
+ if (c.b > max)
+ max = c.b;
+ hue = (c.r > max/2 ? 4 : 0)
+ | (c.g > max/2 ? 2 : 0)
+ | (c.b > max/2 ? 1 : 0);
+ if (hue == 7 && max <= 0x55)
+ hue = 0, vc->vc_intensity = 2;
+ else
+ vc->vc_intensity = (max > 0xaa) + 1;
+ vc->vc_color = (vc->vc_color & 0xf0) | hue;
+}
+
+static void rgb_background(struct vc_data *vc, struct rgb c)
+{
+ /* For backgrounds, err on the dark side. */
+ vc->vc_color = (vc->vc_color & 0x0f)
+ | (c.r&0x80) >> 1 | (c.g&0x80) >> 2 | (c.b&0x80) >> 3;
+}
+
/* console_lock is held */
static void csi_m(struct vc_data *vc)
{
@@ -1302,21 +1348,55 @@ static void csi_m(struct vc_data *vc)
case 27:
vc->vc_reverse = 0;
break;
- case 38: /* ANSI X3.64-1979 (SCO-ish?)
- * Enables underscore, white foreground
- * with white underscore (Linux - use
- * default foreground).
+ case 38: /* 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.
*/
- vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0);
- vc->vc_underline = 1;
+ i++;
+ if (i > vc->vc_npar)
+ break;
+ if (vc->vc_par[i] == 5 && /* 256 colours */
+ i < vc->vc_npar) { /* ubiquitous */
+ i++;
+ rgb_foreground(vc,
+ rgb_from_256(vc->vc_par[i]));
+ } else if (vc->vc_par[i] == 2 && /* 24 bit */
+ i <= vc->vc_npar + 3) {/* extremely rare */
+ struct rgb c = {r:vc->vc_par[i+1],
+ g:vc->vc_par[i+2],
+ b:vc->vc_par[i+3]};
+ rgb_foreground(vc, c);
+ i += 3;
+ }
+ /* Subcommands 3 (CMY) and 4 (CMYK) are so insane
+ * there's no point in supporting them.
+ */
break;
- case 39: /* ANSI X3.64-1979 (SCO-ish?)
- * Disable underline option.
- * Reset colour to default? It did this
- * before...
- */
+ case 48:
+ i++;
+ if (i > vc->vc_npar)
+ break;
+ if (vc->vc_par[i] == 5 && /* 256 colours */
+ i < vc->vc_npar) {
+ i++;
+ rgb_background(vc,
+ rgb_from_256(vc->vc_par[i]));
+ } else if (vc->vc_par[i] == 2 && /* 24 bit */
+ i <= vc->vc_npar + 3) {
+ struct rgb c = {r:vc->vc_par[i+1],
+ g:vc->vc_par[i+2],
+ b:vc->vc_par[i+3]};
+ rgb_background(vc, c);
+ i += 3;
+ }
+ break;
+ case 39:
vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0);
- vc->vc_underline = 0;
break;
case 49:
vc->vc_color = (vc->vc_def_color & 0xf0) | (vc->vc_color & 0x0f);
@@ -1333,13 +1413,13 @@ static void csi_m(struct vc_data *vc)
update_attr(vc);
}
-static void respond_string(const char *p, struct tty_struct *tty)
+static void respond_string(const char *p, struct tty_port *port)
{
while (*p) {
- tty_insert_flip_char(tty, *p, 0);
+ tty_insert_flip_char(port, *p, 0);
p++;
}
- tty_schedule_flip(tty);
+ tty_schedule_flip(port);
}
static void cursor_report(struct vc_data *vc, struct tty_struct *tty)
@@ -1347,17 +1427,17 @@ static void cursor_report(struct vc_data *vc, struct tty_struct *tty)
char buf[40];
sprintf(buf, "\033[%d;%dR", vc->vc_y + (vc->vc_decom ? vc->vc_top + 1 : 1), vc->vc_x + 1);
- respond_string(buf, tty);
+ respond_string(buf, tty->port);
}
static inline void status_report(struct tty_struct *tty)
{
- respond_string("\033[0n", tty); /* Terminal ok */
+ respond_string("\033[0n", tty->port); /* Terminal ok */
}
-static inline void respond_ID(struct tty_struct * tty)
+static inline void respond_ID(struct tty_struct *tty)
{
- respond_string(VT102ID, tty);
+ respond_string(VT102ID, tty->port);
}
void mouse_report(struct tty_struct *tty, int butt, int mrx, int mry)
@@ -1366,7 +1446,7 @@ void mouse_report(struct tty_struct *tty, int butt, int mrx, int mry)
sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx),
(char)('!' + mry));
- respond_string(buf, tty);
+ respond_string(buf, tty->port);
}
/* invoked via ioctl(TIOCLINUX) and through set_selection */
@@ -1581,9 +1661,9 @@ static void restore_cur(struct vc_data *vc)
vc->vc_need_wrap = 0;
}
-enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
+enum { ESnormal, ESesc, ESsquare, ESgetpars, ESfunckey,
EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
- ESpalette };
+ ESpalette, ESosc };
/* console_lock is held (except via vc_init()) */
static void reset_terminal(struct vc_data *vc, int do_clear)
@@ -1643,11 +1723,15 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
* Control characters can be used in the _middle_
* of an escape sequence.
*/
+ if (vc->vc_state == ESosc && c>=8 && c<=13) /* ... except for OSC */
+ return;
switch (c) {
case 0:
return;
case 7:
- if (vc->vc_bell_duration)
+ if (vc->vc_state == ESosc)
+ vc->vc_state = ESnormal;
+ else if (vc->vc_bell_duration)
kd_mksound(vc->vc_bell_pitch, vc->vc_bell_duration);
return;
case 8:
@@ -1758,7 +1842,9 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
} else if (c=='R') { /* reset palette */
reset_palette(vc);
vc->vc_state = ESnormal;
- } else
+ } else if (c>='0' && c<='9')
+ vc->vc_state = ESosc;
+ else
vc->vc_state = ESnormal;
return;
case ESpalette:
@@ -1798,9 +1884,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
vc->vc_par[vc->vc_npar] *= 10;
vc->vc_par[vc->vc_npar] += c - '0';
return;
- } else
- vc->vc_state = ESgotpars;
- case ESgotpars:
+ }
vc->vc_state = ESnormal;
switch(c) {
case 'h':
@@ -2014,6 +2098,8 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
vc->vc_translate = set_translate(vc->vc_G1_charset, vc);
vc->vc_state = ESnormal;
return;
+ case ESosc:
+ return;
default:
vc->vc_state = ESnormal;
}
@@ -2811,8 +2897,10 @@ static void con_shutdown(struct tty_struct *tty)
console_unlock();
}
+static int default_color = 7; /* white */
static int default_italic_color = 2; // green (ASCII)
static int default_underline_color = 3; // cyan (ASCII)
+module_param_named(color, default_color, int, S_IRUGO | S_IWUSR);
module_param_named(italic, default_italic_color, int, S_IRUGO | S_IWUSR);
module_param_named(underline, default_underline_color, int, S_IRUGO | S_IWUSR);
@@ -2834,7 +2922,7 @@ static void vc_init(struct vc_data *vc, unsigned int rows,
vc->vc_palette[k++] = default_grn[j] ;
vc->vc_palette[k++] = default_blu[j] ;
}
- vc->vc_def_color = 0x07; /* white */
+ vc->vc_def_color = default_color;
vc->vc_ulcolor = default_underline_color;
vc->vc_itcolor = default_italic_color;
vc->vc_halfcolor = 0x08; /* grey */
@@ -2987,7 +3075,7 @@ int __init vty_init(const struct file_operations *console_fops)
static struct class *vtconsole_class;
-static int bind_con_driver(const struct consw *csw, int first, int last,
+static int do_bind_con_driver(const struct consw *csw, int first, int last,
int deflt)
{
struct module *owner = csw->owner;
@@ -2998,7 +3086,7 @@ static int bind_con_driver(const struct consw *csw, int first, int last,
if (!try_module_get(owner))
return -ENODEV;
- console_lock();
+ WARN_CONSOLE_UNLOCKED();
/* check if driver is registered */
for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
@@ -3083,11 +3171,11 @@ static int bind_con_driver(const struct consw *csw, int first, int last,
retval = 0;
err:
- console_unlock();
module_put(owner);
return retval;
};
+
#ifdef CONFIG_VT_HW_CONSOLE_BINDING
static int con_is_graphics(const struct consw *csw, int first, int last)
{
@@ -3105,24 +3193,8 @@ static int con_is_graphics(const struct consw *csw, int first, int last)
return retval;
}
-/**
- * unbind_con_driver - unbind a console driver
- * @csw: pointer to console driver to unregister
- * @first: first in range of consoles that @csw should be unbound from
- * @last: last in range of consoles that @csw should be unbound from
- * @deflt: should next bound console driver be default after @csw is unbound?
- *
- * To unbind a driver from all possible consoles, pass 0 as @first and
- * %MAX_NR_CONSOLES as @last.
- *
- * @deflt controls whether the console that ends up replacing @csw should be
- * the default console.
- *
- * RETURNS:
- * -ENODEV if @csw isn't a registered console driver or can't be unregistered
- * or 0 on success.
- */
-int unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
+/* unlocked version of unbind_con_driver() */
+int do_unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
{
struct module *owner = csw->owner;
const struct consw *defcsw = NULL;
@@ -3132,7 +3204,7 @@ int unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
if (!try_module_get(owner))
return -ENODEV;
- console_lock();
+ WARN_CONSOLE_UNLOCKED();
/* check if driver is registered and if it is unbindable */
for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
@@ -3145,10 +3217,8 @@ int unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
}
}
- if (retval) {
- console_unlock();
+ if (retval)
goto err;
- }
retval = -ENODEV;
@@ -3156,23 +3226,18 @@ int unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
con_back = &registered_con_driver[i];
- if (con_back->con &&
- !(con_back->flag & CON_DRIVER_FLAG_MODULE)) {
+ if (con_back->con && con_back->con != csw) {
defcsw = con_back->con;
retval = 0;
break;
}
}
- if (retval) {
- console_unlock();
+ if (retval)
goto err;
- }
- if (!con_is_bound(csw)) {
- console_unlock();
+ if (!con_is_bound(csw))
goto err;
- }
first = max(first, con_driver->first);
last = min(last, con_driver->last);
@@ -3199,15 +3264,14 @@ int unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
if (!con_is_bound(csw))
con_driver->flag &= ~CON_DRIVER_FLAG_INIT;
- console_unlock();
/* ignore return value, binding should not fail */
- bind_con_driver(defcsw, first, last, deflt);
+ do_bind_con_driver(defcsw, first, last, deflt);
err:
module_put(owner);
return retval;
}
-EXPORT_SYMBOL(unbind_con_driver);
+EXPORT_SYMBOL_GPL(do_unbind_con_driver);
static int vt_bind(struct con_driver *con)
{
@@ -3248,8 +3312,11 @@ static int vt_bind(struct con_driver *con)
if (first == 0 && last == MAX_NR_CONSOLES -1)
deflt = 1;
- if (first != -1)
- bind_con_driver(csw, first, last, deflt);
+ if (first != -1) {
+ console_lock();
+ do_bind_con_driver(csw, first, last, deflt);
+ console_unlock();
+ }
first = -1;
last = -1;
@@ -3264,6 +3331,7 @@ static int vt_unbind(struct con_driver *con)
{
const struct consw *csw = NULL;
int i, more = 1, first = -1, last = -1, deflt = 0;
+ int ret;
if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
con_is_graphics(con->con, con->first, con->last))
@@ -3287,8 +3355,13 @@ static int vt_unbind(struct con_driver *con)
if (first == 0 && last == MAX_NR_CONSOLES -1)
deflt = 1;
- if (first != -1)
- unbind_con_driver(csw, first, last, deflt);
+ if (first != -1) {
+ console_lock();
+ ret = do_unbind_con_driver(csw, first, last, deflt);
+ console_unlock();
+ if (ret != 0)
+ return ret;
+ }
first = -1;
last = -1;
@@ -3492,28 +3565,18 @@ int con_debug_leave(void)
}
EXPORT_SYMBOL_GPL(con_debug_leave);
-/**
- * register_con_driver - register console driver to console layer
- * @csw: console driver
- * @first: the first console to take over, minimum value is 0
- * @last: the last console to take over, maximum value is MAX_NR_CONSOLES -1
- *
- * DESCRIPTION: This function registers a console driver which can later
- * bind to a range of consoles specified by @first and @last. It will
- * also initialize the console driver by calling con_startup().
- */
-int register_con_driver(const struct consw *csw, int first, int last)
+static int do_register_con_driver(const struct consw *csw, int first, int last)
{
struct module *owner = csw->owner;
struct con_driver *con_driver;
const char *desc;
int i, retval = 0;
+ WARN_CONSOLE_UNLOCKED();
+
if (!try_module_get(owner))
return -ENODEV;
- console_lock();
-
for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
con_driver = &registered_con_driver[i];
@@ -3566,14 +3629,13 @@ int register_con_driver(const struct consw *csw, int first, int last)
}
err:
- console_unlock();
module_put(owner);
return retval;
}
-EXPORT_SYMBOL(register_con_driver);
+
/**
- * unregister_con_driver - unregister console driver from console layer
+ * do_unregister_con_driver - unregister console driver from console layer
* @csw: console driver
*
* DESCRIPTION: All drivers that registers to the console layer must
@@ -3583,21 +3645,22 @@ EXPORT_SYMBOL(register_con_driver);
*
* The driver must unbind first prior to unregistration.
*/
-int unregister_con_driver(const struct consw *csw)
+int do_unregister_con_driver(const struct consw *csw)
{
- int i, retval = -ENODEV;
-
- console_lock();
+ int i;
/* cannot unregister a bound driver */
if (con_is_bound(csw))
- goto err;
+ return -EBUSY;
+
+ if (csw == conswitchp)
+ return -EINVAL;
for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
struct con_driver *con_driver = &registered_con_driver[i];
if (con_driver->con == csw &&
- con_driver->flag & CON_DRIVER_FLAG_MODULE) {
+ con_driver->flag & CON_DRIVER_FLAG_INIT) {
vtconsole_deinit_device(con_driver);
device_destroy(vtconsole_class,
MKDEV(0, con_driver->node));
@@ -3608,39 +3671,40 @@ int unregister_con_driver(const struct consw *csw)
con_driver->flag = 0;
con_driver->first = 0;
con_driver->last = 0;
- retval = 0;
- break;
+ return 0;
}
}
-err:
- console_unlock();
- return retval;
+
+ return -ENODEV;
}
-EXPORT_SYMBOL(unregister_con_driver);
+EXPORT_SYMBOL_GPL(do_unregister_con_driver);
/*
* If we support more console drivers, this function is used
* when a driver wants to take over some existing consoles
* and become default driver for newly opened ones.
*
- * take_over_console is basically a register followed by unbind
+ * do_take_over_console is basically a register followed by unbind
*/
-int take_over_console(const struct consw *csw, int first, int last, int deflt)
+int do_take_over_console(const struct consw *csw, int first, int last, int deflt)
{
int err;
- err = register_con_driver(csw, first, last);
- /* if we get an busy error we still want to bind the console driver
+ err = do_register_con_driver(csw, first, last);
+ /*
+ * If we get an busy error we still want to bind the console driver
* and return success, as we may have unbound the console driver
-  * but not unregistered it.
- */
+ * but not unregistered it.
+ */
if (err == -EBUSY)
err = 0;
if (!err)
- bind_con_driver(csw, first, last, deflt);
+ do_bind_con_driver(csw, first, last, deflt);
return err;
}
+EXPORT_SYMBOL_GPL(do_take_over_console);
+
/*
* give_up_console is a wrapper to unregister_con_driver. It will only
@@ -3648,7 +3712,9 @@ int take_over_console(const struct consw *csw, int first, int last, int deflt)
*/
void give_up_console(const struct consw *csw)
{
- unregister_con_driver(csw);
+ console_lock();
+ do_unregister_con_driver(csw);
+ console_unlock();
}
static int __init vtconsole_class_init(void)
@@ -4204,6 +4270,5 @@ EXPORT_SYMBOL(console_blanked);
EXPORT_SYMBOL(vc_cons);
EXPORT_SYMBOL(global_cursor_default);
#ifndef VT_SINGLE_DRIVER
-EXPORT_SYMBOL(take_over_console);
EXPORT_SYMBOL(give_up_console);
#endif
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index 98ff1735eaf..2bd78e2ac8e 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -283,6 +283,48 @@ do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_
return 0;
}
+/* deallocate a single console, if possible (leave 0) */
+static int vt_disallocate(unsigned int vc_num)
+{
+ struct vc_data *vc = NULL;
+ int ret = 0;
+
+ console_lock();
+ if (VT_BUSY(vc_num))
+ ret = -EBUSY;
+ else if (vc_num)
+ vc = vc_deallocate(vc_num);
+ console_unlock();
+
+ if (vc && vc_num >= MIN_NR_CONSOLES) {
+ tty_port_destroy(&vc->port);
+ kfree(vc);
+ }
+
+ return ret;
+}
+
+/* deallocate all unused consoles, but leave 0 */
+static void vt_disallocate_all(void)
+{
+ struct vc_data *vc[MAX_NR_CONSOLES];
+ int i;
+
+ console_lock();
+ for (i = 1; i < MAX_NR_CONSOLES; i++)
+ if (!VT_BUSY(i))
+ vc[i] = vc_deallocate(i);
+ else
+ vc[i] = NULL;
+ console_unlock();
+
+ for (i = 1; i < MAX_NR_CONSOLES; i++) {
+ if (vc[i] && i >= MIN_NR_CONSOLES) {
+ tty_port_destroy(&vc[i]->port);
+ kfree(vc[i]);
+ }
+ }
+}
/*
@@ -769,24 +811,10 @@ int vt_ioctl(struct tty_struct *tty,
ret = -ENXIO;
break;
}
- if (arg == 0) {
- /* deallocate all unused consoles, but leave 0 */
- console_lock();
- for (i=1; i<MAX_NR_CONSOLES; i++)
- if (! VT_BUSY(i))
- vc_deallocate(i);
- console_unlock();
- } else {
- /* deallocate a single console, if possible */
- arg--;
- if (VT_BUSY(arg))
- ret = -EBUSY;
- else if (arg) { /* leave 0 */
- console_lock();
- vc_deallocate(arg);
- console_unlock();
- }
- }
+ if (arg == 0)
+ vt_disallocate_all();
+ else
+ ret = vt_disallocate(--arg);
break;
case VT_RESIZE: