summaryrefslogtreecommitdiffstats
path: root/drivers/tty/vt
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/vt')
-rw-r--r--drivers/tty/vt/keyboard.c5
-rw-r--r--drivers/tty/vt/vc_screen.c110
-rw-r--r--drivers/tty/vt/vt.c27
-rw-r--r--drivers/tty/vt/vt_ioctl.c12
4 files changed, 86 insertions, 68 deletions
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index e95d7876ca6b..6dd3c68c13ad 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -654,7 +654,8 @@ static void k_spec(struct vc_data *vc, unsigned char value, char up_flag)
if (value >= ARRAY_SIZE(fn_handler))
return;
if ((kbd->kbdmode == VC_RAW ||
- kbd->kbdmode == VC_MEDIUMRAW) &&
+ kbd->kbdmode == VC_MEDIUMRAW ||
+ kbd->kbdmode == VC_OFF) &&
value != KVAL(K_SAK))
return; /* SAK is allowed even in raw mode */
fn_handler[value](vc);
@@ -1295,7 +1296,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
if (rc == NOTIFY_STOP)
return;
- if (raw_mode && type != KT_SPEC && type != KT_SHIFT)
+ if ((raw_mode || kbd->kbdmode == VC_OFF) && type != KT_SPEC && type != KT_SHIFT)
return;
(*k_handler[type])(vc, keysym & 0xff, !down);
diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c
index 95e05dfc437c..1564261e80c8 100644
--- a/drivers/tty/vt/vc_screen.c
+++ b/drivers/tty/vt/vc_screen.c
@@ -28,7 +28,6 @@
#include <linux/interrupt.h>
#include <linux/mm.h>
#include <linux/init.h>
-#include <linux/mutex.h>
#include <linux/vt_kern.h>
#include <linux/selection.h>
#include <linux/kbd_kern.h>
@@ -50,6 +49,8 @@
#undef addr
#define HEADER_SIZE 4
+#define CON_BUF_SIZE (CONFIG_BASE_SMALL ? 256 : PAGE_SIZE)
+
struct vcs_poll_data {
struct notifier_block notifier;
unsigned int cons_num;
@@ -130,21 +131,45 @@ vcs_poll_data_get(struct file *file)
return poll;
}
+/*
+ * Returns VC for inode.
+ * Must be called with console_lock.
+ */
+static struct vc_data*
+vcs_vc(struct inode *inode, int *viewed)
+{
+ unsigned int currcons = iminor(inode) & 127;
+
+ WARN_CONSOLE_UNLOCKED();
+
+ if (currcons == 0) {
+ currcons = fg_console;
+ if (viewed)
+ *viewed = 1;
+ } else {
+ currcons--;
+ if (viewed)
+ *viewed = 0;
+ }
+ return vc_cons[currcons].d;
+}
+
+/*
+ * Returns size for VC carried by inode.
+ * Must be called with console_lock.
+ */
static int
vcs_size(struct inode *inode)
{
int size;
int minor = iminor(inode);
- int currcons = minor & 127;
struct vc_data *vc;
- if (currcons == 0)
- currcons = fg_console;
- else
- currcons--;
- if (!vc_cons_allocated(currcons))
+ WARN_CONSOLE_UNLOCKED();
+
+ vc = vcs_vc(inode, NULL);
+ if (!vc)
return -ENXIO;
- vc = vc_cons[currcons].d;
size = vc->vc_rows * vc->vc_cols;
@@ -157,11 +182,13 @@ static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
{
int size;
- mutex_lock(&con_buf_mtx);
+ console_lock();
size = vcs_size(file->f_path.dentry->d_inode);
+ console_unlock();
+ if (size < 0)
+ return size;
switch (orig) {
default:
- mutex_unlock(&con_buf_mtx);
return -EINVAL;
case 2:
offset += size;
@@ -172,11 +199,9 @@ static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
break;
}
if (offset < 0 || offset > size) {
- mutex_unlock(&con_buf_mtx);
return -EINVAL;
}
file->f_pos = offset;
- mutex_unlock(&con_buf_mtx);
return file->f_pos;
}
@@ -189,12 +214,15 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
struct vc_data *vc;
struct vcs_poll_data *poll;
long pos;
- long viewed, attr, read;
- int col, maxcol;
+ long attr, read;
+ int col, maxcol, viewed;
unsigned short *org = NULL;
ssize_t ret;
+ char *con_buf;
- mutex_lock(&con_buf_mtx);
+ con_buf = (char *) __get_free_page(GFP_KERNEL);
+ if (!con_buf)
+ return -ENOMEM;
pos = *ppos;
@@ -204,18 +232,10 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
console_lock();
attr = (currcons & 128);
- currcons = (currcons & 127);
- if (currcons == 0) {
- currcons = fg_console;
- viewed = 1;
- } else {
- currcons--;
- viewed = 0;
- }
ret = -ENXIO;
- if (!vc_cons_allocated(currcons))
+ vc = vcs_vc(inode, &viewed);
+ if (!vc)
goto unlock_out;
- vc = vc_cons[currcons].d;
ret = -EINVAL;
if (pos < 0)
@@ -236,6 +256,12 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
* could sleep.
*/
size = vcs_size(inode);
+ if (size < 0) {
+ if (read)
+ break;
+ ret = size;
+ goto unlock_out;
+ }
if (pos >= size)
break;
if (count > size - pos)
@@ -354,7 +380,7 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
ret = read;
unlock_out:
console_unlock();
- mutex_unlock(&con_buf_mtx);
+ free_page((unsigned long) con_buf);
return ret;
}
@@ -365,13 +391,16 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
unsigned int currcons = iminor(inode);
struct vc_data *vc;
long pos;
- long viewed, attr, size, written;
+ long attr, size, written;
char *con_buf0;
- int col, maxcol;
+ int col, maxcol, viewed;
u16 *org0 = NULL, *org = NULL;
size_t ret;
+ char *con_buf;
- mutex_lock(&con_buf_mtx);
+ con_buf = (char *) __get_free_page(GFP_KERNEL);
+ if (!con_buf)
+ return -ENOMEM;
pos = *ppos;
@@ -381,19 +410,10 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
console_lock();
attr = (currcons & 128);
- currcons = (currcons & 127);
-
- if (currcons == 0) {
- currcons = fg_console;
- viewed = 1;
- } else {
- currcons--;
- viewed = 0;
- }
ret = -ENXIO;
- if (!vc_cons_allocated(currcons))
+ vc = vcs_vc(inode, &viewed);
+ if (!vc)
goto unlock_out;
- vc = vc_cons[currcons].d;
size = vcs_size(inode);
ret = -EINVAL;
@@ -435,6 +455,12 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
* Return data written up to now on failure.
*/
size = vcs_size(inode);
+ if (size < 0) {
+ if (written)
+ break;
+ ret = size;
+ goto unlock_out;
+ }
if (pos >= size)
break;
if (this_round > size - pos)
@@ -542,9 +568,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
unlock_out:
console_unlock();
-
- mutex_unlock(&con_buf_mtx);
-
+ free_page((unsigned long) con_buf);
return ret;
}
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 2178efcec1b5..c83cdfb56fcc 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -2067,18 +2067,6 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
}
}
-/* This is a temporary buffer used to prepare a tty console write
- * so that we can easily avoid touching user space while holding the
- * console spinlock. It is allocated in con_init and is shared by
- * this code and the vc_screen read/write tty calls.
- *
- * We have to allocate this statically in the kernel data section
- * since console_init (and thus con_init) are called before any
- * kernel memory allocation is available.
- */
-char con_buf[CON_BUF_SIZE];
-DEFINE_MUTEX(con_buf_mtx);
-
/* is_double_width() is based on the wcwidth() implementation by
* Markus Kuhn -- 2007-05-26 (Unicode 5.0)
* Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
@@ -2156,10 +2144,10 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
currcons = vc->vc_num;
if (!vc_cons_allocated(currcons)) {
- /* could this happen? */
- printk_once("con_write: tty %d not allocated\n", currcons+1);
- console_unlock();
- return 0;
+ /* could this happen? */
+ pr_warn_once("con_write: tty %d not allocated\n", currcons+1);
+ console_unlock();
+ return 0;
}
himask = vc->vc_hi_font_mask;
@@ -2939,7 +2927,7 @@ static int __init con_init(void)
gotoxy(vc, vc->vc_x, vc->vc_y);
csi_J(vc, 0);
update_screen(vc);
- printk("Console: %s %s %dx%d",
+ pr_info("Console: %s %s %dx%d",
vc->vc_can_do_color ? "colour" : "mono",
display_desc, vc->vc_cols, vc->vc_rows);
printable = 1;
@@ -3102,7 +3090,7 @@ static int bind_con_driver(const struct consw *csw, int first, int last,
clear_buffer_attributes(vc);
}
- printk("Console: switching ");
+ pr_info("Console: switching ");
if (!deflt)
printk("consoles %d-%d ", first+1, last+1);
if (j >= 0) {
@@ -3808,7 +3796,8 @@ void do_unblank_screen(int leaving_gfx)
return;
if (!vc_cons_allocated(fg_console)) {
/* impossible */
- printk("unblank_screen: tty %d not allocated ??\n", fg_console+1);
+ pr_warning("unblank_screen: tty %d not allocated ??\n",
+ fg_console+1);
return;
}
vc = vc_cons[fg_console].d;
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index fd4c9376f875..937d17219984 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -494,7 +494,7 @@ do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_
* We handle the console-specific ioctl's here. We allow the
* capability to modify any console, not just the fg_console.
*/
-int vt_ioctl(struct tty_struct *tty, struct file * file,
+int vt_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
struct vc_data *vc = tty->driver_data;
@@ -687,6 +687,9 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
kbd->kbdmode = VC_UNICODE;
compute_shiftstate();
break;
+ case K_OFF:
+ kbd->kbdmode = VC_OFF;
+ break;
default:
ret = -EINVAL;
goto out;
@@ -1006,8 +1009,9 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
if (ret)
break;
/* Commence switch and lock */
- set_console(arg);
+ set_console(vsa.console);
}
+ break;
}
/*
@@ -1490,7 +1494,7 @@ compat_unimap_ioctl(unsigned int cmd, struct compat_unimapdesc __user *user_ud,
return 0;
}
-long vt_compat_ioctl(struct tty_struct *tty, struct file * file,
+long vt_compat_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
struct vc_data *vc = tty->driver_data;
@@ -1576,7 +1580,7 @@ out:
fallback:
tty_unlock();
- return vt_ioctl(tty, file, cmd, arg);
+ return vt_ioctl(tty, cmd, arg);
}