|
@@ -19,6 +19,7 @@
|
|
|
#include <linux/init.h>
|
|
|
#include <linux/tty.h>
|
|
|
#include <asm/uaccess.h>
|
|
|
+#include <linux/console.h>
|
|
|
#include <linux/consolemap.h>
|
|
|
#include <linux/vt_kern.h>
|
|
|
|
|
@@ -312,6 +313,7 @@ int con_set_trans_old(unsigned char __user * arg)
|
|
|
if (!access_ok(VERIFY_READ, arg, E_TABSZ))
|
|
|
return -EFAULT;
|
|
|
|
|
|
+ console_lock();
|
|
|
for (i=0; i<E_TABSZ ; i++) {
|
|
|
unsigned char uc;
|
|
|
__get_user(uc, arg+i);
|
|
@@ -319,6 +321,7 @@ int con_set_trans_old(unsigned char __user * arg)
|
|
|
}
|
|
|
|
|
|
update_user_maps();
|
|
|
+ console_unlock();
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -330,11 +333,13 @@ int con_get_trans_old(unsigned char __user * arg)
|
|
|
if (!access_ok(VERIFY_WRITE, arg, E_TABSZ))
|
|
|
return -EFAULT;
|
|
|
|
|
|
+ console_lock();
|
|
|
for (i=0; i<E_TABSZ ; i++)
|
|
|
- {
|
|
|
- ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
|
|
|
- __put_user((ch & ~0xff) ? 0 : ch, arg+i);
|
|
|
- }
|
|
|
+ {
|
|
|
+ ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
|
|
|
+ __put_user((ch & ~0xff) ? 0 : ch, arg+i);
|
|
|
+ }
|
|
|
+ console_unlock();
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -346,6 +351,7 @@ int con_set_trans_new(ushort __user * arg)
|
|
|
if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short)))
|
|
|
return -EFAULT;
|
|
|
|
|
|
+ console_lock();
|
|
|
for (i=0; i<E_TABSZ ; i++) {
|
|
|
unsigned short us;
|
|
|
__get_user(us, arg+i);
|
|
@@ -353,6 +359,7 @@ int con_set_trans_new(ushort __user * arg)
|
|
|
}
|
|
|
|
|
|
update_user_maps();
|
|
|
+ console_unlock();
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -364,8 +371,10 @@ int con_get_trans_new(ushort __user * arg)
|
|
|
if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short)))
|
|
|
return -EFAULT;
|
|
|
|
|
|
+ console_lock();
|
|
|
for (i=0; i<E_TABSZ ; i++)
|
|
|
__put_user(p[i], arg+i);
|
|
|
+ console_unlock();
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -407,6 +416,7 @@ static void con_release_unimap(struct uni_pagedir *p)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/* Caller must hold the console lock */
|
|
|
void con_free_unimap(struct vc_data *vc)
|
|
|
{
|
|
|
struct uni_pagedir *p;
|
|
@@ -487,17 +497,21 @@ con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/* ui is a leftover from using a hashtable, but might be used again */
|
|
|
-int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
|
|
|
+/* ui is a leftover from using a hashtable, but might be used again
|
|
|
+ Caller must hold the lock */
|
|
|
+static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
|
|
|
{
|
|
|
struct uni_pagedir *p, *q;
|
|
|
-
|
|
|
+
|
|
|
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
|
|
|
- if (p && p->readonly) return -EIO;
|
|
|
+ if (p && p->readonly)
|
|
|
+ return -EIO;
|
|
|
+
|
|
|
if (!p || --p->refcount) {
|
|
|
q = kzalloc(sizeof(*p), GFP_KERNEL);
|
|
|
if (!q) {
|
|
|
- if (p) p->refcount++;
|
|
|
+ if (p)
|
|
|
+ p->refcount++;
|
|
|
return -ENOMEM;
|
|
|
}
|
|
|
q->refcount=1;
|
|
@@ -511,23 +525,43 @@ int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+ console_lock();
|
|
|
+ ret = con_do_clear_unimap(vc, ui);
|
|
|
+ console_unlock();
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
|
|
|
{
|
|
|
int err = 0, err1, i;
|
|
|
struct uni_pagedir *p, *q;
|
|
|
|
|
|
+ console_lock();
|
|
|
+
|
|
|
/* Save original vc_unipagdir_loc in case we allocate a new one */
|
|
|
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
|
|
|
- if (p->readonly) return -EIO;
|
|
|
+ if (p->readonly) {
|
|
|
+ console_unlock();
|
|
|
+ return -EIO;
|
|
|
+ }
|
|
|
|
|
|
- if (!ct) return 0;
|
|
|
+ if (!ct) {
|
|
|
+ console_unlock();
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
|
|
|
if (p->refcount > 1) {
|
|
|
int j, k;
|
|
|
u16 **p1, *p2, l;
|
|
|
|
|
|
- err1 = con_clear_unimap(vc, NULL);
|
|
|
- if (err1) return err1;
|
|
|
+ err1 = con_do_clear_unimap(vc, NULL);
|
|
|
+ if (err1) {
|
|
|
+ console_unlock();
|
|
|
+ return err1;
|
|
|
+ }
|
|
|
|
|
|
/*
|
|
|
* Since refcount was > 1, con_clear_unimap() allocated a
|
|
@@ -558,7 +592,8 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
|
|
|
*vc->vc_uni_pagedir_loc = (unsigned long)p;
|
|
|
con_release_unimap(q);
|
|
|
kfree(q);
|
|
|
- return err1;
|
|
|
+ console_unlock();
|
|
|
+ return err1;
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
@@ -592,21 +627,30 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
|
|
|
/*
|
|
|
* Merge with fontmaps of any other virtual consoles.
|
|
|
*/
|
|
|
- if (con_unify_unimap(vc, p))
|
|
|
+ if (con_unify_unimap(vc, p)) {
|
|
|
+ console_unlock();
|
|
|
return err;
|
|
|
+ }
|
|
|
|
|
|
for (i = 0; i <= 3; i++)
|
|
|
set_inverse_transl(vc, p, i); /* Update inverse translations */
|
|
|
set_inverse_trans_unicode(vc, p);
|
|
|
-
|
|
|
+
|
|
|
+ console_unlock();
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
-/* Loads the unimap for the hardware font, as defined in uni_hash.tbl.
|
|
|
- The representation used was the most compact I could come up
|
|
|
- with. This routine is executed at sys_setup time, and when the
|
|
|
- PIO_FONTRESET ioctl is called. */
|
|
|
-
|
|
|
+/**
|
|
|
+ * con_set_default_unimap - set default unicode map
|
|
|
+ * @vc: the console we are updating
|
|
|
+ *
|
|
|
+ * Loads the unimap for the hardware font, as defined in uni_hash.tbl.
|
|
|
+ * The representation used was the most compact I could come up
|
|
|
+ * with. This routine is executed at video setup, and when the
|
|
|
+ * PIO_FONTRESET ioctl is called.
|
|
|
+ *
|
|
|
+ * The caller must hold the console lock
|
|
|
+ */
|
|
|
int con_set_default_unimap(struct vc_data *vc)
|
|
|
{
|
|
|
int i, j, err = 0, err1;
|
|
@@ -617,6 +661,7 @@ int con_set_default_unimap(struct vc_data *vc)
|
|
|
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
|
|
|
if (p == dflt)
|
|
|
return 0;
|
|
|
+
|
|
|
dflt->refcount++;
|
|
|
*vc->vc_uni_pagedir_loc = (unsigned long)dflt;
|
|
|
if (p && !--p->refcount) {
|
|
@@ -628,8 +673,9 @@ int con_set_default_unimap(struct vc_data *vc)
|
|
|
|
|
|
/* The default font is always 256 characters */
|
|
|
|
|
|
- err = con_clear_unimap(vc, NULL);
|
|
|
- if (err) return err;
|
|
|
+ err = con_do_clear_unimap(vc, NULL);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
|
|
|
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
|
|
|
q = dfont_unitable;
|
|
@@ -654,6 +700,13 @@ int con_set_default_unimap(struct vc_data *vc)
|
|
|
}
|
|
|
EXPORT_SYMBOL(con_set_default_unimap);
|
|
|
|
|
|
+/**
|
|
|
+ * con_copy_unimap - copy unimap between two vts
|
|
|
+ * @dst_vc: target
|
|
|
+ * @src_vt: source
|
|
|
+ *
|
|
|
+ * The caller must hold the console lock when invoking this method
|
|
|
+ */
|
|
|
int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
|
|
|
{
|
|
|
struct uni_pagedir *q;
|
|
@@ -668,13 +721,23 @@ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
|
|
|
*dst_vc->vc_uni_pagedir_loc = (long)q;
|
|
|
return 0;
|
|
|
}
|
|
|
+EXPORT_SYMBOL(con_copy_unimap);
|
|
|
|
|
|
+/**
|
|
|
+ * con_get_unimap - get the unicode map
|
|
|
+ * @vc: the console to read from
|
|
|
+ *
|
|
|
+ * Read the console unicode data for this console. Called from the ioctl
|
|
|
+ * handlers.
|
|
|
+ */
|
|
|
int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list)
|
|
|
{
|
|
|
int i, j, k, ect;
|
|
|
u16 **p1, *p2;
|
|
|
struct uni_pagedir *p;
|
|
|
|
|
|
+ console_lock();
|
|
|
+
|
|
|
ect = 0;
|
|
|
if (*vc->vc_uni_pagedir_loc) {
|
|
|
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
|
|
@@ -694,22 +757,19 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni
|
|
|
}
|
|
|
}
|
|
|
__put_user(ect, uct);
|
|
|
+ console_unlock();
|
|
|
return ((ect <= ct) ? 0 : -ENOMEM);
|
|
|
}
|
|
|
|
|
|
-void con_protect_unimap(struct vc_data *vc, int rdonly)
|
|
|
-{
|
|
|
- struct uni_pagedir *p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
|
|
|
-
|
|
|
- if (p)
|
|
|
- p->readonly = rdonly;
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* Always use USER_MAP. These functions are used by the keyboard,
|
|
|
* which shouldn't be affected by G0/G1 switching, etc.
|
|
|
* If the user map still contains default values, i.e. the
|
|
|
* direct-to-font mapping, then assume user is using Latin1.
|
|
|
+ *
|
|
|
+ * FIXME: at some point we need to decide if we want to lock the table
|
|
|
+ * update element itself via the keyboard_event_lock for consistency with the
|
|
|
+ * keyboard driver as well as the consoles
|
|
|
*/
|
|
|
/* may be called during an interrupt */
|
|
|
u32 conv_8bit_to_uni(unsigned char c)
|
|
@@ -777,4 +837,3 @@ console_map_init(void)
|
|
|
con_set_default_unimap(vc_cons[i].d);
|
|
|
}
|
|
|
|
|
|
-EXPORT_SYMBOL(con_copy_unimap);
|