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