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