Merge tag 'ib-fbdev-drm-v4.19-deferred-console-takeover' of https://github.com/bzolnier/linux into fbdev-for-next
Immutable branch between fbdev and drm for the v4.19 merge window (contains the deferred console takeover feature)
This commit is contained in:
@@ -155,6 +155,13 @@ C. Boot options
|
||||
used by text. By default, this area will be black. The 'color' value
|
||||
is an integer number that depends on the framebuffer driver being used.
|
||||
|
||||
6. fbcon=nodefer
|
||||
|
||||
If the kernel is compiled with deferred fbcon takeover support, normally
|
||||
the framebuffer contents, left in place by the firmware/bootloader, will
|
||||
be preserved until there actually is some text is output to the console.
|
||||
This option causes fbcon to bind immediately to the fbdev device.
|
||||
|
||||
C. Attaching, Detaching and Unloading
|
||||
|
||||
Before going on how to attach, detach and unload the framebuffer console, an
|
||||
|
||||
@@ -150,6 +150,17 @@ config FRAMEBUFFER_CONSOLE_ROTATION
|
||||
such that other users of the framebuffer will remain normally
|
||||
oriented.
|
||||
|
||||
config FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
|
||||
bool "Framebuffer Console Deferred Takeover"
|
||||
depends on FRAMEBUFFER_CONSOLE=y && DUMMY_CONSOLE=y
|
||||
help
|
||||
If enabled this defers the framebuffer console taking over the
|
||||
console from the dummy console until the first text is displayed on
|
||||
the console. This is useful in combination with the "quiet" kernel
|
||||
commandline option to keep the framebuffer contents initially put up
|
||||
by the firmware in place, rather then replacing the contents with a
|
||||
black screen as soon as fbcon loads.
|
||||
|
||||
config STI_CONSOLE
|
||||
bool "STI text console"
|
||||
depends on PARISC && HAS_IOMEM
|
||||
|
||||
@@ -26,6 +26,65 @@
|
||||
#define DUMMY_ROWS CONFIG_DUMMY_CONSOLE_ROWS
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
|
||||
/* These are both protected by the console_lock */
|
||||
static RAW_NOTIFIER_HEAD(dummycon_output_nh);
|
||||
static bool dummycon_putc_called;
|
||||
|
||||
void dummycon_register_output_notifier(struct notifier_block *nb)
|
||||
{
|
||||
raw_notifier_chain_register(&dummycon_output_nh, nb);
|
||||
|
||||
if (dummycon_putc_called)
|
||||
nb->notifier_call(nb, 0, NULL);
|
||||
}
|
||||
|
||||
void dummycon_unregister_output_notifier(struct notifier_block *nb)
|
||||
{
|
||||
raw_notifier_chain_unregister(&dummycon_output_nh, nb);
|
||||
}
|
||||
|
||||
static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos)
|
||||
{
|
||||
dummycon_putc_called = true;
|
||||
raw_notifier_call_chain(&dummycon_output_nh, 0, NULL);
|
||||
}
|
||||
|
||||
static void dummycon_putcs(struct vc_data *vc, const unsigned short *s,
|
||||
int count, int ypos, int xpos)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!dummycon_putc_called) {
|
||||
/* Ignore erases */
|
||||
for (i = 0 ; i < count; i++) {
|
||||
if (s[i] != vc->vc_video_erase_char)
|
||||
break;
|
||||
}
|
||||
if (i == count)
|
||||
return;
|
||||
|
||||
dummycon_putc_called = true;
|
||||
}
|
||||
|
||||
raw_notifier_call_chain(&dummycon_output_nh, 0, NULL);
|
||||
}
|
||||
|
||||
static int dummycon_blank(struct vc_data *vc, int blank, int mode_switch)
|
||||
{
|
||||
/* Redraw, so that we get putc(s) for output done while blanked */
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos) { }
|
||||
static void dummycon_putcs(struct vc_data *vc, const unsigned short *s,
|
||||
int count, int ypos, int xpos) { }
|
||||
static int dummycon_blank(struct vc_data *vc, int blank, int mode_switch)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const char *dummycon_startup(void)
|
||||
{
|
||||
return "dummy device";
|
||||
@@ -44,9 +103,6 @@ static void dummycon_init(struct vc_data *vc, int init)
|
||||
static void dummycon_deinit(struct vc_data *vc) { }
|
||||
static void dummycon_clear(struct vc_data *vc, int sy, int sx, int height,
|
||||
int width) { }
|
||||
static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos) { }
|
||||
static void dummycon_putcs(struct vc_data *vc, const unsigned short *s,
|
||||
int count, int ypos, int xpos) { }
|
||||
static void dummycon_cursor(struct vc_data *vc, int mode) { }
|
||||
|
||||
static bool dummycon_scroll(struct vc_data *vc, unsigned int top,
|
||||
@@ -61,11 +117,6 @@ static int dummycon_switch(struct vc_data *vc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dummycon_blank(struct vc_data *vc, int blank, int mode_switch)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dummycon_font_set(struct vc_data *vc, struct console_font *font,
|
||||
unsigned int flags)
|
||||
{
|
||||
|
||||
@@ -129,6 +129,12 @@ static inline void fbcon_map_override(void)
|
||||
}
|
||||
#endif /* CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY */
|
||||
|
||||
#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
|
||||
static bool deferred_takeover = true;
|
||||
#else
|
||||
#define deferred_takeover false
|
||||
#endif
|
||||
|
||||
/* font data */
|
||||
static char fontname[40];
|
||||
|
||||
@@ -499,6 +505,12 @@ static int __init fb_console_setup(char *this_opt)
|
||||
margin_color = simple_strtoul(options, &options, 0);
|
||||
continue;
|
||||
}
|
||||
#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
|
||||
if (!strcmp(options, "nodefer")) {
|
||||
deferred_takeover = false;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -828,6 +840,8 @@ static int set_con2fb_map(int unit, int newidx, int user)
|
||||
struct fb_info *oldinfo = NULL;
|
||||
int found, err = 0;
|
||||
|
||||
WARN_CONSOLE_UNLOCKED();
|
||||
|
||||
if (oldidx == newidx)
|
||||
return 0;
|
||||
|
||||
@@ -3044,6 +3058,8 @@ static int fbcon_fb_unbind(int idx)
|
||||
{
|
||||
int i, new_idx = -1, ret = 0;
|
||||
|
||||
WARN_CONSOLE_UNLOCKED();
|
||||
|
||||
if (!fbcon_has_console_bind)
|
||||
return 0;
|
||||
|
||||
@@ -3094,6 +3110,11 @@ static int fbcon_fb_unregistered(struct fb_info *info)
|
||||
{
|
||||
int i, idx;
|
||||
|
||||
WARN_CONSOLE_UNLOCKED();
|
||||
|
||||
if (deferred_takeover)
|
||||
return 0;
|
||||
|
||||
idx = info->node;
|
||||
for (i = first_fb_vc; i <= last_fb_vc; i++) {
|
||||
if (con2fb_map[i] == idx)
|
||||
@@ -3131,6 +3152,16 @@ static int fbcon_fb_unregistered(struct fb_info *info)
|
||||
static void fbcon_remap_all(int idx)
|
||||
{
|
||||
int i;
|
||||
|
||||
WARN_CONSOLE_UNLOCKED();
|
||||
|
||||
if (deferred_takeover) {
|
||||
for (i = first_fb_vc; i <= last_fb_vc; i++)
|
||||
con2fb_map_boot[i] = idx;
|
||||
fbcon_map_override();
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = first_fb_vc; i <= last_fb_vc; i++)
|
||||
set_con2fb_map(i, idx, 0);
|
||||
|
||||
@@ -3177,9 +3208,16 @@ static int fbcon_fb_registered(struct fb_info *info)
|
||||
{
|
||||
int ret = 0, i, idx;
|
||||
|
||||
WARN_CONSOLE_UNLOCKED();
|
||||
|
||||
idx = info->node;
|
||||
fbcon_select_primary(info);
|
||||
|
||||
if (deferred_takeover) {
|
||||
pr_info("fbcon: Deferring console take-over\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (info_idx == -1) {
|
||||
for (i = first_fb_vc; i <= last_fb_vc; i++) {
|
||||
if (con2fb_map_boot[i] == idx) {
|
||||
@@ -3555,8 +3593,46 @@ static int fbcon_init_device(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
|
||||
static struct notifier_block fbcon_output_nb;
|
||||
|
||||
static int fbcon_output_notifier(struct notifier_block *nb,
|
||||
unsigned long action, void *data)
|
||||
{
|
||||
int i;
|
||||
|
||||
WARN_CONSOLE_UNLOCKED();
|
||||
|
||||
pr_info("fbcon: Taking over console\n");
|
||||
|
||||
dummycon_unregister_output_notifier(&fbcon_output_nb);
|
||||
deferred_takeover = false;
|
||||
logo_shown = FBCON_LOGO_DONTSHOW;
|
||||
|
||||
for (i = 0; i < FB_MAX; i++) {
|
||||
if (registered_fb[i])
|
||||
fbcon_fb_registered(registered_fb[i]);
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static void fbcon_register_output_notifier(void)
|
||||
{
|
||||
fbcon_output_nb.notifier_call = fbcon_output_notifier;
|
||||
dummycon_register_output_notifier(&fbcon_output_nb);
|
||||
}
|
||||
#else
|
||||
static inline void fbcon_register_output_notifier(void) {}
|
||||
#endif
|
||||
|
||||
static void fbcon_start(void)
|
||||
{
|
||||
if (deferred_takeover) {
|
||||
fbcon_register_output_notifier();
|
||||
return;
|
||||
}
|
||||
|
||||
if (num_registered_fb) {
|
||||
int i;
|
||||
|
||||
@@ -3583,6 +3659,13 @@ static void fbcon_exit(void)
|
||||
if (fbcon_has_exited)
|
||||
return;
|
||||
|
||||
#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
|
||||
if (deferred_takeover) {
|
||||
dummycon_unregister_output_notifier(&fbcon_output_nb);
|
||||
deferred_takeover = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
kfree((void *)softback_buf);
|
||||
softback_buf = 0UL;
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ struct console_font_op;
|
||||
struct console_font;
|
||||
struct module;
|
||||
struct tty_struct;
|
||||
struct notifier_block;
|
||||
|
||||
/*
|
||||
* this is what the terminal answers to a ESC-Z or csi0c query.
|
||||
@@ -220,4 +221,8 @@ static inline bool vgacon_text_force(void) { return false; }
|
||||
|
||||
extern void console_init(void);
|
||||
|
||||
/* For deferred console takeover */
|
||||
void dummycon_register_output_notifier(struct notifier_block *nb);
|
||||
void dummycon_unregister_output_notifier(struct notifier_block *nb);
|
||||
|
||||
#endif /* _LINUX_CONSOLE_H */
|
||||
|
||||
@@ -2243,6 +2243,7 @@ int is_console_locked(void)
|
||||
{
|
||||
return console_locked;
|
||||
}
|
||||
EXPORT_SYMBOL(is_console_locked);
|
||||
|
||||
/*
|
||||
* Check if we have any console that is capable of printing while cpu is
|
||||
|
||||
Reference in New Issue
Block a user