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.c379
1 files changed, 232 insertions, 147 deletions
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index d788a0eaf26a..037d8a3f5882 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -100,12 +100,14 @@
100 100
101#define MAX_NR_CON_DRIVER 16 101#define MAX_NR_CON_DRIVER 16
102 102
103#define CON_DRIVER_FLAG_BIND 1 103#define CON_DRIVER_FLAG_MODULE 1
104#define CON_DRIVER_FLAG_INIT 2 104#define CON_DRIVER_FLAG_INIT 2
105 105
106struct con_driver { 106struct con_driver {
107 const struct consw *con; 107 const struct consw *con;
108 const char *desc; 108 const char *desc;
109 struct class_device *class_dev;
110 int node;
109 int first; 111 int first;
110 int last; 112 int last;
111 int flag; 113 int flag;
@@ -2685,6 +2687,25 @@ int __init vty_init(void)
2685} 2687}
2686 2688
2687#ifndef VT_SINGLE_DRIVER 2689#ifndef VT_SINGLE_DRIVER
2690#include <linux/device.h>
2691
2692static struct class *vtconsole_class;
2693
2694static int con_is_graphics(const struct consw *csw, int first, int last)
2695{
2696 int i, retval = 0;
2697
2698 for (i = first; i <= last; i++) {
2699 struct vc_data *vc = vc_cons[i].d;
2700
2701 if (vc && vc->vc_mode == KD_GRAPHICS) {
2702 retval = 1;
2703 break;
2704 }
2705 }
2706
2707 return retval;
2708}
2688 2709
2689static int bind_con_driver(const struct consw *csw, int first, int last, 2710static int bind_con_driver(const struct consw *csw, int first, int last,
2690 int deflt) 2711 int deflt)
@@ -2805,7 +2826,7 @@ static int unbind_con_driver(const struct consw *csw, int first, int last,
2805 con_driver = &registered_con_driver[i]; 2826 con_driver = &registered_con_driver[i];
2806 2827
2807 if (con_driver->con == csw && 2828 if (con_driver->con == csw &&
2808 con_driver->flag & CON_DRIVER_FLAG_BIND) { 2829 con_driver->flag & CON_DRIVER_FLAG_MODULE) {
2809 retval = 0; 2830 retval = 0;
2810 break; 2831 break;
2811 } 2832 }
@@ -2816,12 +2837,14 @@ static int unbind_con_driver(const struct consw *csw, int first, int last,
2816 goto err; 2837 goto err;
2817 } 2838 }
2818 2839
2840 retval = -ENODEV;
2841
2819 /* check if backup driver exists */ 2842 /* check if backup driver exists */
2820 for (i = 0; i < MAX_NR_CON_DRIVER; i++) { 2843 for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
2821 con_back = &registered_con_driver[i]; 2844 con_back = &registered_con_driver[i];
2822 2845
2823 if (con_back->con && 2846 if (con_back->con &&
2824 !(con_back->flag & CON_DRIVER_FLAG_BIND)) { 2847 !(con_back->flag & CON_DRIVER_FLAG_MODULE)) {
2825 defcsw = con_back->con; 2848 defcsw = con_back->con;
2826 retval = 0; 2849 retval = 0;
2827 break; 2850 break;
@@ -2849,21 +2872,177 @@ static int unbind_con_driver(const struct consw *csw, int first, int last,
2849 } 2872 }
2850 2873
2851 if (!con_is_bound(defcsw)) { 2874 if (!con_is_bound(defcsw)) {
2875 const struct consw *defconsw = conswitchp;
2876
2852 defcsw->con_startup(); 2877 defcsw->con_startup();
2853 con_back->flag |= CON_DRIVER_FLAG_INIT; 2878 con_back->flag |= CON_DRIVER_FLAG_INIT;
2879 /*
2880 * vgacon may change the default driver to point
2881 * to dummycon, we restore it here...
2882 */
2883 conswitchp = defconsw;
2854 } 2884 }
2855 2885
2856 if (!con_is_bound(csw)) 2886 if (!con_is_bound(csw))
2857 con_driver->flag &= ~CON_DRIVER_FLAG_INIT; 2887 con_driver->flag &= ~CON_DRIVER_FLAG_INIT;
2858 2888
2859 release_console_sem(); 2889 release_console_sem();
2860 retval = bind_con_driver(defcsw, first, last, deflt); 2890 /* ignore return value, binding should not fail */
2891 bind_con_driver(defcsw, first, last, deflt);
2861err: 2892err:
2862 module_put(owner); 2893 module_put(owner);
2863 return retval; 2894 return retval;
2864 2895
2865} 2896}
2866 2897
2898static int vt_bind(struct con_driver *con)
2899{
2900 const struct consw *defcsw = NULL, *csw = NULL;
2901 int i, more = 1, first = -1, last = -1, deflt = 0;
2902
2903 if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
2904 con_is_graphics(con->con, con->first, con->last))
2905 goto err;
2906
2907 csw = con->con;
2908
2909 for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
2910 struct con_driver *con = &registered_con_driver[i];
2911
2912 if (con->con && !(con->flag & CON_DRIVER_FLAG_MODULE)) {
2913 defcsw = con->con;
2914 break;
2915 }
2916 }
2917
2918 if (!defcsw)
2919 goto err;
2920
2921 while (more) {
2922 more = 0;
2923
2924 for (i = con->first; i <= con->last; i++) {
2925 if (con_driver_map[i] == defcsw) {
2926 if (first == -1)
2927 first = i;
2928 last = i;
2929 more = 1;
2930 } else if (first != -1)
2931 break;
2932 }
2933
2934 if (first == 0 && last == MAX_NR_CONSOLES -1)
2935 deflt = 1;
2936
2937 if (first != -1)
2938 bind_con_driver(csw, first, last, deflt);
2939
2940 first = -1;
2941 last = -1;
2942 deflt = 0;
2943 }
2944
2945err:
2946 return 0;
2947}
2948
2949static int vt_unbind(struct con_driver *con)
2950{
2951 const struct consw *csw = NULL;
2952 int i, more = 1, first = -1, last = -1, deflt = 0;
2953
2954 if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
2955 con_is_graphics(con->con, con->first, con->last))
2956 goto err;
2957
2958 csw = con->con;
2959
2960 while (more) {
2961 more = 0;
2962
2963 for (i = con->first; i <= con->last; i++) {
2964 if (con_driver_map[i] == csw) {
2965 if (first == -1)
2966 first = i;
2967 last = i;
2968 more = 1;
2969 } else if (first != -1)
2970 break;
2971 }
2972
2973 if (first == 0 && last == MAX_NR_CONSOLES -1)
2974 deflt = 1;
2975
2976 if (first != -1)
2977 unbind_con_driver(csw, first, last, deflt);
2978
2979 first = -1;
2980 last = -1;
2981 deflt = 0;
2982 }
2983
2984err:
2985 return 0;
2986}
2987
2988static ssize_t store_bind(struct class_device *class_device,
2989 const char *buf, size_t count)
2990{
2991 struct con_driver *con = class_get_devdata(class_device);
2992 int bind = simple_strtoul(buf, NULL, 0);
2993
2994 if (bind)
2995 vt_bind(con);
2996 else
2997 vt_unbind(con);
2998
2999 return count;
3000}
3001
3002static ssize_t show_bind(struct class_device *class_device, char *buf)
3003{
3004 struct con_driver *con = class_get_devdata(class_device);
3005 int bind = con_is_bound(con->con);
3006
3007 return snprintf(buf, PAGE_SIZE, "%i\n", bind);
3008}
3009
3010static ssize_t show_name(struct class_device *class_device, char *buf)
3011{
3012 struct con_driver *con = class_get_devdata(class_device);
3013
3014 return snprintf(buf, PAGE_SIZE, "%s %s\n",
3015 (con->flag & CON_DRIVER_FLAG_MODULE) ? "(M)" : "(S)",
3016 con->desc);
3017
3018}
3019
3020static struct class_device_attribute class_device_attrs[] = {
3021 __ATTR(bind, S_IRUGO|S_IWUSR, show_bind, store_bind),
3022 __ATTR(name, S_IRUGO, show_name, NULL),
3023};
3024
3025static int vtconsole_init_class_device(struct con_driver *con)
3026{
3027 int i;
3028
3029 class_set_devdata(con->class_dev, con);
3030 for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
3031 class_device_create_file(con->class_dev,
3032 &class_device_attrs[i]);
3033
3034 return 0;
3035}
3036
3037static void vtconsole_deinit_class_device(struct con_driver *con)
3038{
3039 int i;
3040
3041 for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
3042 class_device_remove_file(con->class_dev,
3043 &class_device_attrs[i]);
3044}
3045
2867/** 3046/**
2868 * con_is_bound - checks if driver is bound to the console 3047 * con_is_bound - checks if driver is bound to the console
2869 * @csw: console driver 3048 * @csw: console driver
@@ -2934,7 +3113,8 @@ int register_con_driver(const struct consw *csw, int first, int last)
2934 if (con_driver->con == NULL) { 3113 if (con_driver->con == NULL) {
2935 con_driver->con = csw; 3114 con_driver->con = csw;
2936 con_driver->desc = desc; 3115 con_driver->desc = desc;
2937 con_driver->flag = CON_DRIVER_FLAG_BIND | 3116 con_driver->node = i;
3117 con_driver->flag = CON_DRIVER_FLAG_MODULE |
2938 CON_DRIVER_FLAG_INIT; 3118 CON_DRIVER_FLAG_INIT;
2939 con_driver->first = first; 3119 con_driver->first = first;
2940 con_driver->last = last; 3120 con_driver->last = last;
@@ -2943,6 +3123,22 @@ int register_con_driver(const struct consw *csw, int first, int last)
2943 } 3123 }
2944 } 3124 }
2945 3125
3126 if (retval)
3127 goto err;
3128
3129 con_driver->class_dev = class_device_create(vtconsole_class, NULL,
3130 MKDEV(0, con_driver->node),
3131 NULL, "vtcon%i",
3132 con_driver->node);
3133
3134 if (IS_ERR(con_driver->class_dev)) {
3135 printk(KERN_WARNING "Unable to create class_device for %s; "
3136 "errno = %ld\n", con_driver->desc,
3137 PTR_ERR(con_driver->class_dev));
3138 con_driver->class_dev = NULL;
3139 } else {
3140 vtconsole_init_class_device(con_driver);
3141 }
2946err: 3142err:
2947 release_console_sem(); 3143 release_console_sem();
2948 module_put(owner); 3144 module_put(owner);
@@ -2975,9 +3171,14 @@ int unregister_con_driver(const struct consw *csw)
2975 struct con_driver *con_driver = &registered_con_driver[i]; 3171 struct con_driver *con_driver = &registered_con_driver[i];
2976 3172
2977 if (con_driver->con == csw && 3173 if (con_driver->con == csw &&
2978 con_driver->flag & CON_DRIVER_FLAG_BIND) { 3174 con_driver->flag & CON_DRIVER_FLAG_MODULE) {
3175 vtconsole_deinit_class_device(con_driver);
3176 class_device_destroy(vtconsole_class,
3177 MKDEV(0, con_driver->node));
2979 con_driver->con = NULL; 3178 con_driver->con = NULL;
2980 con_driver->desc = NULL; 3179 con_driver->desc = NULL;
3180 con_driver->class_dev = NULL;
3181 con_driver->node = 0;
2981 con_driver->flag = 0; 3182 con_driver->flag = 0;
2982 con_driver->first = 0; 3183 con_driver->first = 0;
2983 con_driver->last = 0; 3184 con_driver->last = 0;
@@ -2985,7 +3186,6 @@ int unregister_con_driver(const struct consw *csw)
2985 break; 3186 break;
2986 } 3187 }
2987 } 3188 }
2988
2989err: 3189err:
2990 release_console_sem(); 3190 release_console_sem();
2991 return retval; 3191 return retval;
@@ -3006,7 +3206,7 @@ int take_over_console(const struct consw *csw, int first, int last, int deflt)
3006 err = register_con_driver(csw, first, last); 3206 err = register_con_driver(csw, first, last);
3007 3207
3008 if (!err) 3208 if (!err)
3009 err = bind_con_driver(csw, first, last, deflt); 3209 bind_con_driver(csw, first, last, deflt);
3010 3210
3011 return err; 3211 return err;
3012} 3212}
@@ -3020,160 +3220,45 @@ void give_up_console(const struct consw *csw)
3020 unregister_con_driver(csw); 3220 unregister_con_driver(csw);
3021} 3221}
3022 3222
3023/* 3223static int __init vtconsole_class_init(void)
3024 * this function is intended to be called by the tty layer only
3025 */
3026int vt_bind(int index)
3027{ 3224{
3028 const struct consw *defcsw = NULL, *csw = NULL; 3225 int i;
3029 struct con_driver *con;
3030 int i, more = 1, first = -1, last = -1, deflt = 0;
3031
3032 if (index >= MAX_NR_CON_DRIVER)
3033 goto err;
3034
3035 con = &registered_con_driver[index];
3036
3037 if (!con->con || !(con->flag & CON_DRIVER_FLAG_BIND))
3038 goto err;
3039 3226
3040 csw = con->con; 3227 vtconsole_class = class_create(THIS_MODULE, "vtconsole");
3228 if (IS_ERR(vtconsole_class)) {
3229 printk(KERN_WARNING "Unable to create vt console class; "
3230 "errno = %ld\n", PTR_ERR(vtconsole_class));
3231 vtconsole_class = NULL;
3232 }
3041 3233
3234 /* Add system drivers to sysfs */
3042 for (i = 0; i < MAX_NR_CON_DRIVER; i++) { 3235 for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
3043 struct con_driver *con = &registered_con_driver[i]; 3236 struct con_driver *con = &registered_con_driver[i];
3044 3237
3045 if (con->con && !(con->flag & CON_DRIVER_FLAG_BIND)) { 3238 if (con->con && !con->class_dev) {
3046 defcsw = con->con; 3239 con->class_dev =
3047 break; 3240 class_device_create(vtconsole_class, NULL,
3048 } 3241 MKDEV(0, con->node), NULL,
3049 } 3242 "vtcon%i", con->node);
3050 3243
3051 if (!defcsw) 3244 if (IS_ERR(con->class_dev)) {
3052 goto err; 3245 printk(KERN_WARNING "Unable to create "
3053 3246 "class_device for %s; errno = %ld\n",
3054 while (more) { 3247 con->desc, PTR_ERR(con->class_dev));
3055 more = 0; 3248 con->class_dev = NULL;
3056 3249 } else {
3057 for (i = con->first; i <= con->last; i++) { 3250 vtconsole_init_class_device(con);
3058 if (con_driver_map[i] == defcsw) { 3251 }
3059 if (first == -1)
3060 first = i;
3061 last = i;
3062 more = 1;
3063 } else if (first != -1)
3064 break;
3065 }
3066
3067 if (first == 0 && last == MAX_NR_CONSOLES -1)
3068 deflt = 1;
3069
3070 if (first != -1)
3071 bind_con_driver(csw, first, last, deflt);
3072
3073 first = -1;
3074 last = -1;
3075 deflt = 0;
3076 }
3077
3078err:
3079 return 0;
3080}
3081
3082/*
3083 * this function is intended to be called by the tty layer only
3084 */
3085int vt_unbind(int index)
3086{
3087 const struct consw *csw = NULL;
3088 struct con_driver *con;
3089 int i, more = 1, first = -1, last = -1, deflt = 0;
3090
3091 if (index >= MAX_NR_CON_DRIVER)
3092 goto err;
3093
3094 con = &registered_con_driver[index];
3095
3096 if (!con->con || !(con->flag & CON_DRIVER_FLAG_BIND))
3097 goto err;
3098
3099 csw = con->con;
3100
3101 while (more) {
3102 more = 0;
3103
3104 for (i = con->first; i <= con->last; i++) {
3105 if (con_driver_map[i] == csw) {
3106 if (first == -1)
3107 first = i;
3108 last = i;
3109 more = 1;
3110 } else if (first != -1)
3111 break;
3112 } 3252 }
3113
3114 if (first == 0 && last == MAX_NR_CONSOLES -1)
3115 deflt = 1;
3116
3117 if (first != -1)
3118 unbind_con_driver(csw, first, last, deflt);
3119
3120 first = -1;
3121 last = -1;
3122 deflt = 0;
3123 } 3253 }
3124 3254
3125err:
3126 return 0;
3127}
3128#else
3129int vt_bind(int index)
3130{
3131 return 0; 3255 return 0;
3132} 3256}
3257postcore_initcall(vtconsole_class_init);
3133 3258
3134int vt_unbind(int index)
3135{
3136 return 0;
3137}
3138#endif 3259#endif
3139 3260
3140/* 3261/*
3141 * this function is intended to be called by the tty layer only
3142 */
3143int vt_show_drivers(char *buf)
3144{
3145 int i, j, read, offset = 0, cnt = PAGE_SIZE;
3146
3147 for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
3148 struct con_driver *con_driver = &registered_con_driver[i];
3149
3150 if (con_driver->con != NULL) {
3151 int sys = 0;
3152
3153 if (con_driver->flag & CON_DRIVER_FLAG_BIND) {
3154 sys = 2;
3155
3156 for (j = 0; j < MAX_NR_CONSOLES; j++) {
3157 if (con_driver_map[j] ==
3158 con_driver->con) {
3159 sys = 1;
3160 break;
3161 }
3162 }
3163 }
3164
3165 read = snprintf(buf + offset, cnt, "%i %s: %s\n",
3166 i, (sys) ? ((sys == 1) ? "B" : "U") :
3167 "S", con_driver->desc);
3168 offset += read;
3169 cnt -= read;
3170 }
3171 }
3172
3173 return offset;
3174}
3175
3176/*
3177 * Screen blanking 3262 * Screen blanking
3178 */ 3263 */
3179 3264