aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJesse Barnes <jesse.barnes@intel.com>2007-07-17 07:05:33 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-17 13:23:11 -0400
commitcfafca8067c6defbaeb28cb898b7b3f8abdfe20d (patch)
tree93c5bae1e14a4d9bec3e9396c5dd9ef0fecfaf1d /drivers
parentafd1db1632c3f8f95cbc2786bfa122cead79db58 (diff)
fbdev: fbcon: console unregistration from unregister_framebuffer
This allows for proper console unregistration via the VT layer, and updates the FB layer to use it. This makes debugging new console drivers much easier, since you can properly clean them up before unloading. [adaplas] unregister_framebuffer() is typically called as part of the driver's module_exit(). Doing so otherwise will freeze the machine as the VT layer is holding reference counts on fbcon, and fbcon on the driver. With this change, it allows unregister_framebuffer() to be called safely anywhere as needed. Additions from the original: If multiple drivers are used by fbcon, and if one of them unregisters, a driver will take over the consoles vacated by the outgoing one (via set_con2fb_map). Once only the outgoing driver remains, then fbcon will unbind from the VT layer (if CONFIG_HW_CONSOLE_UNBINDING is set to y). It is important that these drivers implement fb_open() and fb_release() just to ensure that no other process is using the driver. Likewise, these drivers _must_ check the return value of unregister_framebuffer(). [akpm@linux-foundation.org: make fbcon_unbind() stub inline] Signed-off-by: Jesse Barnes <jesse.barnes@intel.com> Signed-off-by: Antonino Daplas <adaplas@gmail.com> Cc: Geert Uytterhoeven <geert@linux-m68k.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/video/console/fbcon.c42
-rw-r--r--drivers/video/fbmem.c26
2 files changed, 64 insertions, 4 deletions
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 9b66331020dd..decfdc8eb9cc 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -3003,6 +3003,45 @@ static int fbcon_mode_deleted(struct fb_info *info,
3003 return found; 3003 return found;
3004} 3004}
3005 3005
3006#ifdef CONFIG_VT_HW_CONSOLE_BINDING
3007static int fbcon_unbind(void)
3008{
3009 int ret;
3010
3011 ret = unbind_con_driver(&fb_con, first_fb_vc, last_fb_vc,
3012 fbcon_is_default);
3013 return ret;
3014}
3015#else
3016static inline int fbcon_unbind(void)
3017{
3018 return -EINVAL;
3019}
3020#endif /* CONFIG_VT_HW_CONSOLE_BINDING */
3021
3022static int fbcon_fb_unbind(int idx)
3023{
3024 int i, new_idx = -1, ret = 0;
3025
3026 for (i = first_fb_vc; i <= last_fb_vc; i++) {
3027 if (con2fb_map[i] != idx &&
3028 con2fb_map[i] != -1) {
3029 new_idx = i;
3030 break;
3031 }
3032 }
3033
3034 if (new_idx != -1) {
3035 for (i = first_fb_vc; i <= last_fb_vc; i++) {
3036 if (con2fb_map[i] == idx)
3037 set_con2fb_map(i, new_idx, 0);
3038 }
3039 } else
3040 ret = fbcon_unbind();
3041
3042 return ret;
3043}
3044
3006static int fbcon_fb_unregistered(struct fb_info *info) 3045static int fbcon_fb_unregistered(struct fb_info *info)
3007{ 3046{
3008 int i, idx = info->node; 3047 int i, idx = info->node;
@@ -3210,6 +3249,9 @@ static int fbcon_event_notify(struct notifier_block *self,
3210 mode = event->data; 3249 mode = event->data;
3211 ret = fbcon_mode_deleted(info, mode); 3250 ret = fbcon_mode_deleted(info, mode);
3212 break; 3251 break;
3252 case FB_EVENT_FB_UNBIND:
3253 ret = fbcon_fb_unbind(info->node);
3254 break;
3213 case FB_EVENT_FB_REGISTERED: 3255 case FB_EVENT_FB_REGISTERED:
3214 ret = fbcon_fb_registered(info); 3256 ret = fbcon_fb_registered(info);
3215 break; 3257 break;
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 8d6dbe8b8dd1..7f3a0cca0fd4 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1334,17 +1334,34 @@ register_framebuffer(struct fb_info *fb_info)
1334 * 1334 *
1335 * Returns negative errno on error, or zero for success. 1335 * Returns negative errno on error, or zero for success.
1336 * 1336 *
1337 * This function will also notify the framebuffer console
1338 * to release the driver.
1339 *
1340 * This is meant to be called within a driver's module_exit()
1341 * function. If this is called outside module_exit(), ensure
1342 * that the driver implements fb_open() and fb_release() to
1343 * check that no processes are using the device.
1337 */ 1344 */
1338 1345
1339int 1346int
1340unregister_framebuffer(struct fb_info *fb_info) 1347unregister_framebuffer(struct fb_info *fb_info)
1341{ 1348{
1342 struct fb_event event; 1349 struct fb_event event;
1343 int i; 1350 int i, ret = 0;
1344 1351
1345 i = fb_info->node; 1352 i = fb_info->node;
1346 if (!registered_fb[i]) 1353 if (!registered_fb[i]) {
1347 return -EINVAL; 1354 ret = -EINVAL;
1355 goto done;
1356 }
1357
1358 event.info = fb_info;
1359 ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event);
1360
1361 if (ret) {
1362 ret = -EINVAL;
1363 goto done;
1364 }
1348 1365
1349 if (fb_info->pixmap.addr && 1366 if (fb_info->pixmap.addr &&
1350 (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) 1367 (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
@@ -1356,7 +1373,8 @@ unregister_framebuffer(struct fb_info *fb_info)
1356 device_destroy(fb_class, MKDEV(FB_MAJOR, i)); 1373 device_destroy(fb_class, MKDEV(FB_MAJOR, i));
1357 event.info = fb_info; 1374 event.info = fb_info;
1358 fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); 1375 fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
1359 return 0; 1376done:
1377 return ret;
1360} 1378}
1361 1379
1362/** 1380/**