aboutsummaryrefslogtreecommitdiffstats
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)
654 if (value >= ARRAY_SIZE(fn_handler)) 654 if (value >= ARRAY_SIZE(fn_handler))
655 return; 655 return;
656 if ((kbd->kbdmode == VC_RAW || 656 if ((kbd->kbdmode == VC_RAW ||
657 kbd->kbdmode == VC_MEDIUMRAW) && 657 kbd->kbdmode == VC_MEDIUMRAW ||
658 kbd->kbdmode == VC_OFF) &&
658 value != KVAL(K_SAK)) 659 value != KVAL(K_SAK))
659 return; /* SAK is allowed even in raw mode */ 660 return; /* SAK is allowed even in raw mode */
660 fn_handler[value](vc); 661 fn_handler[value](vc);
@@ -1295,7 +1296,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
1295 if (rc == NOTIFY_STOP) 1296 if (rc == NOTIFY_STOP)
1296 return; 1297 return;
1297 1298
1298 if (raw_mode && type != KT_SPEC && type != KT_SHIFT) 1299 if ((raw_mode || kbd->kbdmode == VC_OFF) && type != KT_SPEC && type != KT_SHIFT)
1299 return; 1300 return;
1300 1301
1301 (*k_handler[type])(vc, keysym & 0xff, !down); 1302 (*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 @@
28#include <linux/interrupt.h> 28#include <linux/interrupt.h>
29#include <linux/mm.h> 29#include <linux/mm.h>
30#include <linux/init.h> 30#include <linux/init.h>
31#include <linux/mutex.h>
32#include <linux/vt_kern.h> 31#include <linux/vt_kern.h>
33#include <linux/selection.h> 32#include <linux/selection.h>
34#include <linux/kbd_kern.h> 33#include <linux/kbd_kern.h>
@@ -50,6 +49,8 @@
50#undef addr 49#undef addr
51#define HEADER_SIZE 4 50#define HEADER_SIZE 4
52 51
52#define CON_BUF_SIZE (CONFIG_BASE_SMALL ? 256 : PAGE_SIZE)
53
53struct vcs_poll_data { 54struct vcs_poll_data {
54 struct notifier_block notifier; 55 struct notifier_block notifier;
55 unsigned int cons_num; 56 unsigned int cons_num;
@@ -130,21 +131,45 @@ vcs_poll_data_get(struct file *file)
130 return poll; 131 return poll;
131} 132}
132 133
134/*
135 * Returns VC for inode.
136 * Must be called with console_lock.
137 */
138static struct vc_data*
139vcs_vc(struct inode *inode, int *viewed)
140{
141 unsigned int currcons = iminor(inode) & 127;
142
143 WARN_CONSOLE_UNLOCKED();
144
145 if (currcons == 0) {
146 currcons = fg_console;
147 if (viewed)
148 *viewed = 1;
149 } else {
150 currcons--;
151 if (viewed)
152 *viewed = 0;
153 }
154 return vc_cons[currcons].d;
155}
156
157/*
158 * Returns size for VC carried by inode.
159 * Must be called with console_lock.
160 */
133static int 161static int
134vcs_size(struct inode *inode) 162vcs_size(struct inode *inode)
135{ 163{
136 int size; 164 int size;
137 int minor = iminor(inode); 165 int minor = iminor(inode);
138 int currcons = minor & 127;
139 struct vc_data *vc; 166 struct vc_data *vc;
140 167
141 if (currcons == 0) 168 WARN_CONSOLE_UNLOCKED();
142 currcons = fg_console; 169
143 else 170 vc = vcs_vc(inode, NULL);
144 currcons--; 171 if (!vc)
145 if (!vc_cons_allocated(currcons))
146 return -ENXIO; 172 return -ENXIO;
147 vc = vc_cons[currcons].d;
148 173
149 size = vc->vc_rows * vc->vc_cols; 174 size = vc->vc_rows * vc->vc_cols;
150 175
@@ -157,11 +182,13 @@ static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
157{ 182{
158 int size; 183 int size;
159 184
160 mutex_lock(&con_buf_mtx); 185 console_lock();
161 size = vcs_size(file->f_path.dentry->d_inode); 186 size = vcs_size(file->f_path.dentry->d_inode);
187 console_unlock();
188 if (size < 0)
189 return size;
162 switch (orig) { 190 switch (orig) {
163 default: 191 default:
164 mutex_unlock(&con_buf_mtx);
165 return -EINVAL; 192 return -EINVAL;
166 case 2: 193 case 2:
167 offset += size; 194 offset += size;
@@ -172,11 +199,9 @@ static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
172 break; 199 break;
173 } 200 }
174 if (offset < 0 || offset > size) { 201 if (offset < 0 || offset > size) {
175 mutex_unlock(&con_buf_mtx);
176 return -EINVAL; 202 return -EINVAL;
177 } 203 }
178 file->f_pos = offset; 204 file->f_pos = offset;
179 mutex_unlock(&con_buf_mtx);
180 return file->f_pos; 205 return file->f_pos;
181} 206}
182 207
@@ -189,12 +214,15 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
189 struct vc_data *vc; 214 struct vc_data *vc;
190 struct vcs_poll_data *poll; 215 struct vcs_poll_data *poll;
191 long pos; 216 long pos;
192 long viewed, attr, read; 217 long attr, read;
193 int col, maxcol; 218 int col, maxcol, viewed;
194 unsigned short *org = NULL; 219 unsigned short *org = NULL;
195 ssize_t ret; 220 ssize_t ret;
221 char *con_buf;
196 222
197 mutex_lock(&con_buf_mtx); 223 con_buf = (char *) __get_free_page(GFP_KERNEL);
224 if (!con_buf)
225 return -ENOMEM;
198 226
199 pos = *ppos; 227 pos = *ppos;
200 228
@@ -204,18 +232,10 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
204 console_lock(); 232 console_lock();
205 233
206 attr = (currcons & 128); 234 attr = (currcons & 128);
207 currcons = (currcons & 127);
208 if (currcons == 0) {
209 currcons = fg_console;
210 viewed = 1;
211 } else {
212 currcons--;
213 viewed = 0;
214 }
215 ret = -ENXIO; 235 ret = -ENXIO;
216 if (!vc_cons_allocated(currcons)) 236 vc = vcs_vc(inode, &viewed);
237 if (!vc)
217 goto unlock_out; 238 goto unlock_out;
218 vc = vc_cons[currcons].d;
219 239
220 ret = -EINVAL; 240 ret = -EINVAL;
221 if (pos < 0) 241 if (pos < 0)
@@ -236,6 +256,12 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
236 * could sleep. 256 * could sleep.
237 */ 257 */
238 size = vcs_size(inode); 258 size = vcs_size(inode);
259 if (size < 0) {
260 if (read)
261 break;
262 ret = size;
263 goto unlock_out;
264 }
239 if (pos >= size) 265 if (pos >= size)
240 break; 266 break;
241 if (count > size - pos) 267 if (count > size - pos)
@@ -354,7 +380,7 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
354 ret = read; 380 ret = read;
355unlock_out: 381unlock_out:
356 console_unlock(); 382 console_unlock();
357 mutex_unlock(&con_buf_mtx); 383 free_page((unsigned long) con_buf);
358 return ret; 384 return ret;
359} 385}
360 386
@@ -365,13 +391,16 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
365 unsigned int currcons = iminor(inode); 391 unsigned int currcons = iminor(inode);
366 struct vc_data *vc; 392 struct vc_data *vc;
367 long pos; 393 long pos;
368 long viewed, attr, size, written; 394 long attr, size, written;
369 char *con_buf0; 395 char *con_buf0;
370 int col, maxcol; 396 int col, maxcol, viewed;
371 u16 *org0 = NULL, *org = NULL; 397 u16 *org0 = NULL, *org = NULL;
372 size_t ret; 398 size_t ret;
399 char *con_buf;
373 400
374 mutex_lock(&con_buf_mtx); 401 con_buf = (char *) __get_free_page(GFP_KERNEL);
402 if (!con_buf)
403 return -ENOMEM;
375 404
376 pos = *ppos; 405 pos = *ppos;
377 406
@@ -381,19 +410,10 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
381 console_lock(); 410 console_lock();
382 411
383 attr = (currcons & 128); 412 attr = (currcons & 128);
384 currcons = (currcons & 127);
385
386 if (currcons == 0) {
387 currcons = fg_console;
388 viewed = 1;
389 } else {
390 currcons--;
391 viewed = 0;
392 }
393 ret = -ENXIO; 413 ret = -ENXIO;
394 if (!vc_cons_allocated(currcons)) 414 vc = vcs_vc(inode, &viewed);
415 if (!vc)
395 goto unlock_out; 416 goto unlock_out;
396 vc = vc_cons[currcons].d;
397 417
398 size = vcs_size(inode); 418 size = vcs_size(inode);
399 ret = -EINVAL; 419 ret = -EINVAL;
@@ -435,6 +455,12 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
435 * Return data written up to now on failure. 455 * Return data written up to now on failure.
436 */ 456 */
437 size = vcs_size(inode); 457 size = vcs_size(inode);
458 if (size < 0) {
459 if (written)
460 break;
461 ret = size;
462 goto unlock_out;
463 }
438 if (pos >= size) 464 if (pos >= size)
439 break; 465 break;
440 if (this_round > size - pos) 466 if (this_round > size - pos)
@@ -542,9 +568,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
542 568
543unlock_out: 569unlock_out:
544 console_unlock(); 570 console_unlock();
545 571 free_page((unsigned long) con_buf);
546 mutex_unlock(&con_buf_mtx);
547
548 return ret; 572 return ret;
549} 573}
550 574
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)
2067 } 2067 }
2068} 2068}
2069 2069
2070/* This is a temporary buffer used to prepare a tty console write
2071 * so that we can easily avoid touching user space while holding the
2072 * console spinlock. It is allocated in con_init and is shared by
2073 * this code and the vc_screen read/write tty calls.
2074 *
2075 * We have to allocate this statically in the kernel data section
2076 * since console_init (and thus con_init) are called before any
2077 * kernel memory allocation is available.
2078 */
2079char con_buf[CON_BUF_SIZE];
2080DEFINE_MUTEX(con_buf_mtx);
2081
2082/* is_double_width() is based on the wcwidth() implementation by 2070/* is_double_width() is based on the wcwidth() implementation by
2083 * Markus Kuhn -- 2007-05-26 (Unicode 5.0) 2071 * Markus Kuhn -- 2007-05-26 (Unicode 5.0)
2084 * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c 2072 * 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
2156 2144
2157 currcons = vc->vc_num; 2145 currcons = vc->vc_num;
2158 if (!vc_cons_allocated(currcons)) { 2146 if (!vc_cons_allocated(currcons)) {
2159 /* could this happen? */ 2147 /* could this happen? */
2160 printk_once("con_write: tty %d not allocated\n", currcons+1); 2148 pr_warn_once("con_write: tty %d not allocated\n", currcons+1);
2161 console_unlock(); 2149 console_unlock();
2162 return 0; 2150 return 0;
2163 } 2151 }
2164 2152
2165 himask = vc->vc_hi_font_mask; 2153 himask = vc->vc_hi_font_mask;
@@ -2939,7 +2927,7 @@ static int __init con_init(void)
2939 gotoxy(vc, vc->vc_x, vc->vc_y); 2927 gotoxy(vc, vc->vc_x, vc->vc_y);
2940 csi_J(vc, 0); 2928 csi_J(vc, 0);
2941 update_screen(vc); 2929 update_screen(vc);
2942 printk("Console: %s %s %dx%d", 2930 pr_info("Console: %s %s %dx%d",
2943 vc->vc_can_do_color ? "colour" : "mono", 2931 vc->vc_can_do_color ? "colour" : "mono",
2944 display_desc, vc->vc_cols, vc->vc_rows); 2932 display_desc, vc->vc_cols, vc->vc_rows);
2945 printable = 1; 2933 printable = 1;
@@ -3102,7 +3090,7 @@ static int bind_con_driver(const struct consw *csw, int first, int last,
3102 clear_buffer_attributes(vc); 3090 clear_buffer_attributes(vc);
3103 } 3091 }
3104 3092
3105 printk("Console: switching "); 3093 pr_info("Console: switching ");
3106 if (!deflt) 3094 if (!deflt)
3107 printk("consoles %d-%d ", first+1, last+1); 3095 printk("consoles %d-%d ", first+1, last+1);
3108 if (j >= 0) { 3096 if (j >= 0) {
@@ -3808,7 +3796,8 @@ void do_unblank_screen(int leaving_gfx)
3808 return; 3796 return;
3809 if (!vc_cons_allocated(fg_console)) { 3797 if (!vc_cons_allocated(fg_console)) {
3810 /* impossible */ 3798 /* impossible */
3811 printk("unblank_screen: tty %d not allocated ??\n", fg_console+1); 3799 pr_warning("unblank_screen: tty %d not allocated ??\n",
3800 fg_console+1);
3812 return; 3801 return;
3813 } 3802 }
3814 vc = vc_cons[fg_console].d; 3803 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_
494 * We handle the console-specific ioctl's here. We allow the 494 * We handle the console-specific ioctl's here. We allow the
495 * capability to modify any console, not just the fg_console. 495 * capability to modify any console, not just the fg_console.
496 */ 496 */
497int vt_ioctl(struct tty_struct *tty, struct file * file, 497int vt_ioctl(struct tty_struct *tty,
498 unsigned int cmd, unsigned long arg) 498 unsigned int cmd, unsigned long arg)
499{ 499{
500 struct vc_data *vc = tty->driver_data; 500 struct vc_data *vc = tty->driver_data;
@@ -687,6 +687,9 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
687 kbd->kbdmode = VC_UNICODE; 687 kbd->kbdmode = VC_UNICODE;
688 compute_shiftstate(); 688 compute_shiftstate();
689 break; 689 break;
690 case K_OFF:
691 kbd->kbdmode = VC_OFF;
692 break;
690 default: 693 default:
691 ret = -EINVAL; 694 ret = -EINVAL;
692 goto out; 695 goto out;
@@ -1006,8 +1009,9 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
1006 if (ret) 1009 if (ret)
1007 break; 1010 break;
1008 /* Commence switch and lock */ 1011 /* Commence switch and lock */
1009 set_console(arg); 1012 set_console(vsa.console);
1010 } 1013 }
1014 break;
1011 } 1015 }
1012 1016
1013 /* 1017 /*
@@ -1490,7 +1494,7 @@ compat_unimap_ioctl(unsigned int cmd, struct compat_unimapdesc __user *user_ud,
1490 return 0; 1494 return 0;
1491} 1495}
1492 1496
1493long vt_compat_ioctl(struct tty_struct *tty, struct file * file, 1497long vt_compat_ioctl(struct tty_struct *tty,
1494 unsigned int cmd, unsigned long arg) 1498 unsigned int cmd, unsigned long arg)
1495{ 1499{
1496 struct vc_data *vc = tty->driver_data; 1500 struct vc_data *vc = tty->driver_data;
@@ -1576,7 +1580,7 @@ out:
1576 1580
1577fallback: 1581fallback:
1578 tty_unlock(); 1582 tty_unlock();
1579 return vt_ioctl(tty, file, cmd, arg); 1583 return vt_ioctl(tty, cmd, arg);
1580} 1584}
1581 1585
1582 1586