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