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; |
