Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 623e71b0 authored by Antonino A. Daplas's avatar Antonino A. Daplas Committed by Linus Torvalds
Browse files

fbcon: allow fbcon to use the primary display driver



Allow fbcon to select the primary display adapter using the
fb_is_primary_device() arch-specific helper.  If a a primary adapter is
detected, fbcon will unbind the old adapter from the VT layer, then rebind
using the new adapter.  This requires that bind_/unbind_con_driver() be made
public.

Because this feature may produce unexpected behavior (from the user's POV),
this must be explicitly enabled in Kconfig.

[akpm@linux-foundation.org: export unbind_con_driver]
Signed-off-by: default avatarAntonino Daplas <adaplas@gmail.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 317b3c21
Loading
Loading
Loading
Loading
+1 −3
Original line number Diff line number Diff line
@@ -13,13 +13,11 @@

int fb_is_primary_device(struct fb_info *info)
{
	struct device *device;
	struct device *device = info->device;
	struct pci_dev *pci_dev = NULL;
	struct resource *res = NULL;
	int retval = 0;

	device = info->device;

	if (device)
		pci_dev = to_pci_dev(device);

+4 −4
Original line number Diff line number Diff line
@@ -2869,8 +2869,7 @@ int __init vty_init(void)

static struct class *vtconsole_class;

static int bind_con_driver(const struct consw *csw, int first, int last,
			   int deflt)
int bind_con_driver(const struct consw *csw, int first, int last, int deflt)
{
	struct module *owner = csw->owner;
	const char *desc = NULL;
@@ -2969,6 +2968,7 @@ static int bind_con_driver(const struct consw *csw, int first, int last,
	module_put(owner);
	return retval;
};
EXPORT_SYMBOL(bind_con_driver);

#ifdef CONFIG_VT_HW_CONSOLE_BINDING
static int con_is_graphics(const struct consw *csw, int first, int last)
@@ -2987,8 +2987,7 @@ static int con_is_graphics(const struct consw *csw, int first, int last)
	return retval;
}

static int unbind_con_driver(const struct consw *csw, int first, int last,
			     int deflt)
int unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
{
	struct module *owner = csw->owner;
	const struct consw *defcsw = NULL;
@@ -3073,6 +3072,7 @@ static int unbind_con_driver(const struct consw *csw, int first, int last,
	return retval;

}
EXPORT_SYMBOL(unbind_con_driver);

static int vt_bind(struct con_driver *con)
{
+20 −0
Original line number Diff line number Diff line
@@ -118,6 +118,26 @@ config FRAMEBUFFER_CONSOLE
	help
	  Low-level framebuffer-based console driver.

config FRAMEBUFFER_CONSOLE_DETECT_PRIMARY
       bool "Map the console to the primary display device"
       depends on FRAMEBUFFER_CONSOLE && VT_HW_CONSOLE_BINDING
       default n
       ---help---
         If this option is selected, the framebuffer console will
         automatically select the primary display device (if the architecture
	 supports this feature).  Otherwise, the framebuffer console will
         always select the first framebuffer driver that is loaded. The latter
         is the default behavior.

	 You can always override the automatic selection of the primary device
	 by using the fbcon=map: boot option.

	 To select this feature, "Support for binding and unbinding console
         drivers", under "Device Drivers"->"Character Devices" must be set to
	 y.

	 If unsure, select n.

config FRAMEBUFFER_CONSOLE_ROTATION
       bool "Framebuffer Console Rotation"
       depends on FRAMEBUFFER_CONSOLE
+73 −7
Original line number Diff line number Diff line
@@ -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;
+4 −0
Original line number Diff line number Diff line
@@ -75,6 +75,10 @@ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc);
int vt_waitactive(int vt);
void change_console(struct vc_data *new_vc);
void reset_vc(struct vc_data *vc);
extern int bind_con_driver(const struct consw *csw, int first, int last,
			   int deflt);
extern int unbind_con_driver(const struct consw *csw, int first, int last,
			     int deflt);

/*
 * vc_screen.c shares this temporary buffer with the console write code so that