xref: /openbmc/linux/drivers/tty/vt/consolemap.c (revision 9cdb81c7)
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 	u16		*inverse_trans_unicode;
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 static void set_inverse_trans_unicode(struct vc_data *conp,
212 				      struct uni_pagedir *p)
213 {
214 	int i, j, k, glyph;
215 	u16 **p1, *p2;
216 	u16 *q;
217 
218 	if (!p) return;
219 	q = p->inverse_trans_unicode;
220 	if (!q) {
221 		q = p->inverse_trans_unicode =
222 			kmalloc(MAX_GLYPH * sizeof(u16), GFP_KERNEL);
223 		if (!q)
224 			return;
225 	}
226 	memset(q, 0, MAX_GLYPH * sizeof(u16));
227 
228 	for (i = 0; i < 32; i++) {
229 		p1 = p->uni_pgdir[i];
230 		if (!p1)
231 			continue;
232 		for (j = 0; j < 32; j++) {
233 			p2 = p1[j];
234 			if (!p2)
235 				continue;
236 			for (k = 0; k < 64; k++) {
237 				glyph = p2[k];
238 				if (glyph >= 0 && glyph < MAX_GLYPH
239 					       && q[glyph] < 32)
240 		  			q[glyph] = (i << 11) + (j << 6) + k;
241 			}
242 		}
243 	}
244 }
245 
246 unsigned short *set_translate(int m, struct vc_data *vc)
247 {
248 	inv_translate[vc->vc_num] = m;
249 	return translations[m];
250 }
251 
252 /*
253  * Inverse translation is impossible for several reasons:
254  * 1. The font<->character maps are not 1-1.
255  * 2. The text may have been written while a different translation map
256  *    was active.
257  * Still, it is now possible to a certain extent to cut and paste non-ASCII.
258  */
259 u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode)
260 {
261 	struct uni_pagedir *p;
262 	int m;
263 	if (glyph < 0 || glyph >= MAX_GLYPH)
264 		return 0;
265 	else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc))
266 		return glyph;
267 	else if (use_unicode) {
268 		if (!p->inverse_trans_unicode)
269 			return glyph;
270 		else
271 			return p->inverse_trans_unicode[glyph];
272 	} else {
273 		m = inv_translate[conp->vc_num];
274 		if (!p->inverse_translations[m])
275 			return glyph;
276 		else
277 			return p->inverse_translations[m][glyph];
278 	}
279 }
280 EXPORT_SYMBOL_GPL(inverse_translate);
281 
282 static void update_user_maps(void)
283 {
284 	int i;
285 	struct uni_pagedir *p, *q = NULL;
286 
287 	for (i = 0; i < MAX_NR_CONSOLES; i++) {
288 		if (!vc_cons_allocated(i))
289 			continue;
290 		p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
291 		if (p && p != q) {
292 			set_inverse_transl(vc_cons[i].d, p, USER_MAP);
293 			set_inverse_trans_unicode(vc_cons[i].d, p);
294 			q = p;
295 		}
296 	}
297 }
298 
299 /*
300  * Load customizable translation table
301  * arg points to a 256 byte translation table.
302  *
303  * The "old" variants are for translation directly to font (using the
304  * 0xf000-0xf0ff "transparent" Unicodes) whereas the "new" variants set
305  * Unicodes explicitly.
306  */
307 int con_set_trans_old(unsigned char __user * arg)
308 {
309 	int i;
310 	unsigned short *p = translations[USER_MAP];
311 
312 	if (!access_ok(VERIFY_READ, arg, E_TABSZ))
313 		return -EFAULT;
314 
315 	for (i=0; i<E_TABSZ ; i++) {
316 		unsigned char uc;
317 		__get_user(uc, arg+i);
318 		p[i] = UNI_DIRECT_BASE | uc;
319 	}
320 
321 	update_user_maps();
322 	return 0;
323 }
324 
325 int con_get_trans_old(unsigned char __user * arg)
326 {
327 	int i, ch;
328 	unsigned short *p = translations[USER_MAP];
329 
330 	if (!access_ok(VERIFY_WRITE, arg, E_TABSZ))
331 		return -EFAULT;
332 
333 	for (i=0; i<E_TABSZ ; i++)
334 	  {
335 	    ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
336 	    __put_user((ch & ~0xff) ? 0 : ch, arg+i);
337 	  }
338 	return 0;
339 }
340 
341 int con_set_trans_new(ushort __user * arg)
342 {
343 	int i;
344 	unsigned short *p = translations[USER_MAP];
345 
346 	if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short)))
347 		return -EFAULT;
348 
349 	for (i=0; i<E_TABSZ ; i++) {
350 		unsigned short us;
351 		__get_user(us, arg+i);
352 		p[i] = us;
353 	}
354 
355 	update_user_maps();
356 	return 0;
357 }
358 
359 int con_get_trans_new(ushort __user * arg)
360 {
361 	int i;
362 	unsigned short *p = translations[USER_MAP];
363 
364 	if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short)))
365 		return -EFAULT;
366 
367 	for (i=0; i<E_TABSZ ; i++)
368 	  __put_user(p[i], arg+i);
369 
370 	return 0;
371 }
372 
373 /*
374  * Unicode -> current font conversion
375  *
376  * A font has at most 512 chars, usually 256.
377  * But one font position may represent several Unicode chars.
378  * A hashtable is somewhat of a pain to deal with, so use a
379  * "paged table" instead.  Simulation has shown the memory cost of
380  * this 3-level paged table scheme to be comparable to a hash table.
381  */
382 
383 extern u8 dfont_unicount[];	/* Defined in console_defmap.c */
384 extern u16 dfont_unitable[];
385 
386 static void con_release_unimap(struct uni_pagedir *p)
387 {
388 	u16 **p1;
389 	int i, j;
390 
391 	if (p == dflt) dflt = NULL;
392 	for (i = 0; i < 32; i++) {
393 		if ((p1 = p->uni_pgdir[i]) != NULL) {
394 			for (j = 0; j < 32; j++)
395 				kfree(p1[j]);
396 			kfree(p1);
397 		}
398 		p->uni_pgdir[i] = NULL;
399 	}
400 	for (i = 0; i < 4; i++) {
401 		kfree(p->inverse_translations[i]);
402 		p->inverse_translations[i] = NULL;
403 	}
404 	if (p->inverse_trans_unicode) {
405 		kfree(p->inverse_trans_unicode);
406 		p->inverse_trans_unicode = NULL;
407 	}
408 }
409 
410 void con_free_unimap(struct vc_data *vc)
411 {
412 	struct uni_pagedir *p;
413 
414 	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
415 	if (!p)
416 		return;
417 	*vc->vc_uni_pagedir_loc = 0;
418 	if (--p->refcount)
419 		return;
420 	con_release_unimap(p);
421 	kfree(p);
422 }
423 
424 static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
425 {
426 	int i, j, k;
427 	struct uni_pagedir *q;
428 
429 	for (i = 0; i < MAX_NR_CONSOLES; i++) {
430 		if (!vc_cons_allocated(i))
431 			continue;
432 		q = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
433 		if (!q || q == p || q->sum != p->sum)
434 			continue;
435 		for (j = 0; j < 32; j++) {
436 			u16 **p1, **q1;
437 			p1 = p->uni_pgdir[j]; q1 = q->uni_pgdir[j];
438 			if (!p1 && !q1)
439 				continue;
440 			if (!p1 || !q1)
441 				break;
442 			for (k = 0; k < 32; k++) {
443 				if (!p1[k] && !q1[k])
444 					continue;
445 				if (!p1[k] || !q1[k])
446 					break;
447 				if (memcmp(p1[k], q1[k], 64*sizeof(u16)))
448 					break;
449 			}
450 			if (k < 32)
451 				break;
452 		}
453 		if (j == 32) {
454 			q->refcount++;
455 			*conp->vc_uni_pagedir_loc = (unsigned long)q;
456 			con_release_unimap(p);
457 			kfree(p);
458 			return 1;
459 		}
460 	}
461 	return 0;
462 }
463 
464 static int
465 con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
466 {
467 	int i, n;
468 	u16 **p1, *p2;
469 
470 	if (!(p1 = p->uni_pgdir[n = unicode >> 11])) {
471 		p1 = p->uni_pgdir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL);
472 		if (!p1) return -ENOMEM;
473 		for (i = 0; i < 32; i++)
474 			p1[i] = NULL;
475 	}
476 
477 	if (!(p2 = p1[n = (unicode >> 6) & 0x1f])) {
478 		p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL);
479 		if (!p2) return -ENOMEM;
480 		memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */
481 	}
482 
483 	p2[unicode & 0x3f] = fontpos;
484 
485 	p->sum += (fontpos << 20) + unicode;
486 
487 	return 0;
488 }
489 
490 /* ui is a leftover from using a hashtable, but might be used again */
491 int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
492 {
493 	struct uni_pagedir *p, *q;
494 
495 	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
496 	if (p && p->readonly) return -EIO;
497 	if (!p || --p->refcount) {
498 		q = kzalloc(sizeof(*p), GFP_KERNEL);
499 		if (!q) {
500 			if (p) p->refcount++;
501 			return -ENOMEM;
502 		}
503 		q->refcount=1;
504 		*vc->vc_uni_pagedir_loc = (unsigned long)q;
505 	} else {
506 		if (p == dflt) dflt = NULL;
507 		p->refcount++;
508 		p->sum = 0;
509 		con_release_unimap(p);
510 	}
511 	return 0;
512 }
513 
514 int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
515 {
516 	int err = 0, err1, i;
517 	struct uni_pagedir *p, *q;
518 
519 	/* Save original vc_unipagdir_loc in case we allocate a new one */
520 	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
521 	if (p->readonly) return -EIO;
522 
523 	if (!ct) return 0;
524 
525 	if (p->refcount > 1) {
526 		int j, k;
527 		u16 **p1, *p2, l;
528 
529 		err1 = con_clear_unimap(vc, NULL);
530 		if (err1) return err1;
531 
532 		/*
533 		 * Since refcount was > 1, con_clear_unimap() allocated a
534 		 * a new uni_pagedir for this vc.  Re: p != q
535 		 */
536 		q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
537 
538 		/*
539 		 * uni_pgdir is a 32*32*64 table with rows allocated
540 		 * when its first entry is added.  The unicode value must
541 		 * still be incremented for empty rows.  We are copying
542 		 * entries from "p" (old) to "q" (new).
543 		 */
544 		l = 0;		/* unicode value */
545 		for (i = 0; i < 32; i++)
546 		if ((p1 = p->uni_pgdir[i]))
547 			for (j = 0; j < 32; j++)
548 			if ((p2 = p1[j])) {
549 				for (k = 0; k < 64; k++, l++)
550 				if (p2[k] != 0xffff) {
551 					/*
552 					 * Found one, copy entry for unicode
553 					 * l with fontpos value p2[k].
554 					 */
555 					err1 = con_insert_unipair(q, l, p2[k]);
556 					if (err1) {
557 						p->refcount++;
558 						*vc->vc_uni_pagedir_loc = (unsigned long)p;
559 						con_release_unimap(q);
560 						kfree(q);
561 						return err1;
562 					}
563 				}
564 			} else {
565 				/* Account for row of 64 empty entries */
566 				l += 64;
567 			}
568 		else
569 			/* Account for empty table */
570 			l += 32 * 64;
571 
572 		/*
573 		 * Finished copying font table, set vc_uni_pagedir to new table
574 		 */
575 		p = q;
576 	} else if (p == dflt) {
577 		dflt = NULL;
578 	}
579 
580 	/*
581 	 * Insert user specified unicode pairs into new table.
582 	 */
583 	while (ct--) {
584 		unsigned short unicode, fontpos;
585 		__get_user(unicode, &list->unicode);
586 		__get_user(fontpos, &list->fontpos);
587 		if ((err1 = con_insert_unipair(p, unicode,fontpos)) != 0)
588 			err = err1;
589 		list++;
590 	}
591 
592 	/*
593 	 * Merge with fontmaps of any other virtual consoles.
594 	 */
595 	if (con_unify_unimap(vc, p))
596 		return err;
597 
598 	for (i = 0; i <= 3; i++)
599 		set_inverse_transl(vc, p, i); /* Update inverse translations */
600 	set_inverse_trans_unicode(vc, p);
601 
602 	return err;
603 }
604 
605 /* Loads the unimap for the hardware font, as defined in uni_hash.tbl.
606    The representation used was the most compact I could come up
607    with.  This routine is executed at sys_setup time, and when the
608    PIO_FONTRESET ioctl is called. */
609 
610 int con_set_default_unimap(struct vc_data *vc)
611 {
612 	int i, j, err = 0, err1;
613 	u16 *q;
614 	struct uni_pagedir *p;
615 
616 	if (dflt) {
617 		p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
618 		if (p == dflt)
619 			return 0;
620 		dflt->refcount++;
621 		*vc->vc_uni_pagedir_loc = (unsigned long)dflt;
622 		if (p && !--p->refcount) {
623 			con_release_unimap(p);
624 			kfree(p);
625 		}
626 		return 0;
627 	}
628 
629 	/* The default font is always 256 characters */
630 
631 	err = con_clear_unimap(vc, NULL);
632 	if (err) return err;
633 
634 	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
635 	q = dfont_unitable;
636 
637 	for (i = 0; i < 256; i++)
638 		for (j = dfont_unicount[i]; j; j--) {
639 			err1 = con_insert_unipair(p, *(q++), i);
640 			if (err1)
641 				err = err1;
642 		}
643 
644 	if (con_unify_unimap(vc, p)) {
645 		dflt = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
646 		return err;
647 	}
648 
649 	for (i = 0; i <= 3; i++)
650 		set_inverse_transl(vc, p, i);	/* Update all inverse translations */
651 	set_inverse_trans_unicode(vc, p);
652 	dflt = p;
653 	return err;
654 }
655 EXPORT_SYMBOL(con_set_default_unimap);
656 
657 int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
658 {
659 	struct uni_pagedir *q;
660 
661 	if (!*src_vc->vc_uni_pagedir_loc)
662 		return -EINVAL;
663 	if (*dst_vc->vc_uni_pagedir_loc == *src_vc->vc_uni_pagedir_loc)
664 		return 0;
665 	con_free_unimap(dst_vc);
666 	q = (struct uni_pagedir *)*src_vc->vc_uni_pagedir_loc;
667 	q->refcount++;
668 	*dst_vc->vc_uni_pagedir_loc = (long)q;
669 	return 0;
670 }
671 
672 int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list)
673 {
674 	int i, j, k, ect;
675 	u16 **p1, *p2;
676 	struct uni_pagedir *p;
677 
678 	ect = 0;
679 	if (*vc->vc_uni_pagedir_loc) {
680 		p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
681 		for (i = 0; i < 32; i++)
682 		if ((p1 = p->uni_pgdir[i]))
683 			for (j = 0; j < 32; j++)
684 			if ((p2 = *(p1++)))
685 				for (k = 0; k < 64; k++) {
686 					if (*p2 < MAX_GLYPH && ect++ < ct) {
687 						__put_user((u_short)((i<<11)+(j<<6)+k),
688 							   &list->unicode);
689 						__put_user((u_short) *p2,
690 							   &list->fontpos);
691 						list++;
692 					}
693 					p2++;
694 				}
695 	}
696 	__put_user(ect, uct);
697 	return ((ect <= ct) ? 0 : -ENOMEM);
698 }
699 
700 void con_protect_unimap(struct vc_data *vc, int rdonly)
701 {
702 	struct uni_pagedir *p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
703 
704 	if (p)
705 		p->readonly = rdonly;
706 }
707 
708 /*
709  * Always use USER_MAP. These functions are used by the keyboard,
710  * which shouldn't be affected by G0/G1 switching, etc.
711  * If the user map still contains default values, i.e. the
712  * direct-to-font mapping, then assume user is using Latin1.
713  */
714 /* may be called during an interrupt */
715 u32 conv_8bit_to_uni(unsigned char c)
716 {
717 	unsigned short uni = translations[USER_MAP][c];
718 	return uni == (0xf000 | c) ? c : uni;
719 }
720 
721 int conv_uni_to_8bit(u32 uni)
722 {
723 	int c;
724 	for (c = 0; c < 0x100; c++)
725 		if (translations[USER_MAP][c] == uni ||
726 		   (translations[USER_MAP][c] == (c | 0xf000) && uni == c))
727 			return c;
728 	return -1;
729 }
730 
731 int
732 conv_uni_to_pc(struct vc_data *conp, long ucs)
733 {
734 	int h;
735 	u16 **p1, *p2;
736 	struct uni_pagedir *p;
737 
738 	/* Only 16-bit codes supported at this time */
739 	if (ucs > 0xffff)
740 		return -4;		/* Not found */
741 	else if (ucs < 0x20)
742 		return -1;		/* Not a printable character */
743 	else if (ucs == 0xfeff || (ucs >= 0x200b && ucs <= 0x200f))
744 		return -2;			/* Zero-width space */
745 	/*
746 	 * UNI_DIRECT_BASE indicates the start of the region in the User Zone
747 	 * which always has a 1:1 mapping to the currently loaded font.  The
748 	 * UNI_DIRECT_MASK indicates the bit span of the region.
749 	 */
750 	else if ((ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE)
751 		return ucs & UNI_DIRECT_MASK;
752 
753 	if (!*conp->vc_uni_pagedir_loc)
754 		return -3;
755 
756 	p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
757 	if ((p1 = p->uni_pgdir[ucs >> 11]) &&
758 	    (p2 = p1[(ucs >> 6) & 0x1f]) &&
759 	    (h = p2[ucs & 0x3f]) < MAX_GLYPH)
760 		return h;
761 
762 	return -4;		/* not found */
763 }
764 
765 /*
766  * This is called at sys_setup time, after memory and the console are
767  * initialized.  It must be possible to call kmalloc(..., GFP_KERNEL)
768  * from this function, hence the call from sys_setup.
769  */
770 void __init
771 console_map_init(void)
772 {
773 	int i;
774 
775 	for (i = 0; i < MAX_NR_CONSOLES; i++)
776 		if (vc_cons_allocated(i) && !*vc_cons[i].d->vc_uni_pagedir_loc)
777 			con_set_default_unimap(vc_cons[i].d);
778 }
779 
780 EXPORT_SYMBOL(con_copy_unimap);
781