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