Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
[linux-3.10.git] / drivers / video / console / fbcon.c
index f8a61e2..3cd6759 100644 (file)
@@ -529,6 +529,33 @@ static int search_for_mapped_con(void)
        return retval;
 }
 
+static int do_fbcon_takeover(int show_logo)
+{
+       int err, i;
+
+       if (!num_registered_fb)
+               return -ENODEV;
+
+       if (!show_logo)
+               logo_shown = FBCON_LOGO_DONTSHOW;
+
+       for (i = first_fb_vc; i <= last_fb_vc; i++)
+               con2fb_map[i] = info_idx;
+
+       err = do_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;
+               info_idx = -1;
+       } else {
+               fbcon_has_console_bind = 1;
+       }
+
+       return err;
+}
+
 static int fbcon_takeover(int show_logo)
 {
        int err, i;
@@ -815,6 +842,8 @@ static void con2fb_init_display(struct vc_data *vc, struct fb_info *info,
  *
  *     Maps a virtual console @unit to a frame buffer device
  *     @newidx.
+ *
+ *     This should be called with the console lock held.
  */
 static int set_con2fb_map(int unit, int newidx, int user)
 {
@@ -832,7 +861,7 @@ static int set_con2fb_map(int unit, int newidx, int user)
 
        if (!search_for_mapped_con() || !con_is_bound(&fb_con)) {
                info_idx = newidx;
-               return fbcon_takeover(0);
+               return do_fbcon_takeover(0);
        }
 
        if (oldidx != -1)
@@ -840,7 +869,6 @@ static int set_con2fb_map(int unit, int newidx, int user)
 
        found = search_fb_in_map(newidx);
 
-       console_lock();
        con2fb_map[unit] = newidx;
        if (!err && !found)
                err = con2fb_acquire_newinfo(vc, info, unit, oldidx);
@@ -867,7 +895,6 @@ static int set_con2fb_map(int unit, int newidx, int user)
        if (!search_fb_in_map(info_idx))
                info_idx = newidx;
 
-       console_unlock();
        return err;
 }
 
@@ -990,7 +1017,7 @@ static const char *fbcon_startup(void)
        }
 
        /* Setup default font */
-       if (!p->fontdata) {
+       if (!p->fontdata && !vc->vc_font.data) {
                if (!fontname[0] || !(font = find_font(fontname)))
                        font = get_default_font(info->var.xres,
                                                info->var.yres,
@@ -1000,6 +1027,8 @@ static const char *fbcon_startup(void)
                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 */
+       } else {
+               p->fontdata = vc->vc_font.data;
        }
 
        cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
@@ -1159,9 +1188,9 @@ static void fbcon_init(struct vc_data *vc, int init)
        ops->p = &fb_display[fg_console];
 }
 
-static void fbcon_free_font(struct display *p)
+static void fbcon_free_font(struct display *p, bool freefont)
 {
-       if (p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0))
+       if (freefont && p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0))
                kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int));
        p->fontdata = NULL;
        p->userfont = 0;
@@ -1173,8 +1202,8 @@ static void fbcon_deinit(struct vc_data *vc)
        struct fb_info *info;
        struct fbcon_ops *ops;
        int idx;
+       bool free_font = true;
 
-       fbcon_free_font(p);
        idx = con2fb_map[vc->vc_num];
 
        if (idx == -1)
@@ -1185,6 +1214,8 @@ static void fbcon_deinit(struct vc_data *vc)
        if (!info)
                goto finished;
 
+       if (info->flags & FBINFO_MISC_FIRMWARE)
+               free_font = false;
        ops = info->fbcon_par;
 
        if (!ops)
@@ -1196,6 +1227,8 @@ static void fbcon_deinit(struct vc_data *vc)
        ops->flags &= ~FBCON_FLAGS_INIT;
 finished:
 
+       fbcon_free_font(p, free_font);
+
        if (!con_is_bound(&fb_con))
                fbcon_exit();
 
@@ -2985,7 +3018,7 @@ static int fbcon_unbind(void)
 {
        int ret;
 
-       ret = unbind_con_driver(&fb_con, first_fb_vc, last_fb_vc,
+       ret = do_unbind_con_driver(&fb_con, first_fb_vc, last_fb_vc,
                                fbcon_is_default);
 
        if (!ret)
@@ -3000,6 +3033,7 @@ static inline int fbcon_unbind(void)
 }
 #endif /* CONFIG_VT_HW_CONSOLE_BINDING */
 
+/* called with console_lock held */
 static int fbcon_fb_unbind(int idx)
 {
        int i, new_idx = -1, ret = 0;
@@ -3026,6 +3060,7 @@ static int fbcon_fb_unbind(int idx)
        return ret;
 }
 
+/* called with console_lock held */
 static int fbcon_fb_unregistered(struct fb_info *info)
 {
        int i, idx;
@@ -3058,11 +3093,12 @@ static int fbcon_fb_unregistered(struct fb_info *info)
                primary_device = -1;
 
        if (!num_registered_fb)
-               unregister_con_driver(&fb_con);
+               do_unregister_con_driver(&fb_con);
 
        return 0;
 }
 
+/* called with console_lock held */
 static void fbcon_remap_all(int idx)
 {
        int i;
@@ -3107,6 +3143,7 @@ static inline void fbcon_select_primary(struct fb_info *info)
 }
 #endif /* CONFIG_FRAMEBUFFER_DETECT_PRIMARY */
 
+/* called with console_lock held */
 static int fbcon_fb_registered(struct fb_info *info)
 {
        int ret = 0, i, idx;
@@ -3123,7 +3160,7 @@ static int fbcon_fb_registered(struct fb_info *info)
                }
 
                if (info_idx != -1)
-                       ret = fbcon_takeover(1);
+                       ret = do_fbcon_takeover(1);
        } else {
                for (i = first_fb_vc; i <= last_fb_vc; i++) {
                        if (con2fb_map_boot[i] == idx)
@@ -3259,6 +3296,7 @@ static int fbcon_event_notify(struct notifier_block *self,
                ret = fbcon_fb_unregistered(info);
                break;
        case FB_EVENT_SET_CONSOLE_MAP:
+               /* called with console lock held */
                con2fb = event->data;
                ret = set_con2fb_map(con2fb->console - 1,
                                     con2fb->framebuffer, 1);