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