Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / char / 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/config.h>
15 #include <linux/module.h>
16 #include <linux/kd.h>
17 #include <linux/errno.h>
18 #include <linux/mm.h>
19 #include <linux/slab.h>
20 #include <linux/init.h>
21 #include <linux/tty.h>
22 #include <asm/uaccess.h>
23 #include <linux/consolemap.h>
24 #include <linux/vt_kern.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         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 unsigned short *set_translate(int m, struct vc_data *vc)
212 {
213         inv_translate[vc->vc_num] = m;
214         return translations[m];
215 }
216
217 /*
218  * Inverse translation is impossible for several reasons:
219  * 1. The font<->character maps are not 1-1.
220  * 2. The text may have been written while a different translation map
221  *    was active, or using Unicode.
222  * Still, it is now possible to a certain extent to cut and paste non-ASCII.
223  */
224 unsigned char inverse_translate(struct vc_data *conp, int glyph)
225 {
226         struct uni_pagedir *p;
227         if (glyph < 0 || glyph >= MAX_GLYPH)
228                 return 0;
229         else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc) ||
230                  !p->inverse_translations[inv_translate[conp->vc_num]])
231                 return glyph;
232         else
233                 return p->inverse_translations[inv_translate[conp->vc_num]][glyph];
234 }
235
236 static void update_user_maps(void)
237 {
238         int i;
239         struct uni_pagedir *p, *q = NULL;
240         
241         for (i = 0; i < MAX_NR_CONSOLES; i++) {
242                 if (!vc_cons_allocated(i))
243                         continue;
244                 p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
245                 if (p && p != q) {
246                         set_inverse_transl(vc_cons[i].d, p, USER_MAP);
247                         q = p;
248                 }
249         }
250 }
251
252 /*
253  * Load customizable translation table
254  * arg points to a 256 byte translation table.
255  *
256  * The "old" variants are for translation directly to font (using the
257  * 0xf000-0xf0ff "transparent" Unicodes) whereas the "new" variants set
258  * Unicodes explicitly.
259  */
260 int con_set_trans_old(unsigned char __user * arg)
261 {
262         int i;
263         unsigned short *p = translations[USER_MAP];
264
265         if (!access_ok(VERIFY_READ, arg, E_TABSZ))
266                 return -EFAULT;
267
268         for (i=0; i<E_TABSZ ; i++) {
269                 unsigned char uc;
270                 __get_user(uc, arg+i);
271                 p[i] = UNI_DIRECT_BASE | uc;
272         }
273
274         update_user_maps();
275         return 0;
276 }
277
278 int con_get_trans_old(unsigned char __user * arg)
279 {
280         int i, ch;
281         unsigned short *p = translations[USER_MAP];
282
283         if (!access_ok(VERIFY_WRITE, arg, E_TABSZ))
284                 return -EFAULT;
285
286         for (i=0; i<E_TABSZ ; i++)
287           {
288             ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
289             __put_user((ch & ~0xff) ? 0 : ch, arg+i);
290           }
291         return 0;
292 }
293
294 int con_set_trans_new(ushort __user * arg)
295 {
296         int i;
297         unsigned short *p = translations[USER_MAP];
298
299         if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short)))
300                 return -EFAULT;
301
302         for (i=0; i<E_TABSZ ; i++) {
303                 unsigned short us;
304                 __get_user(us, arg+i);
305                 p[i] = us;
306         }
307
308         update_user_maps();
309         return 0;
310 }
311
312 int con_get_trans_new(ushort __user * arg)
313 {
314         int i;
315         unsigned short *p = translations[USER_MAP];
316
317         if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short)))
318                 return -EFAULT;
319
320         for (i=0; i<E_TABSZ ; i++)
321           __put_user(p[i], arg+i);
322         
323         return 0;
324 }
325
326 /*
327  * Unicode -> current font conversion 
328  *
329  * A font has at most 512 chars, usually 256.
330  * But one font position may represent several Unicode chars.
331  * A hashtable is somewhat of a pain to deal with, so use a
332  * "paged table" instead.  Simulation has shown the memory cost of
333  * this 3-level paged table scheme to be comparable to a hash table.
334  */
335
336 extern u8 dfont_unicount[];     /* Defined in console_defmap.c */
337 extern u16 dfont_unitable[];
338
339 static void con_release_unimap(struct uni_pagedir *p)
340 {
341         u16 **p1;
342         int i, j;
343
344         if (p == dflt) dflt = NULL;  
345         for (i = 0; i < 32; i++) {
346                 if ((p1 = p->uni_pgdir[i]) != NULL) {
347                         for (j = 0; j < 32; j++)
348                                 kfree(p1[j]);
349                         kfree(p1);
350                 }
351                 p->uni_pgdir[i] = NULL;
352         }
353         for (i = 0; i < 4; i++) {
354                 kfree(p->inverse_translations[i]);
355                 p->inverse_translations[i] = NULL;
356         }
357 }
358
359 void con_free_unimap(struct vc_data *vc)
360 {
361         struct uni_pagedir *p;
362
363         p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
364         if (!p)
365                 return;
366         *vc->vc_uni_pagedir_loc = 0;
367         if (--p->refcount)
368                 return;
369         con_release_unimap(p);
370         kfree(p);
371 }
372   
373 static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
374 {
375         int i, j, k;
376         struct uni_pagedir *q;
377         
378         for (i = 0; i < MAX_NR_CONSOLES; i++) {
379                 if (!vc_cons_allocated(i))
380                         continue;
381                 q = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
382                 if (!q || q == p || q->sum != p->sum)
383                         continue;
384                 for (j = 0; j < 32; j++) {
385                         u16 **p1, **q1;
386                         p1 = p->uni_pgdir[j]; q1 = q->uni_pgdir[j];
387                         if (!p1 && !q1)
388                                 continue;
389                         if (!p1 || !q1)
390                                 break;
391                         for (k = 0; k < 32; k++) {
392                                 if (!p1[k] && !q1[k])
393                                         continue;
394                                 if (!p1[k] || !q1[k])
395                                         break;
396                                 if (memcmp(p1[k], q1[k], 64*sizeof(u16)))
397                                         break;
398                         }
399                         if (k < 32)
400                                 break;
401                 }
402                 if (j == 32) {
403                         q->refcount++;
404                         *conp->vc_uni_pagedir_loc = (unsigned long)q;
405                         con_release_unimap(p);
406                         kfree(p);
407                         return 1;
408                 }
409         }
410         return 0;
411 }
412
413 static int
414 con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
415 {
416         int i, n;
417         u16 **p1, *p2;
418
419         if (!(p1 = p->uni_pgdir[n = unicode >> 11])) {
420                 p1 = p->uni_pgdir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL);
421                 if (!p1) return -ENOMEM;
422                 for (i = 0; i < 32; i++)
423                         p1[i] = NULL;
424         }
425
426         if (!(p2 = p1[n = (unicode >> 6) & 0x1f])) {
427                 p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL);
428                 if (!p2) return -ENOMEM;
429                 memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */
430         }
431
432         p2[unicode & 0x3f] = fontpos;
433         
434         p->sum += (fontpos << 20) + unicode;
435
436         return 0;
437 }
438
439 /* ui is a leftover from using a hashtable, but might be used again */
440 int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
441 {
442         struct uni_pagedir *p, *q;
443   
444         p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
445         if (p && p->readonly) return -EIO;
446         if (!p || --p->refcount) {
447                 q = (struct uni_pagedir *)kmalloc(sizeof(*p), GFP_KERNEL);
448                 if (!q) {
449                         if (p) p->refcount++;
450                         return -ENOMEM;
451                 }
452                 memset(q, 0, sizeof(*q));
453                 q->refcount=1;
454                 *vc->vc_uni_pagedir_loc = (unsigned long)q;
455         } else {
456                 if (p == dflt) dflt = NULL;
457                 p->refcount++;
458                 p->sum = 0;
459                 con_release_unimap(p);
460         }
461         return 0;
462 }
463
464 int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
465 {
466         int err = 0, err1, i;
467         struct uni_pagedir *p, *q;
468
469         p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
470         if (p->readonly) return -EIO;
471         
472         if (!ct) return 0;
473         
474         if (p->refcount > 1) {
475                 int j, k;
476                 u16 **p1, *p2, l;
477                 
478                 err1 = con_clear_unimap(vc, NULL);
479                 if (err1) return err1;
480                 
481                 q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
482                 for (i = 0, l = 0; i < 32; i++)
483                 if ((p1 = p->uni_pgdir[i]))
484                         for (j = 0; j < 32; j++)
485                         if ((p2 = p1[j]))
486                                 for (k = 0; k < 64; k++, l++)
487                                 if (p2[k] != 0xffff) {
488                                         err1 = con_insert_unipair(q, l, p2[k]);
489                                         if (err1) {
490                                                 p->refcount++;
491                                                 *vc->vc_uni_pagedir_loc = (unsigned long)p;
492                                                 con_release_unimap(q);
493                                                 kfree(q);
494                                                 return err1; 
495                                         }
496                                 }
497                 p = q;
498         } else if (p == dflt)
499                 dflt = NULL;
500         
501         while (ct--) {
502                 unsigned short unicode, fontpos;
503                 __get_user(unicode, &list->unicode);
504                 __get_user(fontpos, &list->fontpos);
505                 if ((err1 = con_insert_unipair(p, unicode,fontpos)) != 0)
506                         err = err1;
507                         list++;
508         }
509         
510         if (con_unify_unimap(vc, p))
511                 return err;
512
513         for (i = 0; i <= 3; i++)
514                 set_inverse_transl(vc, p, i); /* Update all inverse translations */
515   
516         return err;
517 }
518
519 /* Loads the unimap for the hardware font, as defined in uni_hash.tbl.
520    The representation used was the most compact I could come up
521    with.  This routine is executed at sys_setup time, and when the
522    PIO_FONTRESET ioctl is called. */
523
524 int con_set_default_unimap(struct vc_data *vc)
525 {
526         int i, j, err = 0, err1;
527         u16 *q;
528         struct uni_pagedir *p;
529
530         if (dflt) {
531                 p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
532                 if (p == dflt)
533                         return 0;
534                 dflt->refcount++;
535                 *vc->vc_uni_pagedir_loc = (unsigned long)dflt;
536                 if (p && --p->refcount) {
537                         con_release_unimap(p);
538                         kfree(p);
539                 }
540                 return 0;
541         }
542         
543         /* The default font is always 256 characters */
544
545         err = con_clear_unimap(vc, NULL);
546         if (err) return err;
547     
548         p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
549         q = dfont_unitable;
550         
551         for (i = 0; i < 256; i++)
552                 for (j = dfont_unicount[i]; j; j--) {
553                         err1 = con_insert_unipair(p, *(q++), i);
554                         if (err1)
555                                 err = err1;
556                 }
557                         
558         if (con_unify_unimap(vc, p)) {
559                 dflt = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
560                 return err;
561         }
562
563         for (i = 0; i <= 3; i++)
564                 set_inverse_transl(vc, p, i);   /* Update all inverse translations */
565         dflt = p;
566         return err;
567 }
568 EXPORT_SYMBOL(con_set_default_unimap);
569
570 int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
571 {
572         struct uni_pagedir *q;
573
574         if (!*src_vc->vc_uni_pagedir_loc)
575                 return -EINVAL;
576         if (*dst_vc->vc_uni_pagedir_loc == *src_vc->vc_uni_pagedir_loc)
577                 return 0;
578         con_free_unimap(dst_vc);
579         q = (struct uni_pagedir *)*src_vc->vc_uni_pagedir_loc;
580         q->refcount++;
581         *dst_vc->vc_uni_pagedir_loc = (long)q;
582         return 0;
583 }
584
585 int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list)
586 {
587         int i, j, k, ect;
588         u16 **p1, *p2;
589         struct uni_pagedir *p;
590
591         ect = 0;
592         if (*vc->vc_uni_pagedir_loc) {
593                 p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
594                 for (i = 0; i < 32; i++)
595                 if ((p1 = p->uni_pgdir[i]))
596                         for (j = 0; j < 32; j++)
597                         if ((p2 = *(p1++)))
598                                 for (k = 0; k < 64; k++) {
599                                         if (*p2 < MAX_GLYPH && ect++ < ct) {
600                                                 __put_user((u_short)((i<<11)+(j<<6)+k),
601                                                            &list->unicode);
602                                                 __put_user((u_short) *p2, 
603                                                            &list->fontpos);
604                                                 list++;
605                                         }
606                                         p2++;
607                                 }
608         }
609         __put_user(ect, uct);
610         return ((ect <= ct) ? 0 : -ENOMEM);
611 }
612
613 void con_protect_unimap(struct vc_data *vc, int rdonly)
614 {
615         struct uni_pagedir *p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
616         
617         if (p)
618                 p->readonly = rdonly;
619 }
620
621 int
622 conv_uni_to_pc(struct vc_data *conp, long ucs) 
623 {
624         int h;
625         u16 **p1, *p2;
626         struct uni_pagedir *p;
627   
628         /* Only 16-bit codes supported at this time */
629         if (ucs > 0xffff)
630                 ucs = 0xfffd;           /* U+FFFD: REPLACEMENT CHARACTER */
631         else if (ucs < 0x20 || ucs >= 0xfffe)
632                 return -1;              /* Not a printable character */
633         else if (ucs == 0xfeff || (ucs >= 0x200a && ucs <= 0x200f))
634                 return -2;                      /* Zero-width space */
635         /*
636          * UNI_DIRECT_BASE indicates the start of the region in the User Zone
637          * which always has a 1:1 mapping to the currently loaded font.  The
638          * UNI_DIRECT_MASK indicates the bit span of the region.
639          */
640         else if ((ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE)
641                 return ucs & UNI_DIRECT_MASK;
642   
643         if (!*conp->vc_uni_pagedir_loc)
644                 return -3;
645
646         p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;  
647         if ((p1 = p->uni_pgdir[ucs >> 11]) &&
648             (p2 = p1[(ucs >> 6) & 0x1f]) &&
649             (h = p2[ucs & 0x3f]) < MAX_GLYPH)
650                 return h;
651
652         return -4;              /* not found */
653 }
654
655 /*
656  * This is called at sys_setup time, after memory and the console are
657  * initialized.  It must be possible to call kmalloc(..., GFP_KERNEL)
658  * from this function, hence the call from sys_setup.
659  */
660 void __init 
661 console_map_init(void)
662 {
663         int i;
664         
665         for (i = 0; i < MAX_NR_CONSOLES; i++)
666                 if (vc_cons_allocated(i) && !*vc_cons[i].d->vc_uni_pagedir_loc)
667                         con_set_default_unimap(vc_cons[i].d);
668 }
669
670 EXPORT_SYMBOL(con_copy_unimap);