Linux-2.6.12-rc2
[safe/jmp/linux-2.6] / 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                                 if (p1[j])
349                                         kfree(p1[j]);
350                         kfree(p1);
351                 }
352                 p->uni_pgdir[i] = NULL;
353         }
354         for (i = 0; i < 4; i++)
355                 if (p->inverse_translations[i]) {
356                         kfree(p->inverse_translations[i]);
357                         p->inverse_translations[i] = NULL;
358                 }
359 }
360
361 void con_free_unimap(struct vc_data *vc)
362 {
363         struct uni_pagedir *p;
364
365         p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
366         if (!p)
367                 return;
368         *vc->vc_uni_pagedir_loc = 0;
369         if (--p->refcount)
370                 return;
371         con_release_unimap(p);
372         kfree(p);
373 }
374   
375 static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
376 {
377         int i, j, k;
378         struct uni_pagedir *q;
379         
380         for (i = 0; i < MAX_NR_CONSOLES; i++) {
381                 if (!vc_cons_allocated(i))
382                         continue;
383                 q = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
384                 if (!q || q == p || q->sum != p->sum)
385                         continue;
386                 for (j = 0; j < 32; j++) {
387                         u16 **p1, **q1;
388                         p1 = p->uni_pgdir[j]; q1 = q->uni_pgdir[j];
389                         if (!p1 && !q1)
390                                 continue;
391                         if (!p1 || !q1)
392                                 break;
393                         for (k = 0; k < 32; k++) {
394                                 if (!p1[k] && !q1[k])
395                                         continue;
396                                 if (!p1[k] || !q1[k])
397                                         break;
398                                 if (memcmp(p1[k], q1[k], 64*sizeof(u16)))
399                                         break;
400                         }
401                         if (k < 32)
402                                 break;
403                 }
404                 if (j == 32) {
405                         q->refcount++;
406                         *conp->vc_uni_pagedir_loc = (unsigned long)q;
407                         con_release_unimap(p);
408                         kfree(p);
409                         return 1;
410                 }
411         }
412         return 0;
413 }
414
415 static int
416 con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
417 {
418         int i, n;
419         u16 **p1, *p2;
420
421         if (!(p1 = p->uni_pgdir[n = unicode >> 11])) {
422                 p1 = p->uni_pgdir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL);
423                 if (!p1) return -ENOMEM;
424                 for (i = 0; i < 32; i++)
425                         p1[i] = NULL;
426         }
427
428         if (!(p2 = p1[n = (unicode >> 6) & 0x1f])) {
429                 p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL);
430                 if (!p2) return -ENOMEM;
431                 memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */
432         }
433
434         p2[unicode & 0x3f] = fontpos;
435         
436         p->sum += (fontpos << 20) + unicode;
437
438         return 0;
439 }
440
441 /* ui is a leftover from using a hashtable, but might be used again */
442 int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
443 {
444         struct uni_pagedir *p, *q;
445   
446         p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
447         if (p && p->readonly) return -EIO;
448         if (!p || --p->refcount) {
449                 q = (struct uni_pagedir *)kmalloc(sizeof(*p), GFP_KERNEL);
450                 if (!q) {
451                         if (p) p->refcount++;
452                         return -ENOMEM;
453                 }
454                 memset(q, 0, sizeof(*q));
455                 q->refcount=1;
456                 *vc->vc_uni_pagedir_loc = (unsigned long)q;
457         } else {
458                 if (p == dflt) dflt = NULL;
459                 p->refcount++;
460                 p->sum = 0;
461                 con_release_unimap(p);
462         }
463         return 0;
464 }
465
466 int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
467 {
468         int err = 0, err1, i;
469         struct uni_pagedir *p, *q;
470
471         p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
472         if (p->readonly) return -EIO;
473         
474         if (!ct) return 0;
475         
476         if (p->refcount > 1) {
477                 int j, k;
478                 u16 **p1, *p2, l;
479                 
480                 err1 = con_clear_unimap(vc, NULL);
481                 if (err1) return err1;
482                 
483                 q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
484                 for (i = 0, l = 0; i < 32; i++)
485                 if ((p1 = p->uni_pgdir[i]))
486                         for (j = 0; j < 32; j++)
487                         if ((p2 = p1[j]))
488                                 for (k = 0; k < 64; k++, l++)
489                                 if (p2[k] != 0xffff) {
490                                         err1 = con_insert_unipair(q, l, p2[k]);
491                                         if (err1) {
492                                                 p->refcount++;
493                                                 *vc->vc_uni_pagedir_loc = (unsigned long)p;
494                                                 con_release_unimap(q);
495                                                 kfree(q);
496                                                 return err1; 
497                                         }
498                                 }
499                 p = q;
500         } else if (p == dflt)
501                 dflt = NULL;
502         
503         while (ct--) {
504                 unsigned short unicode, fontpos;
505                 __get_user(unicode, &list->unicode);
506                 __get_user(fontpos, &list->fontpos);
507                 if ((err1 = con_insert_unipair(p, unicode,fontpos)) != 0)
508                         err = err1;
509                         list++;
510         }
511         
512         if (con_unify_unimap(vc, p))
513                 return err;
514
515         for (i = 0; i <= 3; i++)
516                 set_inverse_transl(vc, p, i); /* Update all inverse translations */
517   
518         return err;
519 }
520
521 /* Loads the unimap for the hardware font, as defined in uni_hash.tbl.
522    The representation used was the most compact I could come up
523    with.  This routine is executed at sys_setup time, and when the
524    PIO_FONTRESET ioctl is called. */
525
526 int con_set_default_unimap(struct vc_data *vc)
527 {
528         int i, j, err = 0, err1;
529         u16 *q;
530         struct uni_pagedir *p;
531
532         if (dflt) {
533                 p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
534                 if (p == dflt)
535                         return 0;
536                 dflt->refcount++;
537                 *vc->vc_uni_pagedir_loc = (unsigned long)dflt;
538                 if (p && --p->refcount) {
539                         con_release_unimap(p);
540                         kfree(p);
541                 }
542                 return 0;
543         }
544         
545         /* The default font is always 256 characters */
546
547         err = con_clear_unimap(vc, NULL);
548         if (err) return err;
549     
550         p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
551         q = dfont_unitable;
552         
553         for (i = 0; i < 256; i++)
554                 for (j = dfont_unicount[i]; j; j--) {
555                         err1 = con_insert_unipair(p, *(q++), i);
556                         if (err1)
557                                 err = err1;
558                 }
559                         
560         if (con_unify_unimap(vc, p)) {
561                 dflt = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
562                 return err;
563         }
564
565         for (i = 0; i <= 3; i++)
566                 set_inverse_transl(vc, p, i);   /* Update all inverse translations */
567         dflt = p;
568         return err;
569 }
570 EXPORT_SYMBOL(con_set_default_unimap);
571
572 int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
573 {
574         struct uni_pagedir *q;
575
576         if (!*src_vc->vc_uni_pagedir_loc)
577                 return -EINVAL;
578         if (*dst_vc->vc_uni_pagedir_loc == *src_vc->vc_uni_pagedir_loc)
579                 return 0;
580         con_free_unimap(dst_vc);
581         q = (struct uni_pagedir *)*src_vc->vc_uni_pagedir_loc;
582         q->refcount++;
583         *dst_vc->vc_uni_pagedir_loc = (long)q;
584         return 0;
585 }
586
587 int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list)
588 {
589         int i, j, k, ect;
590         u16 **p1, *p2;
591         struct uni_pagedir *p;
592
593         ect = 0;
594         if (*vc->vc_uni_pagedir_loc) {
595                 p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
596                 for (i = 0; i < 32; i++)
597                 if ((p1 = p->uni_pgdir[i]))
598                         for (j = 0; j < 32; j++)
599                         if ((p2 = *(p1++)))
600                                 for (k = 0; k < 64; k++) {
601                                         if (*p2 < MAX_GLYPH && ect++ < ct) {
602                                                 __put_user((u_short)((i<<11)+(j<<6)+k),
603                                                            &list->unicode);
604                                                 __put_user((u_short) *p2, 
605                                                            &list->fontpos);
606                                                 list++;
607                                         }
608                                         p2++;
609                                 }
610         }
611         __put_user(ect, uct);
612         return ((ect <= ct) ? 0 : -ENOMEM);
613 }
614
615 void con_protect_unimap(struct vc_data *vc, int rdonly)
616 {
617         struct uni_pagedir *p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
618         
619         if (p)
620                 p->readonly = rdonly;
621 }
622
623 int
624 conv_uni_to_pc(struct vc_data *conp, long ucs) 
625 {
626         int h;
627         u16 **p1, *p2;
628         struct uni_pagedir *p;
629   
630         /* Only 16-bit codes supported at this time */
631         if (ucs > 0xffff)
632                 ucs = 0xfffd;           /* U+FFFD: REPLACEMENT CHARACTER */
633         else if (ucs < 0x20 || ucs >= 0xfffe)
634                 return -1;              /* Not a printable character */
635         else if (ucs == 0xfeff || (ucs >= 0x200a && ucs <= 0x200f))
636                 return -2;                      /* Zero-width space */
637         /*
638          * UNI_DIRECT_BASE indicates the start of the region in the User Zone
639          * which always has a 1:1 mapping to the currently loaded font.  The
640          * UNI_DIRECT_MASK indicates the bit span of the region.
641          */
642         else if ((ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE)
643                 return ucs & UNI_DIRECT_MASK;
644   
645         if (!*conp->vc_uni_pagedir_loc)
646                 return -3;
647
648         p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;  
649         if ((p1 = p->uni_pgdir[ucs >> 11]) &&
650             (p2 = p1[(ucs >> 6) & 0x1f]) &&
651             (h = p2[ucs & 0x3f]) < MAX_GLYPH)
652                 return h;
653
654         return -4;              /* not found */
655 }
656
657 /*
658  * This is called at sys_setup time, after memory and the console are
659  * initialized.  It must be possible to call kmalloc(..., GFP_KERNEL)
660  * from this function, hence the call from sys_setup.
661  */
662 void __init 
663 console_map_init(void)
664 {
665         int i;
666         
667         for (i = 0; i < MAX_NR_CONSOLES; i++)
668                 if (vc_cons_allocated(i) && !*vc_cons[i].d->vc_uni_pagedir_loc)
669                         con_set_default_unimap(vc_cons[i].d);
670 }
671
672 EXPORT_SYMBOL(con_copy_unimap);