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