summaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorAntonino A. Daplas <adaplas@gmail.com>2006-06-26 00:27:09 -0700
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-26 09:58:33 -0700
commite614b18dcedb247ce6f848e623cdf2336df2b476 (patch)
treea867f1fa177eb2ed6c577e45d297374744adca3b /drivers/video
parent3e795de7631b2366d7301182c8d91f6d2911467b (diff)
[PATCH] VT binding: Update fbcon to support binding
The control for binding/unbinding is moved from fbcon to the console layer. Thus the fbcon sysfs attributes, attach and detach, are also gone. 1. Add a notifier event that tells fbcon if a framebuffer driver has been unregistered. If no registered driver remains, fbcon will unregister itself from the console layer. 2. Replaced calls to give_up_console() with unregister_con_driver(). 3. Still use take_over_console() instead of register_con_driver() to maintain compatibility 4. Respect the parameter first_fb_vc and last_fb_vc instead of using 0 and MAX_NR_CONSOLES - 1. These parameters are settable by the user. 5. When fbcon is completely unbound from the console layer, fbcon will also release (iow, decrement module reference counts to zero) all fbdev drivers. In other words, a bind or unbind request from the console layer will propagate down to the framebuffer drivers. 6. If fbcon is not bound to the console, it will ignore all notifier events (except driver registration and unregistration) and all sysfs requests. 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.c204
-rw-r--r--drivers/video/fbmem.c7
2 files changed, 150 insertions, 61 deletions
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 4b7be685c16..26effab5a13 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -125,6 +125,8 @@ static int softback_lines;
static int first_fb_vc;
static int last_fb_vc = MAX_NR_CONSOLES - 1;
static int fbcon_is_default = 1;
+static int fbcon_has_exited;
+
/* font data */
static char fontname[40];
@@ -140,7 +142,6 @@ static const struct consw fb_con;
#define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row)
-static void fbcon_free_font(struct display *);
static int fbcon_set_origin(struct vc_data *);
#define CURSOR_DRAW_DELAY (1)
@@ -255,7 +256,7 @@ static void fbcon_rotate_all(struct fb_info *info, u32 rotate)
if (!ops || ops->currcon < 0 || rotate > 3)
return;
- for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ for (i = first_fb_vc; i <= last_fb_vc; i++) {
vc = vc_cons[i].d;
if (!vc || vc->vc_mode != KD_TEXT ||
registered_fb[con2fb_map[i]] != info)
@@ -534,7 +535,7 @@ static int search_fb_in_map(int idx)
{
int i, retval = 0;
- for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ for (i = first_fb_vc; i <= last_fb_vc; i++) {
if (con2fb_map[i] == idx)
retval = 1;
}
@@ -545,7 +546,7 @@ static int search_for_mapped_con(void)
{
int i, retval = 0;
- for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ for (i = first_fb_vc; i <= last_fb_vc; i++) {
if (con2fb_map[i] != -1)
retval = 1;
}
@@ -567,6 +568,7 @@ static int fbcon_takeover(int show_logo)
err = take_over_console(&fb_con, first_fb_vc, last_fb_vc,
fbcon_is_default);
+
if (err) {
for (i = first_fb_vc; i <= last_fb_vc; i++) {
con2fb_map[i] = -1;
@@ -801,8 +803,8 @@ static int set_con2fb_map(int unit, int newidx, int user)
if (oldidx == newidx)
return 0;
- if (!info)
- err = -EINVAL;
+ if (!info || fbcon_has_exited)
+ return -EINVAL;
if (!err && !search_for_mapped_con()) {
info_idx = newidx;
@@ -838,6 +840,9 @@ static int set_con2fb_map(int unit, int newidx, int user)
con2fb_init_display(vc, info, unit, show_logo);
}
+ if (!search_fb_in_map(info_idx))
+ info_idx = newidx;
+
release_console_sem();
return err;
}
@@ -1040,6 +1045,7 @@ static const char *fbcon_startup(void)
#endif /* CONFIG_MAC */
fbcon_add_cursor_timer(info);
+ fbcon_has_exited = 0;
return display_desc;
}
@@ -1067,17 +1073,36 @@ static void fbcon_init(struct vc_data *vc, int init)
/* If we are not the first console on this
fb, copy the font from that console */
- t = &fb_display[svc->vc_num];
- if (!vc->vc_font.data) {
- vc->vc_font.data = (void *)(p->fontdata = t->fontdata);
- vc->vc_font.width = (*default_mode)->vc_font.width;
- vc->vc_font.height = (*default_mode)->vc_font.height;
- p->userfont = t->userfont;
- if (p->userfont)
- REFCOUNT(p->fontdata)++;
+ t = &fb_display[fg_console];
+ if (!p->fontdata) {
+ if (t->fontdata) {
+ struct vc_data *fvc = vc_cons[fg_console].d;
+
+ vc->vc_font.data = (void *)(p->fontdata =
+ fvc->vc_font.data);
+ vc->vc_font.width = fvc->vc_font.width;
+ vc->vc_font.height = fvc->vc_font.height;
+ p->userfont = t->userfont;
+
+ if (p->userfont)
+ REFCOUNT(p->fontdata)++;
+ } else {
+ const struct font_desc *font = NULL;
+
+ if (!fontname[0] || !(font = find_font(fontname)))
+ font = get_default_font(info->var.xres,
+ info->var.yres);
+ vc->vc_font.width = font->width;
+ vc->vc_font.height = font->height;
+ vc->vc_font.data = (void *)(p->fontdata = font->data);
+ vc->vc_font.charcount = 256; /* FIXME Need to
+ support more fonts */
+ }
}
+
if (p->userfont)
charcnt = FNTCHARCNT(p->fontdata);
+
vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1);
vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
if (charcnt == 256) {
@@ -1151,13 +1176,47 @@ static void fbcon_init(struct vc_data *vc, int init)
ops->p = &fb_display[fg_console];
}
+static void fbcon_free_font(struct display *p)
+{
+ if (p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0))
+ kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int));
+ p->fontdata = NULL;
+ p->userfont = 0;
+}
+
static void fbcon_deinit(struct vc_data *vc)
{
struct display *p = &fb_display[vc->vc_num];
+ struct fb_info *info;
+ struct fbcon_ops *ops;
+ int idx;
- if (info_idx != -1)
- return;
fbcon_free_font(p);
+ idx = con2fb_map[vc->vc_num];
+
+ if (idx == -1)
+ goto finished;
+
+ info = registered_fb[idx];
+
+ if (!info)
+ goto finished;
+
+ ops = info->fbcon_par;
+
+ if (!ops)
+ goto finished;
+
+ if (CON_IS_VISIBLE(vc))
+ fbcon_del_cursor_timer(info);
+
+ ops->flags &= ~FBCON_FLAGS_INIT;
+finished:
+
+ if (!con_is_bound(&fb_con))
+ fbcon_exit();
+
+ return;
}
/* ====================================================================== */
@@ -2227,14 +2286,6 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
return 0;
}
-static void fbcon_free_font(struct display *p)
-{
- if (p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0))
- kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int));
- p->fontdata = NULL;
- p->userfont = 0;
-}
-
static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
{
u8 *fontdata = vc->vc_font.data;
@@ -2448,7 +2499,7 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font, unsigne
FNTSUM(new_data) = csum;
/* Check if the same font is on some other console already */
- for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ for (i = first_fb_vc; i <= last_fb_vc; i++) {
struct vc_data *tmp = vc_cons[i].d;
if (fb_display[i].userfont &&
@@ -2773,7 +2824,7 @@ static void fbcon_set_all_vcs(struct fb_info *info)
if (!ops || ops->currcon < 0)
return;
- for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ for (i = first_fb_vc; i <= last_fb_vc; i++) {
vc = vc_cons[i].d;
if (!vc || vc->vc_mode != KD_TEXT ||
registered_fb[con2fb_map[i]] != info)
@@ -2835,21 +2886,55 @@ static int fbcon_mode_deleted(struct fb_info *info,
return found;
}
+static int fbcon_fb_unregistered(int idx)
+{
+ int i;
+
+ for (i = first_fb_vc; i <= last_fb_vc; i++) {
+ if (con2fb_map[i] == idx)
+ con2fb_map[i] = -1;
+ }
+
+ if (idx == info_idx) {
+ info_idx = -1;
+
+ for (i = 0; i < FB_MAX; i++) {
+ if (registered_fb[i] != NULL) {
+ info_idx = i;
+ break;
+ }
+ }
+ }
+
+ if (info_idx != -1) {
+ for (i = first_fb_vc; i <= last_fb_vc; i++) {
+ if (con2fb_map[i] == -1)
+ con2fb_map[i] = info_idx;
+ }
+ }
+
+ if (!num_registered_fb)
+ unregister_con_driver(&fb_con);
+
+ return 0;
+}
+
static int fbcon_fb_registered(int idx)
{
int ret = 0, i;
if (info_idx == -1) {
- for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ for (i = first_fb_vc; i <= last_fb_vc; i++) {
if (con2fb_map_boot[i] == idx) {
info_idx = idx;
break;
}
}
+
if (info_idx != -1)
ret = fbcon_takeover(1);
} else {
- for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ for (i = first_fb_vc; i <= last_fb_vc; i++) {
if (con2fb_map_boot[i] == idx &&
con2fb_map[i] == -1)
set_con2fb_map(i, idx, 0);
@@ -2888,7 +2973,7 @@ static void fbcon_new_modelist(struct fb_info *info)
struct fb_var_screeninfo var;
struct fb_videomode *mode;
- for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ for (i = first_fb_vc; i <= last_fb_vc; i++) {
if (registered_fb[con2fb_map[i]] != info)
continue;
if (!fb_display[i].mode)
@@ -2916,6 +3001,14 @@ static int fbcon_event_notify(struct notifier_block *self,
struct fb_con2fbmap *con2fb;
int ret = 0;
+ /*
+ * ignore all events except driver registration and deregistration
+ * if fbcon is not active
+ */
+ if (fbcon_has_exited && !(action == FB_EVENT_FB_REGISTERED ||
+ action == FB_EVENT_FB_UNREGISTERED))
+ goto done;
+
switch(action) {
case FB_EVENT_SUSPEND:
fbcon_suspended(info);
@@ -2936,6 +3029,9 @@ static int fbcon_event_notify(struct notifier_block *self,
case FB_EVENT_FB_REGISTERED:
ret = fbcon_fb_registered(info->node);
break;
+ case FB_EVENT_FB_UNREGISTERED:
+ ret = fbcon_fb_unregistered(info->node);
+ break;
case FB_EVENT_SET_CONSOLE_MAP:
con2fb = event->data;
ret = set_con2fb_map(con2fb->console - 1,
@@ -2953,6 +3049,7 @@ static int fbcon_event_notify(struct notifier_block *self,
break;
}
+done:
return ret;
}
@@ -2997,6 +3094,9 @@ static ssize_t store_rotate(struct class_device *class_device,
int rotate, idx;
char **last = NULL;
+ if (fbcon_has_exited)
+ return count;
+
acquire_console_sem();
idx = con2fb_map[fg_console];
@@ -3018,6 +3118,9 @@ static ssize_t store_rotate_all(struct class_device *class_device,
int rotate, idx;
char **last = NULL;
+ if (fbcon_has_exited)
+ return count;
+
acquire_console_sem();
idx = con2fb_map[fg_console];
@@ -3037,6 +3140,9 @@ static ssize_t show_rotate(struct class_device *class_device, char *buf)
struct fb_info *info;
int rotate = 0, idx;
+ if (fbcon_has_exited)
+ return 0;
+
acquire_console_sem();
idx = con2fb_map[fg_console];
@@ -3050,32 +3156,9 @@ err:
return snprintf(buf, PAGE_SIZE, "%d\n", rotate);
}
-static ssize_t store_attach(struct class_device *class_device,
- const char *buf, size_t count)
-{
- if (info_idx == -1)
- fbcon_start();
-
- return count;
-}
-
-static ssize_t store_detach(struct class_device *class_device,
- const char *buf, size_t count)
-{
- if (info_idx != -1) {
- fbcon_exit();
- give_up_console(&fb_con);
- }
-
- info_idx = -1;
- return count;
-}
-
static struct class_device_attribute class_device_attrs[] = {
__ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate),
__ATTR(rotate_all, S_IWUSR, NULL, store_rotate_all),
- __ATTR(attach, S_IWUSR, NULL, store_attach),
- __ATTR(detach, S_IWUSR, NULL, store_detach),
};
static int fbcon_init_class_device(void)
@@ -3112,7 +3195,9 @@ static void fbcon_exit(void)
struct fb_info *info;
int i, j, mapped;
- acquire_console_sem();
+ if (fbcon_has_exited)
+ return;
+
#ifdef CONFIG_ATARI
free_irq(IRQ_AUTO_4, fbcon_vbl_handler);
#endif
@@ -3131,11 +3216,9 @@ static void fbcon_exit(void)
if (info == NULL)
continue;
- for (j = 0; j < MAX_NR_CONSOLES; j++) {
- if (con2fb_map[j] == i) {
- con2fb_map[j] = -1;
+ for (j = first_fb_vc; j <= last_fb_vc; j++) {
+ if (con2fb_map[j] == i)
mapped = 1;
- }
}
if (mapped) {
@@ -3151,11 +3234,10 @@ static void fbcon_exit(void)
if (info->queue.func == fb_flashcursor)
info->queue.func = NULL;
-
}
}
- release_console_sem();
+ fbcon_has_exited = 1;
}
static int __init fb_console_init(void)
@@ -3189,7 +3271,7 @@ module_init(fb_console_init);
#ifdef MODULE
-static void fbcon_deinit_class_device(void)
+static void __exit fbcon_deinit_class_device(void)
{
int i;
@@ -3204,7 +3286,9 @@ static void __exit fb_console_exit(void)
fb_unregister_client(&fbcon_event_notifier);
fbcon_deinit_class_device();
class_device_destroy(fb_class, MKDEV(FB_MAJOR, FB_MAX));
+ fbcon_exit();
release_console_sem();
+ unregister_con_driver(&fb_con);
}
module_exit(fb_console_exit);
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index a2102a543ee..31143afe7c9 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1353,6 +1353,7 @@ register_framebuffer(struct fb_info *fb_info)
int
unregister_framebuffer(struct fb_info *fb_info)
{
+ struct fb_event event;
int i;
i = fb_info->node;
@@ -1360,13 +1361,17 @@ unregister_framebuffer(struct fb_info *fb_info)
return -EINVAL;
devfs_remove("fb/%d", i);
- if (fb_info->pixmap.addr && (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
+ if (fb_info->pixmap.addr &&
+ (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
kfree(fb_info->pixmap.addr);
fb_destroy_modelist(&fb_info->modelist);
registered_fb[i]=NULL;
num_registered_fb--;
fb_cleanup_class_device(fb_info);
class_device_destroy(fb_class, MKDEV(FB_MAJOR, i));
+ event.info = fb_info;
+ blocking_notifier_call_chain(&fb_notifier_list,
+ FB_EVENT_FB_UNREGISTERED, &event);
return 0;
}