0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026 #include <linux/bitfield.h>
0027 #include <linux/bits.h>
0028 #include <linux/module.h>
0029 #include <linux/kd.h>
0030 #include <linux/errno.h>
0031 #include <linux/mm.h>
0032 #include <linux/slab.h>
0033 #include <linux/init.h>
0034 #include <linux/tty.h>
0035 #include <linux/uaccess.h>
0036 #include <linux/console.h>
0037 #include <linux/consolemap.h>
0038 #include <linux/vt_kern.h>
0039 #include <linux/string.h>
0040
0041 static unsigned short translations[][E_TABSZ] = {
0042
0043 [LAT1_MAP] = {
0044 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
0045 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
0046 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
0047 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
0048 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
0049 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
0050 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
0051 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
0052 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
0053 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
0054 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
0055 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
0056 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
0057 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
0058 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
0059 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
0060 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
0061 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
0062 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
0063 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
0064 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
0065 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
0066 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
0067 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
0068 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
0069 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
0070 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
0071 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
0072 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
0073 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
0074 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
0075 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
0076 },
0077
0078 [GRAF_MAP] = {
0079 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
0080 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
0081 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
0082 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
0083 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
0084 0x0028, 0x0029, 0x002a, 0x2192, 0x2190, 0x2191, 0x2193, 0x002f,
0085 0x2588, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
0086 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
0087 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
0088 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
0089 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
0090 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x00a0,
0091 0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1,
0092 0x2591, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba,
0093 0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c,
0094 0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x007f,
0095 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
0096 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
0097 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
0098 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
0099 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
0100 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
0101 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
0102 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
0103 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
0104 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
0105 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
0106 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
0107 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
0108 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
0109 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
0110 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
0111 },
0112
0113 [IBMPC_MAP] = {
0114 0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022,
0115 0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c,
0116 0x25b6, 0x25c0, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8,
0117 0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc,
0118 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
0119 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
0120 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
0121 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
0122 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
0123 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
0124 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
0125 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
0126 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
0127 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
0128 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
0129 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302,
0130 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
0131 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
0132 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
0133 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
0134 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
0135 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
0136 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
0137 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
0138 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
0139 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
0140 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
0141 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
0142 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
0143 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
0144 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
0145 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0
0146 },
0147
0148 [USER_MAP] = {
0149 0xf000, 0xf001, 0xf002, 0xf003, 0xf004, 0xf005, 0xf006, 0xf007,
0150 0xf008, 0xf009, 0xf00a, 0xf00b, 0xf00c, 0xf00d, 0xf00e, 0xf00f,
0151 0xf010, 0xf011, 0xf012, 0xf013, 0xf014, 0xf015, 0xf016, 0xf017,
0152 0xf018, 0xf019, 0xf01a, 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f,
0153 0xf020, 0xf021, 0xf022, 0xf023, 0xf024, 0xf025, 0xf026, 0xf027,
0154 0xf028, 0xf029, 0xf02a, 0xf02b, 0xf02c, 0xf02d, 0xf02e, 0xf02f,
0155 0xf030, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037,
0156 0xf038, 0xf039, 0xf03a, 0xf03b, 0xf03c, 0xf03d, 0xf03e, 0xf03f,
0157 0xf040, 0xf041, 0xf042, 0xf043, 0xf044, 0xf045, 0xf046, 0xf047,
0158 0xf048, 0xf049, 0xf04a, 0xf04b, 0xf04c, 0xf04d, 0xf04e, 0xf04f,
0159 0xf050, 0xf051, 0xf052, 0xf053, 0xf054, 0xf055, 0xf056, 0xf057,
0160 0xf058, 0xf059, 0xf05a, 0xf05b, 0xf05c, 0xf05d, 0xf05e, 0xf05f,
0161 0xf060, 0xf061, 0xf062, 0xf063, 0xf064, 0xf065, 0xf066, 0xf067,
0162 0xf068, 0xf069, 0xf06a, 0xf06b, 0xf06c, 0xf06d, 0xf06e, 0xf06f,
0163 0xf070, 0xf071, 0xf072, 0xf073, 0xf074, 0xf075, 0xf076, 0xf077,
0164 0xf078, 0xf079, 0xf07a, 0xf07b, 0xf07c, 0xf07d, 0xf07e, 0xf07f,
0165 0xf080, 0xf081, 0xf082, 0xf083, 0xf084, 0xf085, 0xf086, 0xf087,
0166 0xf088, 0xf089, 0xf08a, 0xf08b, 0xf08c, 0xf08d, 0xf08e, 0xf08f,
0167 0xf090, 0xf091, 0xf092, 0xf093, 0xf094, 0xf095, 0xf096, 0xf097,
0168 0xf098, 0xf099, 0xf09a, 0xf09b, 0xf09c, 0xf09d, 0xf09e, 0xf09f,
0169 0xf0a0, 0xf0a1, 0xf0a2, 0xf0a3, 0xf0a4, 0xf0a5, 0xf0a6, 0xf0a7,
0170 0xf0a8, 0xf0a9, 0xf0aa, 0xf0ab, 0xf0ac, 0xf0ad, 0xf0ae, 0xf0af,
0171 0xf0b0, 0xf0b1, 0xf0b2, 0xf0b3, 0xf0b4, 0xf0b5, 0xf0b6, 0xf0b7,
0172 0xf0b8, 0xf0b9, 0xf0ba, 0xf0bb, 0xf0bc, 0xf0bd, 0xf0be, 0xf0bf,
0173 0xf0c0, 0xf0c1, 0xf0c2, 0xf0c3, 0xf0c4, 0xf0c5, 0xf0c6, 0xf0c7,
0174 0xf0c8, 0xf0c9, 0xf0ca, 0xf0cb, 0xf0cc, 0xf0cd, 0xf0ce, 0xf0cf,
0175 0xf0d0, 0xf0d1, 0xf0d2, 0xf0d3, 0xf0d4, 0xf0d5, 0xf0d6, 0xf0d7,
0176 0xf0d8, 0xf0d9, 0xf0da, 0xf0db, 0xf0dc, 0xf0dd, 0xf0de, 0xf0df,
0177 0xf0e0, 0xf0e1, 0xf0e2, 0xf0e3, 0xf0e4, 0xf0e5, 0xf0e6, 0xf0e7,
0178 0xf0e8, 0xf0e9, 0xf0ea, 0xf0eb, 0xf0ec, 0xf0ed, 0xf0ee, 0xf0ef,
0179 0xf0f0, 0xf0f1, 0xf0f2, 0xf0f3, 0xf0f4, 0xf0f5, 0xf0f6, 0xf0f7,
0180 0xf0f8, 0xf0f9, 0xf0fa, 0xf0fb, 0xf0fc, 0xf0fd, 0xf0fe, 0xf0ff
0181 }
0182 };
0183
0184
0185
0186
0187 #define MAX_GLYPH 512
0188
0189 static enum translation_map inv_translate[MAX_NR_CONSOLES];
0190
0191 #define UNI_DIRS 32U
0192 #define UNI_DIR_ROWS 32U
0193 #define UNI_ROW_GLYPHS 64U
0194
0195 #define UNI_DIR_BITS GENMASK(15, 11)
0196 #define UNI_ROW_BITS GENMASK(10, 6)
0197 #define UNI_GLYPH_BITS GENMASK( 5, 0)
0198
0199 #define UNI_DIR(uni) FIELD_GET(UNI_DIR_BITS, (uni))
0200 #define UNI_ROW(uni) FIELD_GET(UNI_ROW_BITS, (uni))
0201 #define UNI_GLYPH(uni) FIELD_GET(UNI_GLYPH_BITS, (uni))
0202
0203 #define UNI(dir, row, glyph) (FIELD_PREP(UNI_DIR_BITS, (dir)) | \
0204 FIELD_PREP(UNI_ROW_BITS, (row)) | \
0205 FIELD_PREP(UNI_GLYPH_BITS, (glyph)))
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216 struct uni_pagedict {
0217 u16 **uni_pgdir[UNI_DIRS];
0218 unsigned long refcount;
0219 unsigned long sum;
0220 unsigned char *inverse_translations[LAST_MAP + 1];
0221 u16 *inverse_trans_unicode;
0222 };
0223
0224 static struct uni_pagedict *dflt;
0225
0226 static void set_inverse_transl(struct vc_data *conp, struct uni_pagedict *dict,
0227 enum translation_map m)
0228 {
0229 unsigned short *t = translations[m];
0230 unsigned char *inv;
0231
0232 if (!dict)
0233 return;
0234 inv = dict->inverse_translations[m];
0235
0236 if (!inv) {
0237 inv = dict->inverse_translations[m] = kmalloc(MAX_GLYPH,
0238 GFP_KERNEL);
0239 if (!inv)
0240 return;
0241 }
0242 memset(inv, 0, MAX_GLYPH);
0243
0244 for (unsigned int ch = 0; ch < ARRAY_SIZE(translations[m]); ch++) {
0245 int glyph = conv_uni_to_pc(conp, t[ch]);
0246 if (glyph >= 0 && glyph < MAX_GLYPH && inv[glyph] < 32) {
0247
0248 inv[glyph] = ch;
0249 }
0250 }
0251 }
0252
0253 static void set_inverse_trans_unicode(struct uni_pagedict *dict)
0254 {
0255 unsigned int d, r, g;
0256 u16 *inv;
0257
0258 if (!dict)
0259 return;
0260
0261 inv = dict->inverse_trans_unicode;
0262 if (!inv) {
0263 inv = dict->inverse_trans_unicode = kmalloc_array(MAX_GLYPH,
0264 sizeof(*inv), GFP_KERNEL);
0265 if (!inv)
0266 return;
0267 }
0268 memset(inv, 0, MAX_GLYPH * sizeof(*inv));
0269
0270 for (d = 0; d < UNI_DIRS; d++) {
0271 u16 **dir = dict->uni_pgdir[d];
0272 if (!dir)
0273 continue;
0274 for (r = 0; r < UNI_DIR_ROWS; r++) {
0275 u16 *row = dir[r];
0276 if (!row)
0277 continue;
0278 for (g = 0; g < UNI_ROW_GLYPHS; g++) {
0279 u16 glyph = row[g];
0280 if (glyph < MAX_GLYPH && inv[glyph] < 32)
0281 inv[glyph] = UNI(d, r, g);
0282 }
0283 }
0284 }
0285 }
0286
0287 unsigned short *set_translate(enum translation_map m, struct vc_data *vc)
0288 {
0289 inv_translate[vc->vc_num] = m;
0290 return translations[m];
0291 }
0292
0293
0294
0295
0296
0297
0298
0299
0300 u16 inverse_translate(const struct vc_data *conp, u16 glyph, bool use_unicode)
0301 {
0302 struct uni_pagedict *p;
0303 enum translation_map m;
0304
0305 if (glyph >= MAX_GLYPH)
0306 return 0;
0307
0308 p = *conp->uni_pagedict_loc;
0309 if (!p)
0310 return glyph;
0311
0312 if (use_unicode) {
0313 if (!p->inverse_trans_unicode)
0314 return glyph;
0315
0316 return p->inverse_trans_unicode[glyph];
0317 }
0318
0319 m = inv_translate[conp->vc_num];
0320 if (!p->inverse_translations[m])
0321 return glyph;
0322
0323 return p->inverse_translations[m][glyph];
0324 }
0325 EXPORT_SYMBOL_GPL(inverse_translate);
0326
0327 static void update_user_maps(void)
0328 {
0329 int i;
0330 struct uni_pagedict *p, *q = NULL;
0331
0332 for (i = 0; i < MAX_NR_CONSOLES; i++) {
0333 if (!vc_cons_allocated(i))
0334 continue;
0335 p = *vc_cons[i].d->uni_pagedict_loc;
0336 if (p && p != q) {
0337 set_inverse_transl(vc_cons[i].d, p, USER_MAP);
0338 set_inverse_trans_unicode(p);
0339 q = p;
0340 }
0341 }
0342 }
0343
0344
0345
0346
0347
0348
0349
0350
0351
0352 int con_set_trans_old(unsigned char __user * arg)
0353 {
0354 unsigned short inbuf[E_TABSZ];
0355 unsigned int i;
0356 unsigned char ch;
0357
0358 for (i = 0; i < ARRAY_SIZE(inbuf); i++) {
0359 if (get_user(ch, &arg[i]))
0360 return -EFAULT;
0361 inbuf[i] = UNI_DIRECT_BASE | ch;
0362 }
0363
0364 console_lock();
0365 memcpy(translations[USER_MAP], inbuf, sizeof(inbuf));
0366 update_user_maps();
0367 console_unlock();
0368 return 0;
0369 }
0370
0371 int con_get_trans_old(unsigned char __user * arg)
0372 {
0373 int i, ch;
0374 unsigned short *p = translations[USER_MAP];
0375 unsigned char outbuf[E_TABSZ];
0376
0377 console_lock();
0378 for (i = 0; i < ARRAY_SIZE(outbuf); i++)
0379 {
0380 ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
0381 outbuf[i] = (ch & ~0xff) ? 0 : ch;
0382 }
0383 console_unlock();
0384
0385 return copy_to_user(arg, outbuf, sizeof(outbuf)) ? -EFAULT : 0;
0386 }
0387
0388 int con_set_trans_new(ushort __user * arg)
0389 {
0390 unsigned short inbuf[E_TABSZ];
0391
0392 if (copy_from_user(inbuf, arg, sizeof(inbuf)))
0393 return -EFAULT;
0394
0395 console_lock();
0396 memcpy(translations[USER_MAP], inbuf, sizeof(inbuf));
0397 update_user_maps();
0398 console_unlock();
0399 return 0;
0400 }
0401
0402 int con_get_trans_new(ushort __user * arg)
0403 {
0404 unsigned short outbuf[E_TABSZ];
0405
0406 console_lock();
0407 memcpy(outbuf, translations[USER_MAP], sizeof(outbuf));
0408 console_unlock();
0409
0410 return copy_to_user(arg, outbuf, sizeof(outbuf)) ? -EFAULT : 0;
0411 }
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423 extern u8 dfont_unicount[];
0424 extern u16 dfont_unitable[];
0425
0426 static void con_release_unimap(struct uni_pagedict *dict)
0427 {
0428 unsigned int d, r;
0429
0430 if (dict == dflt)
0431 dflt = NULL;
0432
0433 for (d = 0; d < UNI_DIRS; d++) {
0434 u16 **dir = dict->uni_pgdir[d];
0435 if (dir != NULL) {
0436 for (r = 0; r < UNI_DIR_ROWS; r++)
0437 kfree(dir[r]);
0438 kfree(dir);
0439 }
0440 dict->uni_pgdir[d] = NULL;
0441 }
0442
0443 for (r = 0; r < ARRAY_SIZE(dict->inverse_translations); r++) {
0444 kfree(dict->inverse_translations[r]);
0445 dict->inverse_translations[r] = NULL;
0446 }
0447
0448 kfree(dict->inverse_trans_unicode);
0449 dict->inverse_trans_unicode = NULL;
0450 }
0451
0452
0453 void con_free_unimap(struct vc_data *vc)
0454 {
0455 struct uni_pagedict *p;
0456
0457 p = *vc->uni_pagedict_loc;
0458 if (!p)
0459 return;
0460 *vc->uni_pagedict_loc = NULL;
0461 if (--p->refcount)
0462 return;
0463 con_release_unimap(p);
0464 kfree(p);
0465 }
0466
0467 static int con_unify_unimap(struct vc_data *conp, struct uni_pagedict *dict1)
0468 {
0469 struct uni_pagedict *dict2;
0470 unsigned int cons, d, r;
0471
0472 for (cons = 0; cons < MAX_NR_CONSOLES; cons++) {
0473 if (!vc_cons_allocated(cons))
0474 continue;
0475 dict2 = *vc_cons[cons].d->uni_pagedict_loc;
0476 if (!dict2 || dict2 == dict1 || dict2->sum != dict1->sum)
0477 continue;
0478 for (d = 0; d < UNI_DIRS; d++) {
0479 u16 **dir1 = dict1->uni_pgdir[d];
0480 u16 **dir2 = dict2->uni_pgdir[d];
0481 if (!dir1 && !dir2)
0482 continue;
0483 if (!dir1 || !dir2)
0484 break;
0485 for (r = 0; r < UNI_DIR_ROWS; r++) {
0486 if (!dir1[r] && !dir2[r])
0487 continue;
0488 if (!dir1[r] || !dir2[r])
0489 break;
0490 if (memcmp(dir1[r], dir2[r], UNI_ROW_GLYPHS *
0491 sizeof(*dir1[r])))
0492 break;
0493 }
0494 if (r < UNI_DIR_ROWS)
0495 break;
0496 }
0497 if (d == UNI_DIRS) {
0498 dict2->refcount++;
0499 *conp->uni_pagedict_loc = dict2;
0500 con_release_unimap(dict1);
0501 kfree(dict1);
0502 return 1;
0503 }
0504 }
0505 return 0;
0506 }
0507
0508 static int
0509 con_insert_unipair(struct uni_pagedict *p, u_short unicode, u_short fontpos)
0510 {
0511 u16 **dir, *row;
0512 unsigned int n;
0513
0514 n = UNI_DIR(unicode);
0515 dir = p->uni_pgdir[n];
0516 if (!dir) {
0517 dir = p->uni_pgdir[n] = kcalloc(UNI_DIR_ROWS, sizeof(*dir),
0518 GFP_KERNEL);
0519 if (!dir)
0520 return -ENOMEM;
0521 }
0522
0523 n = UNI_ROW(unicode);
0524 row = dir[n];
0525 if (!row) {
0526 row = dir[n] = kmalloc_array(UNI_ROW_GLYPHS, sizeof(*row),
0527 GFP_KERNEL);
0528 if (!row)
0529 return -ENOMEM;
0530
0531 memset(row, 0xff, UNI_ROW_GLYPHS * sizeof(*row));
0532 }
0533
0534 row[UNI_GLYPH(unicode)] = fontpos;
0535
0536 p->sum += (fontpos << 20U) + unicode;
0537
0538 return 0;
0539 }
0540
0541 static int con_allocate_new(struct vc_data *vc)
0542 {
0543 struct uni_pagedict *new, *old = *vc->uni_pagedict_loc;
0544
0545 new = kzalloc(sizeof(*new), GFP_KERNEL);
0546 if (!new)
0547 return -ENOMEM;
0548
0549 new->refcount = 1;
0550 *vc->uni_pagedict_loc = new;
0551
0552 if (old)
0553 old->refcount--;
0554
0555 return 0;
0556 }
0557
0558
0559 static int con_do_clear_unimap(struct vc_data *vc)
0560 {
0561 struct uni_pagedict *old = *vc->uni_pagedict_loc;
0562
0563 if (!old || old->refcount > 1)
0564 return con_allocate_new(vc);
0565
0566 old->sum = 0;
0567 con_release_unimap(old);
0568
0569 return 0;
0570 }
0571
0572 int con_clear_unimap(struct vc_data *vc)
0573 {
0574 int ret;
0575 console_lock();
0576 ret = con_do_clear_unimap(vc);
0577 console_unlock();
0578 return ret;
0579 }
0580
0581 static struct uni_pagedict *con_unshare_unimap(struct vc_data *vc,
0582 struct uni_pagedict *old)
0583 {
0584 struct uni_pagedict *new;
0585 unsigned int d, r, g;
0586 int ret;
0587 u16 uni = 0;
0588
0589 ret = con_allocate_new(vc);
0590 if (ret)
0591 return ERR_PTR(ret);
0592
0593 new = *vc->uni_pagedict_loc;
0594
0595
0596
0597
0598
0599
0600 for (d = 0; d < UNI_DIRS; d++) {
0601 u16 **dir = old->uni_pgdir[d];
0602 if (!dir) {
0603
0604 uni += UNI_DIR_ROWS * UNI_ROW_GLYPHS;
0605 continue;
0606 }
0607
0608 for (r = 0; r < UNI_DIR_ROWS; r++) {
0609 u16 *row = dir[r];
0610 if (!row) {
0611
0612 uni += UNI_ROW_GLYPHS;
0613 continue;
0614 }
0615
0616 for (g = 0; g < UNI_ROW_GLYPHS; g++, uni++) {
0617 if (row[g] == 0xffff)
0618 continue;
0619
0620
0621
0622
0623 ret = con_insert_unipair(new, uni, row[g]);
0624 if (ret) {
0625 old->refcount++;
0626 *vc->uni_pagedict_loc = old;
0627 con_release_unimap(new);
0628 kfree(new);
0629 return ERR_PTR(ret);
0630 }
0631 }
0632 }
0633 }
0634
0635 return new;
0636 }
0637
0638 int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
0639 {
0640 int err = 0, err1;
0641 struct uni_pagedict *dict;
0642 struct unipair *unilist, *plist;
0643
0644 if (!ct)
0645 return 0;
0646
0647 unilist = vmemdup_user(list, array_size(sizeof(*unilist), ct));
0648 if (IS_ERR(unilist))
0649 return PTR_ERR(unilist);
0650
0651 console_lock();
0652
0653
0654 dict = *vc->uni_pagedict_loc;
0655 if (!dict) {
0656 err = -EINVAL;
0657 goto out_unlock;
0658 }
0659
0660 if (dict->refcount > 1) {
0661 dict = con_unshare_unimap(vc, dict);
0662 if (IS_ERR(dict)) {
0663 err = PTR_ERR(dict);
0664 goto out_unlock;
0665 }
0666 } else if (dict == dflt) {
0667 dflt = NULL;
0668 }
0669
0670
0671
0672
0673 for (plist = unilist; ct; ct--, plist++) {
0674 err1 = con_insert_unipair(dict, plist->unicode, plist->fontpos);
0675 if (err1)
0676 err = err1;
0677 }
0678
0679
0680
0681
0682 if (con_unify_unimap(vc, dict))
0683 goto out_unlock;
0684
0685 for (enum translation_map m = FIRST_MAP; m <= LAST_MAP; m++)
0686 set_inverse_transl(vc, dict, m);
0687 set_inverse_trans_unicode(dict);
0688
0689 out_unlock:
0690 console_unlock();
0691 kvfree(unilist);
0692 return err;
0693 }
0694
0695
0696
0697
0698
0699
0700
0701
0702
0703
0704
0705
0706 int con_set_default_unimap(struct vc_data *vc)
0707 {
0708 struct uni_pagedict *dict;
0709 unsigned int fontpos, count;
0710 int err = 0, err1;
0711 u16 *dfont;
0712
0713 if (dflt) {
0714 dict = *vc->uni_pagedict_loc;
0715 if (dict == dflt)
0716 return 0;
0717
0718 dflt->refcount++;
0719 *vc->uni_pagedict_loc = dflt;
0720 if (dict && !--dict->refcount) {
0721 con_release_unimap(dict);
0722 kfree(dict);
0723 }
0724 return 0;
0725 }
0726
0727
0728
0729 err = con_do_clear_unimap(vc);
0730 if (err)
0731 return err;
0732
0733 dict = *vc->uni_pagedict_loc;
0734 dfont = dfont_unitable;
0735
0736 for (fontpos = 0; fontpos < 256U; fontpos++)
0737 for (count = dfont_unicount[fontpos]; count; count--) {
0738 err1 = con_insert_unipair(dict, *(dfont++), fontpos);
0739 if (err1)
0740 err = err1;
0741 }
0742
0743 if (con_unify_unimap(vc, dict)) {
0744 dflt = *vc->uni_pagedict_loc;
0745 return err;
0746 }
0747
0748 for (enum translation_map m = FIRST_MAP; m <= LAST_MAP; m++)
0749 set_inverse_transl(vc, dict, m);
0750 set_inverse_trans_unicode(dict);
0751 dflt = dict;
0752 return err;
0753 }
0754 EXPORT_SYMBOL(con_set_default_unimap);
0755
0756
0757
0758
0759
0760
0761
0762
0763 int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
0764 {
0765 struct uni_pagedict *src;
0766
0767 if (!*src_vc->uni_pagedict_loc)
0768 return -EINVAL;
0769 if (*dst_vc->uni_pagedict_loc == *src_vc->uni_pagedict_loc)
0770 return 0;
0771 con_free_unimap(dst_vc);
0772 src = *src_vc->uni_pagedict_loc;
0773 src->refcount++;
0774 *dst_vc->uni_pagedict_loc = src;
0775 return 0;
0776 }
0777 EXPORT_SYMBOL(con_copy_unimap);
0778
0779
0780
0781
0782
0783
0784
0785 int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct,
0786 struct unipair __user *list)
0787 {
0788 ushort ect;
0789 struct uni_pagedict *dict;
0790 struct unipair *unilist;
0791 unsigned int d, r, g;
0792 int ret = 0;
0793
0794 unilist = kvmalloc_array(ct, sizeof(*unilist), GFP_KERNEL);
0795 if (!unilist)
0796 return -ENOMEM;
0797
0798 console_lock();
0799
0800 ect = 0;
0801 dict = *vc->uni_pagedict_loc;
0802 if (!dict)
0803 goto unlock;
0804
0805 for (d = 0; d < UNI_DIRS; d++) {
0806 u16 **dir = dict->uni_pgdir[d];
0807 if (!dir)
0808 continue;
0809
0810 for (r = 0; r < UNI_DIR_ROWS; r++) {
0811 u16 *row = dir[r];
0812 if (!row)
0813 continue;
0814
0815 for (g = 0; g < UNI_ROW_GLYPHS; g++, row++) {
0816 if (*row >= MAX_GLYPH)
0817 continue;
0818 if (ect < ct) {
0819 unilist[ect].unicode = UNI(d, r, g);
0820 unilist[ect].fontpos = *row;
0821 }
0822 ect++;
0823 }
0824 }
0825 }
0826 unlock:
0827 console_unlock();
0828 if (copy_to_user(list, unilist, min(ect, ct) * sizeof(*unilist)))
0829 ret = -EFAULT;
0830 if (put_user(ect, uct))
0831 ret = -EFAULT;
0832 kvfree(unilist);
0833 return ret ? ret : (ect <= ct) ? 0 : -ENOMEM;
0834 }
0835
0836
0837
0838
0839
0840
0841
0842
0843
0844
0845
0846
0847 u32 conv_8bit_to_uni(unsigned char c)
0848 {
0849 unsigned short uni = translations[USER_MAP][c];
0850 return uni == (0xf000 | c) ? c : uni;
0851 }
0852
0853 int conv_uni_to_8bit(u32 uni)
0854 {
0855 int c;
0856 for (c = 0; c < ARRAY_SIZE(translations[USER_MAP]); c++)
0857 if (translations[USER_MAP][c] == uni ||
0858 (translations[USER_MAP][c] == (c | 0xf000) && uni == c))
0859 return c;
0860 return -1;
0861 }
0862
0863 int conv_uni_to_pc(struct vc_data *conp, long ucs)
0864 {
0865 struct uni_pagedict *dict;
0866 u16 **dir, *row, glyph;
0867
0868
0869 if (ucs > 0xffff)
0870 return -4;
0871 else if (ucs < 0x20)
0872 return -1;
0873 else if (ucs == 0xfeff || (ucs >= 0x200b && ucs <= 0x200f))
0874 return -2;
0875
0876
0877
0878
0879
0880 else if ((ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE)
0881 return ucs & UNI_DIRECT_MASK;
0882
0883 dict = *conp->uni_pagedict_loc;
0884 if (!dict)
0885 return -3;
0886
0887 dir = dict->uni_pgdir[UNI_DIR(ucs)];
0888 if (!dir)
0889 return -4;
0890
0891 row = dir[UNI_ROW(ucs)];
0892 if (!row)
0893 return -4;
0894
0895 glyph = row[UNI_GLYPH(ucs)];
0896 if (glyph >= MAX_GLYPH)
0897 return -4;
0898
0899 return glyph;
0900 }
0901
0902
0903
0904
0905
0906
0907 void __init
0908 console_map_init(void)
0909 {
0910 int i;
0911
0912 for (i = 0; i < MAX_NR_CONSOLES; i++)
0913 if (vc_cons_allocated(i) && !*vc_cons[i].d->uni_pagedict_loc)
0914 con_set_default_unimap(vc_cons[i].d);
0915 }
0916