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