linux/drivers/char/consolemap.c
<<
>>
Prefs
   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        u16             *inverse_trans_unicode;
 181        int             readonly;
 182};
 183
 184static struct uni_pagedir *dflt;
 185
 186static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int i)
 187{
 188        int j, glyph;
 189        unsigned short *t = translations[i];
 190        unsigned char *q;
 191        
 192        if (!p) return;
 193        q = p->inverse_translations[i];
 194
 195        if (!q) {
 196                q = p->inverse_translations[i] = (unsigned char *) 
 197                        kmalloc(MAX_GLYPH, GFP_KERNEL);
 198                if (!q) return;
 199        }
 200        memset(q, 0, MAX_GLYPH);
 201
 202        for (j = 0; j < E_TABSZ; j++) {
 203                glyph = conv_uni_to_pc(conp, t[j]);
 204                if (glyph >= 0 && glyph < MAX_GLYPH && q[glyph] < 32) {
 205                        /* prefer '-' above SHY etc. */
 206                        q[glyph] = j;
 207                }
 208        }
 209}
 210
 211static void set_inverse_trans_unicode(struct vc_data *conp,
 212                                      struct uni_pagedir *p)
 213{
 214        int i, j, k, glyph;
 215        u16 **p1, *p2;
 216        u16 *q;
 217
 218        if (!p) return;
 219        q = p->inverse_trans_unicode;
 220        if (!q) {
 221                q = p->inverse_trans_unicode =
 222                        kmalloc(MAX_GLYPH * sizeof(u16), GFP_KERNEL);
 223                if (!q)
 224                        return;
 225        }
 226        memset(q, 0, MAX_GLYPH * sizeof(u16));
 227
 228        for (i = 0; i < 32; i++) {
 229                p1 = p->uni_pgdir[i];
 230                if (!p1)
 231                        continue;
 232                for (j = 0; j < 32; j++) {
 233                        p2 = p1[j];
 234                        if (!p2)
 235                                continue;
 236                        for (k = 0; k < 64; k++) {
 237                                glyph = p2[k];
 238                                if (glyph >= 0 && glyph < MAX_GLYPH
 239                                               && q[glyph] < 32)
 240                                        q[glyph] = (i << 11) + (j << 6) + k;
 241                        }
 242                }
 243        }
 244}
 245
 246unsigned short *set_translate(int m, struct vc_data *vc)
 247{
 248        inv_translate[vc->vc_num] = m;
 249        return translations[m];
 250}
 251
 252/*
 253 * Inverse translation is impossible for several reasons:
 254 * 1. The font<->character maps are not 1-1.
 255 * 2. The text may have been written while a different translation map
 256 *    was active.
 257 * Still, it is now possible to a certain extent to cut and paste non-ASCII.
 258 */
 259u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode)
 260{
 261        struct uni_pagedir *p;
 262        int m;
 263        if (glyph < 0 || glyph >= MAX_GLYPH)
 264                return 0;
 265        else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc))
 266                return glyph;
 267        else if (use_unicode) {
 268                if (!p->inverse_trans_unicode)
 269                        return glyph;
 270                else
 271                        return p->inverse_trans_unicode[glyph];
 272        } else {
 273                m = inv_translate[conp->vc_num];
 274                if (!p->inverse_translations[m])
 275                        return glyph;
 276                else
 277                        return p->inverse_translations[m][glyph];
 278        }
 279}
 280
 281static void update_user_maps(void)
 282{
 283        int i;
 284        struct uni_pagedir *p, *q = NULL;
 285        
 286        for (i = 0; i < MAX_NR_CONSOLES; i++) {
 287                if (!vc_cons_allocated(i))
 288                        continue;
 289                p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
 290                if (p && p != q) {
 291                        set_inverse_transl(vc_cons[i].d, p, USER_MAP);
 292                        set_inverse_trans_unicode(vc_cons[i].d, p);
 293                        q = p;
 294                }
 295        }
 296}
 297
 298/*
 299 * Load customizable translation table
 300 * arg points to a 256 byte translation table.
 301 *
 302 * The "old" variants are for translation directly to font (using the
 303 * 0xf000-0xf0ff "transparent" Unicodes) whereas the "new" variants set
 304 * Unicodes explicitly.
 305 */
 306int con_set_trans_old(unsigned char __user * arg)
 307{
 308        int i;
 309        unsigned short *p = translations[USER_MAP];
 310
 311        if (!access_ok(VERIFY_READ, arg, E_TABSZ))
 312                return -EFAULT;
 313
 314        for (i=0; i<E_TABSZ ; i++) {
 315                unsigned char uc;
 316                __get_user(uc, arg+i);
 317                p[i] = UNI_DIRECT_BASE | uc;
 318        }
 319
 320        update_user_maps();
 321        return 0;
 322}
 323
 324int con_get_trans_old(unsigned char __user * arg)
 325{
 326        int i, ch;
 327        unsigned short *p = translations[USER_MAP];
 328
 329        if (!access_ok(VERIFY_WRITE, arg, E_TABSZ))
 330                return -EFAULT;
 331
 332        for (i=0; i<E_TABSZ ; i++)
 333          {
 334            ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
 335            __put_user((ch & ~0xff) ? 0 : ch, arg+i);
 336          }
 337        return 0;
 338}
 339
 340int con_set_trans_new(ushort __user * arg)
 341{
 342        int i;
 343        unsigned short *p = translations[USER_MAP];
 344
 345        if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short)))
 346                return -EFAULT;
 347
 348        for (i=0; i<E_TABSZ ; i++) {
 349                unsigned short us;
 350                __get_user(us, arg+i);
 351                p[i] = us;
 352        }
 353
 354        update_user_maps();
 355        return 0;
 356}
 357
 358int con_get_trans_new(ushort __user * arg)
 359{
 360        int i;
 361        unsigned short *p = translations[USER_MAP];
 362
 363        if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short)))
 364                return -EFAULT;
 365
 366        for (i=0; i<E_TABSZ ; i++)
 367          __put_user(p[i], arg+i);
 368        
 369        return 0;
 370}
 371
 372/*
 373 * Unicode -> current font conversion 
 374 *
 375 * A font has at most 512 chars, usually 256.
 376 * But one font position may represent several Unicode chars.
 377 * A hashtable is somewhat of a pain to deal with, so use a
 378 * "paged table" instead.  Simulation has shown the memory cost of
 379 * this 3-level paged table scheme to be comparable to a hash table.
 380 */
 381
 382extern u8 dfont_unicount[];     /* Defined in console_defmap.c */
 383extern u16 dfont_unitable[];
 384
 385static void con_release_unimap(struct uni_pagedir *p)
 386{
 387        u16 **p1;
 388        int i, j;
 389
 390        if (p == dflt) dflt = NULL;  
 391        for (i = 0; i < 32; i++) {
 392                if ((p1 = p->uni_pgdir[i]) != NULL) {
 393                        for (j = 0; j < 32; j++)
 394                                kfree(p1[j]);
 395                        kfree(p1);
 396                }
 397                p->uni_pgdir[i] = NULL;
 398        }
 399        for (i = 0; i < 4; i++) {
 400                kfree(p->inverse_translations[i]);
 401                p->inverse_translations[i] = NULL;
 402        }
 403        if (p->inverse_trans_unicode) {
 404                kfree(p->inverse_trans_unicode);
 405                p->inverse_trans_unicode = NULL;
 406        }
 407}
 408
 409void con_free_unimap(struct vc_data *vc)
 410{
 411        struct uni_pagedir *p;
 412
 413        p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
 414        if (!p)
 415                return;
 416        *vc->vc_uni_pagedir_loc = 0;
 417        if (--p->refcount)
 418                return;
 419        con_release_unimap(p);
 420        kfree(p);
 421}
 422  
 423static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
 424{
 425        int i, j, k;
 426        struct uni_pagedir *q;
 427        
 428        for (i = 0; i < MAX_NR_CONSOLES; i++) {
 429                if (!vc_cons_allocated(i))
 430                        continue;
 431                q = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
 432                if (!q || q == p || q->sum != p->sum)
 433                        continue;
 434                for (j = 0; j < 32; j++) {
 435                        u16 **p1, **q1;
 436                        p1 = p->uni_pgdir[j]; q1 = q->uni_pgdir[j];
 437                        if (!p1 && !q1)
 438                                continue;
 439                        if (!p1 || !q1)
 440                                break;
 441                        for (k = 0; k < 32; k++) {
 442                                if (!p1[k] && !q1[k])
 443                                        continue;
 444                                if (!p1[k] || !q1[k])
 445                                        break;
 446                                if (memcmp(p1[k], q1[k], 64*sizeof(u16)))
 447                                        break;
 448                        }
 449                        if (k < 32)
 450                                break;
 451                }
 452                if (j == 32) {
 453                        q->refcount++;
 454                        *conp->vc_uni_pagedir_loc = (unsigned long)q;
 455                        con_release_unimap(p);
 456                        kfree(p);
 457                        return 1;
 458                }
 459        }
 460        return 0;
 461}
 462
 463static int
 464con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
 465{
 466        int i, n;
 467        u16 **p1, *p2;
 468
 469        if (!(p1 = p->uni_pgdir[n = unicode >> 11])) {
 470                p1 = p->uni_pgdir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL);
 471                if (!p1) return -ENOMEM;
 472                for (i = 0; i < 32; i++)
 473                        p1[i] = NULL;
 474        }
 475
 476        if (!(p2 = p1[n = (unicode >> 6) & 0x1f])) {
 477                p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL);
 478                if (!p2) return -ENOMEM;
 479                memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */
 480        }
 481
 482        p2[unicode & 0x3f] = fontpos;
 483        
 484        p->sum += (fontpos << 20) + unicode;
 485
 486        return 0;
 487}
 488
 489/* ui is a leftover from using a hashtable, but might be used again */
 490int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
 491{
 492        struct uni_pagedir *p, *q;
 493  
 494        p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
 495        if (p && p->readonly) return -EIO;
 496        if (!p || --p->refcount) {
 497                q = kzalloc(sizeof(*p), GFP_KERNEL);
 498                if (!q) {
 499                        if (p) p->refcount++;
 500                        return -ENOMEM;
 501                }
 502                q->refcount=1;
 503                *vc->vc_uni_pagedir_loc = (unsigned long)q;
 504        } else {
 505                if (p == dflt) dflt = NULL;
 506                p->refcount++;
 507                p->sum = 0;
 508                con_release_unimap(p);
 509        }
 510        return 0;
 511}
 512
 513int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
 514{
 515        int err = 0, err1, i;
 516        struct uni_pagedir *p, *q;
 517
 518        p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
 519        if (p->readonly) return -EIO;
 520        
 521        if (!ct) return 0;
 522        
 523        if (p->refcount > 1) {
 524                int j, k;
 525                u16 **p1, *p2, l;
 526                
 527                err1 = con_clear_unimap(vc, NULL);
 528                if (err1) return err1;
 529                
 530                q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
 531                for (i = 0, l = 0; i < 32; i++)
 532                if ((p1 = p->uni_pgdir[i]))
 533                        for (j = 0; j < 32; j++)
 534                        if ((p2 = p1[j]))
 535                                for (k = 0; k < 64; k++, l++)
 536                                if (p2[k] != 0xffff) {
 537                                        err1 = con_insert_unipair(q, l, p2[k]);
 538                                        if (err1) {
 539                                                p->refcount++;
 540                                                *vc->vc_uni_pagedir_loc = (unsigned long)p;
 541                                                con_release_unimap(q);
 542                                                kfree(q);
 543                                                return err1; 
 544                                        }
 545                                }
 546                p = q;
 547        } else if (p == dflt)
 548                dflt = NULL;
 549        
 550        while (ct--) {
 551                unsigned short unicode, fontpos;
 552                __get_user(unicode, &list->unicode);
 553                __get_user(fontpos, &list->fontpos);
 554                if ((err1 = con_insert_unipair(p, unicode,fontpos)) != 0)
 555                        err = err1;
 556                        list++;
 557        }
 558        
 559        if (con_unify_unimap(vc, p))
 560                return err;
 561
 562        for (i = 0; i <= 3; i++)
 563                set_inverse_transl(vc, p, i); /* Update all inverse translations */
 564        set_inverse_trans_unicode(vc, p);
 565  
 566        return err;
 567}
 568
 569/* Loads the unimap for the hardware font, as defined in uni_hash.tbl.
 570   The representation used was the most compact I could come up
 571   with.  This routine is executed at sys_setup time, and when the
 572   PIO_FONTRESET ioctl is called. */
 573
 574int con_set_default_unimap(struct vc_data *vc)
 575{
 576        int i, j, err = 0, err1;
 577        u16 *q;
 578        struct uni_pagedir *p;
 579
 580        if (dflt) {
 581                p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
 582                if (p == dflt)
 583                        return 0;
 584                dflt->refcount++;
 585                *vc->vc_uni_pagedir_loc = (unsigned long)dflt;
 586                if (p && --p->refcount) {
 587                        con_release_unimap(p);
 588                        kfree(p);
 589                }
 590                return 0;
 591        }
 592        
 593        /* The default font is always 256 characters */
 594
 595        err = con_clear_unimap(vc, NULL);
 596        if (err) return err;
 597    
 598        p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
 599        q = dfont_unitable;
 600        
 601        for (i = 0; i < 256; i++)
 602                for (j = dfont_unicount[i]; j; j--) {
 603                        err1 = con_insert_unipair(p, *(q++), i);
 604                        if (err1)
 605                                err = err1;
 606                }
 607                        
 608        if (con_unify_unimap(vc, p)) {
 609                dflt = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
 610                return err;
 611        }
 612
 613        for (i = 0; i <= 3; i++)
 614                set_inverse_transl(vc, p, i);   /* Update all inverse translations */
 615        set_inverse_trans_unicode(vc, p);
 616        dflt = p;
 617        return err;
 618}
 619EXPORT_SYMBOL(con_set_default_unimap);
 620
 621int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
 622{
 623        struct uni_pagedir *q;
 624
 625        if (!*src_vc->vc_uni_pagedir_loc)
 626                return -EINVAL;
 627        if (*dst_vc->vc_uni_pagedir_loc == *src_vc->vc_uni_pagedir_loc)
 628                return 0;
 629        con_free_unimap(dst_vc);
 630        q = (struct uni_pagedir *)*src_vc->vc_uni_pagedir_loc;
 631        q->refcount++;
 632        *dst_vc->vc_uni_pagedir_loc = (long)q;
 633        return 0;
 634}
 635
 636int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list)
 637{
 638        int i, j, k, ect;
 639        u16 **p1, *p2;
 640        struct uni_pagedir *p;
 641
 642        ect = 0;
 643        if (*vc->vc_uni_pagedir_loc) {
 644                p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
 645                for (i = 0; i < 32; i++)
 646                if ((p1 = p->uni_pgdir[i]))
 647                        for (j = 0; j < 32; j++)
 648                        if ((p2 = *(p1++)))
 649                                for (k = 0; k < 64; k++) {
 650                                        if (*p2 < MAX_GLYPH && ect++ < ct) {
 651                                                __put_user((u_short)((i<<11)+(j<<6)+k),
 652                                                           &list->unicode);
 653                                                __put_user((u_short) *p2, 
 654                                                           &list->fontpos);
 655                                                list++;
 656                                        }
 657                                        p2++;
 658                                }
 659        }
 660        __put_user(ect, uct);
 661        return ((ect <= ct) ? 0 : -ENOMEM);
 662}
 663
 664void con_protect_unimap(struct vc_data *vc, int rdonly)
 665{
 666        struct uni_pagedir *p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
 667        
 668        if (p)
 669                p->readonly = rdonly;
 670}
 671
 672/*
 673 * Always use USER_MAP. These functions are used by the keyboard,
 674 * which shouldn't be affected by G0/G1 switching, etc.
 675 * If the user map still contains default values, i.e. the
 676 * direct-to-font mapping, then assume user is using Latin1.
 677 */
 678/* may be called during an interrupt */
 679u32 conv_8bit_to_uni(unsigned char c)
 680{
 681        unsigned short uni = translations[USER_MAP][c];
 682        return uni == (0xf000 | c) ? c : uni;
 683}
 684
 685int conv_uni_to_8bit(u32 uni)
 686{
 687        int c;
 688        for (c = 0; c < 0x100; c++)
 689                if (translations[USER_MAP][c] == uni ||
 690                   (translations[USER_MAP][c] == (c | 0xf000) && uni == c))
 691                        return c;
 692        return -1;
 693}
 694
 695int
 696conv_uni_to_pc(struct vc_data *conp, long ucs) 
 697{
 698        int h;
 699        u16 **p1, *p2;
 700        struct uni_pagedir *p;
 701  
 702        /* Only 16-bit codes supported at this time */
 703        if (ucs > 0xffff)
 704                return -4;              /* Not found */
 705        else if (ucs < 0x20)
 706                return -1;              /* Not a printable character */
 707        else if (ucs == 0xfeff || (ucs >= 0x200b && ucs <= 0x200f))
 708                return -2;                      /* Zero-width space */
 709        /*
 710         * UNI_DIRECT_BASE indicates the start of the region in the User Zone
 711         * which always has a 1:1 mapping to the currently loaded font.  The
 712         * UNI_DIRECT_MASK indicates the bit span of the region.
 713         */
 714        else if ((ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE)
 715                return ucs & UNI_DIRECT_MASK;
 716  
 717        if (!*conp->vc_uni_pagedir_loc)
 718                return -3;
 719
 720        p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;  
 721        if ((p1 = p->uni_pgdir[ucs >> 11]) &&
 722            (p2 = p1[(ucs >> 6) & 0x1f]) &&
 723            (h = p2[ucs & 0x3f]) < MAX_GLYPH)
 724                return h;
 725
 726        return -4;              /* not found */
 727}
 728
 729/*
 730 * This is called at sys_setup time, after memory and the console are
 731 * initialized.  It must be possible to call kmalloc(..., GFP_KERNEL)
 732 * from this function, hence the call from sys_setup.
 733 */
 734void __init 
 735console_map_init(void)
 736{
 737        int i;
 738        
 739        for (i = 0; i < MAX_NR_CONSOLES; i++)
 740                if (vc_cons_allocated(i) && !*vc_cons[i].d->vc_uni_pagedir_loc)
 741                        con_set_default_unimap(vc_cons[i].d);
 742}
 743
 744EXPORT_SYMBOL(con_copy_unimap);
 745