aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/vt.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/vt.c')
-rw-r--r--drivers/char/vt.c187
1 files changed, 103 insertions, 84 deletions
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 935f1c207a1f..d8f83e26e4a4 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -59,7 +59,7 @@
59 * by Martin Mares <mj@atrey.karlin.mff.cuni.cz>, July 1998 59 * by Martin Mares <mj@atrey.karlin.mff.cuni.cz>, July 1998
60 * 60 *
61 * Removed old-style timers, introduced console_timer, made timer 61 * Removed old-style timers, introduced console_timer, made timer
62 * deletion SMP-safe. 17Jun00, Andrew Morton <andrewm@uow.edu.au> 62 * deletion SMP-safe. 17Jun00, Andrew Morton
63 * 63 *
64 * Removed console_lock, enabled interrupts across all console operations 64 * Removed console_lock, enabled interrupts across all console operations
65 * 13 March 2001, Andrew Morton 65 * 13 March 2001, Andrew Morton
@@ -100,10 +100,10 @@
100#include <linux/font.h> 100#include <linux/font.h>
101#include <linux/bitops.h> 101#include <linux/bitops.h>
102#include <linux/notifier.h> 102#include <linux/notifier.h>
103 103#include <linux/device.h>
104#include <asm/io.h> 104#include <linux/io.h>
105#include <asm/system.h> 105#include <asm/system.h>
106#include <asm/uaccess.h> 106#include <linux/uaccess.h>
107 107
108#define MAX_NR_CON_DRIVER 16 108#define MAX_NR_CON_DRIVER 16
109 109
@@ -261,7 +261,7 @@ static void notify_update(struct vc_data *vc)
261#ifdef VT_BUF_VRAM_ONLY 261#ifdef VT_BUF_VRAM_ONLY
262#define DO_UPDATE(vc) 0 262#define DO_UPDATE(vc) 0
263#else 263#else
264#define DO_UPDATE(vc) CON_IS_VISIBLE(vc) 264#define DO_UPDATE(vc) (CON_IS_VISIBLE(vc) && !console_blanked)
265#endif 265#endif
266 266
267static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed) 267static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed)
@@ -301,7 +301,7 @@ static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
301 d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t); 301 d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
302 s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr)); 302 s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr));
303 scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row); 303 scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row);
304 scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_scrl_erase_char, 304 scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char,
305 vc->vc_size_row * nr); 305 vc->vc_size_row * nr);
306} 306}
307 307
@@ -319,7 +319,7 @@ static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
319 s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t); 319 s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
320 step = vc->vc_cols * nr; 320 step = vc->vc_cols * nr;
321 scr_memmovew(s + step, s, (b - t - nr) * vc->vc_size_row); 321 scr_memmovew(s + step, s, (b - t - nr) * vc->vc_size_row);
322 scr_memsetw(s, vc->vc_scrl_erase_char, 2 * step); 322 scr_memsetw(s, vc->vc_video_erase_char, 2 * step);
323} 323}
324 324
325static void do_update_region(struct vc_data *vc, unsigned long start, int count) 325static void do_update_region(struct vc_data *vc, unsigned long start, int count)
@@ -434,7 +434,6 @@ static void update_attr(struct vc_data *vc)
434 vc->vc_blink, vc->vc_underline, 434 vc->vc_blink, vc->vc_underline,
435 vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic); 435 vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic);
436 vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm, 0) << 8) | ' '; 436 vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm, 0) << 8) | ' ';
437 vc->vc_scrl_erase_char = (build_attr(vc, vc->vc_def_color, 1, false, false, vc->vc_decscnm, false) << 8) | ' ';
438} 437}
439 438
440/* Note: inverting the screen twice should revert to the original state */ 439/* Note: inverting the screen twice should revert to the original state */
@@ -803,7 +802,25 @@ static inline int resize_screen(struct vc_data *vc, int width, int height,
803 */ 802 */
804#define VC_RESIZE_MAXCOL (32767) 803#define VC_RESIZE_MAXCOL (32767)
805#define VC_RESIZE_MAXROW (32767) 804#define VC_RESIZE_MAXROW (32767)
806int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) 805
806/**
807 * vc_do_resize - resizing method for the tty
808 * @tty: tty being resized
809 * @real_tty: real tty (different to tty if a pty/tty pair)
810 * @vc: virtual console private data
811 * @cols: columns
812 * @lines: lines
813 *
814 * Resize a virtual console, clipping according to the actual constraints.
815 * If the caller passes a tty structure then update the termios winsize
816 * information and perform any neccessary signal handling.
817 *
818 * Caller must hold the console semaphore. Takes the termios mutex and
819 * ctrl_lock of the tty IFF a tty is passed.
820 */
821
822static int vc_do_resize(struct tty_struct *tty, struct tty_struct *real_tty,
823 struct vc_data *vc, unsigned int cols, unsigned int lines)
807{ 824{
808 unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0; 825 unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0;
809 unsigned int old_cols, old_rows, old_row_size, old_screen_size; 826 unsigned int old_cols, old_rows, old_row_size, old_screen_size;
@@ -907,26 +924,15 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
907 gotoxy(vc, vc->vc_x, vc->vc_y); 924 gotoxy(vc, vc->vc_x, vc->vc_y);
908 save_cur(vc); 925 save_cur(vc);
909 926
910 if (vc->vc_tty) { 927 if (tty) {
911 struct winsize ws, *cws = &vc->vc_tty->winsize; 928 /* Rewrite the requested winsize data with the actual
912 struct pid *pgrp = NULL; 929 resulting sizes */
913 930 struct winsize ws;
914 memset(&ws, 0, sizeof(ws)); 931 memset(&ws, 0, sizeof(ws));
915 ws.ws_row = vc->vc_rows; 932 ws.ws_row = vc->vc_rows;
916 ws.ws_col = vc->vc_cols; 933 ws.ws_col = vc->vc_cols;
917 ws.ws_ypixel = vc->vc_scan_lines; 934 ws.ws_ypixel = vc->vc_scan_lines;
918 935 tty_do_resize(tty, real_tty, &ws);
919 mutex_lock(&vc->vc_tty->termios_mutex);
920 spin_lock_irq(&vc->vc_tty->ctrl_lock);
921 if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col))
922 pgrp = get_pid(vc->vc_tty->pgrp);
923 spin_unlock_irq(&vc->vc_tty->ctrl_lock);
924 if (pgrp) {
925 kill_pgrp(vc->vc_tty->pgrp, SIGWINCH, 1);
926 put_pid(pgrp);
927 }
928 *cws = ws;
929 mutex_unlock(&vc->vc_tty->termios_mutex);
930 } 936 }
931 937
932 if (CON_IS_VISIBLE(vc)) 938 if (CON_IS_VISIBLE(vc))
@@ -934,14 +940,47 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
934 return err; 940 return err;
935} 941}
936 942
937int vc_lock_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) 943/**
944 * vc_resize - resize a VT
945 * @vc: virtual console
946 * @cols: columns
947 * @rows: rows
948 *
949 * Resize a virtual console as seen from the console end of things. We
950 * use the common vc_do_resize methods to update the structures. The
951 * caller must hold the console sem to protect console internals and
952 * vc->vc_tty
953 */
954
955int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows)
938{ 956{
939 int rc; 957 return vc_do_resize(vc->vc_tty, vc->vc_tty, vc, cols, rows);
958}
959
960/**
961 * vt_resize - resize a VT
962 * @tty: tty to resize
963 * @real_tty: tty if a pty/tty pair
964 * @ws: winsize attributes
965 *
966 * Resize a virtual terminal. This is called by the tty layer as we
967 * register our own handler for resizing. The mutual helper does all
968 * the actual work.
969 *
970 * Takes the console sem and the called methods then take the tty
971 * termios_mutex and the tty ctrl_lock in that order.
972 */
973
974int vt_resize(struct tty_struct *tty, struct tty_struct *real_tty,
975 struct winsize *ws)
976{
977 struct vc_data *vc = tty->driver_data;
978 int ret;
940 979
941 acquire_console_sem(); 980 acquire_console_sem();
942 rc = vc_resize(vc, cols, lines); 981 ret = vc_do_resize(tty, real_tty, vc, ws->ws_col, ws->ws_row);
943 release_console_sem(); 982 release_console_sem();
944 return rc; 983 return ret;
945} 984}
946 985
947void vc_deallocate(unsigned int currcons) 986void vc_deallocate(unsigned int currcons)
@@ -2096,27 +2135,9 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
2096 release_console_sem(); 2135 release_console_sem();
2097 return 0; 2136 return 0;
2098 } 2137 }
2099 release_console_sem();
2100
2101 orig_buf = buf; 2138 orig_buf = buf;
2102 orig_count = count; 2139 orig_count = count;
2103 2140
2104 /* At this point 'buf' is guaranteed to be a kernel buffer
2105 * and therefore no access to userspace (and therefore sleeping)
2106 * will be needed. The con_buf_mtx serializes all tty based
2107 * console rendering and vcs write/read operations. We hold
2108 * the console spinlock during the entire write.
2109 */
2110
2111 acquire_console_sem();
2112
2113 vc = tty->driver_data;
2114 if (vc == NULL) {
2115 printk(KERN_ERR "vt: argh, driver_data _became_ NULL !\n");
2116 release_console_sem();
2117 goto out;
2118 }
2119
2120 himask = vc->vc_hi_font_mask; 2141 himask = vc->vc_hi_font_mask;
2121 charmask = himask ? 0x1ff : 0xff; 2142 charmask = himask ? 0x1ff : 0xff;
2122 2143
@@ -2211,7 +2232,7 @@ rescan_last_byte:
2211 c = 0xfffd; 2232 c = 0xfffd;
2212 tc = c; 2233 tc = c;
2213 } else { /* no utf or alternate charset mode */ 2234 } else { /* no utf or alternate charset mode */
2214 tc = vc->vc_translate[vc->vc_toggle_meta ? (c | 0x80) : c]; 2235 tc = vc_translate(vc, c);
2215 } 2236 }
2216 2237
2217 param.c = tc; 2238 param.c = tc;
@@ -2330,8 +2351,6 @@ rescan_last_byte:
2330 FLUSH 2351 FLUSH
2331 console_conditional_schedule(); 2352 console_conditional_schedule();
2332 release_console_sem(); 2353 release_console_sem();
2333
2334out:
2335 notify_update(vc); 2354 notify_update(vc);
2336 return n; 2355 return n;
2337#undef FLUSH 2356#undef FLUSH
@@ -2543,8 +2562,6 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
2543 int lines; 2562 int lines;
2544 int ret; 2563 int ret;
2545 2564
2546 if (tty->driver->type != TTY_DRIVER_TYPE_CONSOLE)
2547 return -EINVAL;
2548 if (current->signal->tty != tty && !capable(CAP_SYS_ADMIN)) 2565 if (current->signal->tty != tty && !capable(CAP_SYS_ADMIN))
2549 return -EPERM; 2566 return -EPERM;
2550 if (get_user(type, p)) 2567 if (get_user(type, p))
@@ -2738,6 +2755,12 @@ static int con_open(struct tty_struct *tty, struct file *filp)
2738 ret = vc_allocate(currcons); 2755 ret = vc_allocate(currcons);
2739 if (ret == 0) { 2756 if (ret == 0) {
2740 struct vc_data *vc = vc_cons[currcons].d; 2757 struct vc_data *vc = vc_cons[currcons].d;
2758
2759 /* Still being freed */
2760 if (vc->vc_tty) {
2761 release_console_sem();
2762 return -ERESTARTSYS;
2763 }
2741 tty->driver_data = vc; 2764 tty->driver_data = vc;
2742 vc->vc_tty = tty; 2765 vc->vc_tty = tty;
2743 2766
@@ -2749,8 +2772,8 @@ static int con_open(struct tty_struct *tty, struct file *filp)
2749 tty->termios->c_iflag |= IUTF8; 2772 tty->termios->c_iflag |= IUTF8;
2750 else 2773 else
2751 tty->termios->c_iflag &= ~IUTF8; 2774 tty->termios->c_iflag &= ~IUTF8;
2752 release_console_sem();
2753 vcs_make_sysfs(tty); 2775 vcs_make_sysfs(tty);
2776 release_console_sem();
2754 return ret; 2777 return ret;
2755 } 2778 }
2756 } 2779 }
@@ -2758,34 +2781,20 @@ static int con_open(struct tty_struct *tty, struct file *filp)
2758 return ret; 2781 return ret;
2759} 2782}
2760 2783
2761/*
2762 * We take tty_mutex in here to prevent another thread from coming in via init_dev
2763 * and taking a ref against the tty while we're in the process of forgetting
2764 * about it and cleaning things up.
2765 *
2766 * This is because vcs_remove_sysfs() can sleep and will drop the BKL.
2767 */
2768static void con_close(struct tty_struct *tty, struct file *filp) 2784static void con_close(struct tty_struct *tty, struct file *filp)
2769{ 2785{
2770 mutex_lock(&tty_mutex); 2786 /* Nothing to do - we defer to shutdown */
2771 acquire_console_sem(); 2787}
2772 if (tty && tty->count == 1) {
2773 struct vc_data *vc = tty->driver_data;
2774 2788
2775 if (vc) 2789static void con_shutdown(struct tty_struct *tty)
2776 vc->vc_tty = NULL; 2790{
2777 tty->driver_data = NULL; 2791 struct vc_data *vc = tty->driver_data;
2778 release_console_sem(); 2792 BUG_ON(vc == NULL);
2779 vcs_remove_sysfs(tty); 2793 acquire_console_sem();
2780 mutex_unlock(&tty_mutex); 2794 vc->vc_tty = NULL;
2781 /* 2795 vcs_remove_sysfs(tty);
2782 * tty_mutex is released, but we still hold BKL, so there is
2783 * still exclusion against init_dev()
2784 */
2785 return;
2786 }
2787 release_console_sem(); 2796 release_console_sem();
2788 mutex_unlock(&tty_mutex); 2797 tty_shutdown(tty);
2789} 2798}
2790 2799
2791static int default_italic_color = 2; // green (ASCII) 2800static int default_italic_color = 2; // green (ASCII)
@@ -2909,10 +2918,20 @@ static const struct tty_operations con_ops = {
2909 .start = con_start, 2918 .start = con_start,
2910 .throttle = con_throttle, 2919 .throttle = con_throttle,
2911 .unthrottle = con_unthrottle, 2920 .unthrottle = con_unthrottle,
2921 .resize = vt_resize,
2922 .shutdown = con_shutdown
2912}; 2923};
2913 2924
2914int __init vty_init(void) 2925static struct cdev vc0_cdev;
2926
2927int __init vty_init(const struct file_operations *console_fops)
2915{ 2928{
2929 cdev_init(&vc0_cdev, console_fops);
2930 if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
2931 register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
2932 panic("Couldn't register /dev/tty0 driver\n");
2933 device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
2934
2916 vcs_init(); 2935 vcs_init();
2917 2936
2918 console_driver = alloc_tty_driver(MAX_NR_CONSOLES); 2937 console_driver = alloc_tty_driver(MAX_NR_CONSOLES);
@@ -2931,7 +2950,6 @@ int __init vty_init(void)
2931 tty_set_operations(console_driver, &con_ops); 2950 tty_set_operations(console_driver, &con_ops);
2932 if (tty_register_driver(console_driver)) 2951 if (tty_register_driver(console_driver))
2933 panic("Couldn't register console driver\n"); 2952 panic("Couldn't register console driver\n");
2934
2935 kbd_init(); 2953 kbd_init();
2936 console_map_init(); 2954 console_map_init();
2937#ifdef CONFIG_PROM_CONSOLE 2955#ifdef CONFIG_PROM_CONSOLE
@@ -3426,8 +3444,9 @@ int register_con_driver(const struct consw *csw, int first, int last)
3426 goto err; 3444 goto err;
3427 3445
3428 con_driver->dev = device_create(vtconsole_class, NULL, 3446 con_driver->dev = device_create(vtconsole_class, NULL,
3429 MKDEV(0, con_driver->node), 3447 MKDEV(0, con_driver->node),
3430 "vtcon%i", con_driver->node); 3448 NULL, "vtcon%i",
3449 con_driver->node);
3431 3450
3432 if (IS_ERR(con_driver->dev)) { 3451 if (IS_ERR(con_driver->dev)) {
3433 printk(KERN_WARNING "Unable to create device for %s; " 3452 printk(KERN_WARNING "Unable to create device for %s; "
@@ -3536,8 +3555,9 @@ static int __init vtconsole_class_init(void)
3536 3555
3537 if (con->con && !con->dev) { 3556 if (con->con && !con->dev) {
3538 con->dev = device_create(vtconsole_class, NULL, 3557 con->dev = device_create(vtconsole_class, NULL,
3539 MKDEV(0, con->node), 3558 MKDEV(0, con->node),
3540 "vtcon%i", con->node); 3559 NULL, "vtcon%i",
3560 con->node);
3541 3561
3542 if (IS_ERR(con->dev)) { 3562 if (IS_ERR(con->dev)) {
3543 printk(KERN_WARNING "Unable to create " 3563 printk(KERN_WARNING "Unable to create "
@@ -4061,7 +4081,6 @@ EXPORT_SYMBOL(default_blu);
4061EXPORT_SYMBOL(update_region); 4081EXPORT_SYMBOL(update_region);
4062EXPORT_SYMBOL(redraw_screen); 4082EXPORT_SYMBOL(redraw_screen);
4063EXPORT_SYMBOL(vc_resize); 4083EXPORT_SYMBOL(vc_resize);
4064EXPORT_SYMBOL(vc_lock_resize);
4065EXPORT_SYMBOL(fg_console); 4084EXPORT_SYMBOL(fg_console);
4066EXPORT_SYMBOL(console_blank_hook); 4085EXPORT_SYMBOL(console_blank_hook);
4067EXPORT_SYMBOL(console_blanked); 4086EXPORT_SYMBOL(console_blanked);