diff options
-rw-r--r-- | drivers/video/console/fbcon.c | 42 | ||||
-rw-r--r-- | drivers/video/fbmem.c | 26 | ||||
-rw-r--r-- | include/linux/fb.h | 2 |
3 files changed, 66 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 | ||
3007 | static 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 | ||
3016 | static inline int fbcon_unbind(void) | ||
3017 | { | ||
3018 | return -EINVAL; | ||
3019 | } | ||
3020 | #endif /* CONFIG_VT_HW_CONSOLE_BINDING */ | ||
3021 | |||
3022 | static 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 | |||
3006 | static int fbcon_fb_unregistered(struct fb_info *info) | 3045 | static 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 | ||
1339 | int | 1346 | int |
1340 | unregister_framebuffer(struct fb_info *fb_info) | 1347 | unregister_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; | 1376 | done: |
1377 | return ret; | ||
1360 | } | 1378 | } |
1361 | 1379 | ||
1362 | /** | 1380 | /** |
diff --git a/include/linux/fb.h b/include/linux/fb.h index 66226824ab68..8628423c6dd3 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h | |||
@@ -529,6 +529,8 @@ struct fb_cursor_user { | |||
529 | #define FB_EVENT_CONBLANK 0x0C | 529 | #define FB_EVENT_CONBLANK 0x0C |
530 | /* Get drawing requirements */ | 530 | /* Get drawing requirements */ |
531 | #define FB_EVENT_GET_REQ 0x0D | 531 | #define FB_EVENT_GET_REQ 0x0D |
532 | /* Unbind from the console if possible */ | ||
533 | #define FB_EVENT_FB_UNBIND 0x0E | ||
532 | 534 | ||
533 | struct fb_event { | 535 | struct fb_event { |
534 | struct fb_info *info; | 536 | struct fb_info *info; |