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