diff options
Diffstat (limited to 'drivers/char/vt.c')
-rw-r--r-- | drivers/char/vt.c | 89 |
1 files changed, 33 insertions, 56 deletions
diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 60359c360912..a0f7ffb68087 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c | |||
@@ -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 | ||
@@ -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 | ||
325 | static void do_update_region(struct vc_data *vc, unsigned long start, int count) | 325 | static 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 */ |
@@ -2136,27 +2135,9 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co | |||
2136 | release_console_sem(); | 2135 | release_console_sem(); |
2137 | return 0; | 2136 | return 0; |
2138 | } | 2137 | } |
2139 | release_console_sem(); | ||
2140 | |||
2141 | orig_buf = buf; | 2138 | orig_buf = buf; |
2142 | orig_count = count; | 2139 | orig_count = count; |
2143 | 2140 | ||
2144 | /* At this point 'buf' is guaranteed to be a kernel buffer | ||
2145 | * and therefore no access to userspace (and therefore sleeping) | ||
2146 | * will be needed. The con_buf_mtx serializes all tty based | ||
2147 | * console rendering and vcs write/read operations. We hold | ||
2148 | * the console spinlock during the entire write. | ||
2149 | */ | ||
2150 | |||
2151 | acquire_console_sem(); | ||
2152 | |||
2153 | vc = tty->driver_data; | ||
2154 | if (vc == NULL) { | ||
2155 | printk(KERN_ERR "vt: argh, driver_data _became_ NULL !\n"); | ||
2156 | release_console_sem(); | ||
2157 | goto out; | ||
2158 | } | ||
2159 | |||
2160 | himask = vc->vc_hi_font_mask; | 2141 | himask = vc->vc_hi_font_mask; |
2161 | charmask = himask ? 0x1ff : 0xff; | 2142 | charmask = himask ? 0x1ff : 0xff; |
2162 | 2143 | ||
@@ -2370,8 +2351,6 @@ rescan_last_byte: | |||
2370 | FLUSH | 2351 | FLUSH |
2371 | console_conditional_schedule(); | 2352 | console_conditional_schedule(); |
2372 | release_console_sem(); | 2353 | release_console_sem(); |
2373 | |||
2374 | out: | ||
2375 | notify_update(vc); | 2354 | notify_update(vc); |
2376 | return n; | 2355 | return n; |
2377 | #undef FLUSH | 2356 | #undef FLUSH |
@@ -2583,8 +2562,6 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) | |||
2583 | int lines; | 2562 | int lines; |
2584 | int ret; | 2563 | int ret; |
2585 | 2564 | ||
2586 | if (tty->driver->type != TTY_DRIVER_TYPE_CONSOLE) | ||
2587 | return -EINVAL; | ||
2588 | if (current->signal->tty != tty && !capable(CAP_SYS_ADMIN)) | 2565 | if (current->signal->tty != tty && !capable(CAP_SYS_ADMIN)) |
2589 | return -EPERM; | 2566 | return -EPERM; |
2590 | if (get_user(type, p)) | 2567 | if (get_user(type, p)) |
@@ -2778,6 +2755,12 @@ static int con_open(struct tty_struct *tty, struct file *filp) | |||
2778 | ret = vc_allocate(currcons); | 2755 | ret = vc_allocate(currcons); |
2779 | if (ret == 0) { | 2756 | if (ret == 0) { |
2780 | 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 | } | ||
2781 | tty->driver_data = vc; | 2764 | tty->driver_data = vc; |
2782 | vc->vc_tty = tty; | 2765 | vc->vc_tty = tty; |
2783 | 2766 | ||
@@ -2798,34 +2781,20 @@ static int con_open(struct tty_struct *tty, struct file *filp) | |||
2798 | return ret; | 2781 | return ret; |
2799 | } | 2782 | } |
2800 | 2783 | ||
2801 | /* | ||
2802 | * We take tty_mutex in here to prevent another thread from coming in via init_dev | ||
2803 | * and taking a ref against the tty while we're in the process of forgetting | ||
2804 | * about it and cleaning things up. | ||
2805 | * | ||
2806 | * This is because vcs_remove_sysfs() can sleep and will drop the BKL. | ||
2807 | */ | ||
2808 | static void con_close(struct tty_struct *tty, struct file *filp) | 2784 | static void con_close(struct tty_struct *tty, struct file *filp) |
2809 | { | 2785 | { |
2810 | mutex_lock(&tty_mutex); | 2786 | /* Nothing to do - we defer to shutdown */ |
2811 | acquire_console_sem(); | 2787 | } |
2812 | if (tty && tty->count == 1) { | ||
2813 | struct vc_data *vc = tty->driver_data; | ||
2814 | 2788 | ||
2815 | if (vc) | 2789 | static void con_shutdown(struct tty_struct *tty) |
2816 | vc->vc_tty = NULL; | 2790 | { |
2817 | tty->driver_data = NULL; | 2791 | struct vc_data *vc = tty->driver_data; |
2818 | vcs_remove_sysfs(tty); | 2792 | BUG_ON(vc == NULL); |
2819 | release_console_sem(); | 2793 | acquire_console_sem(); |
2820 | mutex_unlock(&tty_mutex); | 2794 | vc->vc_tty = NULL; |
2821 | /* | 2795 | vcs_remove_sysfs(tty); |
2822 | * tty_mutex is released, but we still hold BKL, so there is | ||
2823 | * still exclusion against init_dev() | ||
2824 | */ | ||
2825 | return; | ||
2826 | } | ||
2827 | release_console_sem(); | 2796 | release_console_sem(); |
2828 | mutex_unlock(&tty_mutex); | 2797 | tty_shutdown(tty); |
2829 | } | 2798 | } |
2830 | 2799 | ||
2831 | static int default_italic_color = 2; // green (ASCII) | 2800 | static int default_italic_color = 2; // green (ASCII) |
@@ -2950,10 +2919,19 @@ static const struct tty_operations con_ops = { | |||
2950 | .throttle = con_throttle, | 2919 | .throttle = con_throttle, |
2951 | .unthrottle = con_unthrottle, | 2920 | .unthrottle = con_unthrottle, |
2952 | .resize = vt_resize, | 2921 | .resize = vt_resize, |
2922 | .shutdown = con_shutdown | ||
2953 | }; | 2923 | }; |
2954 | 2924 | ||
2955 | int __init vty_init(void) | 2925 | static struct cdev vc0_cdev; |
2926 | |||
2927 | int __init vty_init(const struct file_operations *console_fops) | ||
2956 | { | 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 | |||
2957 | vcs_init(); | 2935 | vcs_init(); |
2958 | 2936 | ||
2959 | console_driver = alloc_tty_driver(MAX_NR_CONSOLES); | 2937 | console_driver = alloc_tty_driver(MAX_NR_CONSOLES); |
@@ -2972,7 +2950,6 @@ int __init vty_init(void) | |||
2972 | tty_set_operations(console_driver, &con_ops); | 2950 | tty_set_operations(console_driver, &con_ops); |
2973 | if (tty_register_driver(console_driver)) | 2951 | if (tty_register_driver(console_driver)) |
2974 | panic("Couldn't register console driver\n"); | 2952 | panic("Couldn't register console driver\n"); |
2975 | |||
2976 | kbd_init(); | 2953 | kbd_init(); |
2977 | console_map_init(); | 2954 | console_map_init(); |
2978 | #ifdef CONFIG_PROM_CONSOLE | 2955 | #ifdef CONFIG_PROM_CONSOLE |
@@ -3466,7 +3443,7 @@ int register_con_driver(const struct consw *csw, int first, int last) | |||
3466 | if (retval) | 3443 | if (retval) |
3467 | goto err; | 3444 | goto err; |
3468 | 3445 | ||
3469 | con_driver->dev = device_create_drvdata(vtconsole_class, NULL, | 3446 | con_driver->dev = device_create(vtconsole_class, NULL, |
3470 | MKDEV(0, con_driver->node), | 3447 | MKDEV(0, con_driver->node), |
3471 | NULL, "vtcon%i", | 3448 | NULL, "vtcon%i", |
3472 | con_driver->node); | 3449 | con_driver->node); |
@@ -3577,7 +3554,7 @@ static int __init vtconsole_class_init(void) | |||
3577 | struct con_driver *con = ®istered_con_driver[i]; | 3554 | struct con_driver *con = ®istered_con_driver[i]; |
3578 | 3555 | ||
3579 | if (con->con && !con->dev) { | 3556 | if (con->con && !con->dev) { |
3580 | con->dev = device_create_drvdata(vtconsole_class, NULL, | 3557 | con->dev = device_create(vtconsole_class, NULL, |
3581 | MKDEV(0, con->node), | 3558 | MKDEV(0, con->node), |
3582 | NULL, "vtcon%i", | 3559 | NULL, "vtcon%i", |
3583 | con->node); | 3560 | con->node); |