fbcon: allow fbcon to use the primary display driver
[safe/jmp/linux-2.6] / drivers / video / console / fbcon.c
index 7f4ed79..7ba21eb 100644 (file)
@@ -75,6 +75,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/crc32.h> /* For counting font checksums */
+#include <asm/fb.h>
 #include <asm/irq.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -125,6 +126,8 @@ 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;
+static int primary_device = -1;
+static int map_override;
 
 /* font data */
 static char fontname[40];
@@ -497,13 +500,17 @@ static int __init fb_console_setup(char *this_opt)
                
                if (!strncmp(options, "map:", 4)) {
                        options += 4;
-                       if (*options)
+                       if (*options) {
                                for (i = 0, j = 0; i < MAX_NR_CONSOLES; i++) {
                                        if (!options[j])
                                                j = 0;
                                        con2fb_map_boot[i] =
                                                (options[j++]-'0') % FB_MAX;
                                }
+
+                               map_override = 1;
+                       }
+
                        return 1;
                }
 
@@ -3004,9 +3011,9 @@ static int fbcon_mode_deleted(struct fb_info *info,
        return found;
 }
 
-static int fbcon_fb_unregistered(int idx)
+static int fbcon_fb_unregistered(struct fb_info *info)
 {
-       int i;
+       int i, idx = info->node;
 
        for (i = first_fb_vc; i <= last_fb_vc; i++) {
                if (con2fb_map[i] == idx)
@@ -3034,12 +3041,70 @@ static int fbcon_fb_unregistered(int idx)
        if (!num_registered_fb)
                unregister_con_driver(&fb_con);
 
+
+       if (primary_device == idx)
+               primary_device = -1;
+
+       return 0;
+}
+
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY
+static int fbcon_select_primary(struct fb_info *info)
+{
+       int ret = 0;
+
+       if (!map_override && primary_device == -1 &&
+           fb_is_primary_device(info)) {
+               int i, err;
+
+               printk(KERN_INFO "fbcon: %s is primary device\n",
+                      info->fix.id);
+               primary_device = info->node;
+
+               if (!con_is_bound(&fb_con))
+                       goto done;
+
+               printk(KERN_INFO "fbcon: Unbinding old driver\n");
+               unbind_con_driver(&fb_con, first_fb_vc, last_fb_vc,
+                                 fbcon_is_default);
+               info_idx = primary_device;
+
+               for (i = first_fb_vc; i <= last_fb_vc; i++) {
+                       con2fb_map_boot[i] = primary_device;
+                       con2fb_map[i] = primary_device;
+               }
+
+               printk(KERN_INFO "fbcon: Selecting new driver\n");
+               err = bind_con_driver(&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;
+               }
+
+               ret = 1;
+       }
+
+done:
+       return ret;
+}
+#else
+static inline int fbcon_select_primary(struct fb_info *info)
+{
        return 0;
 }
+#endif /* CONFIG_FRAMEBUFFER_DETECT_PRIMARY */
 
-static int fbcon_fb_registered(int idx)
+static int fbcon_fb_registered(struct fb_info *info)
 {
-       int ret = 0, i;
+       int ret = 0, i, idx = info->node;
+
+       if (fbcon_select_primary(info))
+               goto done;
+
 
        if (info_idx == -1) {
                for (i = first_fb_vc; i <= last_fb_vc; i++) {
@@ -3059,6 +3124,7 @@ static int fbcon_fb_registered(int idx)
                }
        }
 
+done:
        return ret;
 }
 
@@ -3182,10 +3248,10 @@ static int fbcon_event_notify(struct notifier_block *self,
                ret = fbcon_mode_deleted(info, mode);
                break;
        case FB_EVENT_FB_REGISTERED:
-               ret = fbcon_fb_registered(info->node);
+               ret = fbcon_fb_registered(info);
                break;
        case FB_EVENT_FB_UNREGISTERED:
-               ret = fbcon_fb_unregistered(info->node);
+               ret = fbcon_fb_unregistered(info);
                break;
        case FB_EVENT_SET_CONSOLE_MAP:
                con2fb = event->data;