diff options
Diffstat (limited to 'drivers/video/console/fbcon.c')
-rw-r--r-- | drivers/video/console/fbcon.c | 204 |
1 files changed, 144 insertions, 60 deletions
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 4b7be685c160..26effab5a13e 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c | |||
@@ -125,6 +125,8 @@ static int softback_lines; | |||
125 | static int first_fb_vc; | 125 | static int first_fb_vc; |
126 | static int last_fb_vc = MAX_NR_CONSOLES - 1; | 126 | static int last_fb_vc = MAX_NR_CONSOLES - 1; |
127 | static int fbcon_is_default = 1; | 127 | static int fbcon_is_default = 1; |
128 | static int fbcon_has_exited; | ||
129 | |||
128 | /* font data */ | 130 | /* font data */ |
129 | static char fontname[40]; | 131 | static char fontname[40]; |
130 | 132 | ||
@@ -140,7 +142,6 @@ static const struct consw fb_con; | |||
140 | 142 | ||
141 | #define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row) | 143 | #define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row) |
142 | 144 | ||
143 | static void fbcon_free_font(struct display *); | ||
144 | static int fbcon_set_origin(struct vc_data *); | 145 | static int fbcon_set_origin(struct vc_data *); |
145 | 146 | ||
146 | #define CURSOR_DRAW_DELAY (1) | 147 | #define CURSOR_DRAW_DELAY (1) |
@@ -255,7 +256,7 @@ static void fbcon_rotate_all(struct fb_info *info, u32 rotate) | |||
255 | if (!ops || ops->currcon < 0 || rotate > 3) | 256 | if (!ops || ops->currcon < 0 || rotate > 3) |
256 | return; | 257 | return; |
257 | 258 | ||
258 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 259 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
259 | vc = vc_cons[i].d; | 260 | vc = vc_cons[i].d; |
260 | if (!vc || vc->vc_mode != KD_TEXT || | 261 | if (!vc || vc->vc_mode != KD_TEXT || |
261 | registered_fb[con2fb_map[i]] != info) | 262 | registered_fb[con2fb_map[i]] != info) |
@@ -534,7 +535,7 @@ static int search_fb_in_map(int idx) | |||
534 | { | 535 | { |
535 | int i, retval = 0; | 536 | int i, retval = 0; |
536 | 537 | ||
537 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 538 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
538 | if (con2fb_map[i] == idx) | 539 | if (con2fb_map[i] == idx) |
539 | retval = 1; | 540 | retval = 1; |
540 | } | 541 | } |
@@ -545,7 +546,7 @@ static int search_for_mapped_con(void) | |||
545 | { | 546 | { |
546 | int i, retval = 0; | 547 | int i, retval = 0; |
547 | 548 | ||
548 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 549 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
549 | if (con2fb_map[i] != -1) | 550 | if (con2fb_map[i] != -1) |
550 | retval = 1; | 551 | retval = 1; |
551 | } | 552 | } |
@@ -567,6 +568,7 @@ static int fbcon_takeover(int show_logo) | |||
567 | 568 | ||
568 | err = take_over_console(&fb_con, first_fb_vc, last_fb_vc, | 569 | err = take_over_console(&fb_con, first_fb_vc, last_fb_vc, |
569 | fbcon_is_default); | 570 | fbcon_is_default); |
571 | |||
570 | if (err) { | 572 | if (err) { |
571 | for (i = first_fb_vc; i <= last_fb_vc; i++) { | 573 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
572 | con2fb_map[i] = -1; | 574 | con2fb_map[i] = -1; |
@@ -801,8 +803,8 @@ static int set_con2fb_map(int unit, int newidx, int user) | |||
801 | if (oldidx == newidx) | 803 | if (oldidx == newidx) |
802 | return 0; | 804 | return 0; |
803 | 805 | ||
804 | if (!info) | 806 | if (!info || fbcon_has_exited) |
805 | err = -EINVAL; | 807 | return -EINVAL; |
806 | 808 | ||
807 | if (!err && !search_for_mapped_con()) { | 809 | if (!err && !search_for_mapped_con()) { |
808 | info_idx = newidx; | 810 | info_idx = newidx; |
@@ -838,6 +840,9 @@ static int set_con2fb_map(int unit, int newidx, int user) | |||
838 | con2fb_init_display(vc, info, unit, show_logo); | 840 | con2fb_init_display(vc, info, unit, show_logo); |
839 | } | 841 | } |
840 | 842 | ||
843 | if (!search_fb_in_map(info_idx)) | ||
844 | info_idx = newidx; | ||
845 | |||
841 | release_console_sem(); | 846 | release_console_sem(); |
842 | return err; | 847 | return err; |
843 | } | 848 | } |
@@ -1040,6 +1045,7 @@ static const char *fbcon_startup(void) | |||
1040 | #endif /* CONFIG_MAC */ | 1045 | #endif /* CONFIG_MAC */ |
1041 | 1046 | ||
1042 | fbcon_add_cursor_timer(info); | 1047 | fbcon_add_cursor_timer(info); |
1048 | fbcon_has_exited = 0; | ||
1043 | return display_desc; | 1049 | return display_desc; |
1044 | } | 1050 | } |
1045 | 1051 | ||
@@ -1067,17 +1073,36 @@ static void fbcon_init(struct vc_data *vc, int init) | |||
1067 | 1073 | ||
1068 | /* If we are not the first console on this | 1074 | /* If we are not the first console on this |
1069 | fb, copy the font from that console */ | 1075 | fb, copy the font from that console */ |
1070 | t = &fb_display[svc->vc_num]; | 1076 | t = &fb_display[fg_console]; |
1071 | if (!vc->vc_font.data) { | 1077 | if (!p->fontdata) { |
1072 | vc->vc_font.data = (void *)(p->fontdata = t->fontdata); | 1078 | if (t->fontdata) { |
1073 | vc->vc_font.width = (*default_mode)->vc_font.width; | 1079 | struct vc_data *fvc = vc_cons[fg_console].d; |
1074 | vc->vc_font.height = (*default_mode)->vc_font.height; | 1080 | |
1075 | p->userfont = t->userfont; | 1081 | vc->vc_font.data = (void *)(p->fontdata = |
1076 | if (p->userfont) | 1082 | fvc->vc_font.data); |
1077 | REFCOUNT(p->fontdata)++; | 1083 | vc->vc_font.width = fvc->vc_font.width; |
1084 | vc->vc_font.height = fvc->vc_font.height; | ||
1085 | p->userfont = t->userfont; | ||
1086 | |||
1087 | if (p->userfont) | ||
1088 | REFCOUNT(p->fontdata)++; | ||
1089 | } else { | ||
1090 | const struct font_desc *font = NULL; | ||
1091 | |||
1092 | if (!fontname[0] || !(font = find_font(fontname))) | ||
1093 | font = get_default_font(info->var.xres, | ||
1094 | info->var.yres); | ||
1095 | vc->vc_font.width = font->width; | ||
1096 | vc->vc_font.height = font->height; | ||
1097 | vc->vc_font.data = (void *)(p->fontdata = font->data); | ||
1098 | vc->vc_font.charcount = 256; /* FIXME Need to | ||
1099 | support more fonts */ | ||
1100 | } | ||
1078 | } | 1101 | } |
1102 | |||
1079 | if (p->userfont) | 1103 | if (p->userfont) |
1080 | charcnt = FNTCHARCNT(p->fontdata); | 1104 | charcnt = FNTCHARCNT(p->fontdata); |
1105 | |||
1081 | vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1); | 1106 | vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1); |
1082 | vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; | 1107 | vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; |
1083 | if (charcnt == 256) { | 1108 | if (charcnt == 256) { |
@@ -1151,13 +1176,47 @@ static void fbcon_init(struct vc_data *vc, int init) | |||
1151 | ops->p = &fb_display[fg_console]; | 1176 | ops->p = &fb_display[fg_console]; |
1152 | } | 1177 | } |
1153 | 1178 | ||
1179 | static void fbcon_free_font(struct display *p) | ||
1180 | { | ||
1181 | if (p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0)) | ||
1182 | kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int)); | ||
1183 | p->fontdata = NULL; | ||
1184 | p->userfont = 0; | ||
1185 | } | ||
1186 | |||
1154 | static void fbcon_deinit(struct vc_data *vc) | 1187 | static void fbcon_deinit(struct vc_data *vc) |
1155 | { | 1188 | { |
1156 | struct display *p = &fb_display[vc->vc_num]; | 1189 | struct display *p = &fb_display[vc->vc_num]; |
1190 | struct fb_info *info; | ||
1191 | struct fbcon_ops *ops; | ||
1192 | int idx; | ||
1157 | 1193 | ||
1158 | if (info_idx != -1) | ||
1159 | return; | ||
1160 | fbcon_free_font(p); | 1194 | fbcon_free_font(p); |
1195 | idx = con2fb_map[vc->vc_num]; | ||
1196 | |||
1197 | if (idx == -1) | ||
1198 | goto finished; | ||
1199 | |||
1200 | info = registered_fb[idx]; | ||
1201 | |||
1202 | if (!info) | ||
1203 | goto finished; | ||
1204 | |||
1205 | ops = info->fbcon_par; | ||
1206 | |||
1207 | if (!ops) | ||
1208 | goto finished; | ||
1209 | |||
1210 | if (CON_IS_VISIBLE(vc)) | ||
1211 | fbcon_del_cursor_timer(info); | ||
1212 | |||
1213 | ops->flags &= ~FBCON_FLAGS_INIT; | ||
1214 | finished: | ||
1215 | |||
1216 | if (!con_is_bound(&fb_con)) | ||
1217 | fbcon_exit(); | ||
1218 | |||
1219 | return; | ||
1161 | } | 1220 | } |
1162 | 1221 | ||
1163 | /* ====================================================================== */ | 1222 | /* ====================================================================== */ |
@@ -2227,14 +2286,6 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) | |||
2227 | return 0; | 2286 | return 0; |
2228 | } | 2287 | } |
2229 | 2288 | ||
2230 | static void fbcon_free_font(struct display *p) | ||
2231 | { | ||
2232 | if (p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0)) | ||
2233 | kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int)); | ||
2234 | p->fontdata = NULL; | ||
2235 | p->userfont = 0; | ||
2236 | } | ||
2237 | |||
2238 | static int fbcon_get_font(struct vc_data *vc, struct console_font *font) | 2289 | static int fbcon_get_font(struct vc_data *vc, struct console_font *font) |
2239 | { | 2290 | { |
2240 | u8 *fontdata = vc->vc_font.data; | 2291 | u8 *fontdata = vc->vc_font.data; |
@@ -2448,7 +2499,7 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font, unsigne | |||
2448 | 2499 | ||
2449 | FNTSUM(new_data) = csum; | 2500 | FNTSUM(new_data) = csum; |
2450 | /* Check if the same font is on some other console already */ | 2501 | /* Check if the same font is on some other console already */ |
2451 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 2502 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
2452 | struct vc_data *tmp = vc_cons[i].d; | 2503 | struct vc_data *tmp = vc_cons[i].d; |
2453 | 2504 | ||
2454 | if (fb_display[i].userfont && | 2505 | if (fb_display[i].userfont && |
@@ -2773,7 +2824,7 @@ static void fbcon_set_all_vcs(struct fb_info *info) | |||
2773 | if (!ops || ops->currcon < 0) | 2824 | if (!ops || ops->currcon < 0) |
2774 | return; | 2825 | return; |
2775 | 2826 | ||
2776 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 2827 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
2777 | vc = vc_cons[i].d; | 2828 | vc = vc_cons[i].d; |
2778 | if (!vc || vc->vc_mode != KD_TEXT || | 2829 | if (!vc || vc->vc_mode != KD_TEXT || |
2779 | registered_fb[con2fb_map[i]] != info) | 2830 | registered_fb[con2fb_map[i]] != info) |
@@ -2835,21 +2886,55 @@ static int fbcon_mode_deleted(struct fb_info *info, | |||
2835 | return found; | 2886 | return found; |
2836 | } | 2887 | } |
2837 | 2888 | ||
2889 | static int fbcon_fb_unregistered(int idx) | ||
2890 | { | ||
2891 | int i; | ||
2892 | |||
2893 | for (i = first_fb_vc; i <= last_fb_vc; i++) { | ||
2894 | if (con2fb_map[i] == idx) | ||
2895 | con2fb_map[i] = -1; | ||
2896 | } | ||
2897 | |||
2898 | if (idx == info_idx) { | ||
2899 | info_idx = -1; | ||
2900 | |||
2901 | for (i = 0; i < FB_MAX; i++) { | ||
2902 | if (registered_fb[i] != NULL) { | ||
2903 | info_idx = i; | ||
2904 | break; | ||
2905 | } | ||
2906 | } | ||
2907 | } | ||
2908 | |||
2909 | if (info_idx != -1) { | ||
2910 | for (i = first_fb_vc; i <= last_fb_vc; i++) { | ||
2911 | if (con2fb_map[i] == -1) | ||
2912 | con2fb_map[i] = info_idx; | ||
2913 | } | ||
2914 | } | ||
2915 | |||
2916 | if (!num_registered_fb) | ||
2917 | unregister_con_driver(&fb_con); | ||
2918 | |||
2919 | return 0; | ||
2920 | } | ||
2921 | |||
2838 | static int fbcon_fb_registered(int idx) | 2922 | static int fbcon_fb_registered(int idx) |
2839 | { | 2923 | { |
2840 | int ret = 0, i; | 2924 | int ret = 0, i; |
2841 | 2925 | ||
2842 | if (info_idx == -1) { | 2926 | if (info_idx == -1) { |
2843 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 2927 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
2844 | if (con2fb_map_boot[i] == idx) { | 2928 | if (con2fb_map_boot[i] == idx) { |
2845 | info_idx = idx; | 2929 | info_idx = idx; |
2846 | break; | 2930 | break; |
2847 | } | 2931 | } |
2848 | } | 2932 | } |
2933 | |||
2849 | if (info_idx != -1) | 2934 | if (info_idx != -1) |
2850 | ret = fbcon_takeover(1); | 2935 | ret = fbcon_takeover(1); |
2851 | } else { | 2936 | } else { |
2852 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 2937 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
2853 | if (con2fb_map_boot[i] == idx && | 2938 | if (con2fb_map_boot[i] == idx && |
2854 | con2fb_map[i] == -1) | 2939 | con2fb_map[i] == -1) |
2855 | set_con2fb_map(i, idx, 0); | 2940 | set_con2fb_map(i, idx, 0); |
@@ -2888,7 +2973,7 @@ static void fbcon_new_modelist(struct fb_info *info) | |||
2888 | struct fb_var_screeninfo var; | 2973 | struct fb_var_screeninfo var; |
2889 | struct fb_videomode *mode; | 2974 | struct fb_videomode *mode; |
2890 | 2975 | ||
2891 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 2976 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
2892 | if (registered_fb[con2fb_map[i]] != info) | 2977 | if (registered_fb[con2fb_map[i]] != info) |
2893 | continue; | 2978 | continue; |
2894 | if (!fb_display[i].mode) | 2979 | if (!fb_display[i].mode) |
@@ -2916,6 +3001,14 @@ static int fbcon_event_notify(struct notifier_block *self, | |||
2916 | struct fb_con2fbmap *con2fb; | 3001 | struct fb_con2fbmap *con2fb; |
2917 | int ret = 0; | 3002 | int ret = 0; |
2918 | 3003 | ||
3004 | /* | ||
3005 | * ignore all events except driver registration and deregistration | ||
3006 | * if fbcon is not active | ||
3007 | */ | ||
3008 | if (fbcon_has_exited && !(action == FB_EVENT_FB_REGISTERED || | ||
3009 | action == FB_EVENT_FB_UNREGISTERED)) | ||
3010 | goto done; | ||
3011 | |||
2919 | switch(action) { | 3012 | switch(action) { |
2920 | case FB_EVENT_SUSPEND: | 3013 | case FB_EVENT_SUSPEND: |
2921 | fbcon_suspended(info); | 3014 | fbcon_suspended(info); |
@@ -2936,6 +3029,9 @@ static int fbcon_event_notify(struct notifier_block *self, | |||
2936 | case FB_EVENT_FB_REGISTERED: | 3029 | case FB_EVENT_FB_REGISTERED: |
2937 | ret = fbcon_fb_registered(info->node); | 3030 | ret = fbcon_fb_registered(info->node); |
2938 | break; | 3031 | break; |
3032 | case FB_EVENT_FB_UNREGISTERED: | ||
3033 | ret = fbcon_fb_unregistered(info->node); | ||
3034 | break; | ||
2939 | case FB_EVENT_SET_CONSOLE_MAP: | 3035 | case FB_EVENT_SET_CONSOLE_MAP: |
2940 | con2fb = event->data; | 3036 | con2fb = event->data; |
2941 | ret = set_con2fb_map(con2fb->console - 1, | 3037 | ret = set_con2fb_map(con2fb->console - 1, |
@@ -2953,6 +3049,7 @@ static int fbcon_event_notify(struct notifier_block *self, | |||
2953 | break; | 3049 | break; |
2954 | } | 3050 | } |
2955 | 3051 | ||
3052 | done: | ||
2956 | return ret; | 3053 | return ret; |
2957 | } | 3054 | } |
2958 | 3055 | ||
@@ -2997,6 +3094,9 @@ static ssize_t store_rotate(struct class_device *class_device, | |||
2997 | int rotate, idx; | 3094 | int rotate, idx; |
2998 | char **last = NULL; | 3095 | char **last = NULL; |
2999 | 3096 | ||
3097 | if (fbcon_has_exited) | ||
3098 | return count; | ||
3099 | |||
3000 | acquire_console_sem(); | 3100 | acquire_console_sem(); |
3001 | idx = con2fb_map[fg_console]; | 3101 | idx = con2fb_map[fg_console]; |
3002 | 3102 | ||
@@ -3018,6 +3118,9 @@ static ssize_t store_rotate_all(struct class_device *class_device, | |||
3018 | int rotate, idx; | 3118 | int rotate, idx; |
3019 | char **last = NULL; | 3119 | char **last = NULL; |
3020 | 3120 | ||
3121 | if (fbcon_has_exited) | ||
3122 | return count; | ||
3123 | |||
3021 | acquire_console_sem(); | 3124 | acquire_console_sem(); |
3022 | idx = con2fb_map[fg_console]; | 3125 | idx = con2fb_map[fg_console]; |
3023 | 3126 | ||
@@ -3037,6 +3140,9 @@ static ssize_t show_rotate(struct class_device *class_device, char *buf) | |||
3037 | struct fb_info *info; | 3140 | struct fb_info *info; |
3038 | int rotate = 0, idx; | 3141 | int rotate = 0, idx; |
3039 | 3142 | ||
3143 | if (fbcon_has_exited) | ||
3144 | return 0; | ||
3145 | |||
3040 | acquire_console_sem(); | 3146 | acquire_console_sem(); |
3041 | idx = con2fb_map[fg_console]; | 3147 | idx = con2fb_map[fg_console]; |
3042 | 3148 | ||
@@ -3050,32 +3156,9 @@ err: | |||
3050 | return snprintf(buf, PAGE_SIZE, "%d\n", rotate); | 3156 | return snprintf(buf, PAGE_SIZE, "%d\n", rotate); |
3051 | } | 3157 | } |
3052 | 3158 | ||
3053 | static ssize_t store_attach(struct class_device *class_device, | ||
3054 | const char *buf, size_t count) | ||
3055 | { | ||
3056 | if (info_idx == -1) | ||
3057 | fbcon_start(); | ||
3058 | |||
3059 | return count; | ||
3060 | } | ||
3061 | |||
3062 | static ssize_t store_detach(struct class_device *class_device, | ||
3063 | const char *buf, size_t count) | ||
3064 | { | ||
3065 | if (info_idx != -1) { | ||
3066 | fbcon_exit(); | ||
3067 | give_up_console(&fb_con); | ||
3068 | } | ||
3069 | |||
3070 | info_idx = -1; | ||
3071 | return count; | ||
3072 | } | ||
3073 | |||
3074 | static struct class_device_attribute class_device_attrs[] = { | 3159 | static struct class_device_attribute class_device_attrs[] = { |
3075 | __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate), | 3160 | __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate), |
3076 | __ATTR(rotate_all, S_IWUSR, NULL, store_rotate_all), | 3161 | __ATTR(rotate_all, S_IWUSR, NULL, store_rotate_all), |
3077 | __ATTR(attach, S_IWUSR, NULL, store_attach), | ||
3078 | __ATTR(detach, S_IWUSR, NULL, store_detach), | ||
3079 | }; | 3162 | }; |
3080 | 3163 | ||
3081 | static int fbcon_init_class_device(void) | 3164 | static int fbcon_init_class_device(void) |
@@ -3112,7 +3195,9 @@ static void fbcon_exit(void) | |||
3112 | struct fb_info *info; | 3195 | struct fb_info *info; |
3113 | int i, j, mapped; | 3196 | int i, j, mapped; |
3114 | 3197 | ||
3115 | acquire_console_sem(); | 3198 | if (fbcon_has_exited) |
3199 | return; | ||
3200 | |||
3116 | #ifdef CONFIG_ATARI | 3201 | #ifdef CONFIG_ATARI |
3117 | free_irq(IRQ_AUTO_4, fbcon_vbl_handler); | 3202 | free_irq(IRQ_AUTO_4, fbcon_vbl_handler); |
3118 | #endif | 3203 | #endif |
@@ -3131,11 +3216,9 @@ static void fbcon_exit(void) | |||
3131 | if (info == NULL) | 3216 | if (info == NULL) |
3132 | continue; | 3217 | continue; |
3133 | 3218 | ||
3134 | for (j = 0; j < MAX_NR_CONSOLES; j++) { | 3219 | for (j = first_fb_vc; j <= last_fb_vc; j++) { |
3135 | if (con2fb_map[j] == i) { | 3220 | if (con2fb_map[j] == i) |
3136 | con2fb_map[j] = -1; | ||
3137 | mapped = 1; | 3221 | mapped = 1; |
3138 | } | ||
3139 | } | 3222 | } |
3140 | 3223 | ||
3141 | if (mapped) { | 3224 | if (mapped) { |
@@ -3151,11 +3234,10 @@ static void fbcon_exit(void) | |||
3151 | 3234 | ||
3152 | if (info->queue.func == fb_flashcursor) | 3235 | if (info->queue.func == fb_flashcursor) |
3153 | info->queue.func = NULL; | 3236 | info->queue.func = NULL; |
3154 | |||
3155 | } | 3237 | } |
3156 | } | 3238 | } |
3157 | 3239 | ||
3158 | release_console_sem(); | 3240 | fbcon_has_exited = 1; |
3159 | } | 3241 | } |
3160 | 3242 | ||
3161 | static int __init fb_console_init(void) | 3243 | static int __init fb_console_init(void) |
@@ -3189,7 +3271,7 @@ module_init(fb_console_init); | |||
3189 | 3271 | ||
3190 | #ifdef MODULE | 3272 | #ifdef MODULE |
3191 | 3273 | ||
3192 | static void fbcon_deinit_class_device(void) | 3274 | static void __exit fbcon_deinit_class_device(void) |
3193 | { | 3275 | { |
3194 | int i; | 3276 | int i; |
3195 | 3277 | ||
@@ -3204,7 +3286,9 @@ static void __exit fb_console_exit(void) | |||
3204 | fb_unregister_client(&fbcon_event_notifier); | 3286 | fb_unregister_client(&fbcon_event_notifier); |
3205 | fbcon_deinit_class_device(); | 3287 | fbcon_deinit_class_device(); |
3206 | class_device_destroy(fb_class, MKDEV(FB_MAJOR, FB_MAX)); | 3288 | class_device_destroy(fb_class, MKDEV(FB_MAJOR, FB_MAX)); |
3289 | fbcon_exit(); | ||
3207 | release_console_sem(); | 3290 | release_console_sem(); |
3291 | unregister_con_driver(&fb_con); | ||
3208 | } | 3292 | } |
3209 | 3293 | ||
3210 | module_exit(fb_console_exit); | 3294 | module_exit(fb_console_exit); |