diff options
Diffstat (limited to 'drivers/char/consolemap.c')
-rw-r--r-- | drivers/char/consolemap.c | 286 |
1 files changed, 286 insertions, 0 deletions
diff --git a/drivers/char/consolemap.c b/drivers/char/consolemap.c new file mode 100644 index 000000000..54c2d19a4 --- /dev/null +++ b/drivers/char/consolemap.c @@ -0,0 +1,286 @@ +/* + * consolemap.c + * + * Mapping from internal code (such as Latin-1 or Unicode or IBM PC code) + * to font positions. + * + * aeb, 950210 + */ + +#include <linux/kd.h> +#include <linux/errno.h> +#include <linux/mm.h> +#include <linux/malloc.h> +#include <asm/segment.h> +#include "consolemap.h" + +static unsigned char * translations[] = { +/* 8-bit Latin-1 mapped to the PC character set: '\0' means non-printable */ +(unsigned char *) + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\376\0\0\0\0\0" + " !\"#$%&'()*+,-./0123456789:;<=>?" + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + "`abcdefghijklmnopqrstuvwxyz{|}~\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\377\255\233\234\376\235\174\025\376\376\246\256\252\055\376\376" + "\370\361\375\376\376\346\024\371\376\376\247\257\254\253\376\250" + "\376\376\376\376\216\217\222\200\376\220\376\376\376\376\376\376" + "\376\245\376\376\376\376\231\376\350\376\376\376\232\376\376\341" + "\205\240\203\376\204\206\221\207\212\202\210\211\215\241\214\213" + "\376\244\225\242\223\376\224\366\355\227\243\226\201\376\376\230", +/* vt100 graphics */ +(unsigned char *) + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\376\0\0\0\0\0" + " !\"#$%&'()*+,-./0123456789:;<=>?" + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^ " + "\004\261\007\007\007\007\370\361\007\007\331\277\332\300\305\304" + "\304\304\137\137\303\264\301\302\263\363\362\343\330\234\007\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\377\255\233\234\376\235\174\025\376\376\246\256\252\055\376\376" + "\370\361\375\376\376\346\024\371\376\376\247\257\254\253\376\250" + "\376\376\376\376\216\217\222\200\376\220\376\376\376\376\376\376" + "\376\245\376\376\376\376\231\376\376\376\376\376\232\376\376\341" + "\205\240\203\376\204\206\221\207\212\202\210\211\215\241\214\213" + "\376\244\225\242\223\376\224\366\376\227\243\226\201\376\376\230", +/* IBM graphics: minimal translations (BS, CR, LF, LL, SO, SI and ESC) */ +(unsigned char *) + "\000\001\002\003\004\005\006\007\000\011\000\013\000\000\000\000" + "\020\021\022\023\024\025\026\027\030\031\032\000\034\035\036\037" + "\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057" + "\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077" + "\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117" + "\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137" + "\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157" + "\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177" + "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217" + "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237" + "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257" + "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277" + "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317" + "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337" + "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357" + "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377", + /* USER: customizable mappings, initialized as the previous one (IBM) */ +(unsigned char *) + "\000\001\002\003\004\005\006\007\010\011\000\013\000\000\016\017" + "\020\021\022\023\024\025\026\027\030\031\032\000\034\035\036\037" + "\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057" + "\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077" + "\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117" + "\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137" + "\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157" + "\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177" + "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217" + "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237" + "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257" + "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277" + "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317" + "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337" + "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357" + "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377" +}; + +/* the above mappings are not invertible - this is just a best effort */ +static unsigned char * inv_translate = NULL; +static unsigned char inv_norm_transl[E_TABSZ]; +static unsigned char * inverse_translations[4] = { NULL, NULL, NULL, NULL }; + +static void set_inverse_transl(int i) +{ + int j; + unsigned char *p = translations[i]; + unsigned char *q = inverse_translations[i]; + + if (!q) { + /* slightly messy to avoid calling kmalloc too early */ + q = inverse_translations[i] = ((i == NORM_MAP) + ? inv_norm_transl + : (unsigned char *) kmalloc(E_TABSZ, GFP_KERNEL)); + if (!q) + return; + } + for (j=0; j<E_TABSZ; j++) + q[j] = 0; + for (j=0; j<E_TABSZ; j++) + if (q[p[j]] < 32) /* prefer '-' above SHY etc. */ + q[p[j]] = j; +} + +unsigned char *set_translate(int m) +{ + if (!inverse_translations[m]) + set_inverse_transl(m); + inv_translate = inverse_translations[m]; + return translations[m]; +} + +/* + * Inverse translation is impossible for several reasons: + * 1. The translation maps are not 1-1 + * 2. The text may have been written while a different translation map + * was active + * Still, it is now possible to a certain extent to cut and paste non-ASCII. + */ +unsigned char inverse_translate(unsigned char c) { + return ((inv_translate && inv_translate[c]) ? inv_translate[c] : c); +} + +/* + * Load customizable translation table + * arg points to a 256 byte translation table. + */ +int con_set_trans(char * arg) +{ + int i; + unsigned char *p = translations[USER_MAP]; + + i = verify_area(VERIFY_READ, (void *)arg, E_TABSZ); + if (i) + return i; + + for (i=0; i<E_TABSZ ; i++) + p[i] = get_fs_byte(arg+i); + p[012] = p[014] = p[015] = p[033] = 0; + set_inverse_transl(USER_MAP); + return 0; +} + +int con_get_trans(char * arg) +{ + int i; + unsigned char *p = translations[USER_MAP]; + + i = verify_area(VERIFY_WRITE, (void *)arg, E_TABSZ); + if (i) + return i; + + for (i=0; i<E_TABSZ ; i++) put_fs_byte(p[i],arg+i); + return 0; +} + +/* + * Unicode -> current font conversion + * + * A font has at most 512 chars, usually 256. + * But one font position may represent several Unicode chars + * (and moreover, hashtables work best when they are not too full), + * so pick HASHSIZE somewhat larger than 512. + * Since there are likely to be long consecutive stretches + * (like U+0000 to U+00FF), HASHSTEP should not be too small. + * Searches longer than MAXHASHLEVEL steps are refused, unless + * requested explicitly. + * + * Note: no conversion tables are compiled in, so the user + * must supply an explicit mapping herself. See kbd-0.90 (or an + * earlier kernel version) for the default Unicode-to-PC mapping. + * Usually, the mapping will be loaded simultaneously with the font. + */ + +#define HASHSIZE 641 +#define HASHSTEP 189 /* yields hashlevel = 3 initially */ +#define MAXHASHLEVEL 6 +static struct unipair hashtable[HASHSIZE]; + +int hashtable_contents_valid = 0; /* cleared by setfont */ + +static unsigned int hashsize; +static unsigned int hashstep; +static unsigned int hashlevel; +static unsigned int maxhashlevel; + +void +con_clear_unimap(struct unimapinit *ui) { + int i; + + /* read advisory values for hash algorithm */ + hashsize = ui->advised_hashsize; + if (hashsize < 256 || hashsize > HASHSIZE) + hashsize = HASHSIZE; + hashstep = (ui->advised_hashstep % hashsize); + if (hashstep < 64) + hashstep = HASHSTEP; + maxhashlevel = ui->advised_hashlevel; + if (!maxhashlevel) + maxhashlevel = MAXHASHLEVEL; + if (maxhashlevel > hashsize) + maxhashlevel = hashsize; + + /* initialize */ + hashlevel = 0; + for (i=0; i<hashsize; i++) + hashtable[i].unicode = 0xffff; + hashtable_contents_valid = 1; +} + +int +con_set_unimap(ushort ct, struct unipair *list){ + int i, lct; + ushort u, hu; + struct unimapinit hashdefaults = { 0, 0, 0 }; + + if (!hashtable_contents_valid) + con_clear_unimap(&hashdefaults); + while(ct) { + u = get_fs_word(&list->unicode); + i = u % hashsize; + lct = 1; + while ((hu = hashtable[i].unicode) != 0xffff && hu != u) { + if (lct++ >= maxhashlevel) + return -ENOMEM; + i += hashstep; + if (i >= hashsize) + i -= hashsize; + } + if (lct > hashlevel) + hashlevel = lct; + hashtable[i].unicode = u; + hashtable[i].fontpos = get_fs_word(&list->fontpos); + list++; + ct--; + } + return 0; +} + +int +con_get_unimap(ushort ct, ushort *uct, struct unipair *list){ + int i, ect; + + ect = 0; + if (hashtable_contents_valid) + for (i = 0; i<hashsize; i++) + if (hashtable[i].unicode != 0xffff) { + if (ect++ < ct) { + put_fs_word(hashtable[i].unicode, &list->unicode); + put_fs_word(hashtable[i].fontpos, &list->fontpos); + list++; + } + } + put_fs_word(ect, uct); + return ((ect <= ct) ? 0 : -ENOMEM); +} + +int +conv_uni_to_pc(unsigned long ucs) { + int i, h; + + if (!hashtable_contents_valid || ucs < 0x20) + return -3; + if (ucs == 0xffff || ucs == 0xfffe) + return -1; + if (ucs == 0xfeff || (ucs >= 0x200a && ucs <= 0x200f)) + return -2; + + h = ucs % hashsize; + for (i = 0; i < hashlevel; i++) { + if (hashtable[h].unicode == ucs) + return hashtable[h].fontpos; + if ((h += hashstep) >= hashsize) + h -= hashsize; + } + + return -4; /* not found */ +} |