xref: /openbmc/linux/drivers/tty/vt/consolemap.c (revision b5266ea6)
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 	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
520 	if (p->readonly) return -EIO;
521 
522 	if (!ct) return 0;
523 
524 	if (p->refcount > 1) {
525 		int j, k;
526 		u16 **p1, *p2, l;
527 
528 		err1 = con_clear_unimap(vc, NULL);
529 		if (err1) return err1;
530 
531 		q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
532 		for (i = 0, l = 0; i < 32; i++)
533 		if ((p1 = p->uni_pgdir[i]))
534 			for (j = 0; j < 32; j++)
535 			if ((p2 = p1[j]))
536 				for (k = 0; k < 64; k++, l++)
537 				if (p2[k] != 0xffff) {
538 					err1 = con_insert_unipair(q, l, p2[k]);
539 					if (err1) {
540 						p->refcount++;
541 						*vc->vc_uni_pagedir_loc = (unsigned long)p;
542 						con_release_unimap(q);
543 						kfree(q);
544 						return err1;
545 					}
546               			}
547               	p = q;
548 	} else if (p == dflt)
549 		dflt = NULL;
550 
551 	while (ct--) {
552 		unsigned short unicode, fontpos;
553 		__get_user(unicode, &list->unicode);
554 		__get_user(fontpos, &list->fontpos);
555 		if ((err1 = con_insert_unipair(p, unicode,fontpos)) != 0)
556 			err = err1;
557 		list++;
558 	}
559 
560 	if (con_unify_unimap(vc, p))
561 		return err;
562 
563 	for (i = 0; i <= 3; i++)
564 		set_inverse_transl(vc, p, i); /* Update all inverse translations */
565 	set_inverse_trans_unicode(vc, p);
566 
567 	return err;
568 }
569 
570 /* Loads the unimap for the hardware font, as defined in uni_hash.tbl.
571    The representation used was the most compact I could come up
572    with.  This routine is executed at sys_setup time, and when the
573    PIO_FONTRESET ioctl is called. */
574 
575 int con_set_default_unimap(struct vc_data *vc)
576 {
577 	int i, j, err = 0, err1;
578 	u16 *q;
579 	struct uni_pagedir *p;
580 
581 	if (dflt) {
582 		p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
583 		if (p == dflt)
584 			return 0;
585 		dflt->refcount++;
586 		*vc->vc_uni_pagedir_loc = (unsigned long)dflt;
587 		if (p && !--p->refcount) {
588 			con_release_unimap(p);
589 			kfree(p);
590 		}
591 		return 0;
592 	}
593 
594 	/* The default font is always 256 characters */
595 
596 	err = con_clear_unimap(vc, NULL);
597 	if (err) return err;
598 
599 	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
600 	q = dfont_unitable;
601 
602 	for (i = 0; i < 256; i++)
603 		for (j = dfont_unicount[i]; j; j--) {
604 			err1 = con_insert_unipair(p, *(q++), i);
605 			if (err1)
606 				err = err1;
607 		}
608 
609 	if (con_unify_unimap(vc, p)) {
610 		dflt = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
611 		return err;
612 	}
613 
614 	for (i = 0; i <= 3; i++)
615 		set_inverse_transl(vc, p, i);	/* Update all inverse translations */
616 	set_inverse_trans_unicode(vc, p);
617 	dflt = p;
618 	return err;
619 }
620 EXPORT_SYMBOL(con_set_default_unimap);
621 
622 int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
623 {
624 	struct uni_pagedir *q;
625 
626 	if (!*src_vc->vc_uni_pagedir_loc)
627 		return -EINVAL;
628 	if (*dst_vc->vc_uni_pagedir_loc == *src_vc->vc_uni_pagedir_loc)
629 		return 0;
630 	con_free_unimap(dst_vc);
631 	q = (struct uni_pagedir *)*src_vc->vc_uni_pagedir_loc;
632 	q->refcount++;
633 	*dst_vc->vc_uni_pagedir_loc = (long)q;
634 	return 0;
635 }
636 
637 int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list)
638 {
639 	int i, j, k, ect;
640 	u16 **p1, *p2;
641 	struct uni_pagedir *p;
642 
643 	ect = 0;
644 	if (*vc->vc_uni_pagedir_loc) {
645 		p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
646 		for (i = 0; i < 32; i++)
647 		if ((p1 = p->uni_pgdir[i]))
648 			for (j = 0; j < 32; j++)
649 			if ((p2 = *(p1++)))
650 				for (k = 0; k < 64; k++) {
651 					if (*p2 < MAX_GLYPH && ect++ < ct) {
652 						__put_user((u_short)((i<<11)+(j<<6)+k),
653 							   &list->unicode);
654 						__put_user((u_short) *p2,
655 							   &list->fontpos);
656 						list++;
657 					}
658 					p2++;
659 				}
660 	}
661 	__put_user(ect, uct);
662 	return ((ect <= ct) ? 0 : -ENOMEM);
663 }
664 
665 void con_protect_unimap(struct vc_data *vc, int rdonly)
666 {
667 	struct uni_pagedir *p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
668 
669 	if (p)
670 		p->readonly = rdonly;
671 }
672 
673 /*
674  * Always use USER_MAP. These functions are used by the keyboard,
675  * which shouldn't be affected by G0/G1 switching, etc.
676  * If the user map still contains default values, i.e. the
677  * direct-to-font mapping, then assume user is using Latin1.
678  */
679 /* may be called during an interrupt */
680 u32 conv_8bit_to_uni(unsigned char c)
681 {
682 	unsigned short uni = translations[USER_MAP][c];
683 	return uni == (0xf000 | c) ? c : uni;
684 }
685 
686 int conv_uni_to_8bit(u32 uni)
687 {
688 	int c;
689 	for (c = 0; c < 0x100; c++)
690 		if (translations[USER_MAP][c] == uni ||
691 		   (translations[USER_MAP][c] == (c | 0xf000) && uni == c))
692 			return c;
693 	return -1;
694 }
695 
696 int
697 conv_uni_to_pc(struct vc_data *conp, long ucs)
698 {
699 	int h;
700 	u16 **p1, *p2;
701 	struct uni_pagedir *p;
702 
703 	/* Only 16-bit codes supported at this time */
704 	if (ucs > 0xffff)
705 		return -4;		/* Not found */
706 	else if (ucs < 0x20)
707 		return -1;		/* Not a printable character */
708 	else if (ucs == 0xfeff || (ucs >= 0x200b && ucs <= 0x200f))
709 		return -2;			/* Zero-width space */
710 	/*
711 	 * UNI_DIRECT_BASE indicates the start of the region in the User Zone
712 	 * which always has a 1:1 mapping to the currently loaded font.  The
713 	 * UNI_DIRECT_MASK indicates the bit span of the region.
714 	 */
715 	else if ((ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE)
716 		return ucs & UNI_DIRECT_MASK;
717 
718 	if (!*conp->vc_uni_pagedir_loc)
719 		return -3;
720 
721 	p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
722 	if ((p1 = p->uni_pgdir[ucs >> 11]) &&
723 	    (p2 = p1[(ucs >> 6) & 0x1f]) &&
724 	    (h = p2[ucs & 0x3f]) < MAX_GLYPH)
725 		return h;
726 
727 	return -4;		/* not found */
728 }
729 
730 /*
731  * This is called at sys_setup time, after memory and the console are
732  * initialized.  It must be possible to call kmalloc(..., GFP_KERNEL)
733  * from this function, hence the call from sys_setup.
734  */
735 void __init
736 console_map_init(void)
737 {
738 	int i;
739 
740 	for (i = 0; i < MAX_NR_CONSOLES; i++)
741 		if (vc_cons_allocated(i) && !*vc_cons[i].d->vc_uni_pagedir_loc)
742 			con_set_default_unimap(vc_cons[i].d);
743 }
744 
745 EXPORT_SYMBOL(con_copy_unimap);
746