Zwischencommit fuer LFS. Bis Kernel.
[people/pmueller/ipfire-2.x.git] / src / patches / linux-2.6.16.27-utf8_input-1.patch
1 Submitted by: Alexander E. Patrakov <patrakov@ums.usu.ru>
2 Signed-off-by: Alexander E. Patrakov <patrakov@ums.usu.ru>
3 Date: 2005-10-18
4 Initial Package Version: 2.6.15
5 Upstream Status: Rejected: they say it modifies the meaning of an existing ioctl
6 Origin: http://chris.heathens.co.nz/linux/downloads/patches-2.6.4-cdh1.tar.gz
7         Porting to linux-2.6.16 by Alexander E. Patrakov
8 Description: This patch fixes dead keys and copy/paste of non-ASCII characters
9              in UTF-8 mode on Linux console.
10              See more details about the original patch at:
11              http://chris.heathens.co.nz/linux/utf8.html
12
13 diff -ur linux-2.6.15-rc6.orig/drivers/char/consolemap.c linux-2.6.15-rc6.my/drivers/char/consolemap.c
14 --- linux-2.6.15-rc6.orig/drivers/char/consolemap.c     2005-12-25 10:00:12.000000000 +0500
15 +++ linux-2.6.15-rc6.my/drivers/char/consolemap.c       2005-12-25 10:01:22.000000000 +0500
16 @@ -178,6 +178,7 @@
17         unsigned long   refcount;
18         unsigned long   sum;
19         unsigned char   *inverse_translations[4];
20 +       u16             *inverse_trans_unicode;
21         int             readonly;
22  };
23  
24 @@ -208,6 +209,41 @@
25         }
26  }
27  
28 +static void set_inverse_trans_unicode(struct vc_data *conp, 
29 +                                     struct uni_pagedir *p)
30 +{
31 +       int i, j, k, glyph;
32 +       u16 **p1, *p2;
33 +       u16 *q;
34 +       
35 +       if (!p) return;
36 +       q = p->inverse_trans_unicode;
37 +       if (!q) {
38 +               q = p->inverse_trans_unicode =
39 +                       kmalloc(MAX_GLYPH * sizeof(u16), GFP_KERNEL);
40 +               if (!q)
41 +                       return;
42 +       }
43 +       memset(q, 0, MAX_GLYPH * sizeof(u16));
44 +
45 +       for (i = 0; i < 32; i++) {
46 +               p1 = p->uni_pgdir[i];
47 +               if (!p1)
48 +                       continue;
49 +               for (j = 0; j < 32; j++) {
50 +                       p2 = p1[j];
51 +                       if (!p2)
52 +                               continue;
53 +                       for (k = 0; k < 64; k++) {
54 +                               glyph = p2[k];
55 +                               if (glyph >= 0 && glyph < MAX_GLYPH 
56 +                                              && q[glyph] < 32)
57 +                                       q[glyph] = (i << 11) + (j << 6) + k;
58 +                       }
59 +               }
60 +       }
61 +}
62 +
63  unsigned short *set_translate(int m, struct vc_data *vc)
64  {
65         inv_translate[vc->vc_num] = m;
66 @@ -218,19 +254,29 @@
67   * Inverse translation is impossible for several reasons:
68   * 1. The font<->character maps are not 1-1.
69   * 2. The text may have been written while a different translation map
70 - *    was active, or using Unicode.
71 + *    was active.
72   * Still, it is now possible to a certain extent to cut and paste non-ASCII.
73   */
74 -unsigned char inverse_translate(struct vc_data *conp, int glyph)
75 +u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode)
76  {
77         struct uni_pagedir *p;
78 +       int m;
79         if (glyph < 0 || glyph >= MAX_GLYPH)
80                 return 0;
81 -       else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc) ||
82 -                !p->inverse_translations[inv_translate[conp->vc_num]])
83 +       else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc))
84                 return glyph;
85 -       else
86 -               return p->inverse_translations[inv_translate[conp->vc_num]][glyph];
87 +       else if (use_unicode) {
88 +               if (!p->inverse_trans_unicode)
89 +                       return glyph;
90 +               else
91 +                       return p->inverse_trans_unicode[glyph];
92 +       } else {
93 +               m = inv_translate[conp->vc_num];
94 +               if (!p->inverse_translations[m])
95 +                       return glyph;
96 +               else
97 +                       return p->inverse_translations[m][glyph];
98 +       }
99  }
100  
101  static void update_user_maps(void)
102 @@ -244,6 +290,7 @@
103                 p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
104                 if (p && p != q) {
105                         set_inverse_transl(vc_cons[i].d, p, USER_MAP);
106 +                       set_inverse_trans_unicode(vc_cons[i].d, p);
107                         q = p;
108                 }
109         }
110 @@ -354,6 +401,10 @@
111                 kfree(p->inverse_translations[i]);
112                 p->inverse_translations[i] = NULL;
113         }
114 +       if (p->inverse_trans_unicode) {
115 +               kfree(p->inverse_trans_unicode);
116 +               p->inverse_trans_unicode = NULL;
117 +       }
118  }
119  
120  void con_free_unimap(struct vc_data *vc)
121 @@ -512,6 +563,7 @@
122  
123         for (i = 0; i <= 3; i++)
124                 set_inverse_transl(vc, p, i); /* Update all inverse translations */
125 +       set_inverse_trans_unicode(vc, p);
126    
127         return err;
128  }
129 @@ -562,6 +614,7 @@
130  
131         for (i = 0; i <= 3; i++)
132                 set_inverse_transl(vc, p, i);   /* Update all inverse translations */
133 +       set_inverse_trans_unicode(vc, p);
134         dflt = p;
135         return err;
136  }
137 @@ -618,6 +671,19 @@
138                 p->readonly = rdonly;
139  }
140  
141 +/* may be called during an interrupt */
142 +u32 conv_8bit_to_uni(unsigned char c)
143 +{
144 +       /* 
145 +        * Always use USER_MAP. This function is used by the keyboard,
146 +        * which shouldn't be affected by G0/G1 switching, etc.
147 +        * If the user map still contains default values, i.e. the 
148 +        * direct-to-font mapping, then assume user is using Latin1.
149 +        */
150 +       unsigned short uni = translations[USER_MAP][c];
151 +       return uni == (0xf000 | c) ? c : uni;
152 +}
153 +
154  int
155  conv_uni_to_pc(struct vc_data *conp, long ucs) 
156  {
157 diff -ur linux-2.6.15-rc6.orig/drivers/char/keyboard.c linux-2.6.15-rc6.my/drivers/char/keyboard.c
158 --- linux-2.6.15-rc6.orig/drivers/char/keyboard.c       2005-12-25 10:00:12.000000000 +0500
159 +++ linux-2.6.15-rc6.my/drivers/char/keyboard.c 2005-12-25 10:01:22.000000000 +0500
160 @@ -34,6 +34,7 @@
161  #include <linux/init.h>
162  #include <linux/slab.h>
163  
164 +#include <linux/consolemap.h>
165  #include <linux/kbd_kern.h>
166  #include <linux/kbd_diacr.h>
167  #include <linux/vt_kern.h>
168 @@ -329,10 +330,9 @@
169   * Many other routines do put_queue, but I think either
170   * they produce ASCII, or they produce some user-assigned
171   * string, and in both cases we might assume that it is
172 - * in utf-8 already. UTF-8 is defined for words of up to 31 bits,
173 - * but we need only 16 bits here
174 + * in utf-8 already.
175   */
176 -static void to_utf8(struct vc_data *vc, ushort c)
177 +static void to_utf8(struct vc_data *vc, uint c)
178  {
179         if (c < 0x80)
180                 /*  0******* */
181 @@ -341,14 +341,33 @@
182                 /* 110***** 10****** */
183                 put_queue(vc, 0xc0 | (c >> 6));
184                 put_queue(vc, 0x80 | (c & 0x3f));
185 -       } else {
186 +       } else if (c < 0x10000) {
187 +               if (c >= 0xD800 && c < 0xE000)
188 +                       return;
189 +               if (c == 0xFFFF)
190 +                       return;
191                 /* 1110**** 10****** 10****** */
192                 put_queue(vc, 0xe0 | (c >> 12));
193                 put_queue(vc, 0x80 | ((c >> 6) & 0x3f));
194                 put_queue(vc, 0x80 | (c & 0x3f));
195 +       } else if (c < 0x110000) {
196 +               /* 11110*** 10****** 10****** 10****** */
197 +               put_queue(vc, 0xf0 | (c >> 18));
198 +               put_queue(vc, 0x80 | ((c >> 12) & 0x3f));
199 +               put_queue(vc, 0x80 | ((c >> 6) & 0x3f));
200 +               put_queue(vc, 0x80 | (c & 0x3f));
201         }
202  }
203  
204 +static void put_8bit(struct vc_data *vc, u8 c)
205 +{
206 +       if (kbd->kbdmode != VC_UNICODE || c < 32 || c == 127) 
207 +               /* Don't translate control chars */
208 +               put_queue(vc, c);
209 +       else
210 +               to_utf8(vc, conv_8bit_to_uni(c));
211 +}
212 +
213  /*
214   * Called after returning from RAW mode or when changing consoles - recompute
215   * shift_down[] and shift_state from key_down[] maybe called when keymap is
216 @@ -409,7 +428,7 @@
217         if (ch == ' ' || ch == d)
218                 return d;
219  
220 -       put_queue(vc, d);
221 +       put_8bit(vc, d);
222         return ch;
223  }
224  
225 @@ -419,7 +438,7 @@
226  static void fn_enter(struct vc_data *vc, struct pt_regs *regs)
227  {
228         if (diacr) {
229 -               put_queue(vc, diacr);
230 +               put_8bit(vc, diacr);
231                 diacr = 0;
232         }
233         put_queue(vc, 13);
234 @@ -628,7 +647,7 @@
235                 diacr = value;
236                 return;
237         }
238 -       put_queue(vc, value);
239 +       put_8bit(vc, value);
240  }
241  
242  /*
243 @@ -774,7 +793,7 @@
244         /* kludge */
245         if (up_flag && shift_state != old_state && npadch != -1) {
246                 if (kbd->kbdmode == VC_UNICODE)
247 -                       to_utf8(vc, npadch & 0xffff);
248 +                       to_utf8(vc, npadch);
249                 else
250                         put_queue(vc, npadch & 0xff);
251                 npadch = -1;
252 diff -ur linux-2.6.15-rc6.orig/drivers/char/selection.c linux-2.6.15-rc6.my/drivers/char/selection.c
253 --- linux-2.6.15-rc6.orig/drivers/char/selection.c      2005-12-25 10:00:12.000000000 +0500
254 +++ linux-2.6.15-rc6.my/drivers/char/selection.c        2005-12-25 10:01:22.000000000 +0500
255 @@ -20,6 +20,7 @@
256  
257  #include <asm/uaccess.h>
258  
259 +#include <linux/kbd_kern.h>
260  #include <linux/vt_kern.h>
261  #include <linux/consolemap.h>
262  #include <linux/selection.h>
263 @@ -34,6 +35,7 @@
264  /* Variables for selection control. */
265  /* Use a dynamic buffer, instead of static (Dec 1994) */
266  struct vc_data *sel_cons;              /* must not be disallocated */
267 +static int use_unicode;
268  static volatile int sel_start = -1;    /* cleared by clear_selection */
269  static int sel_end;
270  static int sel_buffer_lth;
271 @@ -54,10 +56,11 @@
272         complement_pos(sel_cons, where);
273  }
274  
275 -static unsigned char
276 +static u16
277  sel_pos(int n)
278  {
279 -       return inverse_translate(sel_cons, screen_glyph(sel_cons, n));
280 +       return inverse_translate(sel_cons, screen_glyph(sel_cons, n),
281 +                               use_unicode);
282  }
283  
284  /* remove the current selection highlight, if any,
285 @@ -86,8 +89,8 @@
286    0xFF7FFFFF  /* latin-1 accented letters, not division sign */
287  };
288  
289 -static inline int inword(const unsigned char c) {
290 -       return ( inwordLut[c>>5] >> (c & 0x1F) ) & 1;
291 +static inline int inword(const u16 c) {
292 +       return c > 0xff || (( inwordLut[c>>5] >> (c & 0x1F) ) & 1);
293  }
294  
295  /* set inwordLut contents. Invoked by ioctl(). */
296 @@ -108,13 +111,36 @@
297         return (v > u) ? u : v;
298  }
299  
300 +/* stores the char in UTF8 and returns the number of bytes used (1-3) */
301 +int store_utf8(u16 c, char *p) 
302 +{
303 +       if (c < 0x80) {
304 +               /*  0******* */
305 +               p[0] = c;
306 +               return 1;
307 +       } else if (c < 0x800) {
308 +               /* 110***** 10****** */
309 +               p[0] = 0xc0 | (c >> 6);
310 +               p[1] = 0x80 | (c & 0x3f);
311 +               return 2;
312 +       } else {
313 +               /* 1110**** 10****** 10****** */
314 +               p[0] = 0xe0 | (c >> 12);
315 +               p[1] = 0x80 | ((c >> 6) & 0x3f);
316 +               p[2] = 0x80 | (c & 0x3f);
317 +               return 3;
318 +       }
319 +}
320 +
321  /* set the current selection. Invoked by ioctl() or by kernel code. */
322  int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty)
323  {
324         struct vc_data *vc = vc_cons[fg_console].d;
325         int sel_mode, new_sel_start, new_sel_end, spc;
326         char *bp, *obp;
327 -       int i, ps, pe;
328 +       int i, ps, pe, multiplier;
329 +       u16 c;
330 +       struct kbd_struct *kbd = kbd_table + fg_console;
331  
332         poke_blanked_console();
333  
334 @@ -158,7 +184,8 @@
335                 clear_selection();
336                 sel_cons = vc_cons[fg_console].d;
337         }
338 -
339 +       use_unicode = kbd && kbd->kbdmode == VC_UNICODE;
340 +       
341         switch (sel_mode)
342         {
343                 case TIOCL_SELCHAR:     /* character-by-character selection */
344 @@ -240,7 +267,8 @@
345         sel_end = new_sel_end;
346  
347         /* Allocate a new buffer before freeing the old one ... */
348 -       bp = kmalloc((sel_end-sel_start)/2+1, GFP_KERNEL);
349 +       multiplier = use_unicode ? 3 : 1;  /* chars can take up to 3 bytes */
350 +       bp = kmalloc((sel_end-sel_start)/2*multiplier+1, GFP_KERNEL);
351         if (!bp) {
352                 printk(KERN_WARNING "selection: kmalloc() failed\n");
353                 clear_selection();
354 @@ -251,8 +279,12 @@
355  
356         obp = bp;
357         for (i = sel_start; i <= sel_end; i += 2) {
358 -               *bp = sel_pos(i);
359 -               if (!isspace(*bp++))
360 +               c = sel_pos(i);
361 +               if (use_unicode)
362 +                       bp += store_utf8(c, bp);
363 +               else
364 +                       *bp++ = c;
365 +               if (!isspace(c))
366                         obp = bp;
367                 if (! ((i + 2) % vc->vc_size_row)) {
368                         /* strip trailing blanks from line and add newline,
369 diff -ur linux-2.6.15-rc6.orig/include/linux/consolemap.h linux-2.6.15-rc6.my/include/linux/consolemap.h
370 --- linux-2.6.15-rc6.orig/include/linux/consolemap.h    2005-12-25 10:00:13.000000000 +0500
371 +++ linux-2.6.15-rc6.my/include/linux/consolemap.h      2005-12-25 10:01:22.000000000 +0500
372 @@ -10,6 +10,7 @@
373  
374  struct vc_data;
375  
376 -extern unsigned char inverse_translate(struct vc_data *conp, int glyph);
377 +extern u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode);
378  extern unsigned short *set_translate(int m, struct vc_data *vc);
379  extern int conv_uni_to_pc(struct vc_data *conp, long ucs);
380 +extern u32 conv_8bit_to_uni(unsigned char c);