aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/vt.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/vt.c')
-rw-r--r--drivers/char/vt.c107
1 files changed, 72 insertions, 35 deletions
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index da7e66a2a38b..ec0c070bf15f 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -63,6 +63,13 @@
63 * 63 *
64 * Removed console_lock, enabled interrupts across all console operations 64 * Removed console_lock, enabled interrupts across all console operations
65 * 13 March 2001, Andrew Morton 65 * 13 March 2001, Andrew Morton
66 *
67 * Fixed UTF-8 mode so alternate charset modes always work according
68 * to control sequences interpreted in do_con_trol function
69 * preserving backward VT100 semigraphics compatibility,
70 * malformed UTF sequences represented as sequences of replacement glyphs,
71 * original codes or '?' as a last resort if replacement glyph is undefined
72 * by Adam Tla/lka <atlka@pg.gda.pl>, Aug 2006
66 */ 73 */
67 74
68#include <linux/module.h> 75#include <linux/module.h>
@@ -128,8 +135,8 @@ const struct consw *conswitchp;
128#define DEFAULT_BELL_PITCH 750 135#define DEFAULT_BELL_PITCH 750
129#define DEFAULT_BELL_DURATION (HZ/8) 136#define DEFAULT_BELL_DURATION (HZ/8)
130 137
131extern void vcs_make_devfs(struct tty_struct *tty); 138extern void vcs_make_sysfs(struct tty_struct *tty);
132extern void vcs_remove_devfs(struct tty_struct *tty); 139extern void vcs_remove_sysfs(struct tty_struct *tty);
133 140
134extern void console_map_init(void); 141extern void console_map_init(void);
135#ifdef CONFIG_PROM_CONSOLE 142#ifdef CONFIG_PROM_CONSOLE
@@ -730,7 +737,8 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */
730 visual_init(vc, currcons, 1); 737 visual_init(vc, currcons, 1);
731 if (!*vc->vc_uni_pagedir_loc) 738 if (!*vc->vc_uni_pagedir_loc)
732 con_set_default_unimap(vc); 739 con_set_default_unimap(vc);
733 vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL); 740 if (!vc->vc_kmalloced)
741 vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
734 if (!vc->vc_screenbuf) { 742 if (!vc->vc_screenbuf) {
735 kfree(vc); 743 kfree(vc);
736 vc_cons[currcons].d = NULL; 744 vc_cons[currcons].d = NULL;
@@ -878,14 +886,24 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
878 return err; 886 return err;
879} 887}
880 888
889int vc_lock_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
890{
891 int rc;
892
893 acquire_console_sem();
894 rc = vc_resize(vc, cols, lines);
895 release_console_sem();
896 return rc;
897}
881 898
882void vc_disallocate(unsigned int currcons) 899void vc_deallocate(unsigned int currcons)
883{ 900{
884 WARN_CONSOLE_UNLOCKED(); 901 WARN_CONSOLE_UNLOCKED();
885 902
886 if (vc_cons_allocated(currcons)) { 903 if (vc_cons_allocated(currcons)) {
887 struct vc_data *vc = vc_cons[currcons].d; 904 struct vc_data *vc = vc_cons[currcons].d;
888 vc->vc_sw->con_deinit(vc); 905 vc->vc_sw->con_deinit(vc);
906 put_pid(vc->vt_pid);
889 module_put(vc->vc_sw->owner); 907 module_put(vc->vc_sw->owner);
890 if (vc->vc_kmalloced) 908 if (vc->vc_kmalloced)
891 kfree(vc->vc_screenbuf); 909 kfree(vc->vc_screenbuf);
@@ -2005,17 +2023,23 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
2005 /* Do no translation at all in control states */ 2023 /* Do no translation at all in control states */
2006 if (vc->vc_state != ESnormal) { 2024 if (vc->vc_state != ESnormal) {
2007 tc = c; 2025 tc = c;
2008 } else if (vc->vc_utf) { 2026 } else if (vc->vc_utf && !vc->vc_disp_ctrl) {
2009 /* Combine UTF-8 into Unicode */ 2027 /* Combine UTF-8 into Unicode */
2010 /* Incomplete characters silently ignored */ 2028 /* Malformed sequences as sequences of replacement glyphs */
2029rescan_last_byte:
2011 if(c > 0x7f) { 2030 if(c > 0x7f) {
2012 if (vc->vc_utf_count > 0 && (c & 0xc0) == 0x80) { 2031 if (vc->vc_utf_count) {
2013 vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f); 2032 if ((c & 0xc0) == 0x80) {
2014 vc->vc_utf_count--; 2033 vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
2015 if (vc->vc_utf_count == 0) 2034 if (--vc->vc_utf_count) {
2016 tc = c = vc->vc_utf_char; 2035 vc->vc_npar++;
2017 else continue; 2036 continue;
2037 }
2038 tc = c = vc->vc_utf_char;
2039 } else
2040 goto replacement_glyph;
2018 } else { 2041 } else {
2042 vc->vc_npar = 0;
2019 if ((c & 0xe0) == 0xc0) { 2043 if ((c & 0xe0) == 0xc0) {
2020 vc->vc_utf_count = 1; 2044 vc->vc_utf_count = 1;
2021 vc->vc_utf_char = (c & 0x1f); 2045 vc->vc_utf_char = (c & 0x1f);
@@ -2032,14 +2056,15 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
2032 vc->vc_utf_count = 5; 2056 vc->vc_utf_count = 5;
2033 vc->vc_utf_char = (c & 0x01); 2057 vc->vc_utf_char = (c & 0x01);
2034 } else 2058 } else
2035 vc->vc_utf_count = 0; 2059 goto replacement_glyph;
2036 continue; 2060 continue;
2037 } 2061 }
2038 } else { 2062 } else {
2063 if (vc->vc_utf_count)
2064 goto replacement_glyph;
2039 tc = c; 2065 tc = c;
2040 vc->vc_utf_count = 0;
2041 } 2066 }
2042 } else { /* no utf */ 2067 } else { /* no utf or alternate charset mode */
2043 tc = vc->vc_translate[vc->vc_toggle_meta ? (c | 0x80) : c]; 2068 tc = vc->vc_translate[vc->vc_toggle_meta ? (c | 0x80) : c];
2044 } 2069 }
2045 2070
@@ -2054,31 +2079,33 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
2054 * direct-to-font zone in UTF-8 mode. 2079 * direct-to-font zone in UTF-8 mode.
2055 */ 2080 */
2056 ok = tc && (c >= 32 || 2081 ok = tc && (c >= 32 ||
2057 (!vc->vc_utf && !(((vc->vc_disp_ctrl ? CTRL_ALWAYS 2082 !(vc->vc_disp_ctrl ? (CTRL_ALWAYS >> c) & 1 :
2058 : CTRL_ACTION) >> c) & 1))) 2083 vc->vc_utf || ((CTRL_ACTION >> c) & 1)))
2059 && (c != 127 || vc->vc_disp_ctrl) 2084 && (c != 127 || vc->vc_disp_ctrl)
2060 && (c != 128+27); 2085 && (c != 128+27);
2061 2086
2062 if (vc->vc_state == ESnormal && ok) { 2087 if (vc->vc_state == ESnormal && ok) {
2063 /* Now try to find out how to display it */ 2088 /* Now try to find out how to display it */
2064 tc = conv_uni_to_pc(vc, tc); 2089 tc = conv_uni_to_pc(vc, tc);
2065 if ( tc == -4 ) { 2090 if (tc & ~charmask) {
2091 if ( tc == -4 ) {
2066 /* If we got -4 (not found) then see if we have 2092 /* If we got -4 (not found) then see if we have
2067 defined a replacement character (U+FFFD) */ 2093 defined a replacement character (U+FFFD) */
2068 tc = conv_uni_to_pc(vc, 0xfffd); 2094replacement_glyph:
2069 2095 tc = conv_uni_to_pc(vc, 0xfffd);
2070 /* One reason for the -4 can be that we just 2096 if (!(tc & ~charmask))
2071 did a clear_unimap(); 2097 goto display_glyph;
2072 try at least to show something. */ 2098 } else if ( tc != -3 )
2073 if (tc == -4) 2099 continue; /* nothing to display */
2074 tc = c; 2100 /* no hash table or no replacement --
2075 } else if ( tc == -3 ) { 2101 * hope for the best */
2076 /* Bad hash table -- hope for the best */ 2102 if ( c & ~charmask )
2077 tc = c; 2103 tc = '?';
2078 } 2104 else
2079 if (tc & ~charmask) 2105 tc = c;
2080 continue; /* Conversion failed */ 2106 }
2081 2107
2108display_glyph:
2082 if (vc->vc_need_wrap || vc->vc_decim) 2109 if (vc->vc_need_wrap || vc->vc_decim)
2083 FLUSH 2110 FLUSH
2084 if (vc->vc_need_wrap) { 2111 if (vc->vc_need_wrap) {
@@ -2102,6 +2129,15 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
2102 vc->vc_x++; 2129 vc->vc_x++;
2103 draw_to = (vc->vc_pos += 2); 2130 draw_to = (vc->vc_pos += 2);
2104 } 2131 }
2132 if (vc->vc_utf_count) {
2133 if (vc->vc_npar) {
2134 vc->vc_npar--;
2135 goto display_glyph;
2136 }
2137 vc->vc_utf_count = 0;
2138 c = orig;
2139 goto rescan_last_byte;
2140 }
2105 continue; 2141 continue;
2106 } 2142 }
2107 FLUSH 2143 FLUSH
@@ -2498,7 +2534,7 @@ static int con_open(struct tty_struct *tty, struct file *filp)
2498 tty->winsize.ws_col = vc_cons[currcons].d->vc_cols; 2534 tty->winsize.ws_col = vc_cons[currcons].d->vc_cols;
2499 } 2535 }
2500 release_console_sem(); 2536 release_console_sem();
2501 vcs_make_devfs(tty); 2537 vcs_make_sysfs(tty);
2502 return ret; 2538 return ret;
2503 } 2539 }
2504 } 2540 }
@@ -2511,7 +2547,7 @@ static int con_open(struct tty_struct *tty, struct file *filp)
2511 * and taking a ref against the tty while we're in the process of forgetting 2547 * and taking a ref against the tty while we're in the process of forgetting
2512 * about it and cleaning things up. 2548 * about it and cleaning things up.
2513 * 2549 *
2514 * This is because vcs_remove_devfs() can sleep and will drop the BKL. 2550 * This is because vcs_remove_sysfs() can sleep and will drop the BKL.
2515 */ 2551 */
2516static void con_close(struct tty_struct *tty, struct file *filp) 2552static void con_close(struct tty_struct *tty, struct file *filp)
2517{ 2553{
@@ -2524,7 +2560,7 @@ static void con_close(struct tty_struct *tty, struct file *filp)
2524 vc->vc_tty = NULL; 2560 vc->vc_tty = NULL;
2525 tty->driver_data = NULL; 2561 tty->driver_data = NULL;
2526 release_console_sem(); 2562 release_console_sem();
2527 vcs_remove_devfs(tty); 2563 vcs_remove_sysfs(tty);
2528 mutex_unlock(&tty_mutex); 2564 mutex_unlock(&tty_mutex);
2529 /* 2565 /*
2530 * tty_mutex is released, but we still hold BKL, so there is 2566 * tty_mutex is released, but we still hold BKL, so there is
@@ -2639,7 +2675,7 @@ static int __init con_init(void)
2639} 2675}
2640console_initcall(con_init); 2676console_initcall(con_init);
2641 2677
2642static struct tty_operations con_ops = { 2678static const struct tty_operations con_ops = {
2643 .open = con_open, 2679 .open = con_open,
2644 .close = con_close, 2680 .close = con_close,
2645 .write = con_write, 2681 .write = con_write,
@@ -3765,6 +3801,7 @@ EXPORT_SYMBOL(default_blu);
3765EXPORT_SYMBOL(update_region); 3801EXPORT_SYMBOL(update_region);
3766EXPORT_SYMBOL(redraw_screen); 3802EXPORT_SYMBOL(redraw_screen);
3767EXPORT_SYMBOL(vc_resize); 3803EXPORT_SYMBOL(vc_resize);
3804EXPORT_SYMBOL(vc_lock_resize);
3768EXPORT_SYMBOL(fg_console); 3805EXPORT_SYMBOL(fg_console);
3769EXPORT_SYMBOL(console_blank_hook); 3806EXPORT_SYMBOL(console_blank_hook);
3770EXPORT_SYMBOL(console_blanked); 3807EXPORT_SYMBOL(console_blanked);