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/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++)
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}
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) {
446		q = 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}
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		return -4;		/* Not found */
630	else if (ucs < 0x20)
631		return -1;		/* Not a printable character */
632	else if (ucs == 0xfeff || (ucs >= 0x200b && 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);
670