aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/consolemap.c
diff options
context:
space:
mode:
authorJan Engelhardt <jengelh@linux01.gwdg.de>2007-07-16 02:40:40 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-16 12:05:46 -0400
commit759448f459234bfcf34b82471f0dba77a9aca498 (patch)
tree61cbf8501bdad78c03e034072791fbf3e0436d43 /drivers/char/consolemap.c
parentaa0ac36518be648dda3a32f0b37a8b2b546e1b24 (diff)
Kernel utf-8 handling
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 Already posted on (Oldest) http://lkml.org/lkml/2003/5/31/148 http://lkml.org/lkml/2005/12/24/69 (Recent) http://lkml.org/lkml/2006/8/7/75 [bunk@stusta.de: make drivers/char/selection.c:store_utf8() static] Signed-off-by: Jan Engelhardt <jengelh@gmx.de> Cc: Alexander E. Patrakov <patrakov@ums.usu.ru> Cc: Dmitry Torokhov <dtor@mail.ru> Cc: "Antonino A. Daplas" <adaplas@pol.net> Signed-off-by: Adrian Bunk <bunk@stusta.de> Cc: David Woodhouse <dwmw2@infradead.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/char/consolemap.c')
-rw-r--r--drivers/char/consolemap.c78
1 files changed, 72 insertions, 6 deletions
diff --git a/drivers/char/consolemap.c b/drivers/char/consolemap.c
index fd40b959afdd..4b3916f54909 100644
--- a/drivers/char/consolemap.c
+++ b/drivers/char/consolemap.c
@@ -177,6 +177,7 @@ struct uni_pagedir {
177 unsigned long refcount; 177 unsigned long refcount;
178 unsigned long sum; 178 unsigned long sum;
179 unsigned char *inverse_translations[4]; 179 unsigned char *inverse_translations[4];
180 u16 *inverse_trans_unicode;
180 int readonly; 181 int readonly;
181}; 182};
182 183
@@ -207,6 +208,41 @@ static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int
207 } 208 }
208} 209}
209 210
211static void set_inverse_trans_unicode(struct vc_data *conp,
212 struct uni_pagedir *p)
213{
214 int i, j, k, glyph;
215 u16 **p1, *p2;
216 u16 *q;
217
218 if (!p) return;
219 q = p->inverse_trans_unicode;
220 if (!q) {
221 q = p->inverse_trans_unicode =
222 kmalloc(MAX_GLYPH * sizeof(u16), GFP_KERNEL);
223 if (!q)
224 return;
225 }
226 memset(q, 0, MAX_GLYPH * sizeof(u16));
227
228 for (i = 0; i < 32; i++) {
229 p1 = p->uni_pgdir[i];
230 if (!p1)
231 continue;
232 for (j = 0; j < 32; j++) {
233 p2 = p1[j];
234 if (!p2)
235 continue;
236 for (k = 0; k < 64; k++) {
237 glyph = p2[k];
238 if (glyph >= 0 && glyph < MAX_GLYPH
239 && q[glyph] < 32)
240 q[glyph] = (i << 11) + (j << 6) + k;
241 }
242 }
243 }
244}
245
210unsigned short *set_translate(int m, struct vc_data *vc) 246unsigned short *set_translate(int m, struct vc_data *vc)
211{ 247{
212 inv_translate[vc->vc_num] = m; 248 inv_translate[vc->vc_num] = m;
@@ -217,19 +253,29 @@ unsigned short *set_translate(int m, struct vc_data *vc)
217 * Inverse translation is impossible for several reasons: 253 * Inverse translation is impossible for several reasons:
218 * 1. The font<->character maps are not 1-1. 254 * 1. The font<->character maps are not 1-1.
219 * 2. The text may have been written while a different translation map 255 * 2. The text may have been written while a different translation map
220 * was active, or using Unicode. 256 * was active.
221 * Still, it is now possible to a certain extent to cut and paste non-ASCII. 257 * Still, it is now possible to a certain extent to cut and paste non-ASCII.
222 */ 258 */
223unsigned char inverse_translate(struct vc_data *conp, int glyph) 259u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode)
224{ 260{
225 struct uni_pagedir *p; 261 struct uni_pagedir *p;
262 int m;
226 if (glyph < 0 || glyph >= MAX_GLYPH) 263 if (glyph < 0 || glyph >= MAX_GLYPH)
227 return 0; 264 return 0;
228 else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc) || 265 else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc))
229 !p->inverse_translations[inv_translate[conp->vc_num]])
230 return glyph; 266 return glyph;
231 else 267 else if (use_unicode) {
232 return p->inverse_translations[inv_translate[conp->vc_num]][glyph]; 268 if (!p->inverse_trans_unicode)
269 return glyph;
270 else
271 return p->inverse_trans_unicode[glyph];
272 } else {
273 m = inv_translate[conp->vc_num];
274 if (!p->inverse_translations[m])
275 return glyph;
276 else
277 return p->inverse_translations[m][glyph];
278 }
233} 279}
234 280
235static void update_user_maps(void) 281static void update_user_maps(void)
@@ -243,6 +289,7 @@ static void update_user_maps(void)
243 p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc; 289 p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
244 if (p && p != q) { 290 if (p && p != q) {
245 set_inverse_transl(vc_cons[i].d, p, USER_MAP); 291 set_inverse_transl(vc_cons[i].d, p, USER_MAP);
292 set_inverse_trans_unicode(vc_cons[i].d, p);
246 q = p; 293 q = p;
247 } 294 }
248 } 295 }
@@ -353,6 +400,10 @@ static void con_release_unimap(struct uni_pagedir *p)
353 kfree(p->inverse_translations[i]); 400 kfree(p->inverse_translations[i]);
354 p->inverse_translations[i] = NULL; 401 p->inverse_translations[i] = NULL;
355 } 402 }
403 if (p->inverse_trans_unicode) {
404 kfree(p->inverse_trans_unicode);
405 p->inverse_trans_unicode = NULL;
406 }
356} 407}
357 408
358void con_free_unimap(struct vc_data *vc) 409void con_free_unimap(struct vc_data *vc)
@@ -511,6 +562,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
511 562
512 for (i = 0; i <= 3; i++) 563 for (i = 0; i <= 3; i++)
513 set_inverse_transl(vc, p, i); /* Update all inverse translations */ 564 set_inverse_transl(vc, p, i); /* Update all inverse translations */
565 set_inverse_trans_unicode(vc, p);
514 566
515 return err; 567 return err;
516} 568}
@@ -561,6 +613,7 @@ int con_set_default_unimap(struct vc_data *vc)
561 613
562 for (i = 0; i <= 3; i++) 614 for (i = 0; i <= 3; i++)
563 set_inverse_transl(vc, p, i); /* Update all inverse translations */ 615 set_inverse_transl(vc, p, i); /* Update all inverse translations */
616 set_inverse_trans_unicode(vc, p);
564 dflt = p; 617 dflt = p;
565 return err; 618 return err;
566} 619}
@@ -617,6 +670,19 @@ void con_protect_unimap(struct vc_data *vc, int rdonly)
617 p->readonly = rdonly; 670 p->readonly = rdonly;
618} 671}
619 672
673/* may be called during an interrupt */
674u32 conv_8bit_to_uni(unsigned char c)
675{
676 /*
677 * Always use USER_MAP. This function is used by the keyboard,
678 * which shouldn't be affected by G0/G1 switching, etc.
679 * If the user map still contains default values, i.e. the
680 * direct-to-font mapping, then assume user is using Latin1.
681 */
682 unsigned short uni = translations[USER_MAP][c];
683 return uni == (0xf000 | c) ? c : uni;
684}
685
620int 686int
621conv_uni_to_pc(struct vc_data *conp, long ucs) 687conv_uni_to_pc(struct vc_data *conp, long ucs)
622{ 688{