patch-2.1.112 linux/drivers/char/consolemap.c
Next file: linux/drivers/char/esp.c
Previous file: linux/drivers/char/console.c
Back to the patch index
Back to the overall index
- Lines: 595
- Date:
Sun Jul 26 14:40:18 1998
- Orig file:
v2.1.111/linux/drivers/char/consolemap.c
- Orig date:
Mon Aug 11 17:28:19 1997
diff -u --recursive --new-file v2.1.111/linux/drivers/char/consolemap.c linux/drivers/char/consolemap.c
@@ -5,6 +5,8 @@
* to font positions.
*
* aeb, 950210
+ *
+ * Support for multiple unimaps by Jakub Jelinek <jj@ultra.linux.cz>, July 1998
*/
#include <linux/kd.h>
@@ -14,6 +16,8 @@
#include <linux/init.h>
#include <asm/uaccess.h>
#include <linux/consolemap.h>
+#include <linux/console_struct.h>
+#include <linux/vt_kern.h>
static unsigned short translations[][256] = {
/* 8-bit Latin-1 mapped to Unicode -- trivial mapping */
@@ -163,29 +167,36 @@
#define MAX_GLYPH 512 /* Max possible glyph value */
-static unsigned char * inv_translate = NULL;
-static unsigned char inv_norm_transl[MAX_GLYPH];
-static unsigned char * inverse_translations[4] = { NULL, NULL, NULL, NULL };
+static int inv_translate;
+
+struct uni_pagedir {
+ u16 **uni_pgdir[32];
+ unsigned long refcount;
+ unsigned long sum;
+ unsigned char *inverse_translations[4];
+ int readonly;
+};
-static void set_inverse_transl(int i)
+static struct uni_pagedir *dflt;
+
+static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int i)
{
int j, glyph;
- unsigned short *p = translations[i];
- unsigned char *q = inverse_translations[i];
+ unsigned short *t = translations[i];
+ unsigned char *q;
+
+ if (!p) return;
+ q = p->inverse_translations[i];
if (!q) {
- /* slightly messy to avoid calling kmalloc too early */
- q = inverse_translations[i] = ((i == LAT1_MAP)
- ? inv_norm_transl
- : (unsigned char *) kmalloc(MAX_GLYPH, GFP_KERNEL));
- if (!q)
- return;
+ q = p->inverse_translations[i] = (unsigned char *)
+ kmalloc(MAX_GLYPH, GFP_KERNEL);
+ if (!q) return;
}
- for (j=0; j<MAX_GLYPH; j++)
- q[j] = 0;
+ memset(q, 0, MAX_GLYPH);
- for (j=0; j<E_TABSZ; j++) {
- glyph = conv_uni_to_pc(p[j]);
+ for (j = 0; j < E_TABSZ; j++) {
+ glyph = conv_uni_to_pc(conp, t[j]);
if (glyph >= 0 && glyph < MAX_GLYPH && q[glyph] < 32) {
/* prefer '-' above SHY etc. */
q[glyph] = j;
@@ -195,9 +206,7 @@
unsigned short *set_translate(int m)
{
- if (!inverse_translations[m])
- set_inverse_transl(m);
- inv_translate = inverse_translations[m];
+ inv_translate = m;
return translations[m];
}
@@ -208,13 +217,33 @@
* was active, or using Unicode.
* Still, it is now possible to a certain extent to cut and paste non-ASCII.
*/
-unsigned char inverse_translate(int glyph) {
- if ( glyph < 0 || glyph >= MAX_GLYPH )
+unsigned char inverse_translate(struct vc_data *conp, int glyph)
+{
+ struct uni_pagedir *p;
+
+ if (glyph < 0 || glyph >= MAX_GLYPH)
return 0;
+ else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc) ||
+ !p->inverse_translations[inv_translate])
+ return glyph;
else
- return ((inv_translate && inv_translate[glyph])
- ? inv_translate[glyph]
- : (unsigned char)(glyph & 0xff));
+ return p->inverse_translations[inv_translate][glyph];
+}
+
+static void update_user_maps(void)
+{
+ int i;
+ struct uni_pagedir *p, *q = NULL;
+
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ if (!vc_cons_allocated(i))
+ continue;
+ p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
+ if (p && p != q) {
+ set_inverse_transl(vc_cons[i].d, p, USER_MAP);
+ q = p;
+ }
+ }
}
/*
@@ -240,7 +269,7 @@
p[i] = UNI_DIRECT_BASE | uc;
}
- set_inverse_transl(USER_MAP);
+ update_user_maps();
return 0;
}
@@ -255,7 +284,7 @@
for (i=0; i<E_TABSZ ; i++)
{
- ch = conv_uni_to_pc(p[i]);
+ ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
__put_user((ch & ~0xff) ? 0 : ch, arg+i);
}
return 0;
@@ -277,7 +306,7 @@
p[i] = us;
}
- set_inverse_transl(USER_MAP);
+ update_user_maps();
return 0;
}
@@ -310,90 +339,188 @@
extern u8 dfont_unicount[]; /* Defined in console_defmap.c */
extern u16 dfont_unitable[];
-int hashtable_contents_valid = 0; /* Use ASCII-only mode for bootup */
+static void con_release_unimap(struct uni_pagedir *p)
+{
+ u16 **p1;
+ int i, j;
-static u16 **uni_pagedir[32] =
+ if (p == dflt) dflt = NULL;
+ for (i = 0; i < 32; i++) {
+ if ((p1 = p->uni_pgdir[i]) != NULL) {
+ for (j = 0; j < 32; j++)
+ if (p1[j])
+ kfree(p1[j]);
+ kfree(p1);
+ }
+ p->uni_pgdir[i] = NULL;
+ }
+ for (i = 0; i < 4; i++)
+ if (p->inverse_translations[i]) {
+ kfree(p->inverse_translations[i]);
+ p->inverse_translations[i] = NULL;
+ }
+}
+
+void con_free_unimap(int con)
{
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
-};
+ struct uni_pagedir *p;
+ struct vc_data *conp = vc_cons[con].d;
+
+ p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+ if (!p) return;
+ *conp->vc_uni_pagedir_loc = 0;
+ if (--p->refcount) return;
+ con_release_unimap(p);
+ kfree(p);
+}
+
+static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
+{
+ int i, j, k;
+ struct uni_pagedir *q;
+
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ if (!vc_cons_allocated(i))
+ continue;
+ q = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
+ if (!q || q == p || q->sum != p->sum)
+ continue;
+ for (j = 0; j < 32; j++) {
+ u16 **p1, **q1;
+ p1 = p->uni_pgdir[j]; q1 = q->uni_pgdir[j];
+ if (!p1 && !q1)
+ continue;
+ if (!p1 || !q1)
+ break;
+ for (k = 0; k < 32; k++) {
+ if (!p1[k] && !q1[k])
+ continue;
+ if (!p1[k] || !q1[k])
+ break;
+ if (memcmp(p1[k], q1[k], 64*sizeof(u16)))
+ break;
+ }
+ if (k < 32)
+ break;
+ }
+ if (j == 32) {
+ q->refcount++;
+ *conp->vc_uni_pagedir_loc = (unsigned long)q;
+ con_release_unimap(p);
+ kfree(p);
+ return 1;
+ }
+ }
+ return 0;
+}
static int
-con_insert_unipair(u_short unicode, u_short fontpos)
+con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
{
- int i, n;
- u16 **p1, *p2;
+ int i, n;
+ u16 **p1, *p2;
- if ( !(p1 = uni_pagedir[n = unicode >> 11]) )
- {
- p1 = uni_pagedir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL);
- if ( !p1 )
- return -ENOMEM;
-
- for ( i = 0 ; i < 32 ; i++ )
- p1[i] = NULL;
- }
-
- if ( !(p2 = p1[n = (unicode >> 6) & 0x1f]) )
- {
- p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL);
- if ( !p2 )
- return -ENOMEM;
-
- for ( i = 0 ; i < 64 ; i++ )
- p2[i] = 0xffff; /* No glyph for this character (yet) */
- }
+ if (!(p1 = p->uni_pgdir[n = unicode >> 11])) {
+ p1 = p->uni_pgdir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL);
+ if (!p1) return -ENOMEM;
+ for (i = 0; i < 32; i++)
+ p1[i] = NULL;
+ }
- p2[unicode & 0x3f] = fontpos;
-
- return 0;
+ if (!(p2 = p1[n = (unicode >> 6) & 0x1f])) {
+ p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL);
+ if (!p2) return -ENOMEM;
+ memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */
+ }
+
+ p2[unicode & 0x3f] = fontpos;
+
+ p->sum += (fontpos << 20) + unicode;
+
+ return 0;
}
-
+
/* ui is a leftover from using a hashtable, but might be used again */
-void
-con_clear_unimap(struct unimapinit *ui)
+int con_clear_unimap(int con, struct unimapinit *ui)
{
- int i, j;
- u16 **p1;
+ struct uni_pagedir *p, *q;
+ struct vc_data *conp = vc_cons[con].d;
- for ( i = 0 ; i < 32 ; i++ )
- {
- if ( (p1 = uni_pagedir[i]) != NULL )
- {
- for ( j = 0 ; j < 32 ; j++ )
- {
- if ( p1[j] )
- kfree(p1[j]);
- }
- kfree(p1);
+ p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+ if (p && p->readonly) return -EIO;
+ if (!p || --p->refcount) {
+ q = (struct uni_pagedir *)kmalloc(sizeof(*p), GFP_KERNEL);
+ if (!q) {
+ if (p) p->refcount++;
+ return -ENOMEM;
+ }
+ memset(q, 0, sizeof(*q));
+ q->refcount=1;
+ *conp->vc_uni_pagedir_loc = (unsigned long)q;
+ } else {
+ if (p == dflt) dflt = NULL;
+ p->refcount++;
+ p->sum = 0;
+ con_release_unimap(p);
}
- uni_pagedir[i] = NULL;
- }
-
- hashtable_contents_valid = 1;
+ return 0;
}
int
-con_set_unimap(ushort ct, struct unipair *list)
+con_set_unimap(int con, ushort ct, struct unipair *list)
{
- int err = 0, err1, i;
+ int err = 0, err1, i;
+ struct uni_pagedir *p, *q;
+ struct vc_data *conp = vc_cons[con].d;
- while( ct-- )
- {
- unsigned short unicode, fontpos;
- __get_user(unicode, &list->unicode);
- __get_user(fontpos, &list->fontpos);
- if ( (err1 = con_insert_unipair(unicode,fontpos)) != 0 )
- err = err1;
- list++;
- }
+ p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+ if (p->readonly) return -EIO;
+
+ if (!ct) return 0;
+
+ if (p->refcount > 1) {
+ int j, k;
+ u16 **p1, *p2, l;
+
+ err1 = con_clear_unimap(con, NULL);
+ if (err1) return err1;
+
+ q = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+ for (i = 0, l = 0; i < 32; i++)
+ if ((p1 = p->uni_pgdir[i]))
+ for (j = 0; j < 32; j++)
+ if ((p2 = p1[j]))
+ for (k = 0; k < 64; k++, l++)
+ if (p2[k] != 0xffff) {
+ err1 = con_insert_unipair(q, l, p2[k]);
+ if (err1) {
+ p->refcount++;
+ *conp->vc_uni_pagedir_loc = (unsigned long)p;
+ con_release_unimap(q);
+ kfree(q);
+ return err1;
+ }
+ }
+ p = q;
+ } else if (p == dflt)
+ dflt = NULL;
+
+ while (ct--) {
+ unsigned short unicode, fontpos;
+ __get_user(unicode, &list->unicode);
+ __get_user(fontpos, &list->fontpos);
+ if ((err1 = con_insert_unipair(p, unicode,fontpos)) != 0)
+ err = err1;
+ list++;
+ }
+
+ if (con_unify_unimap(conp, p))
+ return err;
- for ( i = 0 ; i <= 3 ; i++ )
- set_inverse_transl(i); /* Update all inverse translations */
+ for (i = 0; i <= 3; i++)
+ set_inverse_transl(conp, p, i); /* Update all inverse translations */
- return err;
+ return err;
}
/* Loads the unimap for the hardware font, as defined in uni_hash.tbl.
@@ -401,83 +528,123 @@
with. This routine is executed at sys_setup time, and when the
PIO_FONTRESET ioctl is called. */
-void
-con_set_default_unimap(void)
+int
+con_set_default_unimap(int con)
{
- int i, j;
- u16 *p;
-
- /* The default font is always 256 characters */
-
- con_clear_unimap(NULL);
+ int i, j, err = 0, err1;
+ u16 *q;
+ struct uni_pagedir *p;
+ struct vc_data *conp = vc_cons[con].d;
+
+ if (dflt) {
+ p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+ if (p == dflt)
+ return 0;
+ dflt->refcount++;
+ *conp->vc_uni_pagedir_loc = (unsigned long)dflt;
+ if (p && --p->refcount) {
+ con_release_unimap(p);
+ kfree(p);
+ }
+ return 0;
+ }
+
+ /* The default font is always 256 characters */
- p = dfont_unitable;
- for ( i = 0 ; i < 256 ; i++ )
- for ( j = dfont_unicount[i] ; j ; j-- )
- con_insert_unipair(*(p++), i);
+ err = con_clear_unimap(con,NULL);
+ if (err) return err;
+
+ p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+ q = dfont_unitable;
+
+ for (i = 0; i < 256; i++)
+ for (j = dfont_unicount[i]; j; j--) {
+ err1 = con_insert_unipair(p, *(q++), i);
+ if (err1)
+ err = err1;
+ }
+
+ if (con_unify_unimap(conp, p)) {
+ dflt = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+ return err;
+ }
- for ( i = 0 ; i <= 3 ; i++ )
- set_inverse_transl(i); /* Update all inverse translations */
+ for (i = 0; i <= 3; i++)
+ set_inverse_transl(conp, p, i); /* Update all inverse translations */
+ dflt = p;
+ return err;
}
int
-con_get_unimap(ushort ct, ushort *uct, struct unipair *list){
+con_get_unimap(int con, ushort ct, ushort *uct, struct unipair *list)
+{
int i, j, k, ect;
u16 **p1, *p2;
+ struct uni_pagedir *p;
+ struct vc_data *conp = vc_cons[con].d;
ect = 0;
- if (hashtable_contents_valid)
- {
- for ( i = 0 ; i < 32 ; i++ )
- if ( (p1 = uni_pagedir[i]) != NULL )
- for ( j = 0 ; j < 32 ; j++ )
- if ( (p2 = *(p1++)) != NULL )
- for ( k = 0 ; k < 64 ; k++ )
- {
- if ( *p2 < MAX_GLYPH && ect++ < ct )
- {
- __put_user((u_short)((i<<11)+(j<<6)+k),
- &list->unicode);
- __put_user((u_short) *p2, &list->fontpos);
- list++;
- }
- p2++;
- }
- }
+ if (*conp->vc_uni_pagedir_loc) {
+ p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+ for (i = 0; i < 32; i++)
+ if ((p1 = p->uni_pgdir[i]))
+ for (j = 0; j < 32; j++)
+ if ((p2 = *(p1++)))
+ for (k = 0; k < 64; k++) {
+ if (*p2 < MAX_GLYPH && ect++ < ct) {
+ __put_user((u_short)((i<<11)+(j<<6)+k),
+ &list->unicode);
+ __put_user((u_short) *p2,
+ &list->fontpos);
+ list++;
+ }
+ p2++;
+ }
+ }
__put_user(ect, uct);
return ((ect <= ct) ? 0 : -ENOMEM);
}
+void con_protect_unimap(int con, int rdonly)
+{
+ struct uni_pagedir *p = (struct uni_pagedir *)
+ *vc_cons[con].d->vc_uni_pagedir_loc;
+
+ if (p) p->readonly = rdonly;
+}
+
int
-conv_uni_to_pc(long ucs)
+conv_uni_to_pc(struct vc_data *conp, long ucs)
{
- int h;
- u16 **p1, *p2;
-
- /* Only 16-bit codes supported at this time */
- if (ucs > 0xffff)
- ucs = 0xfffd; /* U+FFFD: REPLACEMENT CHARACTER */
- else if (ucs < 0x20 || ucs >= 0xfffe)
- return -1; /* Not a printable character */
- else if (ucs == 0xfeff || (ucs >= 0x200a && ucs <= 0x200f))
- return -2; /* Zero-width space */
- /*
- * UNI_DIRECT_BASE indicates the start of the region in the User Zone
- * which always has a 1:1 mapping to the currently loaded font. The
- * UNI_DIRECT_MASK indicates the bit span of the region.
- */
- else if ( (ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE )
- return ucs & UNI_DIRECT_MASK;
+ int h;
+ u16 **p1, *p2;
+ struct uni_pagedir *p;
- if (!hashtable_contents_valid)
- return -3;
+ /* Only 16-bit codes supported at this time */
+ if (ucs > 0xffff)
+ ucs = 0xfffd; /* U+FFFD: REPLACEMENT CHARACTER */
+ else if (ucs < 0x20 || ucs >= 0xfffe)
+ return -1; /* Not a printable character */
+ else if (ucs == 0xfeff || (ucs >= 0x200a && ucs <= 0x200f))
+ return -2; /* Zero-width space */
+ /*
+ * UNI_DIRECT_BASE indicates the start of the region in the User Zone
+ * which always has a 1:1 mapping to the currently loaded font. The
+ * UNI_DIRECT_MASK indicates the bit span of the region.
+ */
+ else if ((ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE)
+ return ucs & UNI_DIRECT_MASK;
- if ( (p1 = uni_pagedir[ucs >> 11]) &&
- (p2 = p1[(ucs >> 6) & 0x1f]) &&
- (h = p2[ucs & 0x3f]) < MAX_GLYPH )
- return h;
+ if (!*conp->vc_uni_pagedir_loc)
+ return -3;
+
+ p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+ if ((p1 = p->uni_pgdir[ucs >> 11]) &&
+ (p2 = p1[(ucs >> 6) & 0x1f]) &&
+ (h = p2[ucs & 0x3f]) < MAX_GLYPH)
+ return h;
- return -4; /* not found */
+ return -4; /* not found */
}
/*
@@ -488,5 +655,9 @@
__initfunc(void
console_map_init(void))
{
- con_set_default_unimap();
+ int i;
+
+ for (i = 0; i < MAX_NR_CONSOLES; i++)
+ if (vc_cons_allocated(i) && !*vc_cons[i].d->vc_uni_pagedir_loc)
+ con_set_default_unimap(i);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov