LCOV - code coverage report
Current view: top level - tty/vt - consolemap.c (source / functions) Coverage Total Hit
Test: TTY Combined Coverage Lines: 0.0 % 440 0
Test Date: 2025-08-26 15:45:50 Functions: 0.0 % 25 0

            Line data    Source code
       1              : // SPDX-License-Identifier: GPL-2.0
       2              : /*
       3              :  * consolemap.c
       4              :  *
       5              :  * Mapping from internal code (such as Latin-1 or Unicode or IBM PC code)
       6              :  * to font positions.
       7              :  *
       8              :  * aeb, 950210
       9              :  *
      10              :  * Support for multiple unimaps by Jakub Jelinek <[email protected]>, July 1998
      11              :  *
      12              :  * Fix bug in inverse translation. Stanislav Voronyi <[email protected]>, Dec 1998
      13              :  *
      14              :  * In order to prevent the following circular lock dependency:
      15              :  *   &mm->mmap_lock --> cpu_hotplug.lock --> console_lock --> &mm->mmap_lock
      16              :  *
      17              :  * We cannot allow page fault to happen while holding the console_lock.
      18              :  * Therefore, all the userspace copy operations have to be done outside
      19              :  * the console_lock critical sections.
      20              :  *
      21              :  * As all the affected functions are all called directly from vt_ioctl(), we
      22              :  * can allocate some small buffers directly on stack without worrying about
      23              :  * stack overflow.
      24              :  */
      25              : 
      26              : #include <linux/bitfield.h>
      27              : #include <linux/bits.h>
      28              : #include <linux/module.h>
      29              : #include <linux/kd.h>
      30              : #include <linux/errno.h>
      31              : #include <linux/mm.h>
      32              : #include <linux/slab.h>
      33              : #include <linux/init.h>
      34              : #include <linux/tty.h>
      35              : #include <linux/uaccess.h>
      36              : #include <linux/console.h>
      37              : #include <linux/consolemap.h>
      38              : #include <linux/vt_kern.h>
      39              : #include <linux/string.h>
      40              : 
      41              : static unsigned short translations[][E_TABSZ] = {
      42              :   /* 8-bit Latin-1 mapped to Unicode -- trivial mapping */
      43              :   [LAT1_MAP] = {
      44              :     0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
      45              :     0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
      46              :     0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
      47              :     0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
      48              :     0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
      49              :     0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
      50              :     0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
      51              :     0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
      52              :     0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
      53              :     0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
      54              :     0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
      55              :     0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
      56              :     0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
      57              :     0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
      58              :     0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
      59              :     0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
      60              :     0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
      61              :     0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
      62              :     0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
      63              :     0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
      64              :     0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
      65              :     0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
      66              :     0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
      67              :     0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
      68              :     0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
      69              :     0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
      70              :     0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
      71              :     0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
      72              :     0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
      73              :     0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
      74              :     0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
      75              :     0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
      76              :   },
      77              :   /* VT100 graphics mapped to Unicode */
      78              :   [GRAF_MAP] = {
      79              :     0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
      80              :     0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
      81              :     0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
      82              :     0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
      83              :     0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
      84              :     0x0028, 0x0029, 0x002a, 0x2192, 0x2190, 0x2191, 0x2193, 0x002f,
      85              :     0x2588, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
      86              :     0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
      87              :     0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
      88              :     0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
      89              :     0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
      90              :     0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x00a0,
      91              :     0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1,
      92              :     0x2591, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba,
      93              :     0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c,
      94              :     0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x007f,
      95              :     0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
      96              :     0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
      97              :     0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
      98              :     0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
      99              :     0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
     100              :     0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
     101              :     0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
     102              :     0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
     103              :     0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
     104              :     0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
     105              :     0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
     106              :     0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
     107              :     0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
     108              :     0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
     109              :     0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
     110              :     0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
     111              :   },
     112              :   /* IBM Codepage 437 mapped to Unicode */
     113              :   [IBMPC_MAP] = {
     114              :     0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022,
     115              :     0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c,
     116              :     0x25b6, 0x25c0, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8,
     117              :     0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc,
     118              :     0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
     119              :     0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
     120              :     0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
     121              :     0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
     122              :     0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
     123              :     0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
     124              :     0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
     125              :     0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
     126              :     0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
     127              :     0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
     128              :     0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
     129              :     0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302,
     130              :     0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
     131              :     0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
     132              :     0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
     133              :     0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
     134              :     0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
     135              :     0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
     136              :     0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
     137              :     0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
     138              :     0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
     139              :     0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
     140              :     0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
     141              :     0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
     142              :     0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
     143              :     0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
     144              :     0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
     145              :     0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0
     146              :   },
     147              :   /* User mapping -- default to codes for direct font mapping */
     148              :   [USER_MAP] = {
     149              :     0xf000, 0xf001, 0xf002, 0xf003, 0xf004, 0xf005, 0xf006, 0xf007,
     150              :     0xf008, 0xf009, 0xf00a, 0xf00b, 0xf00c, 0xf00d, 0xf00e, 0xf00f,
     151              :     0xf010, 0xf011, 0xf012, 0xf013, 0xf014, 0xf015, 0xf016, 0xf017,
     152              :     0xf018, 0xf019, 0xf01a, 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f,
     153              :     0xf020, 0xf021, 0xf022, 0xf023, 0xf024, 0xf025, 0xf026, 0xf027,
     154              :     0xf028, 0xf029, 0xf02a, 0xf02b, 0xf02c, 0xf02d, 0xf02e, 0xf02f,
     155              :     0xf030, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037,
     156              :     0xf038, 0xf039, 0xf03a, 0xf03b, 0xf03c, 0xf03d, 0xf03e, 0xf03f,
     157              :     0xf040, 0xf041, 0xf042, 0xf043, 0xf044, 0xf045, 0xf046, 0xf047,
     158              :     0xf048, 0xf049, 0xf04a, 0xf04b, 0xf04c, 0xf04d, 0xf04e, 0xf04f,
     159              :     0xf050, 0xf051, 0xf052, 0xf053, 0xf054, 0xf055, 0xf056, 0xf057,
     160              :     0xf058, 0xf059, 0xf05a, 0xf05b, 0xf05c, 0xf05d, 0xf05e, 0xf05f,
     161              :     0xf060, 0xf061, 0xf062, 0xf063, 0xf064, 0xf065, 0xf066, 0xf067,
     162              :     0xf068, 0xf069, 0xf06a, 0xf06b, 0xf06c, 0xf06d, 0xf06e, 0xf06f,
     163              :     0xf070, 0xf071, 0xf072, 0xf073, 0xf074, 0xf075, 0xf076, 0xf077,
     164              :     0xf078, 0xf079, 0xf07a, 0xf07b, 0xf07c, 0xf07d, 0xf07e, 0xf07f,
     165              :     0xf080, 0xf081, 0xf082, 0xf083, 0xf084, 0xf085, 0xf086, 0xf087,
     166              :     0xf088, 0xf089, 0xf08a, 0xf08b, 0xf08c, 0xf08d, 0xf08e, 0xf08f,
     167              :     0xf090, 0xf091, 0xf092, 0xf093, 0xf094, 0xf095, 0xf096, 0xf097,
     168              :     0xf098, 0xf099, 0xf09a, 0xf09b, 0xf09c, 0xf09d, 0xf09e, 0xf09f,
     169              :     0xf0a0, 0xf0a1, 0xf0a2, 0xf0a3, 0xf0a4, 0xf0a5, 0xf0a6, 0xf0a7,
     170              :     0xf0a8, 0xf0a9, 0xf0aa, 0xf0ab, 0xf0ac, 0xf0ad, 0xf0ae, 0xf0af,
     171              :     0xf0b0, 0xf0b1, 0xf0b2, 0xf0b3, 0xf0b4, 0xf0b5, 0xf0b6, 0xf0b7,
     172              :     0xf0b8, 0xf0b9, 0xf0ba, 0xf0bb, 0xf0bc, 0xf0bd, 0xf0be, 0xf0bf,
     173              :     0xf0c0, 0xf0c1, 0xf0c2, 0xf0c3, 0xf0c4, 0xf0c5, 0xf0c6, 0xf0c7,
     174              :     0xf0c8, 0xf0c9, 0xf0ca, 0xf0cb, 0xf0cc, 0xf0cd, 0xf0ce, 0xf0cf,
     175              :     0xf0d0, 0xf0d1, 0xf0d2, 0xf0d3, 0xf0d4, 0xf0d5, 0xf0d6, 0xf0d7,
     176              :     0xf0d8, 0xf0d9, 0xf0da, 0xf0db, 0xf0dc, 0xf0dd, 0xf0de, 0xf0df,
     177              :     0xf0e0, 0xf0e1, 0xf0e2, 0xf0e3, 0xf0e4, 0xf0e5, 0xf0e6, 0xf0e7,
     178              :     0xf0e8, 0xf0e9, 0xf0ea, 0xf0eb, 0xf0ec, 0xf0ed, 0xf0ee, 0xf0ef,
     179              :     0xf0f0, 0xf0f1, 0xf0f2, 0xf0f3, 0xf0f4, 0xf0f5, 0xf0f6, 0xf0f7,
     180              :     0xf0f8, 0xf0f9, 0xf0fa, 0xf0fb, 0xf0fc, 0xf0fd, 0xf0fe, 0xf0ff
     181              :   }
     182              : };
     183              : 
     184              : /* The standard kernel character-to-font mappings are not invertible
     185              :    -- this is just a best effort. */
     186              : 
     187              : #define MAX_GLYPH 512           /* Max possible glyph value */
     188              : 
     189              : static enum translation_map inv_translate[MAX_NR_CONSOLES];
     190              : 
     191              : #define UNI_DIRS        32U
     192              : #define UNI_DIR_ROWS    32U
     193              : #define UNI_ROW_GLYPHS  64U
     194              : 
     195              : #define UNI_DIR_BITS            GENMASK(15, 11)
     196              : #define UNI_ROW_BITS            GENMASK(10,  6)
     197              : #define UNI_GLYPH_BITS          GENMASK( 5,  0)
     198              : 
     199              : #define UNI_DIR(uni)            FIELD_GET(UNI_DIR_BITS, (uni))
     200              : #define UNI_ROW(uni)            FIELD_GET(UNI_ROW_BITS, (uni))
     201              : #define UNI_GLYPH(uni)          FIELD_GET(UNI_GLYPH_BITS, (uni))
     202              : 
     203              : #define UNI(dir, row, glyph)    (FIELD_PREP(UNI_DIR_BITS, (dir)) | \
     204              :                                  FIELD_PREP(UNI_ROW_BITS, (row)) | \
     205              :                                  FIELD_PREP(UNI_GLYPH_BITS, (glyph)))
     206              : 
     207              : /**
     208              :  * struct uni_pagedict - unicode directory
     209              :  *
     210              :  * @uni_pgdir: 32*32*64 table with glyphs
     211              :  * @refcount: reference count of this structure
     212              :  * @sum: checksum
     213              :  * @inverse_translations: best-effort inverse mapping
     214              :  * @inverse_trans_unicode: best-effort inverse mapping to unicode
     215              :  */
     216              : struct uni_pagedict {
     217              :         u16             **uni_pgdir[UNI_DIRS];
     218              :         unsigned long   refcount;
     219              :         unsigned long   sum;
     220              :         unsigned char   *inverse_translations[LAST_MAP + 1];
     221              :         u16             *inverse_trans_unicode;
     222              : };
     223              : 
     224              : static struct uni_pagedict *dflt;
     225              : 
     226            0 : static void set_inverse_transl(struct vc_data *conp, struct uni_pagedict *dict,
     227              :                enum translation_map m)
     228              : {
     229            0 :         unsigned short *t = translations[m];
     230            0 :         unsigned char *inv;
     231              : 
     232            0 :         if (!dict)
     233            0 :                 return;
     234            0 :         inv = dict->inverse_translations[m];
     235              : 
     236            0 :         if (!inv) {
     237            0 :                 inv = dict->inverse_translations[m] = kmalloc(MAX_GLYPH,
     238              :                                 GFP_KERNEL);
     239            0 :                 if (!inv)
     240            0 :                         return;
     241            0 :         }
     242            0 :         memset(inv, 0, MAX_GLYPH);
     243              : 
     244            0 :         for (unsigned int ch = 0; ch < ARRAY_SIZE(translations[m]); ch++) {
     245            0 :                 int glyph = conv_uni_to_pc(conp, t[ch]);
     246            0 :                 if (glyph >= 0 && glyph < MAX_GLYPH && inv[glyph] < 32) {
     247              :                         /* prefer '-' above SHY etc. */
     248            0 :                         inv[glyph] = ch;
     249            0 :                 }
     250            0 :         }
     251            0 : }
     252              : 
     253            0 : static void set_inverse_trans_unicode(struct uni_pagedict *dict)
     254              : {
     255            0 :         unsigned int d, r, g;
     256            0 :         u16 *inv;
     257              : 
     258            0 :         if (!dict)
     259            0 :                 return;
     260              : 
     261            0 :         inv = dict->inverse_trans_unicode;
     262            0 :         if (!inv) {
     263            0 :                 inv = dict->inverse_trans_unicode = kmalloc_array(MAX_GLYPH,
     264              :                                 sizeof(*inv), GFP_KERNEL);
     265            0 :                 if (!inv)
     266            0 :                         return;
     267            0 :         }
     268            0 :         memset(inv, 0, MAX_GLYPH * sizeof(*inv));
     269              : 
     270            0 :         for (d = 0; d < UNI_DIRS; d++) {
     271            0 :                 u16 **dir = dict->uni_pgdir[d];
     272            0 :                 if (!dir)
     273            0 :                         continue;
     274            0 :                 for (r = 0; r < UNI_DIR_ROWS; r++) {
     275            0 :                         u16 *row = dir[r];
     276            0 :                         if (!row)
     277            0 :                                 continue;
     278            0 :                         for (g = 0; g < UNI_ROW_GLYPHS; g++) {
     279            0 :                                 u16 glyph = row[g];
     280            0 :                                 if (glyph < MAX_GLYPH && inv[glyph] < 32)
     281            0 :                                         inv[glyph] = UNI(d, r, g);
     282            0 :                         }
     283            0 :                 }
     284            0 :         }
     285            0 : }
     286              : 
     287            0 : unsigned short *set_translate(enum translation_map m, struct vc_data *vc)
     288              : {
     289            0 :         inv_translate[vc->vc_num] = m;
     290            0 :         return translations[m];
     291              : }
     292              : 
     293              : /*
     294              :  * Inverse translation is impossible for several reasons:
     295              :  * 1. The font<->character maps are not 1-1.
     296              :  * 2. The text may have been written while a different translation map
     297              :  *    was active.
     298              :  * Still, it is now possible to a certain extent to cut and paste non-ASCII.
     299              :  */
     300            0 : u16 inverse_translate(const struct vc_data *conp, u16 glyph, bool use_unicode)
     301              : {
     302            0 :         struct uni_pagedict *p;
     303            0 :         enum translation_map m;
     304              : 
     305            0 :         if (glyph >= MAX_GLYPH)
     306            0 :                 return 0;
     307              : 
     308            0 :         p = *conp->uni_pagedict_loc;
     309            0 :         if (!p)
     310            0 :                 return glyph;
     311              : 
     312            0 :         if (use_unicode) {
     313            0 :                 if (!p->inverse_trans_unicode)
     314            0 :                         return glyph;
     315              : 
     316            0 :                 return p->inverse_trans_unicode[glyph];
     317              :         }
     318              : 
     319            0 :         m = inv_translate[conp->vc_num];
     320            0 :         if (!p->inverse_translations[m])
     321            0 :                 return glyph;
     322              : 
     323            0 :         return p->inverse_translations[m][glyph];
     324            0 : }
     325              : EXPORT_SYMBOL_GPL(inverse_translate);
     326              : 
     327            0 : static void update_user_maps(void)
     328              : {
     329            0 :         int i;
     330            0 :         struct uni_pagedict *p, *q = NULL;
     331              : 
     332            0 :         for (i = 0; i < MAX_NR_CONSOLES; i++) {
     333            0 :                 if (!vc_cons_allocated(i))
     334            0 :                         continue;
     335            0 :                 p = *vc_cons[i].d->uni_pagedict_loc;
     336            0 :                 if (p && p != q) {
     337            0 :                         set_inverse_transl(vc_cons[i].d, p, USER_MAP);
     338            0 :                         set_inverse_trans_unicode(p);
     339            0 :                         q = p;
     340            0 :                 }
     341            0 :         }
     342            0 : }
     343              : 
     344              : /*
     345              :  * Load customizable translation table
     346              :  * arg points to a 256 byte translation table.
     347              :  *
     348              :  * The "old" variants are for translation directly to font (using the
     349              :  * 0xf000-0xf0ff "transparent" Unicodes) whereas the "new" variants set
     350              :  * Unicodes explicitly.
     351              :  */
     352            0 : int con_set_trans_old(unsigned char __user * arg)
     353              : {
     354            0 :         unsigned short inbuf[E_TABSZ];
     355            0 :         unsigned int i;
     356            0 :         unsigned char ch;
     357              : 
     358            0 :         for (i = 0; i < ARRAY_SIZE(inbuf); i++) {
     359            0 :                 if (get_user(ch, &arg[i]))
     360            0 :                         return -EFAULT;
     361            0 :                 inbuf[i] = UNI_DIRECT_BASE | ch;
     362            0 :         }
     363              : 
     364            0 :         console_lock();
     365            0 :         memcpy(translations[USER_MAP], inbuf, sizeof(inbuf));
     366            0 :         update_user_maps();
     367            0 :         console_unlock();
     368            0 :         return 0;
     369            0 : }
     370              : 
     371            0 : int con_get_trans_old(unsigned char __user * arg)
     372              : {
     373            0 :         int i, ch;
     374            0 :         unsigned short *p = translations[USER_MAP];
     375            0 :         unsigned char outbuf[E_TABSZ];
     376              : 
     377            0 :         console_lock();
     378            0 :         for (i = 0; i < ARRAY_SIZE(outbuf); i++)
     379              :         {
     380            0 :                 ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
     381            0 :                 outbuf[i] = (ch & ~0xff) ? 0 : ch;
     382            0 :         }
     383            0 :         console_unlock();
     384              : 
     385            0 :         return copy_to_user(arg, outbuf, sizeof(outbuf)) ? -EFAULT : 0;
     386            0 : }
     387              : 
     388            0 : int con_set_trans_new(ushort __user * arg)
     389              : {
     390            0 :         unsigned short inbuf[E_TABSZ];
     391              : 
     392            0 :         if (copy_from_user(inbuf, arg, sizeof(inbuf)))
     393            0 :                 return -EFAULT;
     394              : 
     395            0 :         console_lock();
     396            0 :         memcpy(translations[USER_MAP], inbuf, sizeof(inbuf));
     397            0 :         update_user_maps();
     398            0 :         console_unlock();
     399            0 :         return 0;
     400            0 : }
     401              : 
     402            0 : int con_get_trans_new(ushort __user * arg)
     403              : {
     404            0 :         unsigned short outbuf[E_TABSZ];
     405              : 
     406            0 :         console_lock();
     407            0 :         memcpy(outbuf, translations[USER_MAP], sizeof(outbuf));
     408            0 :         console_unlock();
     409              : 
     410            0 :         return copy_to_user(arg, outbuf, sizeof(outbuf)) ? -EFAULT : 0;
     411            0 : }
     412              : 
     413              : /*
     414              :  * Unicode -> current font conversion
     415              :  *
     416              :  * A font has at most 512 chars, usually 256.
     417              :  * But one font position may represent several Unicode chars.
     418              :  * A hashtable is somewhat of a pain to deal with, so use a
     419              :  * "paged table" instead.  Simulation has shown the memory cost of
     420              :  * this 3-level paged table scheme to be comparable to a hash table.
     421              :  */
     422              : 
     423              : extern u8 dfont_unicount[];     /* Defined in console_defmap.c */
     424              : extern u16 dfont_unitable[];
     425              : 
     426            0 : static void con_release_unimap(struct uni_pagedict *dict)
     427              : {
     428            0 :         unsigned int d, r;
     429              : 
     430            0 :         if (dict == dflt)
     431            0 :                 dflt = NULL;
     432              : 
     433            0 :         for (d = 0; d < UNI_DIRS; d++) {
     434            0 :                 u16 **dir = dict->uni_pgdir[d];
     435            0 :                 if (dir != NULL) {
     436            0 :                         for (r = 0; r < UNI_DIR_ROWS; r++)
     437            0 :                                 kfree(dir[r]);
     438            0 :                         kfree(dir);
     439            0 :                 }
     440            0 :                 dict->uni_pgdir[d] = NULL;
     441            0 :         }
     442              : 
     443            0 :         for (r = 0; r < ARRAY_SIZE(dict->inverse_translations); r++) {
     444            0 :                 kfree(dict->inverse_translations[r]);
     445            0 :                 dict->inverse_translations[r] = NULL;
     446            0 :         }
     447              : 
     448            0 :         kfree(dict->inverse_trans_unicode);
     449            0 :         dict->inverse_trans_unicode = NULL;
     450            0 : }
     451              : 
     452              : /* Caller must hold the console lock */
     453            0 : void con_free_unimap(struct vc_data *vc)
     454              : {
     455            0 :         struct uni_pagedict *p;
     456              : 
     457            0 :         p = *vc->uni_pagedict_loc;
     458            0 :         if (!p)
     459            0 :                 return;
     460            0 :         *vc->uni_pagedict_loc = NULL;
     461            0 :         if (--p->refcount)
     462            0 :                 return;
     463            0 :         con_release_unimap(p);
     464            0 :         kfree(p);
     465            0 : }
     466              : 
     467            0 : static int con_unify_unimap(struct vc_data *conp, struct uni_pagedict *dict1)
     468              : {
     469            0 :         struct uni_pagedict *dict2;
     470            0 :         unsigned int cons, d, r;
     471              : 
     472            0 :         for (cons = 0; cons < MAX_NR_CONSOLES; cons++) {
     473            0 :                 if (!vc_cons_allocated(cons))
     474            0 :                         continue;
     475            0 :                 dict2 = *vc_cons[cons].d->uni_pagedict_loc;
     476            0 :                 if (!dict2 || dict2 == dict1 || dict2->sum != dict1->sum)
     477            0 :                         continue;
     478            0 :                 for (d = 0; d < UNI_DIRS; d++) {
     479            0 :                         u16 **dir1 = dict1->uni_pgdir[d];
     480            0 :                         u16 **dir2 = dict2->uni_pgdir[d];
     481            0 :                         if (!dir1 && !dir2)
     482            0 :                                 continue;
     483            0 :                         if (!dir1 || !dir2)
     484            0 :                                 break;
     485            0 :                         for (r = 0; r < UNI_DIR_ROWS; r++) {
     486            0 :                                 if (!dir1[r] && !dir2[r])
     487            0 :                                         continue;
     488            0 :                                 if (!dir1[r] || !dir2[r])
     489            0 :                                         break;
     490            0 :                                 if (memcmp(dir1[r], dir2[r], UNI_ROW_GLYPHS *
     491              :                                                         sizeof(*dir1[r])))
     492            0 :                                         break;
     493            0 :                         }
     494            0 :                         if (r < UNI_DIR_ROWS)
     495            0 :                                 break;
     496            0 :                 }
     497            0 :                 if (d == UNI_DIRS) {
     498            0 :                         dict2->refcount++;
     499            0 :                         *conp->uni_pagedict_loc = dict2;
     500            0 :                         con_release_unimap(dict1);
     501            0 :                         kfree(dict1);
     502            0 :                         return 1;
     503              :                 }
     504            0 :         }
     505            0 :         return 0;
     506            0 : }
     507              : 
     508              : static int
     509            0 : con_insert_unipair(struct uni_pagedict *p, u_short unicode, u_short fontpos)
     510              : {
     511            0 :         u16 **dir, *row;
     512            0 :         unsigned int n;
     513              : 
     514            0 :         n = UNI_DIR(unicode);
     515            0 :         dir = p->uni_pgdir[n];
     516            0 :         if (!dir) {
     517            0 :                 dir = p->uni_pgdir[n] = kcalloc(UNI_DIR_ROWS, sizeof(*dir),
     518              :                                 GFP_KERNEL);
     519            0 :                 if (!dir)
     520            0 :                         return -ENOMEM;
     521            0 :         }
     522              : 
     523            0 :         n = UNI_ROW(unicode);
     524            0 :         row = dir[n];
     525            0 :         if (!row) {
     526            0 :                 row = dir[n] = kmalloc_array(UNI_ROW_GLYPHS, sizeof(*row),
     527              :                                 GFP_KERNEL);
     528            0 :                 if (!row)
     529            0 :                         return -ENOMEM;
     530              :                 /* No glyphs for the characters (yet) */
     531            0 :                 memset(row, 0xff, UNI_ROW_GLYPHS * sizeof(*row));
     532            0 :         }
     533              : 
     534            0 :         row[UNI_GLYPH(unicode)] = fontpos;
     535              : 
     536            0 :         p->sum += (fontpos << 20U) + unicode;
     537              : 
     538            0 :         return 0;
     539            0 : }
     540              : 
     541            0 : static int con_allocate_new(struct vc_data *vc)
     542              : {
     543            0 :         struct uni_pagedict *new, *old = *vc->uni_pagedict_loc;
     544              : 
     545            0 :         new = kzalloc(sizeof(*new), GFP_KERNEL);
     546            0 :         if (!new)
     547            0 :                 return -ENOMEM;
     548              : 
     549            0 :         new->refcount = 1;
     550            0 :         *vc->uni_pagedict_loc = new;
     551              : 
     552            0 :         if (old)
     553            0 :                 old->refcount--;
     554              : 
     555            0 :         return 0;
     556            0 : }
     557              : 
     558              : /* Caller must hold the lock */
     559            0 : static int con_do_clear_unimap(struct vc_data *vc)
     560              : {
     561            0 :         struct uni_pagedict *old = *vc->uni_pagedict_loc;
     562              : 
     563            0 :         if (!old || old->refcount > 1)
     564            0 :                 return con_allocate_new(vc);
     565              : 
     566            0 :         old->sum = 0;
     567            0 :         con_release_unimap(old);
     568              : 
     569            0 :         return 0;
     570            0 : }
     571              : 
     572            0 : int con_clear_unimap(struct vc_data *vc)
     573              : {
     574            0 :         int ret;
     575            0 :         console_lock();
     576            0 :         ret = con_do_clear_unimap(vc);
     577            0 :         console_unlock();
     578            0 :         return ret;
     579            0 : }
     580              : 
     581            0 : static struct uni_pagedict *con_unshare_unimap(struct vc_data *vc,
     582              :                 struct uni_pagedict *old)
     583              : {
     584            0 :         struct uni_pagedict *new;
     585            0 :         unsigned int d, r, g;
     586            0 :         int ret;
     587            0 :         u16 uni = 0;
     588              : 
     589            0 :         ret = con_allocate_new(vc);
     590            0 :         if (ret)
     591            0 :                 return ERR_PTR(ret);
     592              : 
     593            0 :         new = *vc->uni_pagedict_loc;
     594              : 
     595              :         /*
     596              :          * uni_pgdir is a 32*32*64 table with rows allocated when its first
     597              :          * entry is added. The unicode value must still be incremented for
     598              :          * empty rows. We are copying entries from "old" to "new".
     599              :          */
     600            0 :         for (d = 0; d < UNI_DIRS; d++) {
     601            0 :                 u16 **dir = old->uni_pgdir[d];
     602            0 :                 if (!dir) {
     603              :                         /* Account for empty table */
     604            0 :                         uni += UNI_DIR_ROWS * UNI_ROW_GLYPHS;
     605            0 :                         continue;
     606              :                 }
     607              : 
     608            0 :                 for (r = 0; r < UNI_DIR_ROWS; r++) {
     609            0 :                         u16 *row = dir[r];
     610            0 :                         if (!row) {
     611              :                                 /* Account for row of 64 empty entries */
     612            0 :                                 uni += UNI_ROW_GLYPHS;
     613            0 :                                 continue;
     614              :                         }
     615              : 
     616            0 :                         for (g = 0; g < UNI_ROW_GLYPHS; g++, uni++) {
     617            0 :                                 if (row[g] == 0xffff)
     618            0 :                                         continue;
     619              :                                 /*
     620              :                                  * Found one, copy entry for unicode uni with
     621              :                                  * fontpos value row[g].
     622              :                                  */
     623            0 :                                 ret = con_insert_unipair(new, uni, row[g]);
     624            0 :                                 if (ret) {
     625            0 :                                         old->refcount++;
     626            0 :                                         *vc->uni_pagedict_loc = old;
     627            0 :                                         con_release_unimap(new);
     628            0 :                                         kfree(new);
     629            0 :                                         return ERR_PTR(ret);
     630              :                                 }
     631            0 :                         }
     632            0 :                 }
     633            0 :         }
     634              : 
     635            0 :         return new;
     636            0 : }
     637              : 
     638            0 : int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
     639              : {
     640            0 :         int err = 0, err1;
     641            0 :         struct uni_pagedict *dict;
     642            0 :         struct unipair *unilist, *plist;
     643              : 
     644            0 :         if (!ct)
     645            0 :                 return 0;
     646              : 
     647            0 :         unilist = vmemdup_array_user(list, ct, sizeof(*unilist));
     648            0 :         if (IS_ERR(unilist))
     649            0 :                 return PTR_ERR(unilist);
     650              : 
     651            0 :         console_lock();
     652              : 
     653              :         /* Save original vc_unipagdir_loc in case we allocate a new one */
     654            0 :         dict = *vc->uni_pagedict_loc;
     655            0 :         if (!dict) {
     656            0 :                 err = -EINVAL;
     657            0 :                 goto out_unlock;
     658              :         }
     659              : 
     660            0 :         if (dict->refcount > 1) {
     661            0 :                 dict = con_unshare_unimap(vc, dict);
     662            0 :                 if (IS_ERR(dict)) {
     663            0 :                         err = PTR_ERR(dict);
     664            0 :                         goto out_unlock;
     665              :                 }
     666            0 :         } else if (dict == dflt) {
     667            0 :                 dflt = NULL;
     668            0 :         }
     669              : 
     670              :         /*
     671              :          * Insert user specified unicode pairs into new table.
     672              :          */
     673            0 :         for (plist = unilist; ct; ct--, plist++) {
     674            0 :                 err1 = con_insert_unipair(dict, plist->unicode, plist->fontpos);
     675            0 :                 if (err1)
     676            0 :                         err = err1;
     677            0 :         }
     678              : 
     679              :         /*
     680              :          * Merge with fontmaps of any other virtual consoles.
     681              :          */
     682            0 :         if (con_unify_unimap(vc, dict))
     683            0 :                 goto out_unlock;
     684              : 
     685            0 :         for (enum translation_map m = FIRST_MAP; m <= LAST_MAP; m++)
     686            0 :                 set_inverse_transl(vc, dict, m);
     687            0 :         set_inverse_trans_unicode(dict);
     688              : 
     689              : out_unlock:
     690            0 :         console_unlock();
     691            0 :         kvfree(unilist);
     692            0 :         return err;
     693            0 : }
     694              : 
     695              : /**
     696              :  *      con_set_default_unimap  -       set default unicode map
     697              :  *      @vc: the console we are updating
     698              :  *
     699              :  *      Loads the unimap for the hardware font, as defined in uni_hash.tbl.
     700              :  *      The representation used was the most compact I could come up
     701              :  *      with.  This routine is executed at video setup, and when the
     702              :  *      PIO_FONTRESET ioctl is called.
     703              :  *
     704              :  *      The caller must hold the console lock
     705              :  */
     706            0 : int con_set_default_unimap(struct vc_data *vc)
     707              : {
     708            0 :         struct uni_pagedict *dict;
     709            0 :         unsigned int fontpos, count;
     710            0 :         int err = 0, err1;
     711            0 :         u16 *dfont;
     712              : 
     713            0 :         if (dflt) {
     714            0 :                 dict = *vc->uni_pagedict_loc;
     715            0 :                 if (dict == dflt)
     716            0 :                         return 0;
     717              : 
     718            0 :                 dflt->refcount++;
     719            0 :                 *vc->uni_pagedict_loc = dflt;
     720            0 :                 if (dict && !--dict->refcount) {
     721            0 :                         con_release_unimap(dict);
     722            0 :                         kfree(dict);
     723            0 :                 }
     724            0 :                 return 0;
     725              :         }
     726              : 
     727              :         /* The default font is always 256 characters */
     728              : 
     729            0 :         err = con_do_clear_unimap(vc);
     730            0 :         if (err)
     731            0 :                 return err;
     732              : 
     733            0 :         dict = *vc->uni_pagedict_loc;
     734            0 :         dfont = dfont_unitable;
     735              : 
     736            0 :         for (fontpos = 0; fontpos < 256U; fontpos++)
     737            0 :                 for (count = dfont_unicount[fontpos]; count; count--) {
     738            0 :                         err1 = con_insert_unipair(dict, *(dfont++), fontpos);
     739            0 :                         if (err1)
     740            0 :                                 err = err1;
     741            0 :                 }
     742              : 
     743            0 :         if (con_unify_unimap(vc, dict)) {
     744            0 :                 dflt = *vc->uni_pagedict_loc;
     745            0 :                 return err;
     746              :         }
     747              : 
     748            0 :         for (enum translation_map m = FIRST_MAP; m <= LAST_MAP; m++)
     749            0 :                 set_inverse_transl(vc, dict, m);
     750            0 :         set_inverse_trans_unicode(dict);
     751            0 :         dflt = dict;
     752            0 :         return err;
     753            0 : }
     754              : EXPORT_SYMBOL(con_set_default_unimap);
     755              : 
     756              : /**
     757              :  *      con_copy_unimap         -       copy unimap between two vts
     758              :  *      @dst_vc: target
     759              :  *      @src_vc: source
     760              :  *
     761              :  *      The caller must hold the console lock when invoking this method
     762              :  */
     763            0 : int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
     764              : {
     765            0 :         struct uni_pagedict *src;
     766              : 
     767            0 :         if (!*src_vc->uni_pagedict_loc)
     768            0 :                 return -EINVAL;
     769            0 :         if (*dst_vc->uni_pagedict_loc == *src_vc->uni_pagedict_loc)
     770            0 :                 return 0;
     771            0 :         con_free_unimap(dst_vc);
     772            0 :         src = *src_vc->uni_pagedict_loc;
     773            0 :         src->refcount++;
     774            0 :         *dst_vc->uni_pagedict_loc = src;
     775            0 :         return 0;
     776            0 : }
     777              : EXPORT_SYMBOL(con_copy_unimap);
     778              : 
     779              : /*
     780              :  *      con_get_unimap          -       get the unicode map
     781              :  *
     782              :  *      Read the console unicode data for this console. Called from the ioctl
     783              :  *      handlers.
     784              :  */
     785            0 : int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct,
     786              :                 struct unipair __user *list)
     787              : {
     788            0 :         ushort ect;
     789            0 :         struct uni_pagedict *dict;
     790            0 :         struct unipair *unilist;
     791            0 :         unsigned int d, r, g;
     792            0 :         int ret = 0;
     793              : 
     794            0 :         unilist = kvmalloc_array(ct, sizeof(*unilist), GFP_KERNEL);
     795            0 :         if (!unilist)
     796            0 :                 return -ENOMEM;
     797              : 
     798            0 :         console_lock();
     799              : 
     800            0 :         ect = 0;
     801            0 :         dict = *vc->uni_pagedict_loc;
     802            0 :         if (!dict)
     803            0 :                 goto unlock;
     804              : 
     805            0 :         for (d = 0; d < UNI_DIRS; d++) {
     806            0 :                 u16 **dir = dict->uni_pgdir[d];
     807            0 :                 if (!dir)
     808            0 :                         continue;
     809              : 
     810            0 :                 for (r = 0; r < UNI_DIR_ROWS; r++) {
     811            0 :                         u16 *row = dir[r];
     812            0 :                         if (!row)
     813            0 :                                 continue;
     814              : 
     815            0 :                         for (g = 0; g < UNI_ROW_GLYPHS; g++, row++) {
     816            0 :                                 if (*row >= MAX_GLYPH)
     817            0 :                                         continue;
     818            0 :                                 if (ect < ct) {
     819            0 :                                         unilist[ect].unicode = UNI(d, r, g);
     820            0 :                                         unilist[ect].fontpos = *row;
     821            0 :                                 }
     822            0 :                                 ect++;
     823            0 :                         }
     824            0 :                 }
     825            0 :         }
     826              : unlock:
     827            0 :         console_unlock();
     828            0 :         if (copy_to_user(list, unilist, min(ect, ct) * sizeof(*unilist)))
     829            0 :                 ret = -EFAULT;
     830            0 :         if (put_user(ect, uct))
     831            0 :                 ret = -EFAULT;
     832            0 :         kvfree(unilist);
     833            0 :         return ret ? ret : (ect <= ct) ? 0 : -ENOMEM;
     834            0 : }
     835              : 
     836              : /*
     837              :  * Always use USER_MAP. These functions are used by the keyboard,
     838              :  * which shouldn't be affected by G0/G1 switching, etc.
     839              :  * If the user map still contains default values, i.e. the
     840              :  * direct-to-font mapping, then assume user is using Latin1.
     841              :  *
     842              :  * FIXME: at some point we need to decide if we want to lock the table
     843              :  * update element itself via the keyboard_event_lock for consistency with the
     844              :  * keyboard driver as well as the consoles
     845              :  */
     846              : /* may be called during an interrupt */
     847            0 : u32 conv_8bit_to_uni(unsigned char c)
     848              : {
     849            0 :         unsigned short uni = translations[USER_MAP][c];
     850            0 :         return uni == (0xf000 | c) ? c : uni;
     851            0 : }
     852              : 
     853            0 : int conv_uni_to_8bit(u32 uni)
     854              : {
     855            0 :         int c;
     856            0 :         for (c = 0; c < ARRAY_SIZE(translations[USER_MAP]); c++)
     857            0 :                 if (translations[USER_MAP][c] == uni ||
     858            0 :                    (translations[USER_MAP][c] == (c | 0xf000) && uni == c))
     859            0 :                         return c;
     860            0 :         return -1;
     861            0 : }
     862              : 
     863            0 : int conv_uni_to_pc(struct vc_data *conp, long ucs)
     864              : {
     865            0 :         struct uni_pagedict *dict;
     866            0 :         u16 **dir, *row, glyph;
     867              : 
     868              :         /* Only 16-bit codes supported at this time */
     869            0 :         if (ucs > 0xffff)
     870            0 :                 return -4;              /* Not found */
     871            0 :         else if (ucs < 0x20)
     872            0 :                 return -1;              /* Not a printable character */
     873              :         /*
     874              :          * UNI_DIRECT_BASE indicates the start of the region in the User Zone
     875              :          * which always has a 1:1 mapping to the currently loaded font.  The
     876              :          * UNI_DIRECT_MASK indicates the bit span of the region.
     877              :          */
     878            0 :         else if ((ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE)
     879            0 :                 return ucs & UNI_DIRECT_MASK;
     880              : 
     881            0 :         dict = *conp->uni_pagedict_loc;
     882            0 :         if (!dict)
     883            0 :                 return -3;
     884              : 
     885            0 :         dir = dict->uni_pgdir[UNI_DIR(ucs)];
     886            0 :         if (!dir)
     887            0 :                 return -4;
     888              : 
     889            0 :         row = dir[UNI_ROW(ucs)];
     890            0 :         if (!row)
     891            0 :                 return -4;
     892              : 
     893            0 :         glyph = row[UNI_GLYPH(ucs)];
     894            0 :         if (glyph >= MAX_GLYPH)
     895            0 :                 return -4;
     896              : 
     897            0 :         return glyph;
     898            0 : }
     899              : 
     900              : /*
     901              :  * This is called at sys_setup time, after memory and the console are
     902              :  * initialized.  It must be possible to call kmalloc(..., GFP_KERNEL)
     903              :  * from this function, hence the call from sys_setup.
     904              :  */
     905              : void __init
     906            0 : console_map_init(void)
     907              : {
     908            0 :         int i;
     909              : 
     910            0 :         for (i = 0; i < MAX_NR_CONSOLES; i++)
     911            0 :                 if (vc_cons_allocated(i) && !*vc_cons[i].d->uni_pagedict_loc)
     912            0 :                         con_set_default_unimap(vc_cons[i].d);
     913            0 : }
     914              : 
        

Generated by: LCOV version 2.0-1