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