aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAntonino A. Daplas <adaplas@gmail.com>2006-06-26 03:27:06 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-26 12:58:32 -0400
commit5428b04405af1bb441aa8aabd314e48b870bc58e (patch)
treef5f94e7ddc3df72e9c323fdab82b0805cf32abe6
parente55186fe5fad31962d0ea5ef267bf0c23d98abd4 (diff)
[PATCH] Detaching fbcon: add capability to attach/detach fbcon
Add the ability to detach and attach the framebuffer console to and from the vt layer. This is done by echo'ing any value to sysfs attributes located in class/graphics/fbcon. The two attributes are: attach - bind fbcon to the vt layer detach - unbind fbcon from the vt layer Once fbcon is detached from the vt layer, fbcon can be unloaded if compiled as a module. This feature is quite useful for developers who work on the framebuffer or console subsystem. This is also useful for users who want to go to text mode or graphics mode without having to reboot. Directly unloading the fbcon module is not possible because the vt layer increments the module reference count for all bound consoles. Detaching fbcon decrements the module reference count to zero so unloading becomes possible. Detaching fbcon may interfere with X and/or DRM. Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--drivers/video/console/fbcon.c155
1 files changed, 97 insertions, 58 deletions
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 0b742497055e..4b7be685c160 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -194,7 +194,8 @@ static void fbcon_redraw_move(struct vc_data *vc, struct display *p,
194 int line, int count, int dy); 194 int line, int count, int dy);
195static void fbcon_modechanged(struct fb_info *info); 195static void fbcon_modechanged(struct fb_info *info);
196static void fbcon_set_all_vcs(struct fb_info *info); 196static void fbcon_set_all_vcs(struct fb_info *info);
197 197static void fbcon_start(void);
198static void fbcon_exit(void);
198static struct class_device *fbcon_class_device; 199static struct class_device *fbcon_class_device;
199 200
200#ifdef CONFIG_MAC 201#ifdef CONFIG_MAC
@@ -391,15 +392,18 @@ static void fb_flashcursor(void *private)
391 int c; 392 int c;
392 int mode; 393 int mode;
393 394
394 if (ops->currcon != -1) 395 acquire_console_sem();
396 if (ops && ops->currcon != -1)
395 vc = vc_cons[ops->currcon].d; 397 vc = vc_cons[ops->currcon].d;
396 398
397 if (!vc || !CON_IS_VISIBLE(vc) || 399 if (!vc || !CON_IS_VISIBLE(vc) ||
398 fbcon_is_inactive(vc, info) || 400 fbcon_is_inactive(vc, info) ||
399 registered_fb[con2fb_map[vc->vc_num]] != info || 401 registered_fb[con2fb_map[vc->vc_num]] != info ||
400 vc_cons[ops->currcon].d->vc_deccm != 1) 402 vc_cons[ops->currcon].d->vc_deccm != 1) {
403 release_console_sem();
401 return; 404 return;
402 acquire_console_sem(); 405 }
406
403 p = &fb_display[vc->vc_num]; 407 p = &fb_display[vc->vc_num];
404 c = scr_readw((u16 *) vc->vc_pos); 408 c = scr_readw((u16 *) vc->vc_pos);
405 mode = (!ops->cursor_flash || ops->cursor_state.enable) ? 409 mode = (!ops->cursor_flash || ops->cursor_state.enable) ?
@@ -2101,12 +2105,11 @@ static int fbcon_switch(struct vc_data *vc)
2101 if (info->fbops->fb_set_par) 2105 if (info->fbops->fb_set_par)
2102 info->fbops->fb_set_par(info); 2106 info->fbops->fb_set_par(info);
2103 2107
2104 if (old_info != info) { 2108 if (old_info != info)
2105 fbcon_del_cursor_timer(old_info); 2109 fbcon_del_cursor_timer(old_info);
2106 fbcon_add_cursor_timer(info);
2107 }
2108 } 2110 }
2109 2111
2112 fbcon_add_cursor_timer(info);
2110 set_blitting_type(vc, info); 2113 set_blitting_type(vc, info);
2111 ops->cursor_reset = 1; 2114 ops->cursor_reset = 1;
2112 2115
@@ -2847,7 +2850,8 @@ static int fbcon_fb_registered(int idx)
2847 ret = fbcon_takeover(1); 2850 ret = fbcon_takeover(1);
2848 } else { 2851 } else {
2849 for (i = 0; i < MAX_NR_CONSOLES; i++) { 2852 for (i = 0; i < MAX_NR_CONSOLES; i++) {
2850 if (con2fb_map_boot[i] == idx) 2853 if (con2fb_map_boot[i] == idx &&
2854 con2fb_map[i] == -1)
2851 set_con2fb_map(i, idx, 0); 2855 set_con2fb_map(i, idx, 0);
2852 } 2856 }
2853 } 2857 }
@@ -3046,9 +3050,32 @@ err:
3046 return snprintf(buf, PAGE_SIZE, "%d\n", rotate); 3050 return snprintf(buf, PAGE_SIZE, "%d\n", rotate);
3047} 3051}
3048 3052
3053static 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
3062static 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
3049static struct class_device_attribute class_device_attrs[] = { 3074static struct class_device_attribute class_device_attrs[] = {
3050 __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate), 3075 __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate),
3051 __ATTR(rotate_all, S_IWUSR, NULL, store_rotate_all), 3076 __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),
3052}; 3079};
3053 3080
3054static int fbcon_init_class_device(void) 3081static int fbcon_init_class_device(void)
@@ -3061,67 +3088,31 @@ static int fbcon_init_class_device(void)
3061 return 0; 3088 return 0;
3062} 3089}
3063 3090
3064static int __init fb_console_init(void) 3091static void fbcon_start(void)
3065{ 3092{
3066 int i; 3093 if (num_registered_fb) {
3067 3094 int i;
3068 acquire_console_sem();
3069 fb_register_client(&fbcon_event_notifier);
3070 release_console_sem();
3071
3072 fbcon_class_device =
3073 class_device_create(fb_class, NULL,
3074 MKDEV(FB_MAJOR, FB_MAX), NULL,
3075 "fbcon");
3076 if (IS_ERR(fbcon_class_device)) {
3077 printk(KERN_WARNING "Unable to create class_device "
3078 "for fbcon; errno = %ld\n",
3079 PTR_ERR(fbcon_class_device));
3080 fbcon_class_device = NULL;
3081 } else
3082 fbcon_init_class_device();
3083 3095
3084 for (i = 0; i < MAX_NR_CONSOLES; i++) 3096 acquire_console_sem();
3085 con2fb_map[i] = -1;
3086 3097
3087 if (num_registered_fb) {
3088 for (i = 0; i < FB_MAX; i++) { 3098 for (i = 0; i < FB_MAX; i++) {
3089 if (registered_fb[i] != NULL) { 3099 if (registered_fb[i] != NULL) {
3090 info_idx = i; 3100 info_idx = i;
3091 break; 3101 break;
3092 } 3102 }
3093 } 3103 }
3104
3105 release_console_sem();
3094 fbcon_takeover(0); 3106 fbcon_takeover(0);
3095 } 3107 }
3096
3097 return 0;
3098}
3099
3100module_init(fb_console_init);
3101
3102#ifdef MODULE
3103
3104static void __exit fbcon_deinit_class_device(void)
3105{
3106 int i;
3107
3108 for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
3109 class_device_remove_file(fbcon_class_device,
3110 &class_device_attrs[i]);
3111} 3108}
3112 3109
3113static void __exit fbcon_exit(void) 3110static void fbcon_exit(void)
3114{ 3111{
3115 struct fb_info *info; 3112 struct fb_info *info;
3116 int i, j, mapped; 3113 int i, j, mapped;
3117 3114
3118 for (i = 0; i < FB_MAX; i++) { 3115 acquire_console_sem();
3119 info = registered_fb[i];
3120
3121 if (info && info->fbcon_par)
3122 fbcon_del_cursor_timer(info);
3123 }
3124
3125#ifdef CONFIG_ATARI 3116#ifdef CONFIG_ATARI
3126 free_irq(IRQ_AUTO_4, fbcon_vbl_handler); 3117 free_irq(IRQ_AUTO_4, fbcon_vbl_handler);
3127#endif 3118#endif
@@ -3131,6 +3122,7 @@ static void __exit fbcon_exit(void)
3131#endif 3122#endif
3132 3123
3133 kfree((void *)softback_buf); 3124 kfree((void *)softback_buf);
3125 softback_buf = 0UL;
3134 3126
3135 for (i = 0; i < FB_MAX; i++) { 3127 for (i = 0; i < FB_MAX; i++) {
3136 mapped = 0; 3128 mapped = 0;
@@ -3150,22 +3142,69 @@ static void __exit fbcon_exit(void)
3150 if (info->fbops->fb_release) 3142 if (info->fbops->fb_release)
3151 info->fbops->fb_release(info, 0); 3143 info->fbops->fb_release(info, 0);
3152 module_put(info->fbops->owner); 3144 module_put(info->fbops->owner);
3153 kfree(info->fbcon_par); 3145
3154 info->fbcon_par = NULL; 3146 if (info->fbcon_par) {
3147 fbcon_del_cursor_timer(info);
3148 kfree(info->fbcon_par);
3149 info->fbcon_par = NULL;
3150 }
3151
3152 if (info->queue.func == fb_flashcursor)
3153 info->queue.func = NULL;
3154
3155 } 3155 }
3156 } 3156 }
3157 3157
3158 fbcon_deinit_class_device(); 3158 release_console_sem();
3159 class_device_destroy(fb_class, MKDEV(FB_MAJOR, FB_MAX)); 3159}
3160
3161static int __init fb_console_init(void)
3162{
3163 int i;
3164
3165 acquire_console_sem();
3166 fb_register_client(&fbcon_event_notifier);
3167 fbcon_class_device =
3168 class_device_create(fb_class, NULL,
3169 MKDEV(FB_MAJOR, FB_MAX), NULL,
3170 "fbcon");
3171
3172 if (IS_ERR(fbcon_class_device)) {
3173 printk(KERN_WARNING "Unable to create class_device "
3174 "for fbcon; errno = %ld\n",
3175 PTR_ERR(fbcon_class_device));
3176 fbcon_class_device = NULL;
3177 } else
3178 fbcon_init_class_device();
3179
3180 for (i = 0; i < MAX_NR_CONSOLES; i++)
3181 con2fb_map[i] = -1;
3182
3183 release_console_sem();
3184 fbcon_start();
3185 return 0;
3186}
3187
3188module_init(fb_console_init);
3189
3190#ifdef MODULE
3191
3192static void fbcon_deinit_class_device(void)
3193{
3194 int i;
3195
3196 for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
3197 class_device_remove_file(fbcon_class_device,
3198 &class_device_attrs[i]);
3160} 3199}
3161 3200
3162static void __exit fb_console_exit(void) 3201static void __exit fb_console_exit(void)
3163{ 3202{
3164 acquire_console_sem(); 3203 acquire_console_sem();
3165 fb_unregister_client(&fbcon_event_notifier); 3204 fb_unregister_client(&fbcon_event_notifier);
3166 fbcon_exit(); 3205 fbcon_deinit_class_device();
3206 class_device_destroy(fb_class, MKDEV(FB_MAJOR, FB_MAX));
3167 release_console_sem(); 3207 release_console_sem();
3168 give_up_console(&fb_con);
3169} 3208}
3170 3209
3171module_exit(fb_console_exit); 3210module_exit(fb_console_exit);