ia64/linux-2.6.18-xen.hg

view drivers/char/consolemap.c @ 893:f994bfe9b93b

linux/blktap2: reduce TLB flush scope

c/s 885 added very coarse TLB flushing. Since these flushes always
follow single page updates, single page flushes (when available) are
sufficient.

Signed-off-by: Jan Beulich <jbeulich@novell.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Jun 04 10:32:57 2009 +0100 (2009-06-04)
parents 831230e53067
children
line source
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 */
14 #include <linux/module.h>
15 #include <linux/kd.h>
16 #include <linux/errno.h>
17 #include <linux/mm.h>
18 #include <linux/slab.h>
19 #include <linux/init.h>
20 #include <linux/tty.h>
21 #include <asm/uaccess.h>
22 #include <linux/consolemap.h>
23 #include <linux/vt_kern.h>
25 static unsigned short translations[][256] = {
26 /* 8-bit Latin-1 mapped to Unicode -- trivial mapping */
27 {
28 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
29 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
30 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
31 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
32 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
33 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
34 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
35 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
36 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
37 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
38 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
39 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
40 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
41 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
42 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
43 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
44 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
45 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
46 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
47 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
48 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
49 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
50 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
51 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
52 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
53 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
54 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
55 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
56 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
57 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
58 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
59 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
60 },
61 /* VT100 graphics mapped to Unicode */
62 {
63 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
64 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
65 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
66 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
67 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
68 0x0028, 0x0029, 0x002a, 0x2192, 0x2190, 0x2191, 0x2193, 0x002f,
69 0x2588, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
70 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
71 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
72 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
73 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
74 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x00a0,
75 0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1,
76 0x2591, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba,
77 0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c,
78 0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x007f,
79 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
80 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
81 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
82 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
83 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
84 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
85 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
86 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
87 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
88 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
89 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
90 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
91 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
92 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
93 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
94 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
95 },
96 /* IBM Codepage 437 mapped to Unicode */
97 {
98 0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022,
99 0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c,
100 0x25b6, 0x25c0, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8,
101 0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc,
102 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
103 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
104 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
105 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
106 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
107 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
108 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
109 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
110 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
111 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
112 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
113 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302,
114 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
115 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
116 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
117 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
118 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
119 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
120 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
121 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
122 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
123 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
124 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
125 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
126 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
127 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
128 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
129 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0
130 },
131 /* User mapping -- default to codes for direct font mapping */
132 {
133 0xf000, 0xf001, 0xf002, 0xf003, 0xf004, 0xf005, 0xf006, 0xf007,
134 0xf008, 0xf009, 0xf00a, 0xf00b, 0xf00c, 0xf00d, 0xf00e, 0xf00f,
135 0xf010, 0xf011, 0xf012, 0xf013, 0xf014, 0xf015, 0xf016, 0xf017,
136 0xf018, 0xf019, 0xf01a, 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f,
137 0xf020, 0xf021, 0xf022, 0xf023, 0xf024, 0xf025, 0xf026, 0xf027,
138 0xf028, 0xf029, 0xf02a, 0xf02b, 0xf02c, 0xf02d, 0xf02e, 0xf02f,
139 0xf030, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037,
140 0xf038, 0xf039, 0xf03a, 0xf03b, 0xf03c, 0xf03d, 0xf03e, 0xf03f,
141 0xf040, 0xf041, 0xf042, 0xf043, 0xf044, 0xf045, 0xf046, 0xf047,
142 0xf048, 0xf049, 0xf04a, 0xf04b, 0xf04c, 0xf04d, 0xf04e, 0xf04f,
143 0xf050, 0xf051, 0xf052, 0xf053, 0xf054, 0xf055, 0xf056, 0xf057,
144 0xf058, 0xf059, 0xf05a, 0xf05b, 0xf05c, 0xf05d, 0xf05e, 0xf05f,
145 0xf060, 0xf061, 0xf062, 0xf063, 0xf064, 0xf065, 0xf066, 0xf067,
146 0xf068, 0xf069, 0xf06a, 0xf06b, 0xf06c, 0xf06d, 0xf06e, 0xf06f,
147 0xf070, 0xf071, 0xf072, 0xf073, 0xf074, 0xf075, 0xf076, 0xf077,
148 0xf078, 0xf079, 0xf07a, 0xf07b, 0xf07c, 0xf07d, 0xf07e, 0xf07f,
149 0xf080, 0xf081, 0xf082, 0xf083, 0xf084, 0xf085, 0xf086, 0xf087,
150 0xf088, 0xf089, 0xf08a, 0xf08b, 0xf08c, 0xf08d, 0xf08e, 0xf08f,
151 0xf090, 0xf091, 0xf092, 0xf093, 0xf094, 0xf095, 0xf096, 0xf097,
152 0xf098, 0xf099, 0xf09a, 0xf09b, 0xf09c, 0xf09d, 0xf09e, 0xf09f,
153 0xf0a0, 0xf0a1, 0xf0a2, 0xf0a3, 0xf0a4, 0xf0a5, 0xf0a6, 0xf0a7,
154 0xf0a8, 0xf0a9, 0xf0aa, 0xf0ab, 0xf0ac, 0xf0ad, 0xf0ae, 0xf0af,
155 0xf0b0, 0xf0b1, 0xf0b2, 0xf0b3, 0xf0b4, 0xf0b5, 0xf0b6, 0xf0b7,
156 0xf0b8, 0xf0b9, 0xf0ba, 0xf0bb, 0xf0bc, 0xf0bd, 0xf0be, 0xf0bf,
157 0xf0c0, 0xf0c1, 0xf0c2, 0xf0c3, 0xf0c4, 0xf0c5, 0xf0c6, 0xf0c7,
158 0xf0c8, 0xf0c9, 0xf0ca, 0xf0cb, 0xf0cc, 0xf0cd, 0xf0ce, 0xf0cf,
159 0xf0d0, 0xf0d1, 0xf0d2, 0xf0d3, 0xf0d4, 0xf0d5, 0xf0d6, 0xf0d7,
160 0xf0d8, 0xf0d9, 0xf0da, 0xf0db, 0xf0dc, 0xf0dd, 0xf0de, 0xf0df,
161 0xf0e0, 0xf0e1, 0xf0e2, 0xf0e3, 0xf0e4, 0xf0e5, 0xf0e6, 0xf0e7,
162 0xf0e8, 0xf0e9, 0xf0ea, 0xf0eb, 0xf0ec, 0xf0ed, 0xf0ee, 0xf0ef,
163 0xf0f0, 0xf0f1, 0xf0f2, 0xf0f3, 0xf0f4, 0xf0f5, 0xf0f6, 0xf0f7,
164 0xf0f8, 0xf0f9, 0xf0fa, 0xf0fb, 0xf0fc, 0xf0fd, 0xf0fe, 0xf0ff
165 }
166 };
168 /* The standard kernel character-to-font mappings are not invertible
169 -- this is just a best effort. */
171 #define MAX_GLYPH 512 /* Max possible glyph value */
173 static int inv_translate[MAX_NR_CONSOLES];
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 };
183 static struct uni_pagedir *dflt;
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;
191 if (!p) return;
192 q = p->inverse_translations[i];
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);
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 }
210 unsigned short *set_translate(int m, struct vc_data *vc)
211 {
212 inv_translate[vc->vc_num] = m;
213 return translations[m];
214 }
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 */
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 }
235 static void update_user_maps(void)
236 {
237 int i;
238 struct uni_pagedir *p, *q = NULL;
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 }
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 */
259 int con_set_trans_old(unsigned char __user * arg)
260 {
261 int i;
262 unsigned short *p = translations[USER_MAP];
264 if (!access_ok(VERIFY_READ, arg, E_TABSZ))
265 return -EFAULT;
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 }
273 update_user_maps();
274 return 0;
275 }
277 int con_get_trans_old(unsigned char __user * arg)
278 {
279 int i, ch;
280 unsigned short *p = translations[USER_MAP];
282 if (!access_ok(VERIFY_WRITE, arg, E_TABSZ))
283 return -EFAULT;
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 }
293 int con_set_trans_new(ushort __user * arg)
294 {
295 int i;
296 unsigned short *p = translations[USER_MAP];
298 if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short)))
299 return -EFAULT;
301 for (i=0; i<E_TABSZ ; i++) {
302 unsigned short us;
303 __get_user(us, arg+i);
304 p[i] = us;
305 }
307 update_user_maps();
308 return 0;
309 }
311 int con_get_trans_new(ushort __user * arg)
312 {
313 int i;
314 unsigned short *p = translations[USER_MAP];
316 if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short)))
317 return -EFAULT;
319 for (i=0; i<E_TABSZ ; i++)
320 __put_user(p[i], arg+i);
322 return 0;
323 }
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 */
335 extern u8 dfont_unicount[]; /* Defined in console_defmap.c */
336 extern u16 dfont_unitable[];
338 static void con_release_unimap(struct uni_pagedir *p)
339 {
340 u16 **p1;
341 int i, j;
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++)
347 kfree(p1[j]);
348 kfree(p1);
349 }
350 p->uni_pgdir[i] = NULL;
351 }
352 for (i = 0; i < 4; i++) {
353 kfree(p->inverse_translations[i]);
354 p->inverse_translations[i] = NULL;
355 }
356 }
358 void con_free_unimap(struct vc_data *vc)
359 {
360 struct uni_pagedir *p;
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 }
372 static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
373 {
374 int i, j, k;
375 struct uni_pagedir *q;
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 }
412 static int
413 con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
414 {
415 int i, n;
416 u16 **p1, *p2;
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 }
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 }
431 p2[unicode & 0x3f] = fontpos;
433 p->sum += (fontpos << 20) + unicode;
435 return 0;
436 }
438 /* ui is a leftover from using a hashtable, but might be used again */
439 int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
440 {
441 struct uni_pagedir *p, *q;
443 p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
444 if (p && p->readonly) return -EIO;
445 if (!p || --p->refcount) {
446 q = (struct uni_pagedir *)kmalloc(sizeof(*p), GFP_KERNEL);
447 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 }
463 int 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;
468 p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
469 if (p->readonly) return -EIO;
471 if (!ct) return 0;
473 if (p->refcount > 1) {
474 int j, k;
475 u16 **p1, *p2, l;
477 err1 = con_clear_unimap(vc, NULL);
478 if (err1) return err1;
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;
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 }
509 if (con_unify_unimap(vc, p))
510 return err;
512 for (i = 0; i <= 3; i++)
513 set_inverse_transl(vc, p, i); /* Update all inverse translations */
515 return err;
516 }
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. */
523 int con_set_default_unimap(struct vc_data *vc)
524 {
525 int i, j, err = 0, err1;
526 u16 *q;
527 struct uni_pagedir *p;
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 }
542 /* The default font is always 256 characters */
544 err = con_clear_unimap(vc, NULL);
545 if (err) return err;
547 p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
548 q = dfont_unitable;
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 }
557 if (con_unify_unimap(vc, p)) {
558 dflt = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
559 return err;
560 }
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 }
567 EXPORT_SYMBOL(con_set_default_unimap);
569 int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
570 {
571 struct uni_pagedir *q;
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 }
584 int 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;
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 }
612 void con_protect_unimap(struct vc_data *vc, int rdonly)
613 {
614 struct uni_pagedir *p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
616 if (p)
617 p->readonly = rdonly;
618 }
620 int
621 conv_uni_to_pc(struct vc_data *conp, long ucs)
622 {
623 int h;
624 u16 **p1, *p2;
625 struct uni_pagedir *p;
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;
642 if (!*conp->vc_uni_pagedir_loc)
643 return -3;
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;
651 return -4; /* not found */
652 }
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 */
659 void __init
660 console_map_init(void)
661 {
662 int i;
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 }
669 EXPORT_SYMBOL(con_copy_unimap);