diff options
Diffstat (limited to 'drivers/tty/vt')
-rw-r--r-- | drivers/tty/vt/keyboard.c | 5 | ||||
-rw-r--r-- | drivers/tty/vt/vc_screen.c | 110 | ||||
-rw-r--r-- | drivers/tty/vt/vt.c | 27 | ||||
-rw-r--r-- | drivers/tty/vt/vt_ioctl.c | 12 |
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); } |