aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/console/fbcon.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/console/fbcon.c')
-rw-r--r--drivers/video/console/fbcon.c361
1 files changed, 311 insertions, 50 deletions
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 47ba1a79adcd..5dc4083552d8 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -125,6 +125,8 @@ static int softback_lines;
125static int first_fb_vc; 125static int first_fb_vc;
126static int last_fb_vc = MAX_NR_CONSOLES - 1; 126static int last_fb_vc = MAX_NR_CONSOLES - 1;
127static int fbcon_is_default = 1; 127static int fbcon_is_default = 1;
128static int fbcon_has_exited;
129
128/* font data */ 130/* font data */
129static char fontname[40]; 131static 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
143static void fbcon_free_font(struct display *);
144static int fbcon_set_origin(struct vc_data *); 145static int fbcon_set_origin(struct vc_data *);
145 146
146#define CURSOR_DRAW_DELAY (1) 147#define CURSOR_DRAW_DELAY (1)
@@ -194,6 +195,9 @@ static void fbcon_redraw_move(struct vc_data *vc, struct display *p,
194 int line, int count, int dy); 195 int line, int count, int dy);
195static void fbcon_modechanged(struct fb_info *info); 196static void fbcon_modechanged(struct fb_info *info);
196static void fbcon_set_all_vcs(struct fb_info *info); 197static void fbcon_set_all_vcs(struct fb_info *info);
198static void fbcon_start(void);
199static void fbcon_exit(void);
200static struct class_device *fbcon_class_device;
197 201
198#ifdef CONFIG_MAC 202#ifdef CONFIG_MAC
199/* 203/*
@@ -252,7 +256,7 @@ static void fbcon_rotate_all(struct fb_info *info, u32 rotate)
252 if (!ops || ops->currcon < 0 || rotate > 3) 256 if (!ops || ops->currcon < 0 || rotate > 3)
253 return; 257 return;
254 258
255 for (i = 0; i < MAX_NR_CONSOLES; i++) { 259 for (i = first_fb_vc; i <= last_fb_vc; i++) {
256 vc = vc_cons[i].d; 260 vc = vc_cons[i].d;
257 if (!vc || vc->vc_mode != KD_TEXT || 261 if (!vc || vc->vc_mode != KD_TEXT ||
258 registered_fb[con2fb_map[i]] != info) 262 registered_fb[con2fb_map[i]] != info)
@@ -389,15 +393,18 @@ static void fb_flashcursor(void *private)
389 int c; 393 int c;
390 int mode; 394 int mode;
391 395
392 if (ops->currcon != -1) 396 acquire_console_sem();
397 if (ops && ops->currcon != -1)
393 vc = vc_cons[ops->currcon].d; 398 vc = vc_cons[ops->currcon].d;
394 399
395 if (!vc || !CON_IS_VISIBLE(vc) || 400 if (!vc || !CON_IS_VISIBLE(vc) ||
396 fbcon_is_inactive(vc, info) || 401 fbcon_is_inactive(vc, info) ||
397 registered_fb[con2fb_map[vc->vc_num]] != info || 402 registered_fb[con2fb_map[vc->vc_num]] != info ||
398 vc_cons[ops->currcon].d->vc_deccm != 1) 403 vc_cons[ops->currcon].d->vc_deccm != 1) {
404 release_console_sem();
399 return; 405 return;
400 acquire_console_sem(); 406 }
407
401 p = &fb_display[vc->vc_num]; 408 p = &fb_display[vc->vc_num];
402 c = scr_readw((u16 *) vc->vc_pos); 409 c = scr_readw((u16 *) vc->vc_pos);
403 mode = (!ops->cursor_flash || ops->cursor_state.enable) ? 410 mode = (!ops->cursor_flash || ops->cursor_state.enable) ?
@@ -528,7 +535,7 @@ static int search_fb_in_map(int idx)
528{ 535{
529 int i, retval = 0; 536 int i, retval = 0;
530 537
531 for (i = 0; i < MAX_NR_CONSOLES; i++) { 538 for (i = first_fb_vc; i <= last_fb_vc; i++) {
532 if (con2fb_map[i] == idx) 539 if (con2fb_map[i] == idx)
533 retval = 1; 540 retval = 1;
534 } 541 }
@@ -539,7 +546,7 @@ static int search_for_mapped_con(void)
539{ 546{
540 int i, retval = 0; 547 int i, retval = 0;
541 548
542 for (i = 0; i < MAX_NR_CONSOLES; i++) { 549 for (i = first_fb_vc; i <= last_fb_vc; i++) {
543 if (con2fb_map[i] != -1) 550 if (con2fb_map[i] != -1)
544 retval = 1; 551 retval = 1;
545 } 552 }
@@ -561,6 +568,7 @@ static int fbcon_takeover(int show_logo)
561 568
562 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,
563 fbcon_is_default); 570 fbcon_is_default);
571
564 if (err) { 572 if (err) {
565 for (i = first_fb_vc; i <= last_fb_vc; i++) { 573 for (i = first_fb_vc; i <= last_fb_vc; i++) {
566 con2fb_map[i] = -1; 574 con2fb_map[i] = -1;
@@ -795,8 +803,8 @@ static int set_con2fb_map(int unit, int newidx, int user)
795 if (oldidx == newidx) 803 if (oldidx == newidx)
796 return 0; 804 return 0;
797 805
798 if (!info) 806 if (!info || fbcon_has_exited)
799 err = -EINVAL; 807 return -EINVAL;
800 808
801 if (!err && !search_for_mapped_con()) { 809 if (!err && !search_for_mapped_con()) {
802 info_idx = newidx; 810 info_idx = newidx;
@@ -832,6 +840,9 @@ static int set_con2fb_map(int unit, int newidx, int user)
832 con2fb_init_display(vc, info, unit, show_logo); 840 con2fb_init_display(vc, info, unit, show_logo);
833 } 841 }
834 842
843 if (!search_fb_in_map(info_idx))
844 info_idx = newidx;
845
835 release_console_sem(); 846 release_console_sem();
836 return err; 847 return err;
837} 848}
@@ -1034,6 +1045,7 @@ static const char *fbcon_startup(void)
1034#endif /* CONFIG_MAC */ 1045#endif /* CONFIG_MAC */
1035 1046
1036 fbcon_add_cursor_timer(info); 1047 fbcon_add_cursor_timer(info);
1048 fbcon_has_exited = 0;
1037 return display_desc; 1049 return display_desc;
1038} 1050}
1039 1051
@@ -1061,17 +1073,36 @@ static void fbcon_init(struct vc_data *vc, int init)
1061 1073
1062 /* If we are not the first console on this 1074 /* If we are not the first console on this
1063 fb, copy the font from that console */ 1075 fb, copy the font from that console */
1064 t = &fb_display[svc->vc_num]; 1076 t = &fb_display[fg_console];
1065 if (!vc->vc_font.data) { 1077 if (!p->fontdata) {
1066 vc->vc_font.data = (void *)(p->fontdata = t->fontdata); 1078 if (t->fontdata) {
1067 vc->vc_font.width = (*default_mode)->vc_font.width; 1079 struct vc_data *fvc = vc_cons[fg_console].d;
1068 vc->vc_font.height = (*default_mode)->vc_font.height; 1080
1069 p->userfont = t->userfont; 1081 vc->vc_font.data = (void *)(p->fontdata =
1070 if (p->userfont) 1082 fvc->vc_font.data);
1071 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 }
1072 } 1101 }
1102
1073 if (p->userfont) 1103 if (p->userfont)
1074 charcnt = FNTCHARCNT(p->fontdata); 1104 charcnt = FNTCHARCNT(p->fontdata);
1105
1075 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);
1076 vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; 1107 vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
1077 if (charcnt == 256) { 1108 if (charcnt == 256) {
@@ -1145,13 +1176,47 @@ static void fbcon_init(struct vc_data *vc, int init)
1145 ops->p = &fb_display[fg_console]; 1176 ops->p = &fb_display[fg_console];
1146} 1177}
1147 1178
1179static 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
1148static void fbcon_deinit(struct vc_data *vc) 1187static void fbcon_deinit(struct vc_data *vc)
1149{ 1188{
1150 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;
1151 1193
1152 if (info_idx != -1)
1153 return;
1154 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;
1214finished:
1215
1216 if (!con_is_bound(&fb_con))
1217 fbcon_exit();
1218
1219 return;
1155} 1220}
1156 1221
1157/* ====================================================================== */ 1222/* ====================================================================== */
@@ -2099,12 +2164,11 @@ static int fbcon_switch(struct vc_data *vc)
2099 if (info->fbops->fb_set_par) 2164 if (info->fbops->fb_set_par)
2100 info->fbops->fb_set_par(info); 2165 info->fbops->fb_set_par(info);
2101 2166
2102 if (old_info != info) { 2167 if (old_info != info)
2103 fbcon_del_cursor_timer(old_info); 2168 fbcon_del_cursor_timer(old_info);
2104 fbcon_add_cursor_timer(info);
2105 }
2106 } 2169 }
2107 2170
2171 fbcon_add_cursor_timer(info);
2108 set_blitting_type(vc, info); 2172 set_blitting_type(vc, info);
2109 ops->cursor_reset = 1; 2173 ops->cursor_reset = 1;
2110 2174
@@ -2222,14 +2286,6 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
2222 return 0; 2286 return 0;
2223} 2287}
2224 2288
2225static void fbcon_free_font(struct display *p)
2226{
2227 if (p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0))
2228 kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int));
2229 p->fontdata = NULL;
2230 p->userfont = 0;
2231}
2232
2233static int fbcon_get_font(struct vc_data *vc, struct console_font *font) 2289static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
2234{ 2290{
2235 u8 *fontdata = vc->vc_font.data; 2291 u8 *fontdata = vc->vc_font.data;
@@ -2443,7 +2499,7 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font, unsigne
2443 2499
2444 FNTSUM(new_data) = csum; 2500 FNTSUM(new_data) = csum;
2445 /* Check if the same font is on some other console already */ 2501 /* Check if the same font is on some other console already */
2446 for (i = 0; i < MAX_NR_CONSOLES; i++) { 2502 for (i = first_fb_vc; i <= last_fb_vc; i++) {
2447 struct vc_data *tmp = vc_cons[i].d; 2503 struct vc_data *tmp = vc_cons[i].d;
2448 2504
2449 if (fb_display[i].userfont && 2505 if (fb_display[i].userfont &&
@@ -2768,7 +2824,7 @@ static void fbcon_set_all_vcs(struct fb_info *info)
2768 if (!ops || ops->currcon < 0) 2824 if (!ops || ops->currcon < 0)
2769 return; 2825 return;
2770 2826
2771 for (i = 0; i < MAX_NR_CONSOLES; i++) { 2827 for (i = first_fb_vc; i <= last_fb_vc; i++) {
2772 vc = vc_cons[i].d; 2828 vc = vc_cons[i].d;
2773 if (!vc || vc->vc_mode != KD_TEXT || 2829 if (!vc || vc->vc_mode != KD_TEXT ||
2774 registered_fb[con2fb_map[i]] != info) 2830 registered_fb[con2fb_map[i]] != info)
@@ -2830,22 +2886,57 @@ static int fbcon_mode_deleted(struct fb_info *info,
2830 return found; 2886 return found;
2831} 2887}
2832 2888
2889static 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
2833static int fbcon_fb_registered(int idx) 2922static int fbcon_fb_registered(int idx)
2834{ 2923{
2835 int ret = 0, i; 2924 int ret = 0, i;
2836 2925
2837 if (info_idx == -1) { 2926 if (info_idx == -1) {
2838 for (i = 0; i < MAX_NR_CONSOLES; i++) { 2927 for (i = first_fb_vc; i <= last_fb_vc; i++) {
2839 if (con2fb_map_boot[i] == idx) { 2928 if (con2fb_map_boot[i] == idx) {
2840 info_idx = idx; 2929 info_idx = idx;
2841 break; 2930 break;
2842 } 2931 }
2843 } 2932 }
2933
2844 if (info_idx != -1) 2934 if (info_idx != -1)
2845 ret = fbcon_takeover(1); 2935 ret = fbcon_takeover(1);
2846 } else { 2936 } else {
2847 for (i = 0; i < MAX_NR_CONSOLES; i++) { 2937 for (i = first_fb_vc; i <= last_fb_vc; i++) {
2848 if (con2fb_map_boot[i] == idx) 2938 if (con2fb_map_boot[i] == idx &&
2939 con2fb_map[i] == -1)
2849 set_con2fb_map(i, idx, 0); 2940 set_con2fb_map(i, idx, 0);
2850 } 2941 }
2851 } 2942 }
@@ -2882,7 +2973,7 @@ static void fbcon_new_modelist(struct fb_info *info)
2882 struct fb_var_screeninfo var; 2973 struct fb_var_screeninfo var;
2883 struct fb_videomode *mode; 2974 struct fb_videomode *mode;
2884 2975
2885 for (i = 0; i < MAX_NR_CONSOLES; i++) { 2976 for (i = first_fb_vc; i <= last_fb_vc; i++) {
2886 if (registered_fb[con2fb_map[i]] != info) 2977 if (registered_fb[con2fb_map[i]] != info)
2887 continue; 2978 continue;
2888 if (!fb_display[i].mode) 2979 if (!fb_display[i].mode)
@@ -2910,6 +3001,14 @@ static int fbcon_event_notify(struct notifier_block *self,
2910 struct fb_con2fbmap *con2fb; 3001 struct fb_con2fbmap *con2fb;
2911 int ret = 0; 3002 int ret = 0;
2912 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
2913 switch(action) { 3012 switch(action) {
2914 case FB_EVENT_SUSPEND: 3013 case FB_EVENT_SUSPEND:
2915 fbcon_suspended(info); 3014 fbcon_suspended(info);
@@ -2930,6 +3029,9 @@ static int fbcon_event_notify(struct notifier_block *self,
2930 case FB_EVENT_FB_REGISTERED: 3029 case FB_EVENT_FB_REGISTERED:
2931 ret = fbcon_fb_registered(info->node); 3030 ret = fbcon_fb_registered(info->node);
2932 break; 3031 break;
3032 case FB_EVENT_FB_UNREGISTERED:
3033 ret = fbcon_fb_unregistered(info->node);
3034 break;
2933 case FB_EVENT_SET_CONSOLE_MAP: 3035 case FB_EVENT_SET_CONSOLE_MAP:
2934 con2fb = event->data; 3036 con2fb = event->data;
2935 ret = set_con2fb_map(con2fb->console - 1, 3037 ret = set_con2fb_map(con2fb->console - 1,
@@ -2945,16 +3047,9 @@ static int fbcon_event_notify(struct notifier_block *self,
2945 case FB_EVENT_NEW_MODELIST: 3047 case FB_EVENT_NEW_MODELIST:
2946 fbcon_new_modelist(info); 3048 fbcon_new_modelist(info);
2947 break; 3049 break;
2948 case FB_EVENT_SET_CON_ROTATE:
2949 fbcon_rotate(info, *(int *)event->data);
2950 break;
2951 case FB_EVENT_GET_CON_ROTATE:
2952 ret = fbcon_get_rotate(info);
2953 break;
2954 case FB_EVENT_SET_CON_ROTATE_ALL:
2955 fbcon_rotate_all(info, *(int *)event->data);
2956 } 3050 }
2957 3051
3052done:
2958 return ret; 3053 return ret;
2959} 3054}
2960 3055
@@ -2992,27 +3087,181 @@ static struct notifier_block fbcon_event_notifier = {
2992 .notifier_call = fbcon_event_notify, 3087 .notifier_call = fbcon_event_notify,
2993}; 3088};
2994 3089
2995static int __init fb_console_init(void) 3090static ssize_t store_rotate(struct class_device *class_device,
3091 const char *buf, size_t count)
2996{ 3092{
2997 int i; 3093 struct fb_info *info;
3094 int rotate, idx;
3095 char **last = NULL;
3096
3097 if (fbcon_has_exited)
3098 return count;
2998 3099
2999 acquire_console_sem(); 3100 acquire_console_sem();
3000 fb_register_client(&fbcon_event_notifier); 3101 idx = con2fb_map[fg_console];
3102
3103 if (idx == -1 || registered_fb[idx] == NULL)
3104 goto err;
3105
3106 info = registered_fb[idx];
3107 rotate = simple_strtoul(buf, last, 0);
3108 fbcon_rotate(info, rotate);
3109err:
3001 release_console_sem(); 3110 release_console_sem();
3111 return count;
3112}
3002 3113
3003 for (i = 0; i < MAX_NR_CONSOLES; i++) 3114static ssize_t store_rotate_all(struct class_device *class_device,
3004 con2fb_map[i] = -1; 3115 const char *buf, size_t count)
3116{
3117 struct fb_info *info;
3118 int rotate, idx;
3119 char **last = NULL;
3120
3121 if (fbcon_has_exited)
3122 return count;
3123
3124 acquire_console_sem();
3125 idx = con2fb_map[fg_console];
3126
3127 if (idx == -1 || registered_fb[idx] == NULL)
3128 goto err;
3005 3129
3130 info = registered_fb[idx];
3131 rotate = simple_strtoul(buf, last, 0);
3132 fbcon_rotate_all(info, rotate);
3133err:
3134 release_console_sem();
3135 return count;
3136}
3137
3138static ssize_t show_rotate(struct class_device *class_device, char *buf)
3139{
3140 struct fb_info *info;
3141 int rotate = 0, idx;
3142
3143 if (fbcon_has_exited)
3144 return 0;
3145
3146 acquire_console_sem();
3147 idx = con2fb_map[fg_console];
3148
3149 if (idx == -1 || registered_fb[idx] == NULL)
3150 goto err;
3151
3152 info = registered_fb[idx];
3153 rotate = fbcon_get_rotate(info);
3154err:
3155 release_console_sem();
3156 return snprintf(buf, PAGE_SIZE, "%d\n", rotate);
3157}
3158
3159static struct class_device_attribute class_device_attrs[] = {
3160 __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate),
3161 __ATTR(rotate_all, S_IWUSR, NULL, store_rotate_all),
3162};
3163
3164static int fbcon_init_class_device(void)
3165{
3166 int i;
3167
3168 for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
3169 class_device_create_file(fbcon_class_device,
3170 &class_device_attrs[i]);
3171 return 0;
3172}
3173
3174static void fbcon_start(void)
3175{
3006 if (num_registered_fb) { 3176 if (num_registered_fb) {
3177 int i;
3178
3179 acquire_console_sem();
3180
3007 for (i = 0; i < FB_MAX; i++) { 3181 for (i = 0; i < FB_MAX; i++) {
3008 if (registered_fb[i] != NULL) { 3182 if (registered_fb[i] != NULL) {
3009 info_idx = i; 3183 info_idx = i;
3010 break; 3184 break;
3011 } 3185 }
3012 } 3186 }
3187
3188 release_console_sem();
3013 fbcon_takeover(0); 3189 fbcon_takeover(0);
3014 } 3190 }
3191}
3192
3193static void fbcon_exit(void)
3194{
3195 struct fb_info *info;
3196 int i, j, mapped;
3197
3198 if (fbcon_has_exited)
3199 return;
3200
3201#ifdef CONFIG_ATARI
3202 free_irq(IRQ_AUTO_4, fbcon_vbl_handler);
3203#endif
3204#ifdef CONFIG_MAC
3205 if (MACH_IS_MAC && vbl_detected)
3206 free_irq(IRQ_MAC_VBL, fbcon_vbl_handler);
3207#endif
3208
3209 kfree((void *)softback_buf);
3210 softback_buf = 0UL;
3211
3212 for (i = 0; i < FB_MAX; i++) {
3213 mapped = 0;
3214 info = registered_fb[i];
3215
3216 if (info == NULL)
3217 continue;
3218
3219 for (j = first_fb_vc; j <= last_fb_vc; j++) {
3220 if (con2fb_map[j] == i)
3221 mapped = 1;
3222 }
3223
3224 if (mapped) {
3225 if (info->fbops->fb_release)
3226 info->fbops->fb_release(info, 0);
3227 module_put(info->fbops->owner);
3228
3229 if (info->fbcon_par) {
3230 fbcon_del_cursor_timer(info);
3231 kfree(info->fbcon_par);
3232 info->fbcon_par = NULL;
3233 }
3015 3234
3235 if (info->queue.func == fb_flashcursor)
3236 info->queue.func = NULL;
3237 }
3238 }
3239
3240 fbcon_has_exited = 1;
3241}
3242
3243static int __init fb_console_init(void)
3244{
3245 int i;
3246
3247 acquire_console_sem();
3248 fb_register_client(&fbcon_event_notifier);
3249 fbcon_class_device =
3250 class_device_create(fb_class, NULL, MKDEV(0, 0), NULL, "fbcon");
3251
3252 if (IS_ERR(fbcon_class_device)) {
3253 printk(KERN_WARNING "Unable to create class_device "
3254 "for fbcon; errno = %ld\n",
3255 PTR_ERR(fbcon_class_device));
3256 fbcon_class_device = NULL;
3257 } else
3258 fbcon_init_class_device();
3259
3260 for (i = 0; i < MAX_NR_CONSOLES; i++)
3261 con2fb_map[i] = -1;
3262
3263 release_console_sem();
3264 fbcon_start();
3016 return 0; 3265 return 0;
3017} 3266}
3018 3267
@@ -3020,12 +3269,24 @@ module_init(fb_console_init);
3020 3269
3021#ifdef MODULE 3270#ifdef MODULE
3022 3271
3272static void __exit fbcon_deinit_class_device(void)
3273{
3274 int i;
3275
3276 for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
3277 class_device_remove_file(fbcon_class_device,
3278 &class_device_attrs[i]);
3279}
3280
3023static void __exit fb_console_exit(void) 3281static void __exit fb_console_exit(void)
3024{ 3282{
3025 acquire_console_sem(); 3283 acquire_console_sem();
3026 fb_unregister_client(&fbcon_event_notifier); 3284 fb_unregister_client(&fbcon_event_notifier);
3285 fbcon_deinit_class_device();
3286 class_device_destroy(fb_class, MKDEV(0, 0));
3287 fbcon_exit();
3027 release_console_sem(); 3288 release_console_sem();
3028 give_up_console(&fb_con); 3289 unregister_con_driver(&fb_con);
3029} 3290}
3030 3291
3031module_exit(fb_console_exit); 3292module_exit(fb_console_exit);