summaryrefslogtreecommitdiff
path: root/drivers/tty/vt
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/vt')
-rw-r--r--drivers/tty/vt/consolemap.c73
-rw-r--r--drivers/tty/vt/keyboard.c216
-rw-r--r--drivers/tty/vt/selection.c5
-rw-r--r--drivers/tty/vt/vt.c698
-rw-r--r--drivers/tty/vt/vt_ioctl.c8
5 files changed, 545 insertions, 455 deletions
diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c
index 59b25e039..9d7ab7b66 100644
--- a/drivers/tty/vt/consolemap.c
+++ b/drivers/tty/vt/consolemap.c
@@ -261,19 +261,22 @@ 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 = *conp->vc_uni_pagedir_loc))
- return glyph;
- else if (use_unicode) {
- if (!p->inverse_trans_unicode)
+ else {
+ p = *conp->vc_uni_pagedir_loc;
+ if (!p)
return glyph;
- else
- return p->inverse_trans_unicode[glyph];
- } else {
- m = inv_translate[conp->vc_num];
- if (!p->inverse_translations[m])
- return glyph;
- else
- return p->inverse_translations[m][glyph];
+ else if (use_unicode) {
+ if (!p->inverse_trans_unicode)
+ return glyph;
+ else
+ return p->inverse_trans_unicode[glyph];
+ } else {
+ m = inv_translate[conp->vc_num];
+ if (!p->inverse_translations[m])
+ return glyph;
+ else
+ return p->inverse_translations[m][glyph];
+ }
}
}
EXPORT_SYMBOL_GPL(inverse_translate);
@@ -397,7 +400,8 @@ static void con_release_unimap(struct uni_pagedir *p)
if (p == dflt) dflt = NULL;
for (i = 0; i < 32; i++) {
- if ((p1 = p->uni_pgdir[i]) != NULL) {
+ p1 = p->uni_pgdir[i];
+ if (p1 != NULL) {
for (j = 0; j < 32; j++)
kfree(p1[j]);
kfree(p1);
@@ -473,14 +477,16 @@ con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
int i, n;
u16 **p1, *p2;
- if (!(p1 = p->uni_pgdir[n = unicode >> 11])) {
+ p1 = p->uni_pgdir[n = unicode >> 11];
+ if (!p1) {
p1 = p->uni_pgdir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL);
if (!p1) return -ENOMEM;
for (i = 0; i < 32; i++)
p1[i] = NULL;
}
- if (!(p2 = p1[n = (unicode >> 6) & 0x1f])) {
+ p2 = p1[n = (unicode >> 6) & 0x1f];
+ if (!p2) {
p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL);
if (!p2) return -ENOMEM;
memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */
@@ -493,9 +499,8 @@ con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
return 0;
}
-/* ui is a leftover from using a hashtable, but might be used again
- Caller must hold the lock */
-static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
+/* Caller must hold the lock */
+static int con_do_clear_unimap(struct vc_data *vc)
{
struct uni_pagedir *p, *q;
@@ -518,11 +523,11 @@ static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
return 0;
}
-int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
+int con_clear_unimap(struct vc_data *vc)
{
int ret;
console_lock();
- ret = con_do_clear_unimap(vc, ui);
+ ret = con_do_clear_unimap(vc);
console_unlock();
return ret;
}
@@ -550,7 +555,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
int j, k;
u16 **p1, *p2, l;
- err1 = con_do_clear_unimap(vc, NULL);
+ err1 = con_do_clear_unimap(vc);
if (err1) {
console_unlock();
return err1;
@@ -569,10 +574,12 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
* entries from "p" (old) to "q" (new).
*/
l = 0; /* unicode value */
- for (i = 0; i < 32; i++)
- if ((p1 = p->uni_pgdir[i]))
- for (j = 0; j < 32; j++)
- if ((p2 = p1[j])) {
+ for (i = 0; i < 32; i++) {
+ p1 = p->uni_pgdir[i];
+ if (p1)
+ for (j = 0; j < 32; j++) {
+ p2 = p1[j];
+ if (p2) {
for (k = 0; k < 64; k++, l++)
if (p2[k] != 0xffff) {
/*
@@ -593,9 +600,11 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
/* Account for row of 64 empty entries */
l += 64;
}
+ }
else
/* Account for empty table */
l += 32 * 64;
+ }
/*
* Finished copying font table, set vc_uni_pagedir to new table
@@ -667,7 +676,7 @@ int con_set_default_unimap(struct vc_data *vc)
/* The default font is always 256 characters */
- err = con_do_clear_unimap(vc, NULL);
+ err = con_do_clear_unimap(vc);
if (err)
return err;
@@ -735,10 +744,12 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni
ect = 0;
if (*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++)
- if ((p2 = *(p1++)))
+ for (i = 0; i < 32; i++) {
+ p1 = p->uni_pgdir[i];
+ if (p1)
+ for (j = 0; j < 32; j++) {
+ p2 = *(p1++);
+ if (p2)
for (k = 0; k < 64; k++) {
if (*p2 < MAX_GLYPH && ect++ < ct) {
__put_user((u_short)((i<<11)+(j<<6)+k),
@@ -749,6 +760,8 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni
}
p2++;
}
+ }
+ }
}
__put_user(ect, uct);
console_unlock();
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 8a89f6e77..0f8caae42 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -33,6 +33,7 @@
#include <linux/string.h>
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/leds.h>
#include <linux/kbd_kern.h>
#include <linux/kbd_diacr.h>
@@ -129,7 +130,7 @@ static char rep; /* flag telling character repeat */
static int shift_state = 0;
-static unsigned char ledstate = 0xff; /* undefined */
+static unsigned int ledstate = -1U; /* undefined */
static unsigned char ledioctl;
/*
@@ -365,34 +366,22 @@ static void to_utf8(struct vc_data *vc, uint c)
static void do_compute_shiftstate(void)
{
- unsigned int i, j, k, sym, val;
+ unsigned int k, sym, val;
shift_state = 0;
memset(shift_down, 0, sizeof(shift_down));
- for (i = 0; i < ARRAY_SIZE(key_down); i++) {
-
- if (!key_down[i])
+ for_each_set_bit(k, key_down, min(NR_KEYS, KEY_CNT)) {
+ sym = U(key_maps[0][k]);
+ if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK)
continue;
- k = i * BITS_PER_LONG;
-
- for (j = 0; j < BITS_PER_LONG; j++, k++) {
-
- if (!test_bit(k, key_down))
- continue;
+ val = KVAL(sym);
+ if (val == KVAL(K_CAPSSHIFT))
+ val = KVAL(K_SHIFT);
- sym = U(key_maps[0][k]);
- if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK)
- continue;
-
- val = KVAL(sym);
- if (val == KVAL(K_CAPSSHIFT))
- val = KVAL(K_SHIFT);
-
- shift_down[val]++;
- shift_state |= (1 << val);
- }
+ shift_down[val]++;
+ shift_state |= BIT(val);
}
}
@@ -578,7 +567,7 @@ static void fn_scroll_forw(struct vc_data *vc)
static void fn_scroll_back(struct vc_data *vc)
{
- scrollback(vc, 0);
+ scrollback(vc);
}
static void fn_show_mem(struct vc_data *vc)
@@ -961,6 +950,122 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag)
}
}
+#if IS_ENABLED(CONFIG_INPUT_LEDS) && IS_ENABLED(CONFIG_LEDS_TRIGGERS)
+
+struct kbd_led_trigger {
+ struct led_trigger trigger;
+ unsigned int mask;
+};
+
+static void kbd_led_trigger_activate(struct led_classdev *cdev)
+{
+ struct kbd_led_trigger *trigger =
+ container_of(cdev->trigger, struct kbd_led_trigger, trigger);
+
+ tasklet_disable(&keyboard_tasklet);
+ if (ledstate != -1U)
+ led_trigger_event(&trigger->trigger,
+ ledstate & trigger->mask ?
+ LED_FULL : LED_OFF);
+ tasklet_enable(&keyboard_tasklet);
+}
+
+#define KBD_LED_TRIGGER(_led_bit, _name) { \
+ .trigger = { \
+ .name = _name, \
+ .activate = kbd_led_trigger_activate, \
+ }, \
+ .mask = BIT(_led_bit), \
+ }
+
+#define KBD_LOCKSTATE_TRIGGER(_led_bit, _name) \
+ KBD_LED_TRIGGER((_led_bit) + 8, _name)
+
+static struct kbd_led_trigger kbd_led_triggers[] = {
+ KBD_LED_TRIGGER(VC_SCROLLOCK, "kbd-scrollock"),
+ KBD_LED_TRIGGER(VC_NUMLOCK, "kbd-numlock"),
+ KBD_LED_TRIGGER(VC_CAPSLOCK, "kbd-capslock"),
+ KBD_LED_TRIGGER(VC_KANALOCK, "kbd-kanalock"),
+
+ KBD_LOCKSTATE_TRIGGER(VC_SHIFTLOCK, "kbd-shiftlock"),
+ KBD_LOCKSTATE_TRIGGER(VC_ALTGRLOCK, "kbd-altgrlock"),
+ KBD_LOCKSTATE_TRIGGER(VC_CTRLLOCK, "kbd-ctrllock"),
+ KBD_LOCKSTATE_TRIGGER(VC_ALTLOCK, "kbd-altlock"),
+ KBD_LOCKSTATE_TRIGGER(VC_SHIFTLLOCK, "kbd-shiftllock"),
+ KBD_LOCKSTATE_TRIGGER(VC_SHIFTRLOCK, "kbd-shiftrlock"),
+ KBD_LOCKSTATE_TRIGGER(VC_CTRLLLOCK, "kbd-ctrlllock"),
+ KBD_LOCKSTATE_TRIGGER(VC_CTRLRLOCK, "kbd-ctrlrlock"),
+};
+
+static void kbd_propagate_led_state(unsigned int old_state,
+ unsigned int new_state)
+{
+ struct kbd_led_trigger *trigger;
+ unsigned int changed = old_state ^ new_state;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(kbd_led_triggers); i++) {
+ trigger = &kbd_led_triggers[i];
+
+ if (changed & trigger->mask)
+ led_trigger_event(&trigger->trigger,
+ new_state & trigger->mask ?
+ LED_FULL : LED_OFF);
+ }
+}
+
+static int kbd_update_leds_helper(struct input_handle *handle, void *data)
+{
+ unsigned int led_state = *(unsigned int *)data;
+
+ if (test_bit(EV_LED, handle->dev->evbit))
+ kbd_propagate_led_state(~led_state, led_state);
+
+ return 0;
+}
+
+static void kbd_init_leds(void)
+{
+ int error;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(kbd_led_triggers); i++) {
+ error = led_trigger_register(&kbd_led_triggers[i].trigger);
+ if (error)
+ pr_err("error %d while registering trigger %s\n",
+ error, kbd_led_triggers[i].trigger.name);
+ }
+}
+
+#else
+
+static int kbd_update_leds_helper(struct input_handle *handle, void *data)
+{
+ unsigned int leds = *(unsigned int *)data;
+
+ if (test_bit(EV_LED, handle->dev->evbit)) {
+ input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));
+ input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02));
+ input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04));
+ input_inject_event(handle, EV_SYN, SYN_REPORT, 0);
+ }
+
+ return 0;
+}
+
+static void kbd_propagate_led_state(unsigned int old_state,
+ unsigned int new_state)
+{
+ input_handler_for_each_handle(&kbd_handler, &new_state,
+ kbd_update_leds_helper);
+}
+
+static void kbd_init_leds(void)
+{
+}
+
+#endif
+
/*
* The leds display either (i) the status of NumLock, CapsLock, ScrollLock,
* or (ii) whatever pattern of lights people want to show using KDSETLED,
@@ -968,7 +1073,7 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag)
*/
static unsigned char getledstate(void)
{
- return ledstate;
+ return ledstate & 0xff;
}
void setledstate(struct kbd_struct *kb, unsigned int led)
@@ -995,20 +1100,6 @@ static inline unsigned char getleds(void)
return kb->ledflagstate;
}
-static int kbd_update_leds_helper(struct input_handle *handle, void *data)
-{
- unsigned char leds = *(unsigned char *)data;
-
- if (test_bit(EV_LED, handle->dev->evbit)) {
- input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));
- input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02));
- input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04));
- input_inject_event(handle, EV_SYN, SYN_REPORT, 0);
- }
-
- return 0;
-}
-
/**
* vt_get_leds - helper for braille console
* @console: console to read
@@ -1085,24 +1176,23 @@ void vt_kbd_con_stop(int console)
}
/*
- * This is the tasklet that updates LED state on all keyboards
- * attached to the box. The reason we use tasklet is that we
- * need to handle the scenario when keyboard handler is not
- * registered yet but we already getting updates from the VT to
- * update led state.
+ * This is the tasklet that updates LED state of LEDs using standard
+ * keyboard triggers. The reason we use tasklet is that we need to
+ * handle the scenario when keyboard handler is not registered yet
+ * but we already getting updates from the VT to update led state.
*/
static void kbd_bh(unsigned long dummy)
{
- unsigned char leds;
+ unsigned int leds;
unsigned long flags;
-
+
spin_lock_irqsave(&led_lock, flags);
leds = getleds();
+ leds |= (unsigned int)kbd->lockstate << 8;
spin_unlock_irqrestore(&led_lock, flags);
if (leds != ledstate) {
- input_handler_for_each_handle(&kbd_handler, &leds,
- kbd_update_leds_helper);
+ kbd_propagate_led_state(ledstate, leds);
ledstate = leds;
}
}
@@ -1450,7 +1540,7 @@ static void kbd_start(struct input_handle *handle)
{
tasklet_disable(&keyboard_tasklet);
- if (ledstate != 0xff)
+ if (ledstate != -1U)
kbd_update_leds_helper(handle, &ledstate);
tasklet_enable(&keyboard_tasklet);
@@ -1497,6 +1587,8 @@ int __init kbd_init(void)
kbd_table[i].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
}
+ kbd_init_leds();
+
error = input_register_handler(&kbd_handler);
if (error)
return error;
@@ -1602,16 +1694,12 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm)
return -EINVAL;
if (ct) {
- dia = kmalloc(sizeof(struct kbdiacr) * ct,
- GFP_KERNEL);
- if (!dia)
- return -ENOMEM;
- if (copy_from_user(dia, a->kbdiacr,
- sizeof(struct kbdiacr) * ct)) {
- kfree(dia);
- return -EFAULT;
- }
+ dia = memdup_user(a->kbdiacr,
+ sizeof(struct kbdiacr) * ct);
+ if (IS_ERR(dia))
+ return PTR_ERR(dia);
+
}
spin_lock_irqsave(&kbd_event_lock, flags);
@@ -1645,16 +1733,10 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm)
return -EINVAL;
if (ct) {
- buf = kmalloc(ct * sizeof(struct kbdiacruc),
- GFP_KERNEL);
- if (buf == NULL)
- return -ENOMEM;
-
- if (copy_from_user(buf, a->kbdiacruc,
- ct * sizeof(struct kbdiacruc))) {
- kfree(buf);
- return -EFAULT;
- }
+ buf = memdup_user(a->kbdiacruc,
+ ct * sizeof(struct kbdiacruc));
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
}
spin_lock_irqsave(&kbd_event_lock, flags);
if (ct)
diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c
index ea27804d8..368ce1803 100644
--- a/drivers/tty/vt/selection.c
+++ b/drivers/tty/vt/selection.c
@@ -347,15 +347,18 @@ int paste_selection(struct tty_struct *tty)
console_unlock();
ld = tty_ldisc_ref_wait(tty);
+ if (!ld)
+ return -EIO; /* ldisc was hung up */
tty_buffer_lock_exclusive(&vc->port);
add_wait_queue(&vc->paste_wait, &wait);
while (sel_buffer && sel_buffer_lth > pasted) {
set_current_state(TASK_INTERRUPTIBLE);
- if (test_bit(TTY_THROTTLED, &tty->flags)) {
+ if (tty_throttled(tty)) {
schedule();
continue;
}
+ __set_current_state(TASK_RUNNING);
count = sel_buffer_lth - pasted;
count = tty_ldisc_receive_buf(ld, sel_buffer + pasted, NULL,
count);
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 07c60a233..fd375f15b 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -71,7 +71,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/tty.h>
@@ -109,6 +108,7 @@
#define CON_DRIVER_FLAG_MODULE 1
#define CON_DRIVER_FLAG_INIT 2
#define CON_DRIVER_FLAG_ATTR 4
+#define CON_DRIVER_FLAG_ZOMBIE 8
struct con_driver {
const struct consw *con;
@@ -136,6 +136,7 @@ const struct consw *conswitchp;
*/
#define DEFAULT_BELL_PITCH 750
#define DEFAULT_BELL_DURATION (HZ/8)
+#define DEFAULT_CURSOR_BLINK_MS 200
struct vc vc_cons [MAX_NR_CONSOLES];
@@ -154,6 +155,7 @@ static int set_vesa_blanking(char __user *p);
static void set_cursor(struct vc_data *vc);
static void hide_cursor(struct vc_data *vc);
static void console_callback(struct work_struct *ignored);
+static void con_driver_unregister_callback(struct work_struct *ignored);
static void blank_screen_t(unsigned long dummy);
static void set_palette(struct vc_data *vc);
@@ -183,6 +185,7 @@ static int blankinterval = 10*60;
core_param(consoleblank, blankinterval, int, 0444);
static DECLARE_WORK(console_work, console_callback);
+static DECLARE_WORK(con_driver_unregister_work, con_driver_unregister_callback);
/*
* fg_console is the current virtual console,
@@ -274,13 +277,15 @@ static void notify_update(struct vc_data *vc)
* Low-Level Functions
*/
-#define IS_FG(vc) ((vc)->vc_num == fg_console)
+static inline bool con_is_fg(const struct vc_data *vc)
+{
+ return vc->vc_num == fg_console;
+}
-#ifdef VT_BUF_VRAM_ONLY
-#define DO_UPDATE(vc) 0
-#else
-#define DO_UPDATE(vc) (CON_IS_VISIBLE(vc) && !console_blanked)
-#endif
+static inline bool con_should_update(const struct vc_data *vc)
+{
+ return con_is_visible(vc) && !console_blanked;
+}
static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed)
{
@@ -318,7 +323,7 @@ static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
nr = b - t - 1;
if (b > vc->vc_rows || t >= b || nr < 1)
return;
- if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_UP, nr))
+ if (con_is_visible(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_UP, nr))
return;
d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr));
@@ -336,7 +341,7 @@ static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
nr = b - t - 1;
if (b > vc->vc_rows || t >= b || nr < 1)
return;
- if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_DOWN, nr))
+ if (con_is_visible(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_DOWN, nr))
return;
s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
step = vc->vc_cols * nr;
@@ -346,7 +351,6 @@ static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
static void do_update_region(struct vc_data *vc, unsigned long start, int count)
{
-#ifndef VT_BUF_VRAM_ONLY
unsigned int xx, yy, offset;
u16 *p;
@@ -387,14 +391,13 @@ static void do_update_region(struct vc_data *vc, unsigned long start, int count)
start = vc->vc_sw->con_getxy(vc, start, NULL, NULL);
}
}
-#endif
}
void update_region(struct vc_data *vc, unsigned long start, int count)
{
WARN_CONSOLE_UNLOCKED();
- if (DO_UPDATE(vc)) {
+ if (con_should_update(vc)) {
hide_cursor(vc);
do_update_region(vc, start, count);
set_cursor(vc);
@@ -410,7 +413,6 @@ static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink,
return vc->vc_sw->con_build_attr(vc, _color, _intensity,
_blink, _underline, _reverse, _italic);
-#ifndef VT_BUF_VRAM_ONLY
/*
* ++roman: I completely changed the attribute format for monochrome
* mode (!can_do_color). The formerly used MDA (monochrome display
@@ -445,9 +447,6 @@ static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink,
a <<= 1;
return a;
}
-#else
- return 0;
-#endif
}
static void update_attr(struct vc_data *vc)
@@ -467,10 +466,9 @@ void invert_screen(struct vc_data *vc, int offset, int count, int viewed)
count /= 2;
p = screenpos(vc, offset, viewed);
- if (vc->vc_sw->con_invert_region)
+ if (vc->vc_sw->con_invert_region) {
vc->vc_sw->con_invert_region(vc, p, count);
-#ifndef VT_BUF_VRAM_ONLY
- else {
+ } else {
u16 *q = p;
int cnt = count;
u16 a;
@@ -498,8 +496,8 @@ void invert_screen(struct vc_data *vc, int offset, int count, int viewed)
}
}
}
-#endif
- if (DO_UPDATE(vc))
+
+ if (con_should_update(vc))
do_update_region(vc, (unsigned long) p, count);
notify_update(vc);
}
@@ -516,7 +514,7 @@ void complement_pos(struct vc_data *vc, int offset)
if (old_offset != -1 && old_offset >= 0 &&
old_offset < vc->vc_screenbuf_size) {
scr_writew(old, screenpos(vc, old_offset, 1));
- if (DO_UPDATE(vc))
+ if (con_should_update(vc))
vc->vc_sw->con_putc(vc, old, oldy, oldx);
notify_update(vc);
}
@@ -531,7 +529,7 @@ void complement_pos(struct vc_data *vc, int offset)
old = scr_readw(p);
new = old ^ vc->vc_complement_mask;
scr_writew(new, p);
- if (DO_UPDATE(vc)) {
+ if (con_should_update(vc)) {
oldx = (offset >> 1) % vc->vc_cols;
oldy = (offset >> 1) / vc->vc_cols;
vc->vc_sw->con_putc(vc, new, oldy, oldx);
@@ -547,7 +545,7 @@ static void insert_char(struct vc_data *vc, unsigned int nr)
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))
+ if (con_should_update(vc))
do_update_region(vc, (unsigned long) p,
vc->vc_cols - vc->vc_x);
}
@@ -560,12 +558,12 @@ static void delete_char(struct vc_data *vc, unsigned int 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))
+ if (con_should_update(vc))
do_update_region(vc, (unsigned long) p,
vc->vc_cols - vc->vc_x);
}
-static int softcursor_original;
+static int softcursor_original = -1;
static void add_softcursor(struct vc_data *vc)
{
@@ -580,7 +578,7 @@ static void add_softcursor(struct vc_data *vc)
if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000;
if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700;
scr_writew(i, (u16 *) vc->vc_pos);
- if (DO_UPDATE(vc))
+ if (con_should_update(vc))
vc->vc_sw->con_putc(vc, i, vc->vc_y, vc->vc_x);
}
@@ -588,7 +586,7 @@ static void hide_softcursor(struct vc_data *vc)
{
if (softcursor_original != -1) {
scr_writew(softcursor_original, (u16 *)vc->vc_pos);
- if (DO_UPDATE(vc))
+ if (con_should_update(vc))
vc->vc_sw->con_putc(vc, softcursor_original,
vc->vc_y, vc->vc_x);
softcursor_original = -1;
@@ -605,8 +603,7 @@ static void hide_cursor(struct vc_data *vc)
static void set_cursor(struct vc_data *vc)
{
- if (!IS_FG(vc) || console_blanked ||
- vc->vc_mode == KD_GRAPHICS)
+ if (!con_is_fg(vc) || console_blanked || vc->vc_mode == KD_GRAPHICS)
return;
if (vc->vc_deccm) {
if (vc == sel_cons)
@@ -622,7 +619,7 @@ static void set_origin(struct vc_data *vc)
{
WARN_CONSOLE_UNLOCKED();
- if (!CON_IS_VISIBLE(vc) ||
+ if (!con_is_visible(vc) ||
!vc->vc_sw->con_set_origin ||
!vc->vc_sw->con_set_origin(vc))
vc->vc_origin = (unsigned long)vc->vc_screenbuf;
@@ -631,7 +628,7 @@ static void set_origin(struct vc_data *vc)
vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->vc_y + 2 * vc->vc_x;
}
-static inline void save_screen(struct vc_data *vc)
+static void save_screen(struct vc_data *vc)
{
WARN_CONSOLE_UNLOCKED();
@@ -670,12 +667,12 @@ void redraw_screen(struct vc_data *vc, int is_switch)
struct vc_data *old_vc = vc_cons[fg_console].d;
if (old_vc == vc)
return;
- if (!CON_IS_VISIBLE(vc))
+ if (!con_is_visible(vc))
redraw = 1;
*vc->vc_display_fg = vc;
fg_console = vc->vc_num;
hide_cursor(old_vc);
- if (!CON_IS_VISIBLE(old_vc)) {
+ if (!con_is_visible(old_vc)) {
save_screen(old_vc);
set_origin(old_vc);
}
@@ -739,12 +736,15 @@ static void visual_init(struct vc_data *vc, int num, int init)
__module_get(vc->vc_sw->owner);
vc->vc_num = num;
vc->vc_display_fg = &master_display_fg;
+ if (vc->vc_uni_pagedir_loc)
+ con_free_unimap(vc);
vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir;
vc->vc_uni_pagedir = NULL;
vc->vc_hi_font_mask = 0;
vc->vc_complement_mask = 0;
vc->vc_can_do_color = 0;
vc->vc_panic_force_write = false;
+ vc->vc_cur_blink_ms = DEFAULT_CURSOR_BLINK_MS;
vc->vc_sw->con_init(vc, init);
if (!vc->vc_complement_mask)
vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
@@ -755,50 +755,54 @@ static void visual_init(struct vc_data *vc, int num, int init)
int vc_allocate(unsigned int currcons) /* return 0 on success */
{
+ struct vt_notifier_param param;
+ struct vc_data *vc;
+
WARN_CONSOLE_UNLOCKED();
if (currcons >= MAX_NR_CONSOLES)
return -ENXIO;
- if (!vc_cons[currcons].d) {
- struct vc_data *vc;
- struct vt_notifier_param param;
-
- /* prevent users from taking too much memory */
- if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE))
- return -EPERM;
-
- /* due to the granularity of kmalloc, we waste some memory here */
- /* the alloc is done in two steps, to optimize the common situation
- of a 25x80 console (structsize=216, screenbuf_size=4000) */
- /* although the numbers above are not valid since long ago, the
- point is still up-to-date and the comment still has its value
- even if only as a historical artifact. --mj, July 1998 */
- param.vc = vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL);
- if (!vc)
+
+ if (vc_cons[currcons].d)
+ return 0;
+
+ /* due to the granularity of kmalloc, we waste some memory here */
+ /* the alloc is done in two steps, to optimize the common situation
+ of a 25x80 console (structsize=216, screenbuf_size=4000) */
+ /* although the numbers above are not valid since long ago, the
+ point is still up-to-date and the comment still has its value
+ even if only as a historical artifact. --mj, July 1998 */
+ param.vc = vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL);
+ if (!vc)
return -ENOMEM;
- vc_cons[currcons].d = vc;
- tty_port_init(&vc->port);
- INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
- visual_init(vc, currcons, 1);
- if (!*vc->vc_uni_pagedir_loc)
+
+ vc_cons[currcons].d = vc;
+ tty_port_init(&vc->port);
+ INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
+
+ visual_init(vc, currcons, 1);
+
+ if (!*vc->vc_uni_pagedir_loc)
con_set_default_unimap(vc);
- vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
- if (!vc->vc_screenbuf) {
- kfree(vc);
- vc_cons[currcons].d = NULL;
- return -ENOMEM;
- }
- /* If no drivers have overridden us and the user didn't pass a
- boot option, default to displaying the cursor */
- if (global_cursor_default == -1)
- global_cursor_default = 1;
+ vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
+ if (!vc->vc_screenbuf)
+ goto err_free;
+
+ /* If no drivers have overridden us and the user didn't pass a
+ boot option, default to displaying the cursor */
+ if (global_cursor_default == -1)
+ global_cursor_default = 1;
+
+ vc_init(vc, vc->vc_rows, vc->vc_cols, 1);
+ vcs_make_sysfs(currcons);
+ atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, &param);
- vc_init(vc, vc->vc_rows, vc->vc_cols, 1);
- vcs_make_sysfs(currcons);
- atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, &param);
- }
return 0;
+err_free:
+ kfree(vc);
+ vc_cons[currcons].d = NULL;
+ return -ENOMEM;
}
static inline int resize_screen(struct vc_data *vc, int width, int height,
@@ -866,10 +870,15 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
if (new_cols == vc->vc_cols && new_rows == vc->vc_rows)
return 0;
+ if (new_screen_size > (4 << 20))
+ return -EINVAL;
newscreen = kmalloc(new_screen_size, GFP_USER);
if (!newscreen)
return -ENOMEM;
+ if (vc == sel_cons)
+ clear_selection();
+
old_rows = vc->vc_rows;
old_row_size = vc->vc_size_row;
@@ -944,7 +953,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
tty_do_resize(tty, &ws);
}
- if (CON_IS_VISIBLE(vc))
+ if (con_is_visible(vc))
update_screen(vc);
vt_event_post(VT_EVENT_RESIZE, vc->vc_num, vc->vc_num);
return err;
@@ -1030,20 +1039,27 @@ struct vc_data *vc_deallocate(unsigned int currcons)
#define VT100ID "\033[?1;2c"
#define VT102ID "\033[?6c"
-unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
+const unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
8,12,10,14, 9,13,11,15 };
/* the default colour table, for VGA+ colour systems */
-int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa,
- 0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff};
-int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa,
- 0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff};
-int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,
- 0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff};
+unsigned char default_red[] = {
+ 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa,
+ 0x55, 0xff, 0x55, 0xff, 0x55, 0xff, 0x55, 0xff
+};
+module_param_array(default_red, byte, NULL, S_IRUGO | S_IWUSR);
-module_param_array(default_red, int, NULL, S_IRUGO | S_IWUSR);
-module_param_array(default_grn, int, NULL, S_IRUGO | S_IWUSR);
-module_param_array(default_blu, int, NULL, S_IRUGO | S_IWUSR);
+unsigned char default_grn[] = {
+ 0x00, 0x00, 0xaa, 0x55, 0x00, 0x00, 0xaa, 0xaa,
+ 0x55, 0x55, 0xff, 0xff, 0x55, 0x55, 0xff, 0xff
+};
+module_param_array(default_grn, byte, NULL, S_IRUGO | S_IWUSR);
+
+unsigned char default_blu[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0x55, 0x55, 0x55, 0x55, 0xff, 0xff, 0xff, 0xff
+};
+module_param_array(default_blu, byte, NULL, S_IRUGO | S_IWUSR);
/*
* gotoxy() must verify all boundaries, because the arguments
@@ -1086,11 +1102,9 @@ static void gotoxay(struct vc_data *vc, int new_x, int new_y)
gotoxy(vc, new_x, vc->vc_decom ? (vc->vc_top + new_y) : new_y);
}
-void scrollback(struct vc_data *vc, int lines)
+void scrollback(struct vc_data *vc)
{
- if (!lines)
- lines = vc->vc_rows / 2;
- scrolldelta(-lines);
+ scrolldelta(-(vc->vc_rows / 2));
}
void scrollfront(struct vc_data *vc, int lines)
@@ -1167,9 +1181,9 @@ static void csi_J(struct vc_data *vc, int vpar)
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);
+ vc->vc_screenbuf_size);
set_origin(vc);
- if (CON_IS_VISIBLE(vc))
+ if (con_is_visible(vc))
update_screen(vc);
/* fall through */
case 2: /* erase whole display */
@@ -1180,7 +1194,7 @@ static void csi_J(struct vc_data *vc, int vpar)
return;
}
scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
- if (DO_UPDATE(vc))
+ if (con_should_update(vc))
do_update_region(vc, (unsigned long) start, count);
vc->vc_need_wrap = 0;
}
@@ -1208,7 +1222,7 @@ static void csi_K(struct vc_data *vc, int vpar)
}
scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
vc->vc_need_wrap = 0;
- if (DO_UPDATE(vc))
+ if (con_should_update(vc))
do_update_region(vc, (unsigned long) start, count);
}
@@ -1221,7 +1235,7 @@ static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar posi
count = (vpar > vc->vc_cols - vc->vc_x) ? (vc->vc_cols - vc->vc_x) : vpar;
scr_memsetw((unsigned short *)vc->vc_pos, vc->vc_video_erase_char, 2 * count);
- if (DO_UPDATE(vc))
+ if (con_should_update(vc))
vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, count);
vc->vc_need_wrap = 0;
}
@@ -1238,48 +1252,87 @@ static void default_attr(struct vc_data *vc)
struct rgb { u8 r; u8 g; u8 b; };
-static struct rgb rgb_from_256(int i)
+static void rgb_from_256(int i, struct rgb *c)
{
- 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;
+ 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;
+ 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;
+ 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;
+ c->r = c->g = c->b = i * 10 - 2312;
}
-static void rgb_foreground(struct vc_data *vc, struct rgb c)
+static void rgb_foreground(struct vc_data *vc, const 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;
+ u8 hue = 0, max = max3(c->r, c->g, c->b);
+
+ if (c->r > max / 2)
+ hue |= 4;
+ if (c->g > max / 2)
+ hue |= 2;
+ if (c->b > max / 2)
+ hue |= 1;
+
+ if (hue == 7 && max <= 0x55) {
+ hue = 0;
+ vc->vc_intensity = 2;
+ } else if (max > 0xaa)
+ vc->vc_intensity = 2;
else
- vc->vc_intensity = (max > 0xaa) + 1;
+ vc->vc_intensity = 1;
+
vc->vc_color = (vc->vc_color & 0xf0) | hue;
}
-static void rgb_background(struct vc_data *vc, struct rgb c)
+static void rgb_background(struct vc_data *vc, const 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;
+ | (c->r&0x80) >> 1 | (c->g&0x80) >> 2 | (c->b&0x80) >> 3;
+}
+
+/*
+ * 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.
+ *
+ * Subcommands 3 (CMY) and 4 (CMYK) are so insane there's no point in
+ * supporting them.
+ */
+static int vc_t416_color(struct vc_data *vc, int i,
+ void(*set_color)(struct vc_data *vc, const struct rgb *c))
+{
+ struct rgb c;
+
+ i++;
+ if (i > vc->vc_npar)
+ return i;
+
+ if (vc->vc_par[i] == 5 && i < vc->vc_npar) {
+ /* 256 colours -- ubiquitous */
+ i++;
+ rgb_from_256(vc->vc_par[i], &c);
+ } else if (vc->vc_par[i] == 2 && i <= vc->vc_npar + 3) {
+ /* 24 bit -- extremely rare */
+ c.r = vc->vc_par[i + 1];
+ c.g = vc->vc_par[i + 2];
+ c.b = vc->vc_par[i + 3];
+ i += 3;
+ } else
+ return i;
+
+ set_color(vc, &c);
+
+ return i;
}
/* console_lock is held */
@@ -1289,135 +1342,91 @@ static void csi_m(struct vc_data *vc)
for (i = 0; i <= vc->vc_npar; i++)
switch (vc->vc_par[i]) {
- case 0: /* all attributes off */
- default_attr(vc);
- break;
- case 1:
- vc->vc_intensity = 2;
- break;
- case 2:
- vc->vc_intensity = 0;
- break;
- case 3:
- vc->vc_italic = 1;
- break;
- case 4:
- vc->vc_underline = 1;
- break;
- case 5:
- vc->vc_blink = 1;
- break;
- case 7:
- vc->vc_reverse = 1;
- break;
- case 10: /* ANSI X3.64-1979 (SCO-ish?)
- * Select primary font, don't display
- * control chars if defined, don't set
- * bit 8 on output.
- */
- vc->vc_translate = set_translate(vc->vc_charset == 0
- ? vc->vc_G0_charset
- : vc->vc_G1_charset, vc);
- vc->vc_disp_ctrl = 0;
- vc->vc_toggle_meta = 0;
- break;
- case 11: /* ANSI X3.64-1979 (SCO-ish?)
- * Select first alternate font, lets
- * chars < 32 be displayed as ROM chars.
- */
- vc->vc_translate = set_translate(IBMPC_MAP, vc);
- vc->vc_disp_ctrl = 1;
- vc->vc_toggle_meta = 0;
- break;
- case 12: /* ANSI X3.64-1979 (SCO-ish?)
- * Select second alternate font, toggle
- * high bit before displaying as ROM char.
- */
- vc->vc_translate = set_translate(IBMPC_MAP, vc);
- vc->vc_disp_ctrl = 1;
- vc->vc_toggle_meta = 1;
- break;
- case 21:
- case 22:
- vc->vc_intensity = 1;
- break;
- case 23:
- vc->vc_italic = 0;
- break;
- case 24:
- vc->vc_underline = 0;
- break;
- case 25:
- vc->vc_blink = 0;
- break;
- case 27:
- vc->vc_reverse = 0;
- break;
- 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.
- */
- 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 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);
- break;
- case 49:
- vc->vc_color = (vc->vc_def_color & 0xf0) | (vc->vc_color & 0x0f);
- break;
- default:
- if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37)
- vc->vc_color = color_table[vc->vc_par[i] - 30]
- | (vc->vc_color & 0xf0);
- else if (vc->vc_par[i] >= 40 && vc->vc_par[i] <= 47)
- vc->vc_color = (color_table[vc->vc_par[i] - 40] << 4)
- | (vc->vc_color & 0x0f);
- break;
+ case 0: /* all attributes off */
+ default_attr(vc);
+ break;
+ case 1:
+ vc->vc_intensity = 2;
+ break;
+ case 2:
+ vc->vc_intensity = 0;
+ break;
+ case 3:
+ vc->vc_italic = 1;
+ break;
+ case 4:
+ vc->vc_underline = 1;
+ break;
+ case 5:
+ vc->vc_blink = 1;
+ break;
+ case 7:
+ vc->vc_reverse = 1;
+ break;
+ case 10: /* ANSI X3.64-1979 (SCO-ish?)
+ * Select primary font, don't display control chars if
+ * defined, don't set bit 8 on output.
+ */
+ vc->vc_translate = set_translate(vc->vc_charset == 0
+ ? vc->vc_G0_charset
+ : vc->vc_G1_charset, vc);
+ vc->vc_disp_ctrl = 0;
+ vc->vc_toggle_meta = 0;
+ break;
+ case 11: /* ANSI X3.64-1979 (SCO-ish?)
+ * Select first alternate font, lets chars < 32 be
+ * displayed as ROM chars.
+ */
+ vc->vc_translate = set_translate(IBMPC_MAP, vc);
+ vc->vc_disp_ctrl = 1;
+ vc->vc_toggle_meta = 0;
+ break;
+ case 12: /* ANSI X3.64-1979 (SCO-ish?)
+ * Select second alternate font, toggle high bit
+ * before displaying as ROM char.
+ */
+ vc->vc_translate = set_translate(IBMPC_MAP, vc);
+ vc->vc_disp_ctrl = 1;
+ vc->vc_toggle_meta = 1;
+ break;
+ case 21:
+ case 22:
+ vc->vc_intensity = 1;
+ break;
+ case 23:
+ vc->vc_italic = 0;
+ break;
+ case 24:
+ vc->vc_underline = 0;
+ break;
+ case 25:
+ vc->vc_blink = 0;
+ break;
+ case 27:
+ vc->vc_reverse = 0;
+ break;
+ case 38:
+ i = vc_t416_color(vc, i, rgb_foreground);
+ break;
+ case 48:
+ i = vc_t416_color(vc, i, rgb_background);
+ break;
+ case 39:
+ vc->vc_color = (vc->vc_def_color & 0x0f) |
+ (vc->vc_color & 0xf0);
+ break;
+ case 49:
+ vc->vc_color = (vc->vc_def_color & 0xf0) |
+ (vc->vc_color & 0x0f);
+ break;
+ default:
+ if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37)
+ vc->vc_color = color_table[vc->vc_par[i] - 30]
+ | (vc->vc_color & 0xf0);
+ else if (vc->vc_par[i] >= 40 && vc->vc_par[i] <= 47)
+ vc->vc_color = (color_table[vc->vc_par[i] - 40] << 4)
+ | (vc->vc_color & 0x0f);
+ break;
}
update_attr(vc);
}
@@ -1479,7 +1488,6 @@ static void set_mode(struct vc_data *vc, int on_off)
clr_kbd(vc, decckm);
break;
case 3: /* 80/132 mode switch unimplemented */
- vc->vc_deccolm = on_off;
#if 0
vc_resize(deccolm ? 132 : 80, vc->vc_rows);
/* this alone does not suffice; some user mode
@@ -1591,6 +1599,13 @@ static void setterm_command(struct vc_data *vc)
case 15: /* activate the previous console */
set_console(last_console);
break;
+ case 16: /* set cursor blink duration in msec */
+ if (vc->vc_npar >= 1 && vc->vc_par[1] >= 50 &&
+ vc->vc_par[1] <= USHRT_MAX)
+ vc->vc_cur_blink_ms = vc->vc_par[1];
+ else
+ vc->vc_cur_blink_ms = DEFAULT_CURSOR_BLINK_MS;
+ break;
}
}
@@ -1718,6 +1733,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear)
vc->vc_bell_pitch = DEFAULT_BELL_PITCH;
vc->vc_bell_duration = DEFAULT_BELL_DURATION;
+ vc->vc_cur_blink_ms = DEFAULT_CURSOR_BLINK_MS;
gotoxy(vc, 0, 0);
save_cur(vc);
@@ -2153,18 +2169,20 @@ static int is_double_width(uint32_t ucs)
return bisearch(ucs, double_width, ARRAY_SIZE(double_width) - 1);
}
+static void con_flush(struct vc_data *vc, unsigned long draw_from,
+ unsigned long draw_to, int *draw_x)
+{
+ if (*draw_x < 0)
+ return;
+
+ vc->vc_sw->con_putcs(vc, (u16 *)draw_from,
+ (u16 *)draw_to - (u16 *)draw_from, vc->vc_y, *draw_x);
+ *draw_x = -1;
+}
+
/* acquires console_lock */
static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count)
{
-#ifdef VT_BUF_VRAM_ONLY
-#define FLUSH do { } while(0);
-#else
-#define FLUSH if (draw_x >= 0) { \
- vc->vc_sw->con_putcs(vc, (u16 *)draw_from, (u16 *)draw_to - (u16 *)draw_from, vc->vc_y, draw_x); \
- draw_x = -1; \
- }
-#endif
-
int c, tc, ok, n = 0, draw_x = -1;
unsigned int currcons;
unsigned long draw_from = 0, draw_to = 0;
@@ -2201,7 +2219,7 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
charmask = himask ? 0x1ff : 0xff;
/* undraw cursor first */
- if (IS_FG(vc))
+ if (con_is_fg(vc))
hide_cursor(vc);
param.vc = vc;
@@ -2356,12 +2374,13 @@ rescan_last_byte:
} else {
vc_attr = ((vc->vc_attr) & 0x88) | (((vc->vc_attr) & 0x70) >> 4) | (((vc->vc_attr) & 0x07) << 4);
}
- FLUSH
+ con_flush(vc, draw_from, draw_to, &draw_x);
}
while (1) {
if (vc->vc_need_wrap || vc->vc_decim)
- FLUSH
+ con_flush(vc, draw_from, draw_to,
+ &draw_x);
if (vc->vc_need_wrap) {
cr(vc);
lf(vc);
@@ -2372,7 +2391,7 @@ rescan_last_byte:
((vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
(vc_attr << 8) + tc,
(u16 *) vc->vc_pos);
- if (DO_UPDATE(vc) && draw_x < 0) {
+ if (con_should_update(vc) && draw_x < 0) {
draw_x = vc->vc_x;
draw_from = vc->vc_pos;
}
@@ -2391,9 +2410,8 @@ rescan_last_byte:
}
notify_write(vc, c);
- if (inverse) {
- FLUSH
- }
+ if (inverse)
+ con_flush(vc, draw_from, draw_to, &draw_x);
if (rescan) {
rescan = 0;
@@ -2404,15 +2422,14 @@ rescan_last_byte:
}
continue;
}
- FLUSH
+ con_flush(vc, draw_from, draw_to, &draw_x);
do_con_trol(tty, vc, orig);
}
- FLUSH
+ con_flush(vc, draw_from, draw_to, &draw_x);
console_conditional_schedule();
console_unlock();
notify_update(vc);
return n;
-#undef FLUSH
}
/*
@@ -2446,7 +2463,7 @@ static void console_callback(struct work_struct *ignored)
if (scrollback_delta) {
struct vc_data *vc = vc_cons[fg_console].d;
clear_selection();
- if (vc->vc_mode == KD_TEXT)
+ if (vc->vc_mode == KD_TEXT && vc->vc_sw->con_scrolldelta)
vc->vc_sw->con_scrolldelta(vc, scrollback_delta);
scrollback_delta = 0;
}
@@ -2518,44 +2535,16 @@ int vt_kmsg_redirect(int new)
return kmsg_con;
}
-#ifdef CONFIG_VT_CKO
-static unsigned int printk_color[8] __read_mostly = {
- CONFIG_VT_PRINTK_EMERG_COLOR, /* KERN_EMERG */
- CONFIG_VT_PRINTK_ALERT_COLOR, /* KERN_ALERT */
- CONFIG_VT_PRINTK_CRIT_COLOR, /* KERN_CRIT */
- CONFIG_VT_PRINTK_ERR_COLOR, /* KERN_ERR */
- CONFIG_VT_PRINTK_WARNING_COLOR, /* KERN_WARNING */
- CONFIG_VT_PRINTK_NOTICE_COLOR, /* KERN_NOTICE */
- CONFIG_VT_PRINTK_INFO_COLOR, /* KERN_INFO */
- CONFIG_VT_PRINTK_DEBUG_COLOR, /* KERN_DEBUG */
-};
-module_param_array(printk_color, uint, NULL, S_IRUGO | S_IWUSR);
-
-static inline void vc_set_color(struct vc_data *vc, unsigned char color)
-{
- vc->vc_color = color_table[color & 0xF] |
- (color_table[(color >> 4) & 0x7] << 4) |
- (color & 0x80);
- update_attr(vc);
-}
-#else
-static unsigned int printk_color[8];
-static inline void vc_set_color(const struct vc_data *vc, unsigned char c)
-{
-}
-#endif
-
/*
* Console on virtual terminal
*
* The console must be locked when we get here.
*/
-static void vt_console_print(struct console *co, const char *b, unsigned count,
- unsigned int loglevel)
+static void vt_console_print(struct console *co, const char *b, unsigned count)
{
struct vc_data *vc = vc_cons[fg_console].d;
- unsigned char current_color, c;
+ unsigned char c;
static DEFINE_SPINLOCK(printing_lock);
const ushort *start;
ushort cnt = 0;
@@ -2586,27 +2575,18 @@ static void vt_console_print(struct console *co, const char *b, unsigned count,
goto quit;
/* undraw cursor first */
- if (IS_FG(vc))
+ if (con_is_fg(vc))
hide_cursor(vc);
start = (ushort *)vc->vc_pos;
- /*
- * We always get a valid loglevel - <8> and "no level" is transformed
- * to <4> in the typical kernel.
- */
- current_color = printk_color[loglevel];
- vc_set_color(vc, current_color);
-
-
/* Contrived structure to try to emulate original need_wrap behaviour
* Problems caused when we have need_wrap set on '\n' character */
while (count--) {
c = *b++;
if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) {
- vc_set_color(vc, vc->vc_def_color);
if (cnt > 0) {
- if (CON_IS_VISIBLE(vc))
+ 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)
@@ -2617,7 +2597,6 @@ static void vt_console_print(struct console *co, const char *b, unsigned count,
bs(vc);
start = (ushort *)vc->vc_pos;
myx = vc->vc_x;
- vc_set_color(vc, current_color);
continue;
}
if (c != 13)
@@ -2625,7 +2604,6 @@ static void vt_console_print(struct console *co, const char *b, unsigned count,
cr(vc);
start = (ushort *)vc->vc_pos;
myx = vc->vc_x;
- vc_set_color(vc, current_color);
if (c == 10 || c == 13)
continue;
}
@@ -2640,7 +2618,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count,
myx++;
}
if (cnt > 0) {
- if (CON_IS_VISIBLE(vc))
+ 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) {
@@ -2648,7 +2626,6 @@ static void vt_console_print(struct console *co, const char *b, unsigned count,
vc->vc_need_wrap = 1;
}
}
- vc_set_color(vc, vc->vc_def_color);
set_cursor(vc);
notify_update(vc);
@@ -3188,7 +3165,7 @@ static int do_bind_con_driver(const struct consw *csw, int first, int last,
j = i;
- if (CON_IS_VISIBLE(vc)) {
+ if (con_is_visible(vc)) {
k = i;
save_screen(vc);
}
@@ -3233,22 +3210,6 @@ err:
#ifdef CONFIG_VT_HW_CONSOLE_BINDING
-static int con_is_graphics(const struct consw *csw, int first, int last)
-{
- int i, retval = 0;
-
- for (i = first; i <= last; i++) {
- struct vc_data *vc = vc_cons[i].d;
-
- if (vc && vc->vc_mode == KD_GRAPHICS) {
- retval = 1;
- break;
- }
- }
-
- return retval;
-}
-
/* unlocked version of unbind_con_driver() */
int do_unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
{
@@ -3334,8 +3295,7 @@ static int vt_bind(struct con_driver *con)
const struct consw *defcsw = NULL, *csw = NULL;
int i, more = 1, first = -1, last = -1, deflt = 0;
- if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
- con_is_graphics(con->con, con->first, con->last))
+ if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE))
goto err;
csw = con->con;
@@ -3386,8 +3346,7 @@ static int vt_unbind(struct con_driver *con)
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))
+ if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE))
goto err;
csw = con->con;
@@ -3609,7 +3568,7 @@ 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;
+ int i, retval;
WARN_CONSOLE_UNLOCKED();
@@ -3620,24 +3579,25 @@ static int do_register_con_driver(const struct consw *csw, int first, int last)
con_driver = &registered_con_driver[i];
/* already registered */
- if (con_driver->con == csw)
+ if (con_driver->con == csw) {
retval = -EBUSY;
+ goto err;
+ }
}
- if (retval)
- goto err;
-
desc = csw->con_startup();
-
- if (!desc)
+ if (!desc) {
+ retval = -ENODEV;
goto err;
+ }
retval = -EINVAL;
for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
con_driver = &registered_con_driver[i];
- if (con_driver->con == NULL) {
+ if (con_driver->con == NULL &&
+ !(con_driver->flag & CON_DRIVER_FLAG_ZOMBIE)) {
con_driver->con = csw;
con_driver->desc = desc;
con_driver->node = i;
@@ -3699,16 +3659,20 @@ int do_unregister_con_driver(const struct consw *csw)
struct con_driver *con_driver = &registered_con_driver[i];
if (con_driver->con == csw) {
- vtconsole_deinit_device(con_driver);
- device_destroy(vtconsole_class,
- MKDEV(0, con_driver->node));
+ /*
+ * Defer the removal of the sysfs entries since that
+ * will acquire the kernfs s_active lock and we can't
+ * acquire this lock while holding the console lock:
+ * the unbind sysfs entry imposes already the opposite
+ * order. Reset con already here to prevent any later
+ * lookup to succeed and mark this slot as zombie, so
+ * it won't get reused until we complete the removal
+ * in the deferred work.
+ */
con_driver->con = NULL;
- con_driver->desc = NULL;
- con_driver->dev = NULL;
- con_driver->node = 0;
- con_driver->flag = 0;
- con_driver->first = 0;
- con_driver->last = 0;
+ con_driver->flag = CON_DRIVER_FLAG_ZOMBIE;
+ schedule_work(&con_driver_unregister_work);
+
return 0;
}
}
@@ -3717,6 +3681,39 @@ int do_unregister_con_driver(const struct consw *csw)
}
EXPORT_SYMBOL_GPL(do_unregister_con_driver);
+static void con_driver_unregister_callback(struct work_struct *ignored)
+{
+ int i;
+
+ console_lock();
+
+ for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+ struct con_driver *con_driver = &registered_con_driver[i];
+
+ if (!(con_driver->flag & CON_DRIVER_FLAG_ZOMBIE))
+ continue;
+
+ console_unlock();
+
+ vtconsole_deinit_device(con_driver);
+ device_destroy(vtconsole_class, MKDEV(0, con_driver->node));
+
+ console_lock();
+
+ if (WARN_ON_ONCE(con_driver->con))
+ con_driver->con = NULL;
+ con_driver->desc = NULL;
+ con_driver->dev = NULL;
+ con_driver->node = 0;
+ WARN_ON_ONCE(con_driver->flag != CON_DRIVER_FLAG_ZOMBIE);
+ con_driver->flag = 0;
+ con_driver->first = 0;
+ con_driver->last = 0;
+ }
+
+ console_unlock();
+}
+
/*
* If we support more console drivers, this function is used
* when a driver wants to take over some existing consoles
@@ -3976,7 +3973,7 @@ static void set_palette(struct vc_data *vc)
{
WARN_CONSOLE_UNLOCKED();
- if (vc->vc_mode != KD_GRAPHICS)
+ if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_set_palette)
vc->vc_sw->con_set_palette(vc, color_table);
}
@@ -4257,6 +4254,7 @@ unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed)
{
return screenpos(vc, 2 * w_offset, viewed);
}
+EXPORT_SYMBOL_GPL(screen_pos);
void getconsxy(struct vc_data *vc, unsigned char *p)
{
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index 97d5a7455..f62c59881 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -1006,16 +1006,10 @@ int vt_ioctl(struct tty_struct *tty,
break;
case PIO_UNIMAPCLR:
- { struct unimapinit ui;
if (!perm)
return -EPERM;
- ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
- if (ret)
- ret = -EFAULT;
- else
- con_clear_unimap(vc, &ui);
+ con_clear_unimap(vc);
break;
- }
case PIO_UNIMAP:
case GIO_UNIMAP: