summaryrefslogtreecommitdiffstats
path: root/drivers/char/vt.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/vt.c')
-rw-r--r--drivers/char/vt.c146
1 files changed, 96 insertions, 50 deletions
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index da7e66a..8e4413f 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -63,6 +63,13 @@
*
* Removed console_lock, enabled interrupts across all console operations
* 13 March 2001, Andrew Morton
+ *
+ * Fixed UTF-8 mode so alternate charset modes always work according
+ * to control sequences interpreted in do_con_trol function
+ * preserving backward VT100 semigraphics compatibility,
+ * malformed UTF sequences represented as sequences of replacement glyphs,
+ * original codes or '?' as a last resort if replacement glyph is undefined
+ * by Adam Tla/lka <atlka@pg.gda.pl>, Aug 2006
*/
#include <linux/module.h>
@@ -99,7 +106,8 @@
#define MAX_NR_CON_DRIVER 16
#define CON_DRIVER_FLAG_MODULE 1
-#define CON_DRIVER_FLAG_INIT 2
+#define CON_DRIVER_FLAG_INIT 2
+#define CON_DRIVER_FLAG_ATTR 4
struct con_driver {
const struct consw *con;
@@ -128,16 +136,8 @@ const struct consw *conswitchp;
#define DEFAULT_BELL_PITCH 750
#define DEFAULT_BELL_DURATION (HZ/8)
-extern void vcs_make_devfs(struct tty_struct *tty);
-extern void vcs_remove_devfs(struct tty_struct *tty);
-
-extern void console_map_init(void);
-#ifdef CONFIG_PROM_CONSOLE
-extern void prom_con_init(void);
-#endif
-#ifdef CONFIG_MDA_CONSOLE
-extern int mda_console_init(void);
-#endif
+extern void vcs_make_sysfs(struct tty_struct *tty);
+extern void vcs_remove_sysfs(struct tty_struct *tty);
struct vc vc_cons [MAX_NR_CONSOLES];
@@ -730,7 +730,8 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */
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_kmalloced)
+ vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
if (!vc->vc_screenbuf) {
kfree(vc);
vc_cons[currcons].d = NULL;
@@ -878,14 +879,24 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
return err;
}
+int vc_lock_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
+{
+ int rc;
+
+ acquire_console_sem();
+ rc = vc_resize(vc, cols, lines);
+ release_console_sem();
+ return rc;
+}
-void vc_disallocate(unsigned int currcons)
+void vc_deallocate(unsigned int currcons)
{
WARN_CONSOLE_UNLOCKED();
if (vc_cons_allocated(currcons)) {
struct vc_data *vc = vc_cons[currcons].d;
vc->vc_sw->con_deinit(vc);
+ put_pid(vc->vt_pid);
module_put(vc->vc_sw->owner);
if (vc->vc_kmalloced)
kfree(vc->vc_screenbuf);
@@ -2005,17 +2016,23 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
/* Do no translation at all in control states */
if (vc->vc_state != ESnormal) {
tc = c;
- } else if (vc->vc_utf) {
+ } else if (vc->vc_utf && !vc->vc_disp_ctrl) {
/* Combine UTF-8 into Unicode */
- /* Incomplete characters silently ignored */
+ /* Malformed sequences as sequences of replacement glyphs */
+rescan_last_byte:
if(c > 0x7f) {
- if (vc->vc_utf_count > 0 && (c & 0xc0) == 0x80) {
- vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
- vc->vc_utf_count--;
- if (vc->vc_utf_count == 0)
- tc = c = vc->vc_utf_char;
- else continue;
+ if (vc->vc_utf_count) {
+ if ((c & 0xc0) == 0x80) {
+ vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
+ if (--vc->vc_utf_count) {
+ vc->vc_npar++;
+ continue;
+ }
+ tc = c = vc->vc_utf_char;
+ } else
+ goto replacement_glyph;
} else {
+ vc->vc_npar = 0;
if ((c & 0xe0) == 0xc0) {
vc->vc_utf_count = 1;
vc->vc_utf_char = (c & 0x1f);
@@ -2032,14 +2049,15 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
vc->vc_utf_count = 5;
vc->vc_utf_char = (c & 0x01);
} else
- vc->vc_utf_count = 0;
+ goto replacement_glyph;
continue;
}
} else {
+ if (vc->vc_utf_count)
+ goto replacement_glyph;
tc = c;
- vc->vc_utf_count = 0;
}
- } else { /* no utf */
+ } else { /* no utf or alternate charset mode */
tc = vc->vc_translate[vc->vc_toggle_meta ? (c | 0x80) : c];
}
@@ -2054,31 +2072,33 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
* direct-to-font zone in UTF-8 mode.
*/
ok = tc && (c >= 32 ||
- (!vc->vc_utf && !(((vc->vc_disp_ctrl ? CTRL_ALWAYS
- : CTRL_ACTION) >> c) & 1)))
+ !(vc->vc_disp_ctrl ? (CTRL_ALWAYS >> c) & 1 :
+ vc->vc_utf || ((CTRL_ACTION >> c) & 1)))
&& (c != 127 || vc->vc_disp_ctrl)
&& (c != 128+27);
if (vc->vc_state == ESnormal && ok) {
/* Now try to find out how to display it */
tc = conv_uni_to_pc(vc, tc);
- if ( tc == -4 ) {
+ if (tc & ~charmask) {
+ if ( tc == -4 ) {
/* If we got -4 (not found) then see if we have
defined a replacement character (U+FFFD) */
- tc = conv_uni_to_pc(vc, 0xfffd);
-
- /* One reason for the -4 can be that we just
- did a clear_unimap();
- try at least to show something. */
- if (tc == -4)
- tc = c;
- } else if ( tc == -3 ) {
- /* Bad hash table -- hope for the best */
- tc = c;
- }
- if (tc & ~charmask)
- continue; /* Conversion failed */
+replacement_glyph:
+ tc = conv_uni_to_pc(vc, 0xfffd);
+ if (!(tc & ~charmask))
+ goto display_glyph;
+ } else if ( tc != -3 )
+ continue; /* nothing to display */
+ /* no hash table or no replacement --
+ * hope for the best */
+ if ( c & ~charmask )
+ tc = '?';
+ else
+ tc = c;
+ }
+display_glyph:
if (vc->vc_need_wrap || vc->vc_decim)
FLUSH
if (vc->vc_need_wrap) {
@@ -2102,6 +2122,15 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
vc->vc_x++;
draw_to = (vc->vc_pos += 2);
}
+ if (vc->vc_utf_count) {
+ if (vc->vc_npar) {
+ vc->vc_npar--;
+ goto display_glyph;
+ }
+ vc->vc_utf_count = 0;
+ c = orig;
+ goto rescan_last_byte;
+ }
continue;
}
FLUSH
@@ -2498,7 +2527,7 @@ static int con_open(struct tty_struct *tty, struct file *filp)
tty->winsize.ws_col = vc_cons[currcons].d->vc_cols;
}
release_console_sem();
- vcs_make_devfs(tty);
+ vcs_make_sysfs(tty);
return ret;
}
}
@@ -2511,7 +2540,7 @@ static int con_open(struct tty_struct *tty, struct file *filp)
* and taking a ref against the tty while we're in the process of forgetting
* about it and cleaning things up.
*
- * This is because vcs_remove_devfs() can sleep and will drop the BKL.
+ * This is because vcs_remove_sysfs() can sleep and will drop the BKL.
*/
static void con_close(struct tty_struct *tty, struct file *filp)
{
@@ -2524,7 +2553,7 @@ static void con_close(struct tty_struct *tty, struct file *filp)
vc->vc_tty = NULL;
tty->driver_data = NULL;
release_console_sem();
- vcs_remove_devfs(tty);
+ vcs_remove_sysfs(tty);
mutex_unlock(&tty_mutex);
/*
* tty_mutex is released, but we still hold BKL, so there is
@@ -2639,7 +2668,7 @@ static int __init con_init(void)
}
console_initcall(con_init);
-static struct tty_operations con_ops = {
+static const struct tty_operations con_ops = {
.open = con_open,
.close = con_close,
.write = con_write,
@@ -3034,22 +3063,37 @@ static struct class_device_attribute class_device_attrs[] = {
static int vtconsole_init_class_device(struct con_driver *con)
{
int i;
+ int error = 0;
+ con->flag |= CON_DRIVER_FLAG_ATTR;
class_set_devdata(con->class_dev, con);
- for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
- class_device_create_file(con->class_dev,
+ for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) {
+ error = class_device_create_file(con->class_dev,
&class_device_attrs[i]);
+ if (error)
+ break;
+ }
- return 0;
+ if (error) {
+ while (--i >= 0)
+ class_device_remove_file(con->class_dev,
+ &class_device_attrs[i]);
+ con->flag &= ~CON_DRIVER_FLAG_ATTR;
+ }
+
+ return error;
}
static void vtconsole_deinit_class_device(struct con_driver *con)
{
int i;
- for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
- class_device_remove_file(con->class_dev,
- &class_device_attrs[i]);
+ if (con->flag & CON_DRIVER_FLAG_ATTR) {
+ for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
+ class_device_remove_file(con->class_dev,
+ &class_device_attrs[i]);
+ con->flag &= ~CON_DRIVER_FLAG_ATTR;
+ }
}
/**
@@ -3148,6 +3192,7 @@ int register_con_driver(const struct consw *csw, int first, int last)
} else {
vtconsole_init_class_device(con_driver);
}
+
err:
release_console_sem();
module_put(owner);
@@ -3765,6 +3810,7 @@ EXPORT_SYMBOL(default_blu);
EXPORT_SYMBOL(update_region);
EXPORT_SYMBOL(redraw_screen);
EXPORT_SYMBOL(vc_resize);
+EXPORT_SYMBOL(vc_lock_resize);
EXPORT_SYMBOL(fg_console);
EXPORT_SYMBOL(console_blank_hook);
EXPORT_SYMBOL(console_blanked);
OpenPOWER on IntegriCloud