tizen 2.4 release
[kernel/linux-3.0.git] / drivers / tty / vt / consolemap.c
1 /*
2  * consolemap.c
3  *
4  * Mapping from internal code (such as Latin-1 or Unicode or IBM PC code)
5  * to font positions.
6  *
7  * aeb, 950210
8  *
9  * Support for multiple unimaps by Jakub Jelinek <jj@ultra.linux.cz>, July 1998
10  *
11  * Fix bug in inverse translation. Stanislav Voronyi <stas@cnti.uanet.kharkov.ua>, Dec 1998
12  */
13
14 #include <linux/module.h>
15 #include <linux/kd.h>
16 #include <linux/errno.h>
17 #include <linux/mm.h>
18 #include <linux/slab.h>
19 #include <linux/init.h>
20 #include <linux/tty.h>
21 #include <asm/uaccess.h>
22 #include <linux/consolemap.h>
23 #include <linux/vt_kern.h>
24 #include <linux/delay.h>
25
26 static unsigned short translations[][256] = {
27   /* 8-bit Latin-1 mapped to Unicode -- trivial mapping */
28   {
29     0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
30     0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
31     0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
32     0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
33     0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
34     0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
35     0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
36     0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
37     0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
38     0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
39     0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
40     0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
41     0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
42     0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
43     0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
44     0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
45     0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
46     0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
47     0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
48     0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
49     0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
50     0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
51     0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
52     0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
53     0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
54     0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
55     0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
56     0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
57     0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
58     0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
59     0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
60     0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
61   }, 
62   /* VT100 graphics mapped to Unicode */
63   {
64     0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
65     0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
66     0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
67     0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
68     0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
69     0x0028, 0x0029, 0x002a, 0x2192, 0x2190, 0x2191, 0x2193, 0x002f,
70     0x2588, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
71     0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
72     0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
73     0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
74     0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
75     0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x00a0,
76     0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1,
77     0x2591, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba,
78     0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c,
79     0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x007f,
80     0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
81     0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
82     0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
83     0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
84     0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
85     0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
86     0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
87     0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
88     0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
89     0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
90     0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
91     0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
92     0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
93     0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
94     0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
95     0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
96   },
97   /* IBM Codepage 437 mapped to Unicode */
98   {
99     0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, 
100     0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c,
101     0x25b6, 0x25c0, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8,
102     0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc,
103     0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
104     0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
105     0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
106     0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
107     0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
108     0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
109     0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
110     0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
111     0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
112     0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
113     0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
114     0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302,
115     0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
116     0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
117     0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
118     0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
119     0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
120     0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
121     0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
122     0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
123     0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
124     0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
125     0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
126     0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
127     0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
128     0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
129     0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
130     0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0
131   }, 
132   /* User mapping -- default to codes for direct font mapping */
133   {
134     0xf000, 0xf001, 0xf002, 0xf003, 0xf004, 0xf005, 0xf006, 0xf007,
135     0xf008, 0xf009, 0xf00a, 0xf00b, 0xf00c, 0xf00d, 0xf00e, 0xf00f,
136     0xf010, 0xf011, 0xf012, 0xf013, 0xf014, 0xf015, 0xf016, 0xf017,
137     0xf018, 0xf019, 0xf01a, 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f,
138     0xf020, 0xf021, 0xf022, 0xf023, 0xf024, 0xf025, 0xf026, 0xf027,
139     0xf028, 0xf029, 0xf02a, 0xf02b, 0xf02c, 0xf02d, 0xf02e, 0xf02f,
140     0xf030, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037,
141     0xf038, 0xf039, 0xf03a, 0xf03b, 0xf03c, 0xf03d, 0xf03e, 0xf03f,
142     0xf040, 0xf041, 0xf042, 0xf043, 0xf044, 0xf045, 0xf046, 0xf047,
143     0xf048, 0xf049, 0xf04a, 0xf04b, 0xf04c, 0xf04d, 0xf04e, 0xf04f,
144     0xf050, 0xf051, 0xf052, 0xf053, 0xf054, 0xf055, 0xf056, 0xf057,
145     0xf058, 0xf059, 0xf05a, 0xf05b, 0xf05c, 0xf05d, 0xf05e, 0xf05f,
146     0xf060, 0xf061, 0xf062, 0xf063, 0xf064, 0xf065, 0xf066, 0xf067,
147     0xf068, 0xf069, 0xf06a, 0xf06b, 0xf06c, 0xf06d, 0xf06e, 0xf06f,
148     0xf070, 0xf071, 0xf072, 0xf073, 0xf074, 0xf075, 0xf076, 0xf077,
149     0xf078, 0xf079, 0xf07a, 0xf07b, 0xf07c, 0xf07d, 0xf07e, 0xf07f,
150     0xf080, 0xf081, 0xf082, 0xf083, 0xf084, 0xf085, 0xf086, 0xf087,
151     0xf088, 0xf089, 0xf08a, 0xf08b, 0xf08c, 0xf08d, 0xf08e, 0xf08f,
152     0xf090, 0xf091, 0xf092, 0xf093, 0xf094, 0xf095, 0xf096, 0xf097,
153     0xf098, 0xf099, 0xf09a, 0xf09b, 0xf09c, 0xf09d, 0xf09e, 0xf09f,
154     0xf0a0, 0xf0a1, 0xf0a2, 0xf0a3, 0xf0a4, 0xf0a5, 0xf0a6, 0xf0a7,
155     0xf0a8, 0xf0a9, 0xf0aa, 0xf0ab, 0xf0ac, 0xf0ad, 0xf0ae, 0xf0af,
156     0xf0b0, 0xf0b1, 0xf0b2, 0xf0b3, 0xf0b4, 0xf0b5, 0xf0b6, 0xf0b7,
157     0xf0b8, 0xf0b9, 0xf0ba, 0xf0bb, 0xf0bc, 0xf0bd, 0xf0be, 0xf0bf,
158     0xf0c0, 0xf0c1, 0xf0c2, 0xf0c3, 0xf0c4, 0xf0c5, 0xf0c6, 0xf0c7,
159     0xf0c8, 0xf0c9, 0xf0ca, 0xf0cb, 0xf0cc, 0xf0cd, 0xf0ce, 0xf0cf,
160     0xf0d0, 0xf0d1, 0xf0d2, 0xf0d3, 0xf0d4, 0xf0d5, 0xf0d6, 0xf0d7,
161     0xf0d8, 0xf0d9, 0xf0da, 0xf0db, 0xf0dc, 0xf0dd, 0xf0de, 0xf0df,
162     0xf0e0, 0xf0e1, 0xf0e2, 0xf0e3, 0xf0e4, 0xf0e5, 0xf0e6, 0xf0e7,
163     0xf0e8, 0xf0e9, 0xf0ea, 0xf0eb, 0xf0ec, 0xf0ed, 0xf0ee, 0xf0ef,
164     0xf0f0, 0xf0f1, 0xf0f2, 0xf0f3, 0xf0f4, 0xf0f5, 0xf0f6, 0xf0f7,
165     0xf0f8, 0xf0f9, 0xf0fa, 0xf0fb, 0xf0fc, 0xf0fd, 0xf0fe, 0xf0ff
166   }
167 };
168
169 /* The standard kernel character-to-font mappings are not invertible
170    -- this is just a best effort. */
171
172 #define MAX_GLYPH 512           /* Max possible glyph value */
173
174 static int inv_translate[MAX_NR_CONSOLES];
175
176 struct uni_pagedir {
177         u16             **uni_pgdir[32];
178         unsigned long   refcount;
179         unsigned long   sum;
180         unsigned char   *inverse_translations[4];
181         u16             *inverse_trans_unicode;
182         int             readonly;
183 };
184
185 static struct uni_pagedir *dflt;
186
187 static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int i)
188 {
189         int j, glyph;
190         unsigned short *t = translations[i];
191         unsigned char *q;
192         
193         if (!p) return;
194         q = p->inverse_translations[i];
195
196         if (!q) {
197                 q = p->inverse_translations[i] = (unsigned char *) 
198                         kmalloc(MAX_GLYPH, GFP_KERNEL);
199                 if (!q) return;
200         }
201         memset(q, 0, MAX_GLYPH);
202
203         for (j = 0; j < E_TABSZ; j++) {
204                 glyph = conv_uni_to_pc(conp, t[j]);
205                 if (glyph >= 0 && glyph < MAX_GLYPH && q[glyph] < 32) {
206                         /* prefer '-' above SHY etc. */
207                         q[glyph] = j;
208                 }
209         }
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
247 unsigned short *set_translate(int m, struct vc_data *vc)
248 {
249         inv_translate[vc->vc_num] = m;
250         return translations[m];
251 }
252
253 /*
254  * Inverse translation is impossible for several reasons:
255  * 1. The font<->character maps are not 1-1.
256  * 2. The text may have been written while a different translation map
257  *    was active.
258  * Still, it is now possible to a certain extent to cut and paste non-ASCII.
259  */
260 u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode)
261 {
262         struct uni_pagedir *p;
263         int m;
264         if (glyph < 0 || glyph >= MAX_GLYPH)
265                 return 0;
266         else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc))
267                 return 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         }
280 }
281 EXPORT_SYMBOL_GPL(inverse_translate);
282
283 static void update_user_maps(void)
284 {
285         int i;
286         struct uni_pagedir *p, *q = NULL;
287         
288         for (i = 0; i < MAX_NR_CONSOLES; i++) {
289                 if (!vc_cons_allocated(i))
290                         continue;
291                 p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
292                 if (p && p != q) {
293                         set_inverse_transl(vc_cons[i].d, p, USER_MAP);
294                         set_inverse_trans_unicode(vc_cons[i].d, p);
295                         q = p;
296                 }
297         }
298 }
299
300 /*
301  * Load customizable translation table
302  * arg points to a 256 byte translation table.
303  *
304  * The "old" variants are for translation directly to font (using the
305  * 0xf000-0xf0ff "transparent" Unicodes) whereas the "new" variants set
306  * Unicodes explicitly.
307  */
308 int con_set_trans_old(unsigned char __user * arg)
309 {
310         int i;
311         unsigned short *p = translations[USER_MAP];
312
313         if (!access_ok(VERIFY_READ, arg, E_TABSZ))
314                 return -EFAULT;
315
316         for (i=0; i<E_TABSZ ; i++) {
317                 unsigned char uc;
318                 __get_user(uc, arg+i);
319                 p[i] = UNI_DIRECT_BASE | uc;
320         }
321
322         update_user_maps();
323         return 0;
324 }
325
326 int con_get_trans_old(unsigned char __user * arg)
327 {
328         int i, ch;
329         unsigned short *p = translations[USER_MAP];
330
331         if (!access_ok(VERIFY_WRITE, arg, E_TABSZ))
332                 return -EFAULT;
333
334         for (i=0; i<E_TABSZ ; i++)
335           {
336             ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
337             __put_user((ch & ~0xff) ? 0 : ch, arg+i);
338           }
339         return 0;
340 }
341
342 int con_set_trans_new(ushort __user * arg)
343 {
344         int i;
345         unsigned short *p = translations[USER_MAP];
346
347         if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short)))
348                 return -EFAULT;
349
350         for (i=0; i<E_TABSZ ; i++) {
351                 unsigned short us;
352                 __get_user(us, arg+i);
353                 p[i] = us;
354         }
355
356         update_user_maps();
357         return 0;
358 }
359
360 int con_get_trans_new(ushort __user * arg)
361 {
362         int i;
363         unsigned short *p = translations[USER_MAP];
364
365         if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short)))
366                 return -EFAULT;
367
368         for (i=0; i<E_TABSZ ; i++)
369           __put_user(p[i], arg+i);
370         
371         return 0;
372 }
373
374 /*
375  * Unicode -> current font conversion 
376  *
377  * A font has at most 512 chars, usually 256.
378  * But one font position may represent several Unicode chars.
379  * A hashtable is somewhat of a pain to deal with, so use a
380  * "paged table" instead.  Simulation has shown the memory cost of
381  * this 3-level paged table scheme to be comparable to a hash table.
382  */
383
384 extern u8 dfont_unicount[];     /* Defined in console_defmap.c */
385 extern u16 dfont_unitable[];
386
387 static void con_release_unimap(struct uni_pagedir *p)
388 {
389         u16 **p1;
390         int i, j;
391
392         if (p == dflt) dflt = NULL;  
393         for (i = 0; i < 32; i++) {
394                 if ((p1 = p->uni_pgdir[i]) != NULL) {
395                         for (j = 0; j < 32; j++)
396                                 kfree(p1[j]);
397                         kfree(p1);
398                 }
399                 p->uni_pgdir[i] = NULL;
400         }
401         for (i = 0; i < 4; i++) {
402                 kfree(p->inverse_translations[i]);
403                 p->inverse_translations[i] = NULL;
404         }
405         if (p->inverse_trans_unicode) {
406                 kfree(p->inverse_trans_unicode);
407                 p->inverse_trans_unicode = NULL;
408         }
409 }
410
411 void con_free_unimap(struct vc_data *vc)
412 {
413         struct uni_pagedir *p;
414
415         p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
416         if (!p)
417                 return;
418         *vc->vc_uni_pagedir_loc = 0;
419         if (--p->refcount)
420                 return;
421         con_release_unimap(p);
422         kfree(p);
423 }
424   
425 static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
426 {
427         int i, j, k;
428         struct uni_pagedir *q;
429         
430         for (i = 0; i < MAX_NR_CONSOLES; i++) {
431                 if (!vc_cons_allocated(i))
432                         continue;
433                 q = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
434                 if (!q || q == p || q->sum != p->sum)
435                         continue;
436                 for (j = 0; j < 32; j++) {
437                         u16 **p1, **q1;
438                         p1 = p->uni_pgdir[j]; q1 = q->uni_pgdir[j];
439                         if (!p1 && !q1)
440                                 continue;
441                         if (!p1 || !q1)
442                                 break;
443                         for (k = 0; k < 32; k++) {
444                                 if (!p1[k] && !q1[k])
445                                         continue;
446                                 if (!p1[k] || !q1[k])
447                                         break;
448                                 if (memcmp(p1[k], q1[k], 64*sizeof(u16)))
449                                         break;
450                         }
451                         if (k < 32)
452                                 break;
453                 }
454                 if (j == 32) {
455                         q->refcount++;
456                         *conp->vc_uni_pagedir_loc = (unsigned long)q;
457                         con_release_unimap(p);
458                         kfree(p);
459                         return 1;
460                 }
461         }
462         return 0;
463 }
464
465 static int
466 con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
467 {
468         int i, n;
469         u16 **p1, *p2;
470
471         if (!(p1 = p->uni_pgdir[n = unicode >> 11])) {
472                 p1 = p->uni_pgdir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL);
473                 if (!p1) return -ENOMEM;
474                 for (i = 0; i < 32; i++)
475                         p1[i] = NULL;
476         }
477
478         if (!(p2 = p1[n = (unicode >> 6) & 0x1f])) {
479                 p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL);
480                 if (!p2) return -ENOMEM;
481
482                 /* WORKAROUND: This delay time prevent NULL point error. */
483                 udelay(1);
484
485                 memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */
486         }
487
488         p2[unicode & 0x3f] = fontpos;
489         
490         p->sum += (fontpos << 20) + unicode;
491
492         return 0;
493 }
494
495 /* ui is a leftover from using a hashtable, but might be used again */
496 int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
497 {
498         struct uni_pagedir *p, *q;
499   
500         p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
501         if (p && p->readonly) return -EIO;
502         if (!p || --p->refcount) {
503                 q = kzalloc(sizeof(*p), GFP_KERNEL);
504                 if (!q) {
505                         if (p) p->refcount++;
506                         return -ENOMEM;
507                 }
508                 q->refcount=1;
509                 *vc->vc_uni_pagedir_loc = (unsigned long)q;
510         } else {
511                 if (p == dflt) dflt = NULL;
512                 p->refcount++;
513                 p->sum = 0;
514                 con_release_unimap(p);
515         }
516         return 0;
517 }
518
519 int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
520 {
521         int err = 0, err1, i;
522         struct uni_pagedir *p, *q;
523
524         /* Save original vc_unipagdir_loc in case we allocate a new one */
525         p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
526         if (p->readonly) return -EIO;
527         
528         if (!ct) return 0;
529         
530         if (p->refcount > 1) {
531                 int j, k;
532                 u16 **p1, *p2, l;
533                 
534                 err1 = con_clear_unimap(vc, NULL);
535                 if (err1) return err1;
536                 
537                 /*
538                  * Since refcount was > 1, con_clear_unimap() allocated a
539                  * a new uni_pagedir for this vc.  Re: p != q
540                  */
541                 q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
542
543                 /*
544                  * uni_pgdir is a 32*32*64 table with rows allocated
545                  * when its first entry is added.  The unicode value must
546                  * still be incremented for empty rows.  We are copying
547                  * entries from "p" (old) to "q" (new).
548                  */
549                 l = 0;          /* unicode value */
550                 for (i = 0; i < 32; i++)
551                 if ((p1 = p->uni_pgdir[i]))
552                         for (j = 0; j < 32; j++)
553                         if ((p2 = p1[j])) {
554                                 for (k = 0; k < 64; k++, l++)
555                                 if (p2[k] != 0xffff) {
556                                         /*
557                                          * Found one, copy entry for unicode
558                                          * l with fontpos value p2[k].
559                                          */
560                                         err1 = con_insert_unipair(q, l, p2[k]);
561                                         if (err1) {
562                                                 p->refcount++;
563                                                 *vc->vc_uni_pagedir_loc = (unsigned long)p;
564                                                 con_release_unimap(q);
565                                                 kfree(q);
566                                                 return err1;
567                                         }
568                                 }
569                         } else {
570                                 /* Account for row of 64 empty entries */
571                                 l += 64;
572                         }
573                 else
574                         /* Account for empty table */
575                         l += 32 * 64;
576
577                 /*
578                  * Finished copying font table, set vc_uni_pagedir to new table
579                  */
580                 p = q;
581         } else if (p == dflt) {
582                 dflt = NULL;
583         }
584
585         /*
586          * Insert user specified unicode pairs into new table.
587          */
588         while (ct--) {
589                 unsigned short unicode, fontpos;
590                 __get_user(unicode, &list->unicode);
591                 __get_user(fontpos, &list->fontpos);
592                 if ((err1 = con_insert_unipair(p, unicode,fontpos)) != 0)
593                         err = err1;
594                 list++;
595         }
596         
597         /*
598          * Merge with fontmaps of any other virtual consoles.
599          */
600         if (con_unify_unimap(vc, p))
601                 return err;
602
603         for (i = 0; i <= 3; i++)
604                 set_inverse_transl(vc, p, i); /* Update inverse translations */
605         set_inverse_trans_unicode(vc, p);
606   
607         return err;
608 }
609
610 /* Loads the unimap for the hardware font, as defined in uni_hash.tbl.
611    The representation used was the most compact I could come up
612    with.  This routine is executed at sys_setup time, and when the
613    PIO_FONTRESET ioctl is called. */
614
615 int con_set_default_unimap(struct vc_data *vc)
616 {
617         int i, j, err = 0, err1;
618         u16 *q;
619         struct uni_pagedir *p;
620
621         if (dflt) {
622                 p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
623                 if (p == dflt)
624                         return 0;
625                 dflt->refcount++;
626                 *vc->vc_uni_pagedir_loc = (unsigned long)dflt;
627                 if (p && --p->refcount) {
628                         con_release_unimap(p);
629                         kfree(p);
630                 }
631                 return 0;
632         }
633         
634         /* The default font is always 256 characters */
635
636         err = con_clear_unimap(vc, NULL);
637         if (err) return err;
638     
639         p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
640         q = dfont_unitable;
641         
642         for (i = 0; i < 256; i++)
643                 for (j = dfont_unicount[i]; j; j--) {
644                         err1 = con_insert_unipair(p, *(q++), i);
645                         if (err1)
646                                 err = err1;
647                 }
648                         
649         if (con_unify_unimap(vc, p)) {
650                 dflt = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
651                 return err;
652         }
653
654         for (i = 0; i <= 3; i++)
655                 set_inverse_transl(vc, p, i);   /* Update all inverse translations */
656         set_inverse_trans_unicode(vc, p);
657         dflt = p;
658         return err;
659 }
660 EXPORT_SYMBOL(con_set_default_unimap);
661
662 int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
663 {
664         struct uni_pagedir *q;
665
666         if (!*src_vc->vc_uni_pagedir_loc)
667                 return -EINVAL;
668         if (*dst_vc->vc_uni_pagedir_loc == *src_vc->vc_uni_pagedir_loc)
669                 return 0;
670         con_free_unimap(dst_vc);
671         q = (struct uni_pagedir *)*src_vc->vc_uni_pagedir_loc;
672         q->refcount++;
673         *dst_vc->vc_uni_pagedir_loc = (long)q;
674         return 0;
675 }
676
677 int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list)
678 {
679         int i, j, k, ect;
680         u16 **p1, *p2;
681         struct uni_pagedir *p;
682
683         ect = 0;
684         if (*vc->vc_uni_pagedir_loc) {
685                 p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
686                 for (i = 0; i < 32; i++)
687                 if ((p1 = p->uni_pgdir[i]))
688                         for (j = 0; j < 32; j++)
689                         if ((p2 = *(p1++)))
690                                 for (k = 0; k < 64; k++) {
691                                         if (*p2 < MAX_GLYPH && ect++ < ct) {
692                                                 __put_user((u_short)((i<<11)+(j<<6)+k),
693                                                            &list->unicode);
694                                                 __put_user((u_short) *p2, 
695                                                            &list->fontpos);
696                                                 list++;
697                                         }
698                                         p2++;
699                                 }
700         }
701         __put_user(ect, uct);
702         return ((ect <= ct) ? 0 : -ENOMEM);
703 }
704
705 void con_protect_unimap(struct vc_data *vc, int rdonly)
706 {
707         struct uni_pagedir *p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
708         
709         if (p)
710                 p->readonly = rdonly;
711 }
712
713 /*
714  * Always use USER_MAP. These functions are used by the keyboard,
715  * which shouldn't be affected by G0/G1 switching, etc.
716  * If the user map still contains default values, i.e. the
717  * direct-to-font mapping, then assume user is using Latin1.
718  */
719 /* may be called during an interrupt */
720 u32 conv_8bit_to_uni(unsigned char c)
721 {
722         unsigned short uni = translations[USER_MAP][c];
723         return uni == (0xf000 | c) ? c : uni;
724 }
725
726 int conv_uni_to_8bit(u32 uni)
727 {
728         int c;
729         for (c = 0; c < 0x100; c++)
730                 if (translations[USER_MAP][c] == uni ||
731                    (translations[USER_MAP][c] == (c | 0xf000) && uni == c))
732                         return c;
733         return -1;
734 }
735
736 int
737 conv_uni_to_pc(struct vc_data *conp, long ucs) 
738 {
739         int h;
740         u16 **p1, *p2;
741         struct uni_pagedir *p;
742   
743         /* Only 16-bit codes supported at this time */
744         if (ucs > 0xffff)
745                 return -4;              /* Not found */
746         else if (ucs < 0x20)
747                 return -1;              /* Not a printable character */
748         else if (ucs == 0xfeff || (ucs >= 0x200b && ucs <= 0x200f))
749                 return -2;                      /* Zero-width space */
750         /*
751          * UNI_DIRECT_BASE indicates the start of the region in the User Zone
752          * which always has a 1:1 mapping to the currently loaded font.  The
753          * UNI_DIRECT_MASK indicates the bit span of the region.
754          */
755         else if ((ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE)
756                 return ucs & UNI_DIRECT_MASK;
757   
758         if (!*conp->vc_uni_pagedir_loc)
759                 return -3;
760
761         p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;  
762         if ((p1 = p->uni_pgdir[ucs >> 11]) &&
763             (p2 = p1[(ucs >> 6) & 0x1f]) &&
764             (h = p2[ucs & 0x3f]) < MAX_GLYPH)
765                 return h;
766
767         return -4;              /* not found */
768 }
769
770 /*
771  * This is called at sys_setup time, after memory and the console are
772  * initialized.  It must be possible to call kmalloc(..., GFP_KERNEL)
773  * from this function, hence the call from sys_setup.
774  */
775 void __init 
776 console_map_init(void)
777 {
778         int i;
779         
780         for (i = 0; i < MAX_NR_CONSOLES; i++)
781                 if (vc_cons_allocated(i) && !*vc_cons[i].d->vc_uni_pagedir_loc)
782                         con_set_default_unimap(vc_cons[i].d);
783 }
784
785 EXPORT_SYMBOL(con_copy_unimap);