Submitted by: Alexander E. Patrakov <patrakov@ums.usu.ru>
Signed-off-by: Alexander E. Patrakov <patrakov@ums.usu.ru>
Date: 2006-07-24
Initial Package Version: 2.6.17.6
Upstream Status: Rejected: they say it modifies the meaning of an existing ioctl
Origin: http://chris.heathens.co.nz/linux/downloads/patches-2.6.4-cdh1.tar.gz
Porting to linux-2.6.16 by Alexander E. Patrakov
Description: This patch fixes dead keys and copy/paste of non-ASCII characters
in UTF-8 mode on Linux console.
See more details about the original patch at:
http://chris.heathens.co.nz/linux/utf8.html
diff -Naur linux-2.6.17.6.orig/drivers/char/consolemap.c linux-2.6.17.6/drivers/char/consolemap.c
|
old
|
new
|
|
| 178 | 178 | unsigned long refcount; |
| 179 | 179 | unsigned long sum; |
| 180 | 180 | unsigned char *inverse_translations[4]; |
| | 181 | u16 *inverse_trans_unicode; |
| 181 | 182 | int readonly; |
| 182 | 183 | }; |
| 183 | 184 | |
| … |
… |
|
| 208 | 209 | } |
| 209 | 210 | } |
| 210 | 211 | |
| | 212 | static void set_inverse_trans_unicode(struct vc_data *conp, |
| | 213 | struct uni_pagedir *p) |
| | 214 | { |
| | 215 | int i, j, k, glyph; |
| | 216 | u16 **p1, *p2; |
| | 217 | u16 *q; |
| | 218 | |
| | 219 | if (!p) return; |
| | 220 | q = p->inverse_trans_unicode; |
| | 221 | if (!q) { |
| | 222 | q = p->inverse_trans_unicode = |
| | 223 | kmalloc(MAX_GLYPH * sizeof(u16), GFP_KERNEL); |
| | 224 | if (!q) |
| | 225 | return; |
| | 226 | } |
| | 227 | memset(q, 0, MAX_GLYPH * sizeof(u16)); |
| | 228 | |
| | 229 | for (i = 0; i < 32; i++) { |
| | 230 | p1 = p->uni_pgdir[i]; |
| | 231 | if (!p1) |
| | 232 | continue; |
| | 233 | for (j = 0; j < 32; j++) { |
| | 234 | p2 = p1[j]; |
| | 235 | if (!p2) |
| | 236 | continue; |
| | 237 | for (k = 0; k < 64; k++) { |
| | 238 | glyph = p2[k]; |
| | 239 | if (glyph >= 0 && glyph < MAX_GLYPH |
| | 240 | && q[glyph] < 32) |
| | 241 | q[glyph] = (i << 11) + (j << 6) + k; |
| | 242 | } |
| | 243 | } |
| | 244 | } |
| | 245 | } |
| | 246 | |
| 211 | 247 | unsigned short *set_translate(int m, struct vc_data *vc) |
| 212 | 248 | { |
| 213 | 249 | inv_translate[vc->vc_num] = m; |
| … |
… |
|
| 218 | 254 | * Inverse translation is impossible for several reasons: |
| 219 | 255 | * 1. The font<->character maps are not 1-1. |
| 220 | 256 | * 2. The text may have been written while a different translation map |
| 221 | | * was active, or using Unicode. |
| | 257 | * was active. |
| 222 | 258 | * Still, it is now possible to a certain extent to cut and paste non-ASCII. |
| 223 | 259 | */ |
| 224 | | unsigned char inverse_translate(struct vc_data *conp, int glyph) |
| | 260 | u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode) |
| 225 | 261 | { |
| 226 | 262 | struct uni_pagedir *p; |
| | 263 | int m; |
| 227 | 264 | if (glyph < 0 || glyph >= MAX_GLYPH) |
| 228 | 265 | return 0; |
| 229 | | else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc) || |
| 230 | | !p->inverse_translations[inv_translate[conp->vc_num]]) |
| | 266 | else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc)) |
| 231 | 267 | return glyph; |
| 232 | | else |
| 233 | | return p->inverse_translations[inv_translate[conp->vc_num]][glyph]; |
| | 268 | else if (use_unicode) { |
| | 269 | if (!p->inverse_trans_unicode) |
| | 270 | return glyph; |
| | 271 | else |
| | 272 | return p->inverse_trans_unicode[glyph]; |
| | 273 | } else { |
| | 274 | m = inv_translate[conp->vc_num]; |
| | 275 | if (!p->inverse_translations[m]) |
| | 276 | return glyph; |
| | 277 | else |
| | 278 | return p->inverse_translations[m][glyph]; |
| | 279 | } |
| 234 | 280 | } |
| 235 | 281 | |
| 236 | 282 | static void update_user_maps(void) |
| … |
… |
|
| 244 | 290 | p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc; |
| 245 | 291 | if (p && p != q) { |
| 246 | 292 | set_inverse_transl(vc_cons[i].d, p, USER_MAP); |
| | 293 | set_inverse_trans_unicode(vc_cons[i].d, p); |
| 247 | 294 | q = p; |
| 248 | 295 | } |
| 249 | 296 | } |
| … |
… |
|
| 354 | 401 | kfree(p->inverse_translations[i]); |
| 355 | 402 | p->inverse_translations[i] = NULL; |
| 356 | 403 | } |
| | 404 | if (p->inverse_trans_unicode) { |
| | 405 | kfree(p->inverse_trans_unicode); |
| | 406 | p->inverse_trans_unicode = NULL; |
| | 407 | } |
| 357 | 408 | } |
| 358 | 409 | |
| 359 | 410 | void con_free_unimap(struct vc_data *vc) |
| … |
… |
|
| 512 | 563 | |
| 513 | 564 | for (i = 0; i <= 3; i++) |
| 514 | 565 | set_inverse_transl(vc, p, i); /* Update all inverse translations */ |
| | 566 | set_inverse_trans_unicode(vc, p); |
| 515 | 567 | |
| 516 | 568 | return err; |
| 517 | 569 | } |
| … |
… |
|
| 562 | 614 | |
| 563 | 615 | for (i = 0; i <= 3; i++) |
| 564 | 616 | set_inverse_transl(vc, p, i); /* Update all inverse translations */ |
| | 617 | set_inverse_trans_unicode(vc, p); |
| 565 | 618 | dflt = p; |
| 566 | 619 | return err; |
| 567 | 620 | } |
| … |
… |
|
| 618 | 671 | p->readonly = rdonly; |
| 619 | 672 | } |
| 620 | 673 | |
| | 674 | /* may be called during an interrupt */ |
| | 675 | u32 conv_8bit_to_uni(unsigned char c) |
| | 676 | { |
| | 677 | /* |
| | 678 | * Always use USER_MAP. This function is used by the keyboard, |
| | 679 | * which shouldn't be affected by G0/G1 switching, etc. |
| | 680 | * If the user map still contains default values, i.e. the |
| | 681 | * direct-to-font mapping, then assume user is using Latin1. |
| | 682 | */ |
| | 683 | unsigned short uni = translations[USER_MAP][c]; |
| | 684 | return uni == (0xf000 | c) ? c : uni; |
| | 685 | } |
| | 686 | |
| 621 | 687 | int |
| 622 | 688 | conv_uni_to_pc(struct vc_data *conp, long ucs) |
| 623 | 689 | { |
diff -Naur linux-2.6.17.6.orig/drivers/char/keyboard.c linux-2.6.17.6/drivers/char/keyboard.c
|
old
|
new
|
|
| 34 | 34 | #include <linux/init.h> |
| 35 | 35 | #include <linux/slab.h> |
| 36 | 36 | |
| | 37 | #include <linux/consolemap.h> |
| 37 | 38 | #include <linux/kbd_kern.h> |
| 38 | 39 | #include <linux/kbd_diacr.h> |
| 39 | 40 | #include <linux/vt_kern.h> |
| … |
… |
|
| 329 | 330 | * Many other routines do put_queue, but I think either |
| 330 | 331 | * they produce ASCII, or they produce some user-assigned |
| 331 | 332 | * string, and in both cases we might assume that it is |
| 332 | | * in utf-8 already. UTF-8 is defined for words of up to 31 bits, |
| 333 | | * but we need only 16 bits here |
| | 333 | * in utf-8 already. |
| 334 | 334 | */ |
| 335 | | static void to_utf8(struct vc_data *vc, ushort c) |
| | 335 | static void to_utf8(struct vc_data *vc, uint c) |
| 336 | 336 | { |
| 337 | 337 | if (c < 0x80) |
| 338 | 338 | /* 0******* */ |
| … |
… |
|
| 341 | 341 | /* 110***** 10****** */ |
| 342 | 342 | put_queue(vc, 0xc0 | (c >> 6)); |
| 343 | 343 | put_queue(vc, 0x80 | (c & 0x3f)); |
| 344 | | } else { |
| | 344 | } else if (c < 0x10000) { |
| | 345 | if (c >= 0xD800 && c < 0xE000) |
| | 346 | return; |
| | 347 | if (c == 0xFFFF) |
| | 348 | return; |
| 345 | 349 | /* 1110**** 10****** 10****** */ |
| 346 | 350 | put_queue(vc, 0xe0 | (c >> 12)); |
| 347 | 351 | put_queue(vc, 0x80 | ((c >> 6) & 0x3f)); |
| 348 | 352 | put_queue(vc, 0x80 | (c & 0x3f)); |
| | 353 | } else if (c < 0x110000) { |
| | 354 | /* 11110*** 10****** 10****** 10****** */ |
| | 355 | put_queue(vc, 0xf0 | (c >> 18)); |
| | 356 | put_queue(vc, 0x80 | ((c >> 12) & 0x3f)); |
| | 357 | put_queue(vc, 0x80 | ((c >> 6) & 0x3f)); |
| | 358 | put_queue(vc, 0x80 | (c & 0x3f)); |
| 349 | 359 | } |
| 350 | 360 | } |
| 351 | 361 | |
| | 362 | static void put_8bit(struct vc_data *vc, u8 c) |
| | 363 | { |
| | 364 | if (kbd->kbdmode != VC_UNICODE || c < 32 || c == 127) |
| | 365 | /* Don't translate control chars */ |
| | 366 | put_queue(vc, c); |
| | 367 | else |
| | 368 | to_utf8(vc, conv_8bit_to_uni(c)); |
| | 369 | } |
| | 370 | |
| 352 | 371 | /* |
| 353 | 372 | * Called after returning from RAW mode or when changing consoles - recompute |
| 354 | 373 | * shift_down[] and shift_state from key_down[] maybe called when keymap is |
| … |
… |
|
| 416 | 435 | if (kbd->kbdmode == VC_UNICODE) |
| 417 | 436 | to_utf8(vc, d); |
| 418 | 437 | else if (d < 0x100) |
| 419 | | put_queue(vc, d); |
| | 438 | put_8bit(vc, d); |
| 420 | 439 | |
| 421 | 440 | return ch; |
| 422 | 441 | } |
| … |
… |
|
| 430 | 449 | if (kbd->kbdmode == VC_UNICODE) |
| 431 | 450 | to_utf8(vc, diacr); |
| 432 | 451 | else if (diacr < 0x100) |
| 433 | | put_queue(vc, diacr); |
| | 452 | put_8bit(vc, diacr); |
| 434 | 453 | diacr = 0; |
| 435 | 454 | } |
| 436 | 455 | put_queue(vc, 13); |
| … |
… |
|
| 798 | 817 | /* kludge */ |
| 799 | 818 | if (up_flag && shift_state != old_state && npadch != -1) { |
| 800 | 819 | if (kbd->kbdmode == VC_UNICODE) |
| 801 | | to_utf8(vc, npadch & 0xffff); |
| | 820 | to_utf8(vc, npadch); |
| 802 | 821 | else |
| 803 | 822 | put_queue(vc, npadch & 0xff); |
| 804 | 823 | npadch = -1; |
diff -Naur linux-2.6.17.6.orig/drivers/char/selection.c linux-2.6.17.6/drivers/char/selection.c
|
old
|
new
|
|
| 20 | 20 | |
| 21 | 21 | #include <asm/uaccess.h> |
| 22 | 22 | |
| | 23 | #include <linux/kbd_kern.h> |
| 23 | 24 | #include <linux/vt_kern.h> |
| 24 | 25 | #include <linux/consolemap.h> |
| 25 | 26 | #include <linux/selection.h> |
| … |
… |
|
| 34 | 35 | /* Variables for selection control. */ |
| 35 | 36 | /* Use a dynamic buffer, instead of static (Dec 1994) */ |
| 36 | 37 | struct vc_data *sel_cons; /* must not be disallocated */ |
| | 38 | static int use_unicode; |
| 37 | 39 | static volatile int sel_start = -1; /* cleared by clear_selection */ |
| 38 | 40 | static int sel_end; |
| 39 | 41 | static int sel_buffer_lth; |
| … |
… |
|
| 54 | 56 | complement_pos(sel_cons, where); |
| 55 | 57 | } |
| 56 | 58 | |
| 57 | | static unsigned char |
| | 59 | static u16 |
| 58 | 60 | sel_pos(int n) |
| 59 | 61 | { |
| 60 | | return inverse_translate(sel_cons, screen_glyph(sel_cons, n)); |
| | 62 | return inverse_translate(sel_cons, screen_glyph(sel_cons, n), |
| | 63 | use_unicode); |
| 61 | 64 | } |
| 62 | 65 | |
| 63 | 66 | /* remove the current selection highlight, if any, |
| … |
… |
|
| 86 | 89 | 0xFF7FFFFF /* latin-1 accented letters, not division sign */ |
| 87 | 90 | }; |
| 88 | 91 | |
| 89 | | static inline int inword(const unsigned char c) { |
| 90 | | return ( inwordLut[c>>5] >> (c & 0x1F) ) & 1; |
| | 92 | static inline int inword(const u16 c) { |
| | 93 | return c > 0xff || (( inwordLut[c>>5] >> (c & 0x1F) ) & 1); |
| 91 | 94 | } |
| 92 | 95 | |
| 93 | 96 | /* set inwordLut contents. Invoked by ioctl(). */ |
| … |
… |
|
| 108 | 111 | return (v > u) ? u : v; |
| 109 | 112 | } |
| 110 | 113 | |
| | 114 | /* stores the char in UTF8 and returns the number of bytes used (1-3) */ |
| | 115 | int store_utf8(u16 c, char *p) |
| | 116 | { |
| | 117 | if (c < 0x80) { |
| | 118 | /* 0******* */ |
| | 119 | p[0] = c; |
| | 120 | return 1; |
| | 121 | } else if (c < 0x800) { |
| | 122 | /* 110***** 10****** */ |
| | 123 | p[0] = 0xc0 | (c >> 6); |
| | 124 | p[1] = 0x80 | (c & 0x3f); |
| | 125 | return 2; |
| | 126 | } else { |
| | 127 | /* 1110**** 10****** 10****** */ |
| | 128 | p[0] = 0xe0 | (c >> 12); |
| | 129 | p[1] = 0x80 | ((c >> 6) & 0x3f); |
| | 130 | p[2] = 0x80 | (c & 0x3f); |
| | 131 | return 3; |
| | 132 | } |
| | 133 | } |
| | 134 | |
| 111 | 135 | /* set the current selection. Invoked by ioctl() or by kernel code. */ |
| 112 | 136 | int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty) |
| 113 | 137 | { |
| 114 | 138 | struct vc_data *vc = vc_cons[fg_console].d; |
| 115 | 139 | int sel_mode, new_sel_start, new_sel_end, spc; |
| 116 | 140 | char *bp, *obp; |
| 117 | | int i, ps, pe; |
| | 141 | int i, ps, pe, multiplier; |
| | 142 | u16 c; |
| | 143 | struct kbd_struct *kbd = kbd_table + fg_console; |
| 118 | 144 | |
| 119 | 145 | poke_blanked_console(); |
| 120 | 146 | |
| … |
… |
|
| 158 | 184 | clear_selection(); |
| 159 | 185 | sel_cons = vc_cons[fg_console].d; |
| 160 | 186 | } |
| 161 | | |
| | 187 | use_unicode = kbd && kbd->kbdmode == VC_UNICODE; |
| | 188 | |
| 162 | 189 | switch (sel_mode) |
| 163 | 190 | { |
| 164 | 191 | case TIOCL_SELCHAR: /* character-by-character selection */ |
| … |
… |
|
| 240 | 267 | sel_end = new_sel_end; |
| 241 | 268 | |
| 242 | 269 | /* Allocate a new buffer before freeing the old one ... */ |
| 243 | | bp = kmalloc((sel_end-sel_start)/2+1, GFP_KERNEL); |
| | 270 | multiplier = use_unicode ? 3 : 1; /* chars can take up to 3 bytes */ |
| | 271 | bp = kmalloc((sel_end-sel_start)/2*multiplier+1, GFP_KERNEL); |
| 244 | 272 | if (!bp) { |
| 245 | 273 | printk(KERN_WARNING "selection: kmalloc() failed\n"); |
| 246 | 274 | clear_selection(); |
| … |
… |
|
| 251 | 279 | |
| 252 | 280 | obp = bp; |
| 253 | 281 | for (i = sel_start; i <= sel_end; i += 2) { |
| 254 | | *bp = sel_pos(i); |
| 255 | | if (!isspace(*bp++)) |
| | 282 | c = sel_pos(i); |
| | 283 | if (use_unicode) |
| | 284 | bp += store_utf8(c, bp); |
| | 285 | else |
| | 286 | *bp++ = c; |
| | 287 | if (!isspace(c)) |
| 256 | 288 | obp = bp; |
| 257 | 289 | if (! ((i + 2) % vc->vc_size_row)) { |
| 258 | 290 | /* strip trailing blanks from line and add newline, |
diff -Naur linux-2.6.17.6.orig/include/linux/consolemap.h linux-2.6.17.6/include/linux/consolemap.h
|
old
|
new
|
|
| 10 | 10 | |
| 11 | 11 | struct vc_data; |
| 12 | 12 | |
| 13 | | extern unsigned char inverse_translate(struct vc_data *conp, int glyph); |
| | 13 | extern u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode); |
| 14 | 14 | extern unsigned short *set_translate(int m, struct vc_data *vc); |
| 15 | 15 | extern int conv_uni_to_pc(struct vc_data *conp, long ucs); |
| | 16 | extern u32 conv_8bit_to_uni(unsigned char c); |