summaryrefslogtreecommitdiffstats
path: root/drivers/char/consolemap.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/consolemap.c')
-rw-r--r--drivers/char/consolemap.c286
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 */
+}