diff options
author | Antonino A. Daplas <adaplas@gmail.com> | 2006-06-26 03:27:06 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-26 12:58:32 -0400 |
commit | 5428b04405af1bb441aa8aabd314e48b870bc58e (patch) | |
tree | f5f94e7ddc3df72e9c323fdab82b0805cf32abe6 /drivers/video | |
parent | e55186fe5fad31962d0ea5ef267bf0c23d98abd4 (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>
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/console/fbcon.c | 155 |
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); |
195 | static void fbcon_modechanged(struct fb_info *info); | 195 | static void fbcon_modechanged(struct fb_info *info); |
196 | static void fbcon_set_all_vcs(struct fb_info *info); | 196 | static void fbcon_set_all_vcs(struct fb_info *info); |
197 | 197 | static void fbcon_start(void); | |
198 | static void fbcon_exit(void); | ||
198 | static struct class_device *fbcon_class_device; | 199 | static 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 | ||
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 | |||
3049 | static struct class_device_attribute class_device_attrs[] = { | 3074 | static 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 | ||
3054 | static int fbcon_init_class_device(void) | 3081 | static 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 | ||
3064 | static int __init fb_console_init(void) | 3091 | static 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 | |||
3100 | module_init(fb_console_init); | ||
3101 | |||
3102 | #ifdef MODULE | ||
3103 | |||
3104 | static 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 | ||
3113 | static void __exit fbcon_exit(void) | 3110 | static 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 | |||
3161 | static 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 | |||
3188 | module_init(fb_console_init); | ||
3189 | |||
3190 | #ifdef MODULE | ||
3191 | |||
3192 | static 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 | ||
3162 | static void __exit fb_console_exit(void) | 3201 | static 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 | ||
3171 | module_exit(fb_console_exit); | 3210 | module_exit(fb_console_exit); |