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        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 = (struct uni_pagedir *)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                ucs = 0xfffd;           /* U+FFFD: REPLACEMENT CHARACTER */
 630        else if (ucs < 0x20 || ucs >= 0xfffe)
 631                return -1;              /* Not a printable character */
 632        else if (ucs == 0xfeff || (ucs >= 0x200a && 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
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.