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