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.c688
1 files changed, 620 insertions, 68 deletions
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 6c94879e0b99..fb75da940b59 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -63,6 +63,13 @@
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
66 *
67 * Fixed UTF-8 mode so alternate charset modes always work according
68 * to control sequences interpreted in do_con_trol function
69 * preserving backward VT100 semigraphics compatibility,
70 * malformed UTF sequences represented as sequences of replacement glyphs,
71 * original codes or '?' as a last resort if replacement glyph is undefined
72 * by Adam Tla/lka <atlka@pg.gda.pl>, Aug 2006
66 */ 73 */
67 74
68#include <linux/module.h> 75#include <linux/module.h>
@@ -79,7 +86,6 @@
79#include <linux/mm.h> 86#include <linux/mm.h>
80#include <linux/console.h> 87#include <linux/console.h>
81#include <linux/init.h> 88#include <linux/init.h>
82#include <linux/devfs_fs_kernel.h>
83#include <linux/vt_kern.h> 89#include <linux/vt_kern.h>
84#include <linux/selection.h> 90#include <linux/selection.h>
85#include <linux/tiocl.h> 91#include <linux/tiocl.h>
@@ -87,7 +93,6 @@
87#include <linux/consolemap.h> 93#include <linux/consolemap.h>
88#include <linux/timer.h> 94#include <linux/timer.h>
89#include <linux/interrupt.h> 95#include <linux/interrupt.h>
90#include <linux/config.h>
91#include <linux/workqueue.h> 96#include <linux/workqueue.h>
92#include <linux/bootmem.h> 97#include <linux/bootmem.h>
93#include <linux/pm.h> 98#include <linux/pm.h>
@@ -98,7 +103,22 @@
98#include <asm/system.h> 103#include <asm/system.h>
99#include <asm/uaccess.h> 104#include <asm/uaccess.h>
100 105
106#define MAX_NR_CON_DRIVER 16
107
108#define CON_DRIVER_FLAG_MODULE 1
109#define CON_DRIVER_FLAG_INIT 2
110
111struct con_driver {
112 const struct consw *con;
113 const char *desc;
114 struct class_device *class_dev;
115 int node;
116 int first;
117 int last;
118 int flag;
119};
101 120
121static struct con_driver registered_con_driver[MAX_NR_CON_DRIVER];
102const struct consw *conswitchp; 122const struct consw *conswitchp;
103 123
104/* A bitmap for codes <32. A bit of 1 indicates that the code 124/* A bitmap for codes <32. A bit of 1 indicates that the code
@@ -115,8 +135,8 @@ const struct consw *conswitchp;
115#define DEFAULT_BELL_PITCH 750 135#define DEFAULT_BELL_PITCH 750
116#define DEFAULT_BELL_DURATION (HZ/8) 136#define DEFAULT_BELL_DURATION (HZ/8)
117 137
118extern void vcs_make_devfs(struct tty_struct *tty); 138extern void vcs_make_sysfs(struct tty_struct *tty);
119extern void vcs_remove_devfs(struct tty_struct *tty); 139extern void vcs_remove_sysfs(struct tty_struct *tty);
120 140
121extern void console_map_init(void); 141extern void console_map_init(void);
122#ifdef CONFIG_PROM_CONSOLE 142#ifdef CONFIG_PROM_CONSOLE
@@ -717,7 +737,8 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */
717 visual_init(vc, currcons, 1); 737 visual_init(vc, currcons, 1);
718 if (!*vc->vc_uni_pagedir_loc) 738 if (!*vc->vc_uni_pagedir_loc)
719 con_set_default_unimap(vc); 739 con_set_default_unimap(vc);
720 vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL); 740 if (!vc->vc_kmalloced)
741 vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
721 if (!vc->vc_screenbuf) { 742 if (!vc->vc_screenbuf) {
722 kfree(vc); 743 kfree(vc);
723 vc_cons[currcons].d = NULL; 744 vc_cons[currcons].d = NULL;
@@ -865,14 +886,24 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
865 return err; 886 return err;
866} 887}
867 888
889int vc_lock_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
890{
891 int rc;
892
893 acquire_console_sem();
894 rc = vc_resize(vc, cols, lines);
895 release_console_sem();
896 return rc;
897}
868 898
869void vc_disallocate(unsigned int currcons) 899void vc_deallocate(unsigned int currcons)
870{ 900{
871 WARN_CONSOLE_UNLOCKED(); 901 WARN_CONSOLE_UNLOCKED();
872 902
873 if (vc_cons_allocated(currcons)) { 903 if (vc_cons_allocated(currcons)) {
874 struct vc_data *vc = vc_cons[currcons].d; 904 struct vc_data *vc = vc_cons[currcons].d;
875 vc->vc_sw->con_deinit(vc); 905 vc->vc_sw->con_deinit(vc);
906 module_put(vc->vc_sw->owner);
876 if (vc->vc_kmalloced) 907 if (vc->vc_kmalloced)
877 kfree(vc->vc_screenbuf); 908 kfree(vc->vc_screenbuf);
878 if (currcons >= MIN_NR_CONSOLES) 909 if (currcons >= MIN_NR_CONSOLES)
@@ -1991,17 +2022,23 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
1991 /* Do no translation at all in control states */ 2022 /* Do no translation at all in control states */
1992 if (vc->vc_state != ESnormal) { 2023 if (vc->vc_state != ESnormal) {
1993 tc = c; 2024 tc = c;
1994 } else if (vc->vc_utf) { 2025 } else if (vc->vc_utf && !vc->vc_disp_ctrl) {
1995 /* Combine UTF-8 into Unicode */ 2026 /* Combine UTF-8 into Unicode */
1996 /* Incomplete characters silently ignored */ 2027 /* Malformed sequences as sequences of replacement glyphs */
2028rescan_last_byte:
1997 if(c > 0x7f) { 2029 if(c > 0x7f) {
1998 if (vc->vc_utf_count > 0 && (c & 0xc0) == 0x80) { 2030 if (vc->vc_utf_count) {
1999 vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f); 2031 if ((c & 0xc0) == 0x80) {
2000 vc->vc_utf_count--; 2032 vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
2001 if (vc->vc_utf_count == 0) 2033 if (--vc->vc_utf_count) {
2002 tc = c = vc->vc_utf_char; 2034 vc->vc_npar++;
2003 else continue; 2035 continue;
2036 }
2037 tc = c = vc->vc_utf_char;
2038 } else
2039 goto replacement_glyph;
2004 } else { 2040 } else {
2041 vc->vc_npar = 0;
2005 if ((c & 0xe0) == 0xc0) { 2042 if ((c & 0xe0) == 0xc0) {
2006 vc->vc_utf_count = 1; 2043 vc->vc_utf_count = 1;
2007 vc->vc_utf_char = (c & 0x1f); 2044 vc->vc_utf_char = (c & 0x1f);
@@ -2018,14 +2055,15 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
2018 vc->vc_utf_count = 5; 2055 vc->vc_utf_count = 5;
2019 vc->vc_utf_char = (c & 0x01); 2056 vc->vc_utf_char = (c & 0x01);
2020 } else 2057 } else
2021 vc->vc_utf_count = 0; 2058 goto replacement_glyph;
2022 continue; 2059 continue;
2023 } 2060 }
2024 } else { 2061 } else {
2062 if (vc->vc_utf_count)
2063 goto replacement_glyph;
2025 tc = c; 2064 tc = c;
2026 vc->vc_utf_count = 0;
2027 } 2065 }
2028 } else { /* no utf */ 2066 } else { /* no utf or alternate charset mode */
2029 tc = vc->vc_translate[vc->vc_toggle_meta ? (c | 0x80) : c]; 2067 tc = vc->vc_translate[vc->vc_toggle_meta ? (c | 0x80) : c];
2030 } 2068 }
2031 2069
@@ -2040,31 +2078,33 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
2040 * direct-to-font zone in UTF-8 mode. 2078 * direct-to-font zone in UTF-8 mode.
2041 */ 2079 */
2042 ok = tc && (c >= 32 || 2080 ok = tc && (c >= 32 ||
2043 (!vc->vc_utf && !(((vc->vc_disp_ctrl ? CTRL_ALWAYS 2081 !(vc->vc_disp_ctrl ? (CTRL_ALWAYS >> c) & 1 :
2044 : CTRL_ACTION) >> c) & 1))) 2082 vc->vc_utf || ((CTRL_ACTION >> c) & 1)))
2045 && (c != 127 || vc->vc_disp_ctrl) 2083 && (c != 127 || vc->vc_disp_ctrl)
2046 && (c != 128+27); 2084 && (c != 128+27);
2047 2085
2048 if (vc->vc_state == ESnormal && ok) { 2086 if (vc->vc_state == ESnormal && ok) {
2049 /* Now try to find out how to display it */ 2087 /* Now try to find out how to display it */
2050 tc = conv_uni_to_pc(vc, tc); 2088 tc = conv_uni_to_pc(vc, tc);
2051 if ( tc == -4 ) { 2089 if (tc & ~charmask) {
2090 if ( tc == -4 ) {
2052 /* If we got -4 (not found) then see if we have 2091 /* If we got -4 (not found) then see if we have
2053 defined a replacement character (U+FFFD) */ 2092 defined a replacement character (U+FFFD) */
2054 tc = conv_uni_to_pc(vc, 0xfffd); 2093replacement_glyph:
2055 2094 tc = conv_uni_to_pc(vc, 0xfffd);
2056 /* One reason for the -4 can be that we just 2095 if (!(tc & ~charmask))
2057 did a clear_unimap(); 2096 goto display_glyph;
2058 try at least to show something. */ 2097 } else if ( tc != -3 )
2059 if (tc == -4) 2098 continue; /* nothing to display */
2060 tc = c; 2099 /* no hash table or no replacement --
2061 } else if ( tc == -3 ) { 2100 * hope for the best */
2062 /* Bad hash table -- hope for the best */ 2101 if ( c & ~charmask )
2063 tc = c; 2102 tc = '?';
2064 } 2103 else
2065 if (tc & ~charmask) 2104 tc = c;
2066 continue; /* Conversion failed */ 2105 }
2067 2106
2107display_glyph:
2068 if (vc->vc_need_wrap || vc->vc_decim) 2108 if (vc->vc_need_wrap || vc->vc_decim)
2069 FLUSH 2109 FLUSH
2070 if (vc->vc_need_wrap) { 2110 if (vc->vc_need_wrap) {
@@ -2088,6 +2128,15 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
2088 vc->vc_x++; 2128 vc->vc_x++;
2089 draw_to = (vc->vc_pos += 2); 2129 draw_to = (vc->vc_pos += 2);
2090 } 2130 }
2131 if (vc->vc_utf_count) {
2132 if (vc->vc_npar) {
2133 vc->vc_npar--;
2134 goto display_glyph;
2135 }
2136 vc->vc_utf_count = 0;
2137 c = orig;
2138 goto rescan_last_byte;
2139 }
2091 continue; 2140 continue;
2092 } 2141 }
2093 FLUSH 2142 FLUSH
@@ -2484,7 +2533,7 @@ static int con_open(struct tty_struct *tty, struct file *filp)
2484 tty->winsize.ws_col = vc_cons[currcons].d->vc_cols; 2533 tty->winsize.ws_col = vc_cons[currcons].d->vc_cols;
2485 } 2534 }
2486 release_console_sem(); 2535 release_console_sem();
2487 vcs_make_devfs(tty); 2536 vcs_make_sysfs(tty);
2488 return ret; 2537 return ret;
2489 } 2538 }
2490 } 2539 }
@@ -2497,7 +2546,7 @@ static int con_open(struct tty_struct *tty, struct file *filp)
2497 * and taking a ref against the tty while we're in the process of forgetting 2546 * and taking a ref against the tty while we're in the process of forgetting
2498 * about it and cleaning things up. 2547 * about it and cleaning things up.
2499 * 2548 *
2500 * This is because vcs_remove_devfs() can sleep and will drop the BKL. 2549 * This is because vcs_remove_sysfs() can sleep and will drop the BKL.
2501 */ 2550 */
2502static void con_close(struct tty_struct *tty, struct file *filp) 2551static void con_close(struct tty_struct *tty, struct file *filp)
2503{ 2552{
@@ -2510,7 +2559,7 @@ static void con_close(struct tty_struct *tty, struct file *filp)
2510 vc->vc_tty = NULL; 2559 vc->vc_tty = NULL;
2511 tty->driver_data = NULL; 2560 tty->driver_data = NULL;
2512 release_console_sem(); 2561 release_console_sem();
2513 vcs_remove_devfs(tty); 2562 vcs_remove_sysfs(tty);
2514 mutex_unlock(&tty_mutex); 2563 mutex_unlock(&tty_mutex);
2515 /* 2564 /*
2516 * tty_mutex is released, but we still hold BKL, so there is 2565 * tty_mutex is released, but we still hold BKL, so there is
@@ -2557,7 +2606,7 @@ static int __init con_init(void)
2557{ 2606{
2558 const char *display_desc = NULL; 2607 const char *display_desc = NULL;
2559 struct vc_data *vc; 2608 struct vc_data *vc;
2560 unsigned int currcons = 0; 2609 unsigned int currcons = 0, i;
2561 2610
2562 acquire_console_sem(); 2611 acquire_console_sem();
2563 2612
@@ -2569,6 +2618,22 @@ static int __init con_init(void)
2569 return 0; 2618 return 0;
2570 } 2619 }
2571 2620
2621 for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
2622 struct con_driver *con_driver = &registered_con_driver[i];
2623
2624 if (con_driver->con == NULL) {
2625 con_driver->con = conswitchp;
2626 con_driver->desc = display_desc;
2627 con_driver->flag = CON_DRIVER_FLAG_INIT;
2628 con_driver->first = 0;
2629 con_driver->last = MAX_NR_CONSOLES - 1;
2630 break;
2631 }
2632 }
2633
2634 for (i = 0; i < MAX_NR_CONSOLES; i++)
2635 con_driver_map[i] = conswitchp;
2636
2572 init_timer(&console_timer); 2637 init_timer(&console_timer);
2573 console_timer.function = blank_screen_t; 2638 console_timer.function = blank_screen_t;
2574 if (blankinterval) { 2639 if (blankinterval) {
@@ -2632,7 +2697,6 @@ int __init vty_init(void)
2632 if (!console_driver) 2697 if (!console_driver)
2633 panic("Couldn't allocate console driver\n"); 2698 panic("Couldn't allocate console driver\n");
2634 console_driver->owner = THIS_MODULE; 2699 console_driver->owner = THIS_MODULE;
2635 console_driver->devfs_name = "vc/";
2636 console_driver->name = "tty"; 2700 console_driver->name = "tty";
2637 console_driver->name_base = 1; 2701 console_driver->name_base = 1;
2638 console_driver->major = TTY_MAJOR; 2702 console_driver->major = TTY_MAJOR;
@@ -2656,38 +2720,53 @@ int __init vty_init(void)
2656} 2720}
2657 2721
2658#ifndef VT_SINGLE_DRIVER 2722#ifndef VT_SINGLE_DRIVER
2723#include <linux/device.h>
2659 2724
2660/* 2725static struct class *vtconsole_class;
2661 * If we support more console drivers, this function is used
2662 * when a driver wants to take over some existing consoles
2663 * and become default driver for newly opened ones.
2664 */
2665 2726
2666int take_over_console(const struct consw *csw, int first, int last, int deflt) 2727static int bind_con_driver(const struct consw *csw, int first, int last,
2728 int deflt)
2667{ 2729{
2668 int i, j = -1; 2730 struct module *owner = csw->owner;
2669 const char *desc; 2731 const char *desc = NULL;
2670 struct module *owner; 2732 struct con_driver *con_driver;
2733 int i, j = -1, k = -1, retval = -ENODEV;
2671 2734
2672 owner = csw->owner;
2673 if (!try_module_get(owner)) 2735 if (!try_module_get(owner))
2674 return -ENODEV; 2736 return -ENODEV;
2675 2737
2676 acquire_console_sem(); 2738 acquire_console_sem();
2677 2739
2678 desc = csw->con_startup(); 2740 /* check if driver is registered */
2679 if (!desc) { 2741 for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
2680 release_console_sem(); 2742 con_driver = &registered_con_driver[i];
2681 module_put(owner); 2743
2682 return -ENODEV; 2744 if (con_driver->con == csw) {
2745 desc = con_driver->desc;
2746 retval = 0;
2747 break;
2748 }
2749 }
2750
2751 if (retval)
2752 goto err;
2753
2754 if (!(con_driver->flag & CON_DRIVER_FLAG_INIT)) {
2755 csw->con_startup();
2756 con_driver->flag |= CON_DRIVER_FLAG_INIT;
2683 } 2757 }
2758
2684 if (deflt) { 2759 if (deflt) {
2685 if (conswitchp) 2760 if (conswitchp)
2686 module_put(conswitchp->owner); 2761 module_put(conswitchp->owner);
2762
2687 __module_get(owner); 2763 __module_get(owner);
2688 conswitchp = csw; 2764 conswitchp = csw;
2689 } 2765 }
2690 2766
2767 first = max(first, con_driver->first);
2768 last = min(last, con_driver->last);
2769
2691 for (i = first; i <= last; i++) { 2770 for (i = first; i <= last; i++) {
2692 int old_was_color; 2771 int old_was_color;
2693 struct vc_data *vc = vc_cons[i].d; 2772 struct vc_data *vc = vc_cons[i].d;
@@ -2701,15 +2780,17 @@ int take_over_console(const struct consw *csw, int first, int last, int deflt)
2701 continue; 2780 continue;
2702 2781
2703 j = i; 2782 j = i;
2704 if (CON_IS_VISIBLE(vc)) 2783
2784 if (CON_IS_VISIBLE(vc)) {
2785 k = i;
2705 save_screen(vc); 2786 save_screen(vc);
2787 }
2788
2706 old_was_color = vc->vc_can_do_color; 2789 old_was_color = vc->vc_can_do_color;
2707 vc->vc_sw->con_deinit(vc); 2790 vc->vc_sw->con_deinit(vc);
2708 vc->vc_origin = (unsigned long)vc->vc_screenbuf; 2791 vc->vc_origin = (unsigned long)vc->vc_screenbuf;
2709 vc->vc_visible_origin = vc->vc_origin;
2710 vc->vc_scr_end = vc->vc_origin + vc->vc_screenbuf_size;
2711 vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->vc_y + 2 * vc->vc_x;
2712 visual_init(vc, i, 0); 2792 visual_init(vc, i, 0);
2793 set_origin(vc);
2713 update_attr(vc); 2794 update_attr(vc);
2714 2795
2715 /* If the console changed between mono <-> color, then 2796 /* If the console changed between mono <-> color, then
@@ -2718,36 +2799,506 @@ int take_over_console(const struct consw *csw, int first, int last, int deflt)
2718 */ 2799 */
2719 if (old_was_color != vc->vc_can_do_color) 2800 if (old_was_color != vc->vc_can_do_color)
2720 clear_buffer_attributes(vc); 2801 clear_buffer_attributes(vc);
2721
2722 if (CON_IS_VISIBLE(vc))
2723 update_screen(vc);
2724 } 2802 }
2803
2725 printk("Console: switching "); 2804 printk("Console: switching ");
2726 if (!deflt) 2805 if (!deflt)
2727 printk("consoles %d-%d ", first+1, last+1); 2806 printk("consoles %d-%d ", first+1, last+1);
2728 if (j >= 0) 2807 if (j >= 0) {
2808 struct vc_data *vc = vc_cons[j].d;
2809
2729 printk("to %s %s %dx%d\n", 2810 printk("to %s %s %dx%d\n",
2730 vc_cons[j].d->vc_can_do_color ? "colour" : "mono", 2811 vc->vc_can_do_color ? "colour" : "mono",
2731 desc, vc_cons[j].d->vc_cols, vc_cons[j].d->vc_rows); 2812 desc, vc->vc_cols, vc->vc_rows);
2732 else 2813
2814 if (k >= 0) {
2815 vc = vc_cons[k].d;
2816 update_screen(vc);
2817 }
2818 } else
2733 printk("to %s\n", desc); 2819 printk("to %s\n", desc);
2734 2820
2821 retval = 0;
2822err:
2735 release_console_sem(); 2823 release_console_sem();
2824 module_put(owner);
2825 return retval;
2826};
2827
2828#ifdef CONFIG_VT_HW_CONSOLE_BINDING
2829static int con_is_graphics(const struct consw *csw, int first, int last)
2830{
2831 int i, retval = 0;
2832
2833 for (i = first; i <= last; i++) {
2834 struct vc_data *vc = vc_cons[i].d;
2835
2836 if (vc && vc->vc_mode == KD_GRAPHICS) {
2837 retval = 1;
2838 break;
2839 }
2840 }
2736 2841
2842 return retval;
2843}
2844
2845static int unbind_con_driver(const struct consw *csw, int first, int last,
2846 int deflt)
2847{
2848 struct module *owner = csw->owner;
2849 const struct consw *defcsw = NULL;
2850 struct con_driver *con_driver = NULL, *con_back = NULL;
2851 int i, retval = -ENODEV;
2852
2853 if (!try_module_get(owner))
2854 return -ENODEV;
2855
2856 acquire_console_sem();
2857
2858 /* check if driver is registered and if it is unbindable */
2859 for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
2860 con_driver = &registered_con_driver[i];
2861
2862 if (con_driver->con == csw &&
2863 con_driver->flag & CON_DRIVER_FLAG_MODULE) {
2864 retval = 0;
2865 break;
2866 }
2867 }
2868
2869 if (retval) {
2870 release_console_sem();
2871 goto err;
2872 }
2873
2874 retval = -ENODEV;
2875
2876 /* check if backup driver exists */
2877 for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
2878 con_back = &registered_con_driver[i];
2879
2880 if (con_back->con &&
2881 !(con_back->flag & CON_DRIVER_FLAG_MODULE)) {
2882 defcsw = con_back->con;
2883 retval = 0;
2884 break;
2885 }
2886 }
2887
2888 if (retval) {
2889 release_console_sem();
2890 goto err;
2891 }
2892
2893 if (!con_is_bound(csw)) {
2894 release_console_sem();
2895 goto err;
2896 }
2897
2898 first = max(first, con_driver->first);
2899 last = min(last, con_driver->last);
2900
2901 for (i = first; i <= last; i++) {
2902 if (con_driver_map[i] == csw) {
2903 module_put(csw->owner);
2904 con_driver_map[i] = NULL;
2905 }
2906 }
2907
2908 if (!con_is_bound(defcsw)) {
2909 const struct consw *defconsw = conswitchp;
2910
2911 defcsw->con_startup();
2912 con_back->flag |= CON_DRIVER_FLAG_INIT;
2913 /*
2914 * vgacon may change the default driver to point
2915 * to dummycon, we restore it here...
2916 */
2917 conswitchp = defconsw;
2918 }
2919
2920 if (!con_is_bound(csw))
2921 con_driver->flag &= ~CON_DRIVER_FLAG_INIT;
2922
2923 release_console_sem();
2924 /* ignore return value, binding should not fail */
2925 bind_con_driver(defcsw, first, last, deflt);
2926err:
2737 module_put(owner); 2927 module_put(owner);
2928 return retval;
2929
2930}
2931
2932static int vt_bind(struct con_driver *con)
2933{
2934 const struct consw *defcsw = NULL, *csw = NULL;
2935 int i, more = 1, first = -1, last = -1, deflt = 0;
2936
2937 if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
2938 con_is_graphics(con->con, con->first, con->last))
2939 goto err;
2940
2941 csw = con->con;
2942
2943 for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
2944 struct con_driver *con = &registered_con_driver[i];
2945
2946 if (con->con && !(con->flag & CON_DRIVER_FLAG_MODULE)) {
2947 defcsw = con->con;
2948 break;
2949 }
2950 }
2951
2952 if (!defcsw)
2953 goto err;
2954
2955 while (more) {
2956 more = 0;
2957
2958 for (i = con->first; i <= con->last; i++) {
2959 if (con_driver_map[i] == defcsw) {
2960 if (first == -1)
2961 first = i;
2962 last = i;
2963 more = 1;
2964 } else if (first != -1)
2965 break;
2966 }
2967
2968 if (first == 0 && last == MAX_NR_CONSOLES -1)
2969 deflt = 1;
2970
2971 if (first != -1)
2972 bind_con_driver(csw, first, last, deflt);
2973
2974 first = -1;
2975 last = -1;
2976 deflt = 0;
2977 }
2978
2979err:
2738 return 0; 2980 return 0;
2739} 2981}
2740 2982
2741void give_up_console(const struct consw *csw) 2983static int vt_unbind(struct con_driver *con)
2984{
2985 const struct consw *csw = NULL;
2986 int i, more = 1, first = -1, last = -1, deflt = 0;
2987
2988 if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
2989 con_is_graphics(con->con, con->first, con->last))
2990 goto err;
2991
2992 csw = con->con;
2993
2994 while (more) {
2995 more = 0;
2996
2997 for (i = con->first; i <= con->last; i++) {
2998 if (con_driver_map[i] == csw) {
2999 if (first == -1)
3000 first = i;
3001 last = i;
3002 more = 1;
3003 } else if (first != -1)
3004 break;
3005 }
3006
3007 if (first == 0 && last == MAX_NR_CONSOLES -1)
3008 deflt = 1;
3009
3010 if (first != -1)
3011 unbind_con_driver(csw, first, last, deflt);
3012
3013 first = -1;
3014 last = -1;
3015 deflt = 0;
3016 }
3017
3018err:
3019 return 0;
3020}
3021#else
3022static inline int vt_bind(struct con_driver *con)
3023{
3024 return 0;
3025}
3026static inline int vt_unbind(struct con_driver *con)
3027{
3028 return 0;
3029}
3030#endif /* CONFIG_VT_HW_CONSOLE_BINDING */
3031
3032static ssize_t store_bind(struct class_device *class_device,
3033 const char *buf, size_t count)
3034{
3035 struct con_driver *con = class_get_devdata(class_device);
3036 int bind = simple_strtoul(buf, NULL, 0);
3037
3038 if (bind)
3039 vt_bind(con);
3040 else
3041 vt_unbind(con);
3042
3043 return count;
3044}
3045
3046static ssize_t show_bind(struct class_device *class_device, char *buf)
3047{
3048 struct con_driver *con = class_get_devdata(class_device);
3049 int bind = con_is_bound(con->con);
3050
3051 return snprintf(buf, PAGE_SIZE, "%i\n", bind);
3052}
3053
3054static ssize_t show_name(struct class_device *class_device, char *buf)
3055{
3056 struct con_driver *con = class_get_devdata(class_device);
3057
3058 return snprintf(buf, PAGE_SIZE, "%s %s\n",
3059 (con->flag & CON_DRIVER_FLAG_MODULE) ? "(M)" : "(S)",
3060 con->desc);
3061
3062}
3063
3064static struct class_device_attribute class_device_attrs[] = {
3065 __ATTR(bind, S_IRUGO|S_IWUSR, show_bind, store_bind),
3066 __ATTR(name, S_IRUGO, show_name, NULL),
3067};
3068
3069static int vtconsole_init_class_device(struct con_driver *con)
2742{ 3070{
2743 int i; 3071 int i;
2744 3072
2745 for(i = 0; i < MAX_NR_CONSOLES; i++) 3073 class_set_devdata(con->class_dev, con);
3074 for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
3075 class_device_create_file(con->class_dev,
3076 &class_device_attrs[i]);
3077
3078 return 0;
3079}
3080
3081static void vtconsole_deinit_class_device(struct con_driver *con)
3082{
3083 int i;
3084
3085 for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
3086 class_device_remove_file(con->class_dev,
3087 &class_device_attrs[i]);
3088}
3089
3090/**
3091 * con_is_bound - checks if driver is bound to the console
3092 * @csw: console driver
3093 *
3094 * RETURNS: zero if unbound, nonzero if bound
3095 *
3096 * Drivers can call this and if zero, they should release
3097 * all resources allocated on con_startup()
3098 */
3099int con_is_bound(const struct consw *csw)
3100{
3101 int i, bound = 0;
3102
3103 for (i = 0; i < MAX_NR_CONSOLES; i++) {
2746 if (con_driver_map[i] == csw) { 3104 if (con_driver_map[i] == csw) {
2747 module_put(csw->owner); 3105 bound = 1;
2748 con_driver_map[i] = NULL; 3106 break;
3107 }
3108 }
3109
3110 return bound;
3111}
3112EXPORT_SYMBOL(con_is_bound);
3113
3114/**
3115 * register_con_driver - register console driver to console layer
3116 * @csw: console driver
3117 * @first: the first console to take over, minimum value is 0
3118 * @last: the last console to take over, maximum value is MAX_NR_CONSOLES -1
3119 *
3120 * DESCRIPTION: This function registers a console driver which can later
3121 * bind to a range of consoles specified by @first and @last. It will
3122 * also initialize the console driver by calling con_startup().
3123 */
3124int register_con_driver(const struct consw *csw, int first, int last)
3125{
3126 struct module *owner = csw->owner;
3127 struct con_driver *con_driver;
3128 const char *desc;
3129 int i, retval = 0;
3130
3131 if (!try_module_get(owner))
3132 return -ENODEV;
3133
3134 acquire_console_sem();
3135
3136 for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
3137 con_driver = &registered_con_driver[i];
3138
3139 /* already registered */
3140 if (con_driver->con == csw)
3141 retval = -EINVAL;
3142 }
3143
3144 if (retval)
3145 goto err;
3146
3147 desc = csw->con_startup();
3148
3149 if (!desc)
3150 goto err;
3151
3152 retval = -EINVAL;
3153
3154 for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
3155 con_driver = &registered_con_driver[i];
3156
3157 if (con_driver->con == NULL) {
3158 con_driver->con = csw;
3159 con_driver->desc = desc;
3160 con_driver->node = i;
3161 con_driver->flag = CON_DRIVER_FLAG_MODULE |
3162 CON_DRIVER_FLAG_INIT;
3163 con_driver->first = first;
3164 con_driver->last = last;
3165 retval = 0;
3166 break;
2749 } 3167 }
3168 }
3169
3170 if (retval)
3171 goto err;
3172
3173 con_driver->class_dev = class_device_create(vtconsole_class, NULL,
3174 MKDEV(0, con_driver->node),
3175 NULL, "vtcon%i",
3176 con_driver->node);
3177
3178 if (IS_ERR(con_driver->class_dev)) {
3179 printk(KERN_WARNING "Unable to create class_device for %s; "
3180 "errno = %ld\n", con_driver->desc,
3181 PTR_ERR(con_driver->class_dev));
3182 con_driver->class_dev = NULL;
3183 } else {
3184 vtconsole_init_class_device(con_driver);
3185 }
3186err:
3187 release_console_sem();
3188 module_put(owner);
3189 return retval;
3190}
3191EXPORT_SYMBOL(register_con_driver);
3192
3193/**
3194 * unregister_con_driver - unregister console driver from console layer
3195 * @csw: console driver
3196 *
3197 * DESCRIPTION: All drivers that registers to the console layer must
3198 * call this function upon exit, or if the console driver is in a state
3199 * where it won't be able to handle console services, such as the
3200 * framebuffer console without loaded framebuffer drivers.
3201 *
3202 * The driver must unbind first prior to unregistration.
3203 */
3204int unregister_con_driver(const struct consw *csw)
3205{
3206 int i, retval = -ENODEV;
3207
3208 acquire_console_sem();
3209
3210 /* cannot unregister a bound driver */
3211 if (con_is_bound(csw))
3212 goto err;
3213
3214 for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
3215 struct con_driver *con_driver = &registered_con_driver[i];
3216
3217 if (con_driver->con == csw &&
3218 con_driver->flag & CON_DRIVER_FLAG_MODULE) {
3219 vtconsole_deinit_class_device(con_driver);
3220 class_device_destroy(vtconsole_class,
3221 MKDEV(0, con_driver->node));
3222 con_driver->con = NULL;
3223 con_driver->desc = NULL;
3224 con_driver->class_dev = NULL;
3225 con_driver->node = 0;
3226 con_driver->flag = 0;
3227 con_driver->first = 0;
3228 con_driver->last = 0;
3229 retval = 0;
3230 break;
3231 }
3232 }
3233err:
3234 release_console_sem();
3235 return retval;
3236}
3237EXPORT_SYMBOL(unregister_con_driver);
3238
3239/*
3240 * If we support more console drivers, this function is used
3241 * when a driver wants to take over some existing consoles
3242 * and become default driver for newly opened ones.
3243 *
3244 * take_over_console is basically a register followed by unbind
3245 */
3246int take_over_console(const struct consw *csw, int first, int last, int deflt)
3247{
3248 int err;
3249
3250 err = register_con_driver(csw, first, last);
3251
3252 if (!err)
3253 bind_con_driver(csw, first, last, deflt);
3254
3255 return err;
3256}
3257
3258/*
3259 * give_up_console is a wrapper to unregister_con_driver. It will only
3260 * work if driver is fully unbound.
3261 */
3262void give_up_console(const struct consw *csw)
3263{
3264 unregister_con_driver(csw);
3265}
3266
3267static int __init vtconsole_class_init(void)
3268{
3269 int i;
3270
3271 vtconsole_class = class_create(THIS_MODULE, "vtconsole");
3272 if (IS_ERR(vtconsole_class)) {
3273 printk(KERN_WARNING "Unable to create vt console class; "
3274 "errno = %ld\n", PTR_ERR(vtconsole_class));
3275 vtconsole_class = NULL;
3276 }
3277
3278 /* Add system drivers to sysfs */
3279 for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
3280 struct con_driver *con = &registered_con_driver[i];
3281
3282 if (con->con && !con->class_dev) {
3283 con->class_dev =
3284 class_device_create(vtconsole_class, NULL,
3285 MKDEV(0, con->node), NULL,
3286 "vtcon%i", con->node);
3287
3288 if (IS_ERR(con->class_dev)) {
3289 printk(KERN_WARNING "Unable to create "
3290 "class_device for %s; errno = %ld\n",
3291 con->desc, PTR_ERR(con->class_dev));
3292 con->class_dev = NULL;
3293 } else {
3294 vtconsole_init_class_device(con);
3295 }
3296 }
3297 }
3298
3299 return 0;
2750} 3300}
3301postcore_initcall(vtconsole_class_init);
2751 3302
2752#endif 3303#endif
2753 3304
@@ -3249,6 +3800,7 @@ EXPORT_SYMBOL(default_blu);
3249EXPORT_SYMBOL(update_region); 3800EXPORT_SYMBOL(update_region);
3250EXPORT_SYMBOL(redraw_screen); 3801EXPORT_SYMBOL(redraw_screen);
3251EXPORT_SYMBOL(vc_resize); 3802EXPORT_SYMBOL(vc_resize);
3803EXPORT_SYMBOL(vc_lock_resize);
3252EXPORT_SYMBOL(fg_console); 3804EXPORT_SYMBOL(fg_console);
3253EXPORT_SYMBOL(console_blank_hook); 3805EXPORT_SYMBOL(console_blank_hook);
3254EXPORT_SYMBOL(console_blanked); 3806EXPORT_SYMBOL(console_blanked);