X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fchar%2Fvt.c;h=8e4413f6fbaf6145352ffb5e7c9af0530240cc79;hb=aaa9b971398f62ab97c1da4f7c352667eb3452c9;hp=714d95ff2f1e462fe36c881a17a7fb61ea5414a9;hpb=5f2f444136abdb13dbd2094555aa65fc252aef6c;p=linux-2.6-omap-h63xx.git diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 714d95ff2f1..8e4413f6fba 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 , Aug 2006 */ #include @@ -79,7 +86,6 @@ #include #include #include -#include #include #include #include @@ -87,7 +93,6 @@ #include #include #include -#include #include #include #include @@ -101,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; @@ -130,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]; @@ -732,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; @@ -880,14 +879,25 @@ 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); if (currcons >= MIN_NR_CONSOLES) @@ -2006,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); @@ -2033,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]; } @@ -2055,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) { @@ -2103,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 @@ -2499,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; } } @@ -2512,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) { @@ -2525,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 @@ -2640,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, @@ -2663,7 +2691,6 @@ int __init vty_init(void) if (!console_driver) panic("Couldn't allocate console driver\n"); console_driver->owner = THIS_MODULE; - console_driver->devfs_name = "vc/"; console_driver->name = "tty"; console_driver->name_base = 1; console_driver->major = TTY_MAJOR; @@ -3036,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; + } } /** @@ -3150,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); @@ -3767,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);