mirror of
https://github.com/Fishwaldo/build.git
synced 2025-06-23 14:48:34 +00:00
Rollback Linus changes related to software scrollback support which prevented bootsplash logo to show up (#2219)
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/drivers/video/fbdev/core?h=v5.8.10&id=20782abbbdfe922496a28f9cc0c3c0030f7dfb8f
This commit is contained in:
parent
3daec70153
commit
33d9a4cfc2
5 changed files with 1042 additions and 750 deletions
|
@ -78,11 +78,15 @@ compilation_prepare()
|
|||
if linux-version compare "${version}" ge 5.4; then
|
||||
|
||||
display_alert "Adding" "Kernel splash file" "info"
|
||||
if linux-version compare "${version}" ge 5.8 && linux-version compare "${version}" lt 5.9 ; then
|
||||
process_patch_file "${SRC}/patch/misc/0001-bootsplash-5.8.patch" "applying -- assumes patchlevel 5.8.10 or above"
|
||||
else
|
||||
process_patch_file "${SRC}/patch/misc/0001-bootsplash.patch" "applying"
|
||||
|
||||
if linux-version compare "${version}" ge 5.8.10; then
|
||||
|
||||
process_patch_file "${SRC}/patch/misc/bootsplash-5.8.10-0001-Revert-vgacon-remove-software-scrollback-support.patch" "applying"
|
||||
process_patch_file "${SRC}/patch/misc/bootsplash-5.8.10-0002-Revert-fbcon-remove-now-unusued-softback_lines-curso.patch" "applying"
|
||||
process_patch_file "${SRC}/patch/misc/bootsplash-5.8.10-0003-Revert-fbcon-remove-soft-scrollback-code.patch" "applying"
|
||||
fi
|
||||
|
||||
process_patch_file "${SRC}/patch/misc/0001-bootsplash.patch" "applying"
|
||||
process_patch_file "${SRC}/patch/misc/0002-bootsplash.patch" "applying"
|
||||
process_patch_file "${SRC}/patch/misc/0003-bootsplash.patch" "applying"
|
||||
process_patch_file "${SRC}/patch/misc/0004-bootsplash.patch" "applying"
|
||||
|
|
|
@ -1,746 +0,0 @@
|
|||
diff --git a/MAINTAINERS b/MAINTAINERS
|
||||
index a74227ad082e..b5633b56391e 100644
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -2705,6 +2705,14 @@ S: Supported
|
||||
F: drivers/net/bonding/
|
||||
F: include/uapi/linux/if_bonding.h
|
||||
|
||||
+BOOTSPLASH
|
||||
+M: Max Staudt <mstaudt@suse.de>
|
||||
+L: linux-fbdev@vger.kernel.org
|
||||
+S: Maintained
|
||||
+F: drivers/video/fbdev/core/bootsplash*.*
|
||||
+F: drivers/video/fbdev/core/dummycon.c
|
||||
+F: include/linux/bootsplash.h
|
||||
+
|
||||
BPF (Safe dynamic programs and tools)
|
||||
M: Alexei Starovoitov <ast@kernel.org>
|
||||
M: Daniel Borkmann <daniel@iogearbox.net>
|
||||
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
|
||||
index 7f1f1fbcef9e..f3ff976266fe 100644
|
||||
--- a/drivers/video/console/Kconfig
|
||||
+++ b/drivers/video/console/Kconfig
|
||||
@@ -151,6 +151,30 @@ config FRAMEBUFFER_CONSOLE_ROTATION
|
||||
such that other users of the framebuffer will remain normally
|
||||
oriented.
|
||||
|
||||
+config BOOTSPLASH
|
||||
+ bool "Bootup splash screen"
|
||||
+ depends on FRAMEBUFFER_CONSOLE
|
||||
+ help
|
||||
+ This option enables the Linux bootsplash screen.
|
||||
+
|
||||
+ The bootsplash is a full-screen logo or animation indicating a
|
||||
+ booting system. It replaces the classic scrolling text with a
|
||||
+ graphical alternative, similar to other systems.
|
||||
+
|
||||
+ Since this is technically implemented as a hook on top of fbcon,
|
||||
+ it can only work if the FRAMEBUFFER_CONSOLE is enabled and a
|
||||
+ framebuffer driver is active. Thus, to get a text-free boot,
|
||||
+ the system needs to boot with vesafb, efifb, or similar.
|
||||
+
|
||||
+ Once built into the kernel, the bootsplash needs to be enabled
|
||||
+ with bootsplash.enabled=1 and a splash file needs to be supplied.
|
||||
+
|
||||
+ Further documentation can be found in:
|
||||
+ Documentation/fb/bootsplash.txt
|
||||
+
|
||||
+ If unsure, say N.
|
||||
+ This is typically used by distributors and system integrators.
|
||||
+
|
||||
config STI_CONSOLE
|
||||
bool "STI text console"
|
||||
depends on PARISC
|
||||
diff --git a/drivers/video/fbdev/core/Makefile b/drivers/video/fbdev/core/Makefile
|
||||
index 73493bbd7a15..66895321928e 100644
|
||||
--- a/drivers/video/fbdev/core/Makefile
|
||||
+++ b/drivers/video/fbdev/core/Makefile
|
||||
@@ -29,3 +29,6 @@ obj-$(CONFIG_FB_SYS_IMAGEBLIT) += sysimgblt.o
|
||||
obj-$(CONFIG_FB_SYS_FOPS) += fb_sys_fops.o
|
||||
obj-$(CONFIG_FB_SVGALIB) += svgalib.o
|
||||
obj-$(CONFIG_FB_DDC) += fb_ddc.o
|
||||
+
|
||||
+obj-$(CONFIG_BOOTSPLASH) += bootsplash.o bootsplash_render.o \
|
||||
+ dummyblit.o
|
||||
diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
|
||||
new file mode 100644
|
||||
index 000000000000..e449755af268
|
||||
--- /dev/null
|
||||
+++ b/drivers/video/fbdev/core/bootsplash.c
|
||||
@@ -0,0 +1,294 @@
|
||||
+/*
|
||||
+ * Kernel based bootsplash.
|
||||
+ *
|
||||
+ * (Main file: Glue code, workers, timer, PM, kernel and userland API)
|
||||
+ *
|
||||
+ * Authors:
|
||||
+ * Max Staudt <mstaudt@suse.de>
|
||||
+ *
|
||||
+ * SPDX-License-Identifier: GPL-2.0
|
||||
+ */
|
||||
+
|
||||
+#define pr_fmt(fmt) "bootsplash: " fmt
|
||||
+
|
||||
+
|
||||
+#include <linux/atomic.h>
|
||||
+#include <linux/bootsplash.h>
|
||||
+#include <linux/console.h>
|
||||
+#include <linux/device.h> /* dev_warn() */
|
||||
+#include <linux/fb.h>
|
||||
+#include <linux/fs.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/jiffies.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/mutex.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/printk.h>
|
||||
+#include <linux/selection.h> /* console_blanked */
|
||||
+#include <linux/stringify.h>
|
||||
+#include <linux/types.h>
|
||||
+#include <linux/vmalloc.h>
|
||||
+#include <linux/vt_kern.h>
|
||||
+#include <linux/workqueue.h>
|
||||
+
|
||||
+#include "bootsplash_internal.h"
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * We only have one splash screen, so let's keep a single
|
||||
+ * instance of the internal state.
|
||||
+ */
|
||||
+static struct splash_priv splash_state;
|
||||
+
|
||||
+
|
||||
+static void splash_callback_redraw_vc(struct work_struct *ignored)
|
||||
+{
|
||||
+ if (console_blanked)
|
||||
+ return;
|
||||
+
|
||||
+ console_lock();
|
||||
+ if (vc_cons[fg_console].d)
|
||||
+ update_screen(vc_cons[fg_console].d);
|
||||
+ console_unlock();
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static bool is_fb_compatible(const struct fb_info *info)
|
||||
+{
|
||||
+ if (!(info->flags & FBINFO_BE_MATH)
|
||||
+ != !fb_be_math((struct fb_info *)info)) {
|
||||
+ dev_warn(info->device,
|
||||
+ "Can't draw on foreign endianness framebuffer.\n");
|
||||
+
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ if (info->flags & FBINFO_MISC_TILEBLITTING) {
|
||||
+ dev_warn(info->device,
|
||||
+ "Can't draw splash on tiling framebuffer.\n");
|
||||
+
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ if (info->fix.type != FB_TYPE_PACKED_PIXELS
|
||||
+ || (info->fix.visual != FB_VISUAL_TRUECOLOR
|
||||
+ && info->fix.visual != FB_VISUAL_DIRECTCOLOR)) {
|
||||
+ dev_warn(info->device,
|
||||
+ "Can't draw splash on non-packed or non-truecolor framebuffer.\n");
|
||||
+
|
||||
+ dev_warn(info->device,
|
||||
+ " type: %u visual: %u\n",
|
||||
+ info->fix.type, info->fix.visual);
|
||||
+
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ if (info->var.bits_per_pixel != 16
|
||||
+ && info->var.bits_per_pixel != 24
|
||||
+ && info->var.bits_per_pixel != 32) {
|
||||
+ dev_warn(info->device,
|
||||
+ "We only support drawing on framebuffers with 16, 24, or 32 bpp, not %d.\n",
|
||||
+ info->var.bits_per_pixel);
|
||||
+
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * Called by fbcon_switch() when an instance is activated or refreshed.
|
||||
+ */
|
||||
+void bootsplash_render_full(struct fb_info *info)
|
||||
+{
|
||||
+ if (!is_fb_compatible(info))
|
||||
+ return;
|
||||
+
|
||||
+ bootsplash_do_render_background(info);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * External status enquiry and on/off switch
|
||||
+ */
|
||||
+bool bootsplash_would_render_now(void)
|
||||
+{
|
||||
+ return !oops_in_progress
|
||||
+ && !console_blanked
|
||||
+ && bootsplash_is_enabled();
|
||||
+}
|
||||
+
|
||||
+bool bootsplash_is_enabled(void)
|
||||
+{
|
||||
+ bool was_enabled;
|
||||
+
|
||||
+ /* Make sure we have the newest state */
|
||||
+ smp_rmb();
|
||||
+
|
||||
+ was_enabled = test_bit(0, &splash_state.enabled);
|
||||
+
|
||||
+ return was_enabled;
|
||||
+}
|
||||
+
|
||||
+void bootsplash_disable(void)
|
||||
+{
|
||||
+ int was_enabled;
|
||||
+
|
||||
+ was_enabled = test_and_clear_bit(0, &splash_state.enabled);
|
||||
+
|
||||
+ if (was_enabled) {
|
||||
+ if (oops_in_progress) {
|
||||
+ /* Redraw screen now so we can see a panic */
|
||||
+ if (vc_cons[fg_console].d)
|
||||
+ update_screen(vc_cons[fg_console].d);
|
||||
+ } else {
|
||||
+ /* No urgency, redraw at next opportunity */
|
||||
+ schedule_work(&splash_state.work_redraw_vc);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void bootsplash_enable(void)
|
||||
+{
|
||||
+ bool was_enabled;
|
||||
+
|
||||
+ if (oops_in_progress)
|
||||
+ return;
|
||||
+
|
||||
+ was_enabled = test_and_set_bit(0, &splash_state.enabled);
|
||||
+
|
||||
+ if (!was_enabled)
|
||||
+ schedule_work(&splash_state.work_redraw_vc);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * Userland API via platform device in sysfs
|
||||
+ */
|
||||
+static ssize_t splash_show_enabled(struct device *dev,
|
||||
+ struct device_attribute *attr, char *buf)
|
||||
+{
|
||||
+ return sprintf(buf, "%d\n", bootsplash_is_enabled());
|
||||
+}
|
||||
+
|
||||
+static ssize_t splash_store_enabled(struct device *device,
|
||||
+ struct device_attribute *attr,
|
||||
+ const char *buf, size_t count)
|
||||
+{
|
||||
+ bool enable;
|
||||
+ int err;
|
||||
+
|
||||
+ if (!buf || !count)
|
||||
+ return -EFAULT;
|
||||
+
|
||||
+ err = kstrtobool(buf, &enable);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ if (enable)
|
||||
+ bootsplash_enable();
|
||||
+ else
|
||||
+ bootsplash_disable();
|
||||
+
|
||||
+ return count;
|
||||
+}
|
||||
+
|
||||
+static DEVICE_ATTR(enabled, 0644, splash_show_enabled, splash_store_enabled);
|
||||
+
|
||||
+
|
||||
+static struct attribute *splash_dev_attrs[] = {
|
||||
+ &dev_attr_enabled.attr,
|
||||
+ NULL
|
||||
+};
|
||||
+
|
||||
+ATTRIBUTE_GROUPS(splash_dev);
|
||||
+
|
||||
+
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * Power management fixup via platform device
|
||||
+ *
|
||||
+ * When the system is woken from sleep or restored after hibernating, we
|
||||
+ * cannot expect the screen contents to still be present in video RAM.
|
||||
+ * Thus, we have to redraw the splash if we're currently active.
|
||||
+ */
|
||||
+static int splash_resume(struct device *device)
|
||||
+{
|
||||
+ if (bootsplash_would_render_now())
|
||||
+ schedule_work(&splash_state.work_redraw_vc);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int splash_suspend(struct device *device)
|
||||
+{
|
||||
+ cancel_work_sync(&splash_state.work_redraw_vc);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static const struct dev_pm_ops splash_pm_ops = {
|
||||
+ .thaw = splash_resume,
|
||||
+ .restore = splash_resume,
|
||||
+ .resume = splash_resume,
|
||||
+ .suspend = splash_suspend,
|
||||
+ .freeze = splash_suspend,
|
||||
+};
|
||||
+
|
||||
+static struct platform_driver splash_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "bootsplash",
|
||||
+ .pm = &splash_pm_ops,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * Main init
|
||||
+ */
|
||||
+void bootsplash_init(void)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ /* Initialized already? */
|
||||
+ if (splash_state.splash_device)
|
||||
+ return;
|
||||
+
|
||||
+
|
||||
+ /* Register platform device to export user API */
|
||||
+ ret = platform_driver_register(&splash_driver);
|
||||
+ if (ret) {
|
||||
+ pr_err("platform_driver_register() failed: %d\n", ret);
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ splash_state.splash_device
|
||||
+ = platform_device_alloc("bootsplash", 0);
|
||||
+
|
||||
+ if (!splash_state.splash_device)
|
||||
+ goto err_driver;
|
||||
+
|
||||
+ splash_state.splash_device->dev.groups = splash_dev_groups;
|
||||
+
|
||||
+ ret = platform_device_add(splash_state.splash_device);
|
||||
+ if (ret) {
|
||||
+ pr_err("platform_device_add() failed: %d\n", ret);
|
||||
+ goto err_device;
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ INIT_WORK(&splash_state.work_redraw_vc, splash_callback_redraw_vc);
|
||||
+
|
||||
+ return;
|
||||
+
|
||||
+err_device:
|
||||
+ platform_device_put(splash_state.splash_device);
|
||||
+ splash_state.splash_device = NULL;
|
||||
+err_driver:
|
||||
+ platform_driver_unregister(&splash_driver);
|
||||
+err:
|
||||
+ pr_err("Failed to initialize.\n");
|
||||
+}
|
||||
diff --git a/drivers/video/fbdev/core/bootsplash_internal.h b/drivers/video/fbdev/core/bootsplash_internal.h
|
||||
new file mode 100644
|
||||
index 000000000000..b11da5cb90bf
|
||||
--- /dev/null
|
||||
+++ b/drivers/video/fbdev/core/bootsplash_internal.h
|
||||
@@ -0,0 +1,55 @@
|
||||
+/*
|
||||
+ * Kernel based bootsplash.
|
||||
+ *
|
||||
+ * (Internal data structures used at runtime)
|
||||
+ *
|
||||
+ * Authors:
|
||||
+ * Max Staudt <mstaudt@suse.de>
|
||||
+ *
|
||||
+ * SPDX-License-Identifier: GPL-2.0
|
||||
+ */
|
||||
+
|
||||
+#ifndef __BOOTSPLASH_INTERNAL_H
|
||||
+#define __BOOTSPLASH_INTERNAL_H
|
||||
+
|
||||
+
|
||||
+#include <linux/types.h>
|
||||
+#include <linux/fb.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/mutex.h>
|
||||
+#include <linux/spinlock.h>
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * Runtime types
|
||||
+ */
|
||||
+struct splash_priv {
|
||||
+ /*
|
||||
+ * Enabled/disabled state, to be used with atomic bit operations.
|
||||
+ * Bit 0: 0 = Splash hidden
|
||||
+ * 1 = Splash shown
|
||||
+ *
|
||||
+ * Note: fbcon.c uses this twice, by calling
|
||||
+ * bootsplash_would_render_now() in set_blitting_type() and
|
||||
+ * in fbcon_switch().
|
||||
+ * This is racy, but eventually consistent: Turning the
|
||||
+ * splash on/off will cause a redraw, which calls
|
||||
+ * fbcon_switch(), which calls set_blitting_type().
|
||||
+ * So the last on/off toggle will make things consistent.
|
||||
+ */
|
||||
+ unsigned long enabled;
|
||||
+
|
||||
+ /* Our gateway to userland via sysfs */
|
||||
+ struct platform_device *splash_device;
|
||||
+
|
||||
+ struct work_struct work_redraw_vc;
|
||||
+};
|
||||
+
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * Rendering functions
|
||||
+ */
|
||||
+void bootsplash_do_render_background(struct fb_info *info);
|
||||
+
|
||||
+#endif
|
||||
diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c
|
||||
new file mode 100644
|
||||
index 000000000000..4d7e0117f653
|
||||
--- /dev/null
|
||||
+++ b/drivers/video/fbdev/core/bootsplash_render.c
|
||||
@@ -0,0 +1,93 @@
|
||||
+/*
|
||||
+ * Kernel based bootsplash.
|
||||
+ *
|
||||
+ * (Rendering functions)
|
||||
+ *
|
||||
+ * Authors:
|
||||
+ * Max Staudt <mstaudt@suse.de>
|
||||
+ *
|
||||
+ * SPDX-License-Identifier: GPL-2.0
|
||||
+ */
|
||||
+
|
||||
+#define pr_fmt(fmt) "bootsplash: " fmt
|
||||
+
|
||||
+
|
||||
+#include <linux/bootsplash.h>
|
||||
+#include <linux/fb.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/printk.h>
|
||||
+#include <linux/types.h>
|
||||
+
|
||||
+#include "bootsplash_internal.h"
|
||||
+
|
||||
+
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * Rendering: Internal drawing routines
|
||||
+ */
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * Pack pixel into target format and do Big/Little Endian handling.
|
||||
+ * This would be a good place to handle endianness conversion if necessary.
|
||||
+ */
|
||||
+static inline u32 pack_pixel(const struct fb_var_screeninfo *dst_var,
|
||||
+ u8 red, u8 green, u8 blue)
|
||||
+{
|
||||
+ u32 dstpix;
|
||||
+
|
||||
+ /* Quantize pixel */
|
||||
+ red = red >> (8 - dst_var->red.length);
|
||||
+ green = green >> (8 - dst_var->green.length);
|
||||
+ blue = blue >> (8 - dst_var->blue.length);
|
||||
+
|
||||
+ /* Pack pixel */
|
||||
+ dstpix = red << (dst_var->red.offset)
|
||||
+ | green << (dst_var->green.offset)
|
||||
+ | blue << (dst_var->blue.offset);
|
||||
+
|
||||
+ /*
|
||||
+ * Move packed pixel to the beginning of the memory cell,
|
||||
+ * so we can memcpy() it out easily
|
||||
+ */
|
||||
+#ifdef __BIG_ENDIAN
|
||||
+ switch (dst_var->bits_per_pixel) {
|
||||
+ case 16:
|
||||
+ dstpix <<= 16;
|
||||
+ break;
|
||||
+ case 24:
|
||||
+ dstpix <<= 8;
|
||||
+ break;
|
||||
+ case 32:
|
||||
+ break;
|
||||
+ }
|
||||
+#else
|
||||
+ /* This is intrinsically unnecessary on Little Endian */
|
||||
+#endif
|
||||
+
|
||||
+ return dstpix;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+void bootsplash_do_render_background(struct fb_info *info)
|
||||
+{
|
||||
+ unsigned int x, y;
|
||||
+ u32 dstpix;
|
||||
+ u32 dst_octpp = info->var.bits_per_pixel / 8;
|
||||
+
|
||||
+ dstpix = pack_pixel(&info->var,
|
||||
+ 0,
|
||||
+ 0,
|
||||
+ 0);
|
||||
+
|
||||
+ for (y = 0; y < info->var.yres_virtual; y++) {
|
||||
+ u8 *dstline = info->screen_buffer + (y * info->fix.line_length);
|
||||
+
|
||||
+ for (x = 0; x < info->var.xres_virtual; x++) {
|
||||
+ memcpy(dstline, &dstpix, dst_octpp);
|
||||
+
|
||||
+ dstline += dst_octpp;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/drivers/video/fbdev/core/dummyblit.c b/drivers/video/fbdev/core/dummyblit.c
|
||||
new file mode 100644
|
||||
index 000000000000..8c22ff92ce24
|
||||
--- /dev/null
|
||||
+++ b/drivers/video/fbdev/core/dummyblit.c
|
||||
@@ -0,0 +1,89 @@
|
||||
+/*
|
||||
+ * linux/drivers/video/fbdev/core/dummyblit.c -- Dummy Blitting Operation
|
||||
+ *
|
||||
+ * Authors:
|
||||
+ * Max Staudt <mstaudt@suse.de>
|
||||
+ *
|
||||
+ * These functions are used in place of blitblit/tileblit to suppress
|
||||
+ * fbcon's text output while a splash is shown.
|
||||
+ *
|
||||
+ * Only suppressing actual rendering keeps the text buffer in the VC layer
|
||||
+ * intact and makes it easy to switch back from the bootsplash to a full
|
||||
+ * text console with a simple redraw (with the original functions in place).
|
||||
+ *
|
||||
+ * Based on linux/drivers/video/fbdev/core/bitblit.c
|
||||
+ * and linux/drivers/video/fbdev/core/tileblit.c
|
||||
+ *
|
||||
+ * SPDX-License-Identifier: GPL-2.0
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/fb.h>
|
||||
+#include <linux/vt_kern.h>
|
||||
+#include <linux/console.h>
|
||||
+#include <asm/types.h>
|
||||
+#include "fbcon.h"
|
||||
+
|
||||
+static void dummy_bmove(struct vc_data *vc, struct fb_info *info, int sy,
|
||||
+ int sx, int dy, int dx, int height, int width)
|
||||
+{
|
||||
+ ;
|
||||
+}
|
||||
+
|
||||
+static void dummy_clear(struct vc_data *vc, struct fb_info *info, int sy,
|
||||
+ int sx, int height, int width)
|
||||
+{
|
||||
+ ;
|
||||
+}
|
||||
+
|
||||
+static void dummy_putcs(struct vc_data *vc, struct fb_info *info,
|
||||
+ const unsigned short *s, int count, int yy, int xx,
|
||||
+ int fg, int bg)
|
||||
+{
|
||||
+ ;
|
||||
+}
|
||||
+
|
||||
+static void dummy_clear_margins(struct vc_data *vc, struct fb_info *info,
|
||||
+ int color, int bottom_only)
|
||||
+{
|
||||
+ ;
|
||||
+}
|
||||
+
|
||||
+static void dummy_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
||||
+ int fg, int bg)
|
||||
+{
|
||||
+ ;
|
||||
+}
|
||||
+
|
||||
+static int dummy_update_start(struct fb_info *info)
|
||||
+{
|
||||
+ /*
|
||||
+ * Copied from bitblit.c and tileblit.c
|
||||
+ *
|
||||
+ * As of Linux 4.12, nobody seems to care about our return value.
|
||||
+ */
|
||||
+ struct fbcon_ops *ops = info->fbcon_par;
|
||||
+ int err;
|
||||
+
|
||||
+ err = fb_pan_display(info, &ops->var);
|
||||
+ ops->var.xoffset = info->var.xoffset;
|
||||
+ ops->var.yoffset = info->var.yoffset;
|
||||
+ ops->var.vmode = info->var.vmode;
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+void fbcon_set_dummyops(struct fbcon_ops *ops)
|
||||
+{
|
||||
+ ops->bmove = dummy_bmove;
|
||||
+ ops->clear = dummy_clear;
|
||||
+ ops->putcs = dummy_putcs;
|
||||
+ ops->clear_margins = dummy_clear_margins;
|
||||
+ ops->cursor = dummy_cursor;
|
||||
+ ops->update_start = dummy_update_start;
|
||||
+ ops->rotate_font = NULL;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(fbcon_set_dummyops);
|
||||
+
|
||||
+MODULE_AUTHOR("Max Staudt <mstaudt@suse.de>");
|
||||
+MODULE_DESCRIPTION("Dummy Blitting Operation");
|
||||
+MODULE_LICENSE("GPL");
|
||||
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
|
||||
index 04612f938bab..9a39a6fcfe98 100644
|
||||
--- a/drivers/video/fbdev/core/fbcon.c
|
||||
+++ b/drivers/video/fbdev/core/fbcon.c
|
||||
@@ -80,6 +80,7 @@
|
||||
#include <asm/irq.h>
|
||||
|
||||
#include "fbcon.h"
|
||||
+#include <linux/bootsplash.h>
|
||||
|
||||
#ifdef FBCONDEBUG
|
||||
# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args)
|
||||
@@ -542,6 +543,8 @@ static int do_fbcon_takeover(int show_logo)
|
||||
for (i = first_fb_vc; i <= last_fb_vc; i++)
|
||||
con2fb_map[i] = info_idx;
|
||||
|
||||
+ bootsplash_init();
|
||||
+
|
||||
err = do_take_over_console(&fb_con, first_fb_vc, last_fb_vc,
|
||||
fbcon_is_default);
|
||||
|
||||
@@ -661,6 +664,9 @@ static void set_blitting_type(struct vc_data *vc, struct fb_info *info)
|
||||
else {
|
||||
fbcon_set_rotation(info);
|
||||
fbcon_set_bitops(ops);
|
||||
+
|
||||
+ if (bootsplash_would_render_now())
|
||||
+ fbcon_set_dummyops(ops);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -683,6 +689,19 @@ static void set_blitting_type(struct vc_data *vc, struct fb_info *info)
|
||||
ops->p = &fb_display[vc->vc_num];
|
||||
fbcon_set_rotation(info);
|
||||
fbcon_set_bitops(ops);
|
||||
+
|
||||
+ /*
|
||||
+ * Note:
|
||||
+ * This is *eventually correct*.
|
||||
+ * Setting the fbcon operations and drawing the splash happen at
|
||||
+ * different points in time. If the splash is enabled/disabled
|
||||
+ * in between, then bootsplash_{en,dis}able will schedule a
|
||||
+ * redraw, which will again render the splash (or not) and set
|
||||
+ * the correct fbcon ops.
|
||||
+ * The last run will then be the right one.
|
||||
+ */
|
||||
+ if (bootsplash_would_render_now())
|
||||
+ fbcon_set_dummyops(ops);
|
||||
}
|
||||
|
||||
static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount)
|
||||
@@ -2184,6 +2203,9 @@ static int fbcon_switch(struct vc_data *vc)
|
||||
info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
ops = info->fbcon_par;
|
||||
|
||||
+ if (bootsplash_would_render_now())
|
||||
+ bootsplash_render_full(info);
|
||||
+
|
||||
if (softback_top) {
|
||||
if (softback_lines)
|
||||
fbcon_set_origin(vc);
|
||||
diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h
|
||||
index 18f3ac144237..45f94347fe5e 100644
|
||||
--- a/drivers/video/fbdev/core/fbcon.h
|
||||
+++ b/drivers/video/fbdev/core/fbcon.h
|
||||
@@ -214,6 +214,11 @@ static inline int attr_col_ec(int shift, struct vc_data *vc,
|
||||
#define SCROLL_REDRAW 0x004
|
||||
#define SCROLL_PAN_REDRAW 0x005
|
||||
|
||||
+#ifdef CONFIG_BOOTSPLASH
|
||||
+extern void fbcon_set_dummyops(struct fbcon_ops *ops);
|
||||
+#else /* CONFIG_BOOTSPLASH */
|
||||
+#define fbcon_set_dummyops(x)
|
||||
+#endif /* CONFIG_BOOTSPLASH */
|
||||
#ifdef CONFIG_FB_TILEBLITTING
|
||||
extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info);
|
||||
#endif
|
||||
diff --git a/include/linux/bootsplash.h b/include/linux/bootsplash.h
|
||||
new file mode 100644
|
||||
index 000000000000..c6dd0b43180d
|
||||
--- /dev/null
|
||||
+++ b/include/linux/bootsplash.h
|
||||
@@ -0,0 +1,43 @@
|
||||
+/*
|
||||
+ * Kernel based bootsplash.
|
||||
+ *
|
||||
+ * Authors:
|
||||
+ * Max Staudt <mstaudt@suse.de>
|
||||
+ *
|
||||
+ * SPDX-License-Identifier: GPL-2.0
|
||||
+ */
|
||||
+
|
||||
+#ifndef __LINUX_BOOTSPLASH_H
|
||||
+#define __LINUX_BOOTSPLASH_H
|
||||
+
|
||||
+#include <linux/fb.h>
|
||||
+
|
||||
+
|
||||
+#ifdef CONFIG_BOOTSPLASH
|
||||
+
|
||||
+extern void bootsplash_render_full(struct fb_info *info);
|
||||
+
|
||||
+extern bool bootsplash_would_render_now(void);
|
||||
+
|
||||
+extern bool bootsplash_is_enabled(void);
|
||||
+extern void bootsplash_disable(void);
|
||||
+extern void bootsplash_enable(void);
|
||||
+
|
||||
+extern void bootsplash_init(void);
|
||||
+
|
||||
+#else /* CONFIG_BOOTSPLASH */
|
||||
+
|
||||
+#define bootsplash_render_full(x)
|
||||
+
|
||||
+#define bootsplash_would_render_now() (false)
|
||||
+
|
||||
+#define bootsplash_is_enabled() (false)
|
||||
+#define bootsplash_disable()
|
||||
+#define bootsplash_enable()
|
||||
+
|
||||
+#define bootsplash_init()
|
||||
+
|
||||
+#endif /* CONFIG_BOOTSPLASH */
|
||||
+
|
||||
+
|
||||
+#endif
|
|
@ -0,0 +1,338 @@
|
|||
From 440d5cecaf940b722f9f78a14db7f1e0bc0f61e8 Mon Sep 17 00:00:00 2001
|
||||
From: Igor Pecovnik <igor.pecovnik@gmail.com>
|
||||
Date: Mon, 21 Sep 2020 17:15:09 +0200
|
||||
Subject: [PATCH 1/3] Revert "vgacon: remove software scrollback support"
|
||||
|
||||
This reverts commit 20782abbbdfe922496a28f9cc0c3c0030f7dfb8f.
|
||||
---
|
||||
drivers/video/console/Kconfig | 46 ++++++
|
||||
drivers/video/console/vgacon.c | 221 +++++++++++++++++++++++++-
|
||||
6 files changed, 270 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
|
||||
index 39deb22a4180..5e850cc9f891 100644
|
||||
--- a/drivers/video/console/Kconfig
|
||||
+++ b/drivers/video/console/Kconfig
|
||||
@@ -22,6 +22,52 @@ config VGA_CONSOLE
|
||||
|
||||
Say Y.
|
||||
|
||||
+config VGACON_SOFT_SCROLLBACK
|
||||
+ bool "Enable Scrollback Buffer in System RAM"
|
||||
+ depends on VGA_CONSOLE
|
||||
+ default n
|
||||
+ help
|
||||
+ The scrollback buffer of the standard VGA console is located in
|
||||
+ the VGA RAM. The size of this RAM is fixed and is quite small.
|
||||
+ If you require a larger scrollback buffer, this can be placed in
|
||||
+ System RAM which is dynamically allocated during initialization.
|
||||
+ Placing the scrollback buffer in System RAM will slightly slow
|
||||
+ down the console.
|
||||
+
|
||||
+ If you want this feature, say 'Y' here and enter the amount of
|
||||
+ RAM to allocate for this buffer. If unsure, say 'N'.
|
||||
+
|
||||
+config VGACON_SOFT_SCROLLBACK_SIZE
|
||||
+ int "Scrollback Buffer Size (in KB)"
|
||||
+ depends on VGACON_SOFT_SCROLLBACK
|
||||
+ range 1 1024
|
||||
+ default "64"
|
||||
+ help
|
||||
+ Enter the amount of System RAM to allocate for scrollback
|
||||
+ buffers of VGA consoles. Each 64KB will give you approximately
|
||||
+ 16 80x25 screenfuls of scrollback buffer.
|
||||
+
|
||||
+config VGACON_SOFT_SCROLLBACK_PERSISTENT_ENABLE_BY_DEFAULT
|
||||
+ bool "Persistent Scrollback History for each console by default"
|
||||
+ depends on VGACON_SOFT_SCROLLBACK
|
||||
+ default n
|
||||
+ help
|
||||
+ Say Y here if the scrollback history should persist by default when
|
||||
+ switching between consoles. Otherwise, the scrollback history will be
|
||||
+ flushed each time the console is switched. This feature can also be
|
||||
+ enabled using the boot command line parameter
|
||||
+ 'vgacon.scrollback_persistent=1'.
|
||||
+
|
||||
+ This feature might break your tool of choice to flush the scrollback
|
||||
+ buffer, e.g. clear(1) will work fine but Debian's clear_console(1)
|
||||
+ will be broken, which might cause security issues.
|
||||
+ You can use the escape sequence \e[3J instead if this feature is
|
||||
+ activated.
|
||||
+
|
||||
+ Note that a buffer of VGACON_SOFT_SCROLLBACK_SIZE is taken for each
|
||||
+ created tty device.
|
||||
+ So if you use a RAM-constrained system, say N here.
|
||||
+
|
||||
config MDA_CONSOLE
|
||||
depends on !M68K && !PARISC && ISA
|
||||
tristate "MDA text console (dual-headed)"
|
||||
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
|
||||
index 6d0418e88ad7..e9254b3085a3 100644
|
||||
--- a/drivers/video/console/vgacon.c
|
||||
+++ b/drivers/video/console/vgacon.c
|
||||
@@ -165,6 +165,214 @@ static inline void vga_set_mem_top(struct vc_data *c)
|
||||
write_vga(12, (c->vc_visible_origin - vga_vram_base) / 2);
|
||||
}
|
||||
|
||||
+#ifdef CONFIG_VGACON_SOFT_SCROLLBACK
|
||||
+/* software scrollback */
|
||||
+struct vgacon_scrollback_info {
|
||||
+ void *data;
|
||||
+ int tail;
|
||||
+ int size;
|
||||
+ int rows;
|
||||
+ int cnt;
|
||||
+ int cur;
|
||||
+ int save;
|
||||
+ int restore;
|
||||
+};
|
||||
+
|
||||
+static struct vgacon_scrollback_info *vgacon_scrollback_cur;
|
||||
+static struct vgacon_scrollback_info vgacon_scrollbacks[MAX_NR_CONSOLES];
|
||||
+static bool scrollback_persistent = \
|
||||
+ IS_ENABLED(CONFIG_VGACON_SOFT_SCROLLBACK_PERSISTENT_ENABLE_BY_DEFAULT);
|
||||
+module_param_named(scrollback_persistent, scrollback_persistent, bool, 0000);
|
||||
+MODULE_PARM_DESC(scrollback_persistent, "Enable persistent scrollback for all vga consoles");
|
||||
+
|
||||
+static void vgacon_scrollback_reset(int vc_num, size_t reset_size)
|
||||
+{
|
||||
+ struct vgacon_scrollback_info *scrollback = &vgacon_scrollbacks[vc_num];
|
||||
+
|
||||
+ if (scrollback->data && reset_size > 0)
|
||||
+ memset(scrollback->data, 0, reset_size);
|
||||
+
|
||||
+ scrollback->cnt = 0;
|
||||
+ scrollback->tail = 0;
|
||||
+ scrollback->cur = 0;
|
||||
+}
|
||||
+
|
||||
+static void vgacon_scrollback_init(int vc_num)
|
||||
+{
|
||||
+ int pitch = vga_video_num_columns * 2;
|
||||
+ size_t size = CONFIG_VGACON_SOFT_SCROLLBACK_SIZE * 1024;
|
||||
+ int rows = size / pitch;
|
||||
+ void *data;
|
||||
+
|
||||
+ data = kmalloc_array(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE, 1024,
|
||||
+ GFP_NOWAIT);
|
||||
+
|
||||
+ vgacon_scrollbacks[vc_num].data = data;
|
||||
+ vgacon_scrollback_cur = &vgacon_scrollbacks[vc_num];
|
||||
+
|
||||
+ vgacon_scrollback_cur->rows = rows - 1;
|
||||
+ vgacon_scrollback_cur->size = rows * pitch;
|
||||
+
|
||||
+ vgacon_scrollback_reset(vc_num, size);
|
||||
+}
|
||||
+
|
||||
+static void vgacon_scrollback_switch(int vc_num)
|
||||
+{
|
||||
+ if (!scrollback_persistent)
|
||||
+ vc_num = 0;
|
||||
+
|
||||
+ if (!vgacon_scrollbacks[vc_num].data) {
|
||||
+ vgacon_scrollback_init(vc_num);
|
||||
+ } else {
|
||||
+ if (scrollback_persistent) {
|
||||
+ vgacon_scrollback_cur = &vgacon_scrollbacks[vc_num];
|
||||
+ } else {
|
||||
+ size_t size = CONFIG_VGACON_SOFT_SCROLLBACK_SIZE * 1024;
|
||||
+
|
||||
+ vgacon_scrollback_reset(vc_num, size);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void vgacon_scrollback_startup(void)
|
||||
+{
|
||||
+ vgacon_scrollback_cur = &vgacon_scrollbacks[0];
|
||||
+ vgacon_scrollback_init(0);
|
||||
+}
|
||||
+
|
||||
+static void vgacon_scrollback_update(struct vc_data *c, int t, int count)
|
||||
+{
|
||||
+ void *p;
|
||||
+
|
||||
+ if (!vgacon_scrollback_cur->data || !vgacon_scrollback_cur->size ||
|
||||
+ c->vc_num != fg_console)
|
||||
+ return;
|
||||
+
|
||||
+ p = (void *) (c->vc_origin + t * c->vc_size_row);
|
||||
+
|
||||
+ while (count--) {
|
||||
+ if ((vgacon_scrollback_cur->tail + c->vc_size_row) >
|
||||
+ vgacon_scrollback_cur->size)
|
||||
+ vgacon_scrollback_cur->tail = 0;
|
||||
+
|
||||
+ scr_memcpyw(vgacon_scrollback_cur->data +
|
||||
+ vgacon_scrollback_cur->tail,
|
||||
+ p, c->vc_size_row);
|
||||
+
|
||||
+ vgacon_scrollback_cur->cnt++;
|
||||
+ p += c->vc_size_row;
|
||||
+ vgacon_scrollback_cur->tail += c->vc_size_row;
|
||||
+
|
||||
+ if (vgacon_scrollback_cur->tail >= vgacon_scrollback_cur->size)
|
||||
+ vgacon_scrollback_cur->tail = 0;
|
||||
+
|
||||
+ if (vgacon_scrollback_cur->cnt > vgacon_scrollback_cur->rows)
|
||||
+ vgacon_scrollback_cur->cnt = vgacon_scrollback_cur->rows;
|
||||
+
|
||||
+ vgacon_scrollback_cur->cur = vgacon_scrollback_cur->cnt;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void vgacon_restore_screen(struct vc_data *c)
|
||||
+{
|
||||
+ c->vc_origin = c->vc_visible_origin;
|
||||
+ vgacon_scrollback_cur->save = 0;
|
||||
+
|
||||
+ if (!vga_is_gfx && !vgacon_scrollback_cur->restore) {
|
||||
+ scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf,
|
||||
+ c->vc_screenbuf_size > vga_vram_size ?
|
||||
+ vga_vram_size : c->vc_screenbuf_size);
|
||||
+ vgacon_scrollback_cur->restore = 1;
|
||||
+ vgacon_scrollback_cur->cur = vgacon_scrollback_cur->cnt;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void vgacon_scrolldelta(struct vc_data *c, int lines)
|
||||
+{
|
||||
+ int start, end, count, soff;
|
||||
+
|
||||
+ if (!lines) {
|
||||
+ vgacon_restore_screen(c);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (!vgacon_scrollback_cur->data)
|
||||
+ return;
|
||||
+
|
||||
+ if (!vgacon_scrollback_cur->save) {
|
||||
+ vgacon_cursor(c, CM_ERASE);
|
||||
+ vgacon_save_screen(c);
|
||||
+ c->vc_origin = (unsigned long)c->vc_screenbuf;
|
||||
+ vgacon_scrollback_cur->save = 1;
|
||||
+ }
|
||||
+
|
||||
+ vgacon_scrollback_cur->restore = 0;
|
||||
+ start = vgacon_scrollback_cur->cur + lines;
|
||||
+ end = start + abs(lines);
|
||||
+
|
||||
+ if (start < 0)
|
||||
+ start = 0;
|
||||
+
|
||||
+ if (start > vgacon_scrollback_cur->cnt)
|
||||
+ start = vgacon_scrollback_cur->cnt;
|
||||
+
|
||||
+ if (end < 0)
|
||||
+ end = 0;
|
||||
+
|
||||
+ if (end > vgacon_scrollback_cur->cnt)
|
||||
+ end = vgacon_scrollback_cur->cnt;
|
||||
+
|
||||
+ vgacon_scrollback_cur->cur = start;
|
||||
+ count = end - start;
|
||||
+ soff = vgacon_scrollback_cur->tail -
|
||||
+ ((vgacon_scrollback_cur->cnt - end) * c->vc_size_row);
|
||||
+ soff -= count * c->vc_size_row;
|
||||
+
|
||||
+ if (soff < 0)
|
||||
+ soff += vgacon_scrollback_cur->size;
|
||||
+
|
||||
+ count = vgacon_scrollback_cur->cnt - start;
|
||||
+
|
||||
+ if (count > c->vc_rows)
|
||||
+ count = c->vc_rows;
|
||||
+
|
||||
+ if (count) {
|
||||
+ int copysize;
|
||||
+
|
||||
+ int diff = c->vc_rows - count;
|
||||
+ void *d = (void *) c->vc_visible_origin;
|
||||
+ void *s = (void *) c->vc_screenbuf;
|
||||
+
|
||||
+ count *= c->vc_size_row;
|
||||
+ /* how much memory to end of buffer left? */
|
||||
+ copysize = min(count, vgacon_scrollback_cur->size - soff);
|
||||
+ scr_memcpyw(d, vgacon_scrollback_cur->data + soff, copysize);
|
||||
+ d += copysize;
|
||||
+ count -= copysize;
|
||||
+
|
||||
+ if (count) {
|
||||
+ scr_memcpyw(d, vgacon_scrollback_cur->data, count);
|
||||
+ d += count;
|
||||
+ }
|
||||
+
|
||||
+ if (diff)
|
||||
+ scr_memcpyw(d, s, diff * c->vc_size_row);
|
||||
+ } else
|
||||
+ vgacon_cursor(c, CM_MOVE);
|
||||
+}
|
||||
+
|
||||
+static void vgacon_flush_scrollback(struct vc_data *c)
|
||||
+{
|
||||
+ size_t size = CONFIG_VGACON_SOFT_SCROLLBACK_SIZE * 1024;
|
||||
+
|
||||
+ vgacon_scrollback_reset(c->vc_num, size);
|
||||
+}
|
||||
+#else
|
||||
+#define vgacon_scrollback_startup(...) do { } while (0)
|
||||
+#define vgacon_scrollback_init(...) do { } while (0)
|
||||
+#define vgacon_scrollback_update(...) do { } while (0)
|
||||
+#define vgacon_scrollback_switch(...) do { } while (0)
|
||||
+
|
||||
static void vgacon_restore_screen(struct vc_data *c)
|
||||
{
|
||||
if (c->vc_origin != c->vc_visible_origin)
|
||||
@@ -178,6 +386,11 @@ static void vgacon_scrolldelta(struct vc_data *c, int lines)
|
||||
vga_set_mem_top(c);
|
||||
}
|
||||
|
||||
+static void vgacon_flush_scrollback(struct vc_data *c)
|
||||
+{
|
||||
+}
|
||||
+#endif /* CONFIG_VGACON_SOFT_SCROLLBACK */
|
||||
+
|
||||
static const char *vgacon_startup(void)
|
||||
{
|
||||
const char *display_desc = NULL;
|
||||
@@ -360,7 +573,10 @@ static const char *vgacon_startup(void)
|
||||
vgacon_xres = screen_info.orig_video_cols * VGA_FONTWIDTH;
|
||||
vgacon_yres = vga_scan_lines;
|
||||
|
||||
- vga_init_done = true;
|
||||
+ if (!vga_init_done) {
|
||||
+ vgacon_scrollback_startup();
|
||||
+ vga_init_done = true;
|
||||
+ }
|
||||
|
||||
return display_desc;
|
||||
}
|
||||
@@ -651,6 +867,7 @@ static int vgacon_switch(struct vc_data *c)
|
||||
vgacon_doresize(c, c->vc_cols, c->vc_rows);
|
||||
}
|
||||
|
||||
+ vgacon_scrollback_switch(c->vc_num);
|
||||
return 0; /* Redrawing not needed */
|
||||
}
|
||||
|
||||
@@ -1167,6 +1384,7 @@ static bool vgacon_scroll(struct vc_data *c, unsigned int t, unsigned int b,
|
||||
oldo = c->vc_origin;
|
||||
delta = lines * c->vc_size_row;
|
||||
if (dir == SM_UP) {
|
||||
+ vgacon_scrollback_update(c, t, lines);
|
||||
if (c->vc_scr_end + delta >= vga_vram_end) {
|
||||
scr_memcpyw((u16 *) vga_vram_base,
|
||||
(u16 *) (oldo + delta),
|
||||
@@ -1230,6 +1448,7 @@ const struct consw vga_con = {
|
||||
.con_save_screen = vgacon_save_screen,
|
||||
.con_build_attr = vgacon_build_attr,
|
||||
.con_invert_region = vgacon_invert_region,
|
||||
+ .con_flush_scrollback = vgacon_flush_scrollback,
|
||||
};
|
||||
EXPORT_SYMBOL(vga_con);
|
||||
|
||||
--
|
||||
2.25.1
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
From 103bdb34be969b844d4854733adc47cdd5d7d236 Mon Sep 17 00:00:00 2001
|
||||
From: Igor Pecovnik <igor.pecovnik@gmail.com>
|
||||
Date: Mon, 21 Sep 2020 17:15:30 +0200
|
||||
Subject: [PATCH 2/3] Revert "fbcon: remove now unusued 'softback_lines'
|
||||
cursor() argument"
|
||||
|
||||
This reverts commit ffa74c8e58b8f42b2d95b29443befba2e28fb260.
|
||||
---
|
||||
drivers/video/fbdev/core/bitblit.c | 11 ++++++++++-
|
||||
drivers/video/fbdev/core/fbcon.c | 4 ++--
|
||||
drivers/video/fbdev/core/fbcon.h | 2 +-
|
||||
drivers/video/fbdev/core/fbcon_ccw.c | 11 ++++++++++-
|
||||
drivers/video/fbdev/core/fbcon_cw.c | 11 ++++++++++-
|
||||
drivers/video/fbdev/core/fbcon_ud.c | 11 ++++++++++-
|
||||
drivers/video/fbdev/core/tileblit.c | 2 +-
|
||||
7 files changed, 44 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c
|
||||
index 436365efae73..35ebeeccde4d 100644
|
||||
--- a/drivers/video/fbdev/core/bitblit.c
|
||||
+++ b/drivers/video/fbdev/core/bitblit.c
|
||||
@@ -234,7 +234,7 @@ static void bit_clear_margins(struct vc_data *vc, struct fb_info *info,
|
||||
}
|
||||
|
||||
static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
||||
- int fg, int bg)
|
||||
+ int softback_lines, int fg, int bg)
|
||||
{
|
||||
struct fb_cursor cursor;
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
@@ -247,6 +247,15 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
||||
|
||||
cursor.set = 0;
|
||||
|
||||
+ if (softback_lines) {
|
||||
+ if (y + softback_lines >= vc->vc_rows) {
|
||||
+ mode = CM_ERASE;
|
||||
+ ops->cursor_flash = 0;
|
||||
+ return;
|
||||
+ } else
|
||||
+ y += softback_lines;
|
||||
+ }
|
||||
+
|
||||
c = scr_readw((u16 *) vc->vc_pos);
|
||||
attribute = get_attribute(info, c);
|
||||
src = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height));
|
||||
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
|
||||
index b36bfe10c712..b30a667663ef 100644
|
||||
--- a/drivers/video/fbdev/core/fbcon.c
|
||||
+++ b/drivers/video/fbdev/core/fbcon.c
|
||||
@@ -394,7 +394,7 @@ static void fb_flashcursor(struct work_struct *work)
|
||||
c = scr_readw((u16 *) vc->vc_pos);
|
||||
mode = (!ops->cursor_flash || ops->cursor_state.enable) ?
|
||||
CM_ERASE : CM_DRAW;
|
||||
- ops->cursor(vc, info, mode, get_color(vc, info, c, 1),
|
||||
+ ops->cursor(vc, info, mode, 0, get_color(vc, info, c, 1),
|
||||
get_color(vc, info, c, 0));
|
||||
console_unlock();
|
||||
}
|
||||
@@ -1345,7 +1345,7 @@ static void fbcon_cursor(struct vc_data *vc, int mode)
|
||||
|
||||
ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1;
|
||||
|
||||
- ops->cursor(vc, info, mode, get_color(vc, info, c, 1),
|
||||
+ ops->cursor(vc, info, mode, 0, get_color(vc, info, c, 1),
|
||||
get_color(vc, info, c, 0));
|
||||
}
|
||||
|
||||
diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h
|
||||
index 78bb14c03643..20dea853765f 100644
|
||||
--- a/drivers/video/fbdev/core/fbcon.h
|
||||
+++ b/drivers/video/fbdev/core/fbcon.h
|
||||
@@ -62,7 +62,7 @@ struct fbcon_ops {
|
||||
void (*clear_margins)(struct vc_data *vc, struct fb_info *info,
|
||||
int color, int bottom_only);
|
||||
void (*cursor)(struct vc_data *vc, struct fb_info *info, int mode,
|
||||
- int fg, int bg);
|
||||
+ int softback_lines, int fg, int bg);
|
||||
int (*update_start)(struct fb_info *info);
|
||||
int (*rotate_font)(struct fb_info *info, struct vc_data *vc);
|
||||
struct fb_var_screeninfo var; /* copy of the current fb_var_screeninfo */
|
||||
diff --git a/drivers/video/fbdev/core/fbcon_ccw.c b/drivers/video/fbdev/core/fbcon_ccw.c
|
||||
index 71ad6967a70e..78f3a5621478 100644
|
||||
--- a/drivers/video/fbdev/core/fbcon_ccw.c
|
||||
+++ b/drivers/video/fbdev/core/fbcon_ccw.c
|
||||
@@ -219,7 +219,7 @@ static void ccw_clear_margins(struct vc_data *vc, struct fb_info *info,
|
||||
}
|
||||
|
||||
static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
||||
- int fg, int bg)
|
||||
+ int softback_lines, int fg, int bg)
|
||||
{
|
||||
struct fb_cursor cursor;
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
@@ -236,6 +236,15 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
||||
|
||||
cursor.set = 0;
|
||||
|
||||
+ if (softback_lines) {
|
||||
+ if (y + softback_lines >= vc->vc_rows) {
|
||||
+ mode = CM_ERASE;
|
||||
+ ops->cursor_flash = 0;
|
||||
+ return;
|
||||
+ } else
|
||||
+ y += softback_lines;
|
||||
+ }
|
||||
+
|
||||
c = scr_readw((u16 *) vc->vc_pos);
|
||||
attribute = get_attribute(info, c);
|
||||
src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
|
||||
diff --git a/drivers/video/fbdev/core/fbcon_cw.c b/drivers/video/fbdev/core/fbcon_cw.c
|
||||
index 31fe5dd651d4..fd098ff17574 100644
|
||||
--- a/drivers/video/fbdev/core/fbcon_cw.c
|
||||
+++ b/drivers/video/fbdev/core/fbcon_cw.c
|
||||
@@ -202,7 +202,7 @@ static void cw_clear_margins(struct vc_data *vc, struct fb_info *info,
|
||||
}
|
||||
|
||||
static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
||||
- int fg, int bg)
|
||||
+ int softback_lines, int fg, int bg)
|
||||
{
|
||||
struct fb_cursor cursor;
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
@@ -219,6 +219,15 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
||||
|
||||
cursor.set = 0;
|
||||
|
||||
+ if (softback_lines) {
|
||||
+ if (y + softback_lines >= vc->vc_rows) {
|
||||
+ mode = CM_ERASE;
|
||||
+ ops->cursor_flash = 0;
|
||||
+ return;
|
||||
+ } else
|
||||
+ y += softback_lines;
|
||||
+ }
|
||||
+
|
||||
c = scr_readw((u16 *) vc->vc_pos);
|
||||
attribute = get_attribute(info, c);
|
||||
src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
|
||||
diff --git a/drivers/video/fbdev/core/fbcon_ud.c b/drivers/video/fbdev/core/fbcon_ud.c
|
||||
index b2dd1370e39b..e165a3fad29a 100644
|
||||
--- a/drivers/video/fbdev/core/fbcon_ud.c
|
||||
+++ b/drivers/video/fbdev/core/fbcon_ud.c
|
||||
@@ -249,7 +249,7 @@ static void ud_clear_margins(struct vc_data *vc, struct fb_info *info,
|
||||
}
|
||||
|
||||
static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
||||
- int fg, int bg)
|
||||
+ int softback_lines, int fg, int bg)
|
||||
{
|
||||
struct fb_cursor cursor;
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
@@ -267,6 +267,15 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
||||
|
||||
cursor.set = 0;
|
||||
|
||||
+ if (softback_lines) {
|
||||
+ if (y + softback_lines >= vc->vc_rows) {
|
||||
+ mode = CM_ERASE;
|
||||
+ ops->cursor_flash = 0;
|
||||
+ return;
|
||||
+ } else
|
||||
+ y += softback_lines;
|
||||
+ }
|
||||
+
|
||||
c = scr_readw((u16 *) vc->vc_pos);
|
||||
attribute = get_attribute(info, c);
|
||||
src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.height));
|
||||
diff --git a/drivers/video/fbdev/core/tileblit.c b/drivers/video/fbdev/core/tileblit.c
|
||||
index eb664dbf96f6..93390312957f 100644
|
||||
--- a/drivers/video/fbdev/core/tileblit.c
|
||||
+++ b/drivers/video/fbdev/core/tileblit.c
|
||||
@@ -80,7 +80,7 @@ static void tile_clear_margins(struct vc_data *vc, struct fb_info *info,
|
||||
}
|
||||
|
||||
static void tile_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
||||
- int fg, int bg)
|
||||
+ int softback_lines, int fg, int bg)
|
||||
{
|
||||
struct fb_tilecursor cursor;
|
||||
int use_sw = (vc->vc_cursor_type & 0x10);
|
||||
--
|
||||
2.25.1
|
||||
|
|
@ -0,0 +1,512 @@
|
|||
From b204d7d23b3d15b338207b37930ebbe0141007ce Mon Sep 17 00:00:00 2001
|
||||
From: Igor Pecovnik <igor.pecovnik@gmail.com>
|
||||
Date: Mon, 21 Sep 2020 17:15:44 +0200
|
||||
Subject: [PATCH 3/3] Revert "fbcon: remove soft scrollback code"
|
||||
|
||||
This reverts commit 245a228891e3627e47921db1ec1b6612f118158b.
|
||||
---
|
||||
drivers/video/fbdev/core/fbcon.c | 334 ++++++++++++++++++++++++++++++-
|
||||
1 file changed, 330 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
|
||||
index b30a667663ef..fbf10e62bcde 100644
|
||||
--- a/drivers/video/fbdev/core/fbcon.c
|
||||
+++ b/drivers/video/fbdev/core/fbcon.c
|
||||
@@ -122,6 +122,12 @@ static int logo_lines;
|
||||
/* logo_shown is an index to vc_cons when >= 0; otherwise follows FBCON_LOGO
|
||||
enums. */
|
||||
static int logo_shown = FBCON_LOGO_CANSHOW;
|
||||
+/* Software scrollback */
|
||||
+static int fbcon_softback_size = 32768;
|
||||
+static unsigned long softback_buf, softback_curr;
|
||||
+static unsigned long softback_in;
|
||||
+static unsigned long softback_top, softback_end;
|
||||
+static int softback_lines;
|
||||
/* console mappings */
|
||||
static int first_fb_vc;
|
||||
static int last_fb_vc = MAX_NR_CONSOLES - 1;
|
||||
@@ -161,6 +167,8 @@ static int margin_color;
|
||||
|
||||
static const struct consw fb_con;
|
||||
|
||||
+#define CM_SOFTBACK (8)
|
||||
+
|
||||
#define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row)
|
||||
|
||||
static int fbcon_set_origin(struct vc_data *);
|
||||
@@ -365,6 +373,18 @@ static int get_color(struct vc_data *vc, struct fb_info *info,
|
||||
return color;
|
||||
}
|
||||
|
||||
+static void fbcon_update_softback(struct vc_data *vc)
|
||||
+{
|
||||
+ int l = fbcon_softback_size / vc->vc_size_row;
|
||||
+
|
||||
+ if (l > 5)
|
||||
+ softback_end = softback_buf + l * vc->vc_size_row;
|
||||
+ else
|
||||
+ /* Smaller scrollback makes no sense, and 0 would screw
|
||||
+ the operation totally */
|
||||
+ softback_top = 0;
|
||||
+}
|
||||
+
|
||||
static void fb_flashcursor(struct work_struct *work)
|
||||
{
|
||||
struct fb_info *info = container_of(work, struct fb_info, queue);
|
||||
@@ -394,7 +414,7 @@ static void fb_flashcursor(struct work_struct *work)
|
||||
c = scr_readw((u16 *) vc->vc_pos);
|
||||
mode = (!ops->cursor_flash || ops->cursor_state.enable) ?
|
||||
CM_ERASE : CM_DRAW;
|
||||
- ops->cursor(vc, info, mode, 0, get_color(vc, info, c, 1),
|
||||
+ ops->cursor(vc, info, mode, softback_lines, get_color(vc, info, c, 1),
|
||||
get_color(vc, info, c, 0));
|
||||
console_unlock();
|
||||
}
|
||||
@@ -451,7 +471,13 @@ static int __init fb_console_setup(char *this_opt)
|
||||
}
|
||||
|
||||
if (!strncmp(options, "scrollback:", 11)) {
|
||||
- pr_warn("Ignoring scrollback size option\n");
|
||||
+ options += 11;
|
||||
+ if (*options) {
|
||||
+ fbcon_softback_size = simple_strtoul(options, &options, 0);
|
||||
+ if (*options == 'k' || *options == 'K') {
|
||||
+ fbcon_softback_size *= 1024;
|
||||
+ }
|
||||
+ }
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -996,6 +1022,31 @@ static const char *fbcon_startup(void)
|
||||
|
||||
set_blitting_type(vc, info);
|
||||
|
||||
+ if (info->fix.type != FB_TYPE_TEXT) {
|
||||
+ if (fbcon_softback_size) {
|
||||
+ if (!softback_buf) {
|
||||
+ softback_buf =
|
||||
+ (unsigned long)
|
||||
+ kvmalloc(fbcon_softback_size,
|
||||
+ GFP_KERNEL);
|
||||
+ if (!softback_buf) {
|
||||
+ fbcon_softback_size = 0;
|
||||
+ softback_top = 0;
|
||||
+ }
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (softback_buf) {
|
||||
+ kvfree((void *) softback_buf);
|
||||
+ softback_buf = 0;
|
||||
+ softback_top = 0;
|
||||
+ }
|
||||
+ }
|
||||
+ if (softback_buf)
|
||||
+ softback_in = softback_top = softback_curr =
|
||||
+ softback_buf;
|
||||
+ softback_lines = 0;
|
||||
+ }
|
||||
+
|
||||
/* Setup default font */
|
||||
if (!p->fontdata && !vc->vc_font.data) {
|
||||
if (!fontname[0] || !(font = find_font(fontname)))
|
||||
@@ -1169,6 +1220,9 @@ static void fbcon_init(struct vc_data *vc, int init)
|
||||
if (logo)
|
||||
fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows);
|
||||
|
||||
+ if (vc == svc && softback_buf)
|
||||
+ fbcon_update_softback(vc);
|
||||
+
|
||||
if (ops->rotate_font && ops->rotate_font(info, vc)) {
|
||||
ops->rotate = FB_ROTATE_UR;
|
||||
set_blitting_type(vc, info);
|
||||
@@ -1331,6 +1385,7 @@ static void fbcon_cursor(struct vc_data *vc, int mode)
|
||||
{
|
||||
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
+ int y;
|
||||
int c = scr_readw((u16 *) vc->vc_pos);
|
||||
|
||||
ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
|
||||
@@ -1344,8 +1399,16 @@ static void fbcon_cursor(struct vc_data *vc, int mode)
|
||||
fbcon_add_cursor_timer(info);
|
||||
|
||||
ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1;
|
||||
+ if (mode & CM_SOFTBACK) {
|
||||
+ mode &= ~CM_SOFTBACK;
|
||||
+ y = softback_lines;
|
||||
+ } else {
|
||||
+ if (softback_lines)
|
||||
+ fbcon_set_origin(vc);
|
||||
+ y = 0;
|
||||
+ }
|
||||
|
||||
- ops->cursor(vc, info, mode, 0, get_color(vc, info, c, 1),
|
||||
+ ops->cursor(vc, info, mode, y, get_color(vc, info, c, 1),
|
||||
get_color(vc, info, c, 0));
|
||||
}
|
||||
|
||||
@@ -1416,6 +1479,8 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
|
||||
|
||||
if (con_is_visible(vc)) {
|
||||
update_screen(vc);
|
||||
+ if (softback_buf)
|
||||
+ fbcon_update_softback(vc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1553,6 +1618,99 @@ static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count)
|
||||
scrollback_current = 0;
|
||||
}
|
||||
|
||||
+static void fbcon_redraw_softback(struct vc_data *vc, struct fbcon_display *p,
|
||||
+ long delta)
|
||||
+{
|
||||
+ int count = vc->vc_rows;
|
||||
+ unsigned short *d, *s;
|
||||
+ unsigned long n;
|
||||
+ int line = 0;
|
||||
+
|
||||
+ d = (u16 *) softback_curr;
|
||||
+ if (d == (u16 *) softback_in)
|
||||
+ d = (u16 *) vc->vc_origin;
|
||||
+ n = softback_curr + delta * vc->vc_size_row;
|
||||
+ softback_lines -= delta;
|
||||
+ if (delta < 0) {
|
||||
+ if (softback_curr < softback_top && n < softback_buf) {
|
||||
+ n += softback_end - softback_buf;
|
||||
+ if (n < softback_top) {
|
||||
+ softback_lines -=
|
||||
+ (softback_top - n) / vc->vc_size_row;
|
||||
+ n = softback_top;
|
||||
+ }
|
||||
+ } else if (softback_curr >= softback_top
|
||||
+ && n < softback_top) {
|
||||
+ softback_lines -=
|
||||
+ (softback_top - n) / vc->vc_size_row;
|
||||
+ n = softback_top;
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (softback_curr > softback_in && n >= softback_end) {
|
||||
+ n += softback_buf - softback_end;
|
||||
+ if (n > softback_in) {
|
||||
+ n = softback_in;
|
||||
+ softback_lines = 0;
|
||||
+ }
|
||||
+ } else if (softback_curr <= softback_in && n > softback_in) {
|
||||
+ n = softback_in;
|
||||
+ softback_lines = 0;
|
||||
+ }
|
||||
+ }
|
||||
+ if (n == softback_curr)
|
||||
+ return;
|
||||
+ softback_curr = n;
|
||||
+ s = (u16 *) softback_curr;
|
||||
+ if (s == (u16 *) softback_in)
|
||||
+ s = (u16 *) vc->vc_origin;
|
||||
+ while (count--) {
|
||||
+ unsigned short *start;
|
||||
+ unsigned short *le;
|
||||
+ unsigned short c;
|
||||
+ int x = 0;
|
||||
+ unsigned short attr = 1;
|
||||
+
|
||||
+ start = s;
|
||||
+ le = advance_row(s, 1);
|
||||
+ do {
|
||||
+ c = scr_readw(s);
|
||||
+ if (attr != (c & 0xff00)) {
|
||||
+ attr = c & 0xff00;
|
||||
+ if (s > start) {
|
||||
+ fbcon_putcs(vc, start, s - start,
|
||||
+ line, x);
|
||||
+ x += s - start;
|
||||
+ start = s;
|
||||
+ }
|
||||
+ }
|
||||
+ if (c == scr_readw(d)) {
|
||||
+ if (s > start) {
|
||||
+ fbcon_putcs(vc, start, s - start,
|
||||
+ line, x);
|
||||
+ x += s - start + 1;
|
||||
+ start = s + 1;
|
||||
+ } else {
|
||||
+ x++;
|
||||
+ start++;
|
||||
+ }
|
||||
+ }
|
||||
+ s++;
|
||||
+ d++;
|
||||
+ } while (s < le);
|
||||
+ if (s > start)
|
||||
+ fbcon_putcs(vc, start, s - start, line, x);
|
||||
+ line++;
|
||||
+ if (d == (u16 *) softback_end)
|
||||
+ d = (u16 *) softback_buf;
|
||||
+ if (d == (u16 *) softback_in)
|
||||
+ d = (u16 *) vc->vc_origin;
|
||||
+ if (s == (u16 *) softback_end)
|
||||
+ s = (u16 *) softback_buf;
|
||||
+ if (s == (u16 *) softback_in)
|
||||
+ s = (u16 *) vc->vc_origin;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p,
|
||||
int line, int count, int dy)
|
||||
{
|
||||
@@ -1692,6 +1850,31 @@ static void fbcon_redraw(struct vc_data *vc, struct fbcon_display *p,
|
||||
}
|
||||
}
|
||||
|
||||
+static inline void fbcon_softback_note(struct vc_data *vc, int t,
|
||||
+ int count)
|
||||
+{
|
||||
+ unsigned short *p;
|
||||
+
|
||||
+ if (vc->vc_num != fg_console)
|
||||
+ return;
|
||||
+ p = (unsigned short *) (vc->vc_origin + t * vc->vc_size_row);
|
||||
+
|
||||
+ while (count) {
|
||||
+ scr_memcpyw((u16 *) softback_in, p, vc->vc_size_row);
|
||||
+ count--;
|
||||
+ p = advance_row(p, 1);
|
||||
+ softback_in += vc->vc_size_row;
|
||||
+ if (softback_in == softback_end)
|
||||
+ softback_in = softback_buf;
|
||||
+ if (softback_in == softback_top) {
|
||||
+ softback_top += vc->vc_size_row;
|
||||
+ if (softback_top == softback_end)
|
||||
+ softback_top = softback_buf;
|
||||
+ }
|
||||
+ }
|
||||
+ softback_curr = softback_in;
|
||||
+}
|
||||
+
|
||||
static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
|
||||
enum con_scroll dir, unsigned int count)
|
||||
{
|
||||
@@ -1714,6 +1897,8 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
|
||||
case SM_UP:
|
||||
if (count > vc->vc_rows) /* Maximum realistic size */
|
||||
count = vc->vc_rows;
|
||||
+ if (softback_top)
|
||||
+ fbcon_softback_note(vc, t, count);
|
||||
if (logo_shown >= 0)
|
||||
goto redraw_up;
|
||||
switch (p->scrollmode) {
|
||||
@@ -2084,6 +2269,14 @@ static int fbcon_switch(struct vc_data *vc)
|
||||
info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
ops = info->fbcon_par;
|
||||
|
||||
+ if (softback_top) {
|
||||
+ if (softback_lines)
|
||||
+ fbcon_set_origin(vc);
|
||||
+ softback_top = softback_curr = softback_in = softback_buf;
|
||||
+ softback_lines = 0;
|
||||
+ fbcon_update_softback(vc);
|
||||
+ }
|
||||
+
|
||||
if (logo_shown >= 0) {
|
||||
struct vc_data *conp2 = vc_cons[logo_shown].d;
|
||||
|
||||
@@ -2407,6 +2600,9 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
|
||||
int cnt;
|
||||
char *old_data = NULL;
|
||||
|
||||
+ if (con_is_visible(vc) && softback_lines)
|
||||
+ fbcon_set_origin(vc);
|
||||
+
|
||||
resize = (w != vc->vc_font.width) || (h != vc->vc_font.height);
|
||||
if (p->userfont)
|
||||
old_data = vc->vc_font.data;
|
||||
@@ -2432,6 +2628,8 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
|
||||
cols /= w;
|
||||
rows /= h;
|
||||
vc_resize(vc, cols, rows);
|
||||
+ if (con_is_visible(vc) && softback_buf)
|
||||
+ fbcon_update_softback(vc);
|
||||
} else if (con_is_visible(vc)
|
||||
&& vc->vc_mode == KD_TEXT) {
|
||||
fbcon_clear_margins(vc, 0);
|
||||
@@ -2590,7 +2788,19 @@ static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table)
|
||||
|
||||
static u16 *fbcon_screen_pos(struct vc_data *vc, int offset)
|
||||
{
|
||||
- return (u16 *) (vc->vc_origin + offset);
|
||||
+ unsigned long p;
|
||||
+ int line;
|
||||
+
|
||||
+ if (vc->vc_num != fg_console || !softback_lines)
|
||||
+ return (u16 *) (vc->vc_origin + offset);
|
||||
+ line = offset / vc->vc_size_row;
|
||||
+ if (line >= softback_lines)
|
||||
+ return (u16 *) (vc->vc_origin + offset -
|
||||
+ softback_lines * vc->vc_size_row);
|
||||
+ p = softback_curr + offset;
|
||||
+ if (p >= softback_end)
|
||||
+ p += softback_buf - softback_end;
|
||||
+ return (u16 *) p;
|
||||
}
|
||||
|
||||
static unsigned long fbcon_getxy(struct vc_data *vc, unsigned long pos,
|
||||
@@ -2604,7 +2814,22 @@ static unsigned long fbcon_getxy(struct vc_data *vc, unsigned long pos,
|
||||
|
||||
x = offset % vc->vc_cols;
|
||||
y = offset / vc->vc_cols;
|
||||
+ if (vc->vc_num == fg_console)
|
||||
+ y += softback_lines;
|
||||
ret = pos + (vc->vc_cols - x) * 2;
|
||||
+ } else if (vc->vc_num == fg_console && softback_lines) {
|
||||
+ unsigned long offset = pos - softback_curr;
|
||||
+
|
||||
+ if (pos < softback_curr)
|
||||
+ offset += softback_end - softback_buf;
|
||||
+ offset /= 2;
|
||||
+ x = offset % vc->vc_cols;
|
||||
+ y = offset / vc->vc_cols;
|
||||
+ ret = pos + (vc->vc_cols - x) * 2;
|
||||
+ if (ret == softback_end)
|
||||
+ ret = softback_buf;
|
||||
+ if (ret == softback_in)
|
||||
+ ret = vc->vc_origin;
|
||||
} else {
|
||||
/* Should not happen */
|
||||
x = y = 0;
|
||||
@@ -2632,11 +2857,106 @@ static void fbcon_invert_region(struct vc_data *vc, u16 * p, int cnt)
|
||||
a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) |
|
||||
(((a) & 0x0700) << 4);
|
||||
scr_writew(a, p++);
|
||||
+ if (p == (u16 *) softback_end)
|
||||
+ p = (u16 *) softback_buf;
|
||||
+ if (p == (u16 *) softback_in)
|
||||
+ p = (u16 *) vc->vc_origin;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void fbcon_scrolldelta(struct vc_data *vc, int lines)
|
||||
+{
|
||||
+ struct fb_info *info = registered_fb[con2fb_map[fg_console]];
|
||||
+ struct fbcon_ops *ops = info->fbcon_par;
|
||||
+ struct fbcon_display *disp = &fb_display[fg_console];
|
||||
+ int offset, limit, scrollback_old;
|
||||
+
|
||||
+ if (softback_top) {
|
||||
+ if (vc->vc_num != fg_console)
|
||||
+ return;
|
||||
+ if (vc->vc_mode != KD_TEXT || !lines)
|
||||
+ return;
|
||||
+ if (logo_shown >= 0) {
|
||||
+ struct vc_data *conp2 = vc_cons[logo_shown].d;
|
||||
+
|
||||
+ if (conp2->vc_top == logo_lines
|
||||
+ && conp2->vc_bottom == conp2->vc_rows)
|
||||
+ conp2->vc_top = 0;
|
||||
+ if (logo_shown == vc->vc_num) {
|
||||
+ unsigned long p, q;
|
||||
+ int i;
|
||||
+
|
||||
+ p = softback_in;
|
||||
+ q = vc->vc_origin +
|
||||
+ logo_lines * vc->vc_size_row;
|
||||
+ for (i = 0; i < logo_lines; i++) {
|
||||
+ if (p == softback_top)
|
||||
+ break;
|
||||
+ if (p == softback_buf)
|
||||
+ p = softback_end;
|
||||
+ p -= vc->vc_size_row;
|
||||
+ q -= vc->vc_size_row;
|
||||
+ scr_memcpyw((u16 *) q, (u16 *) p,
|
||||
+ vc->vc_size_row);
|
||||
+ }
|
||||
+ softback_in = softback_curr = p;
|
||||
+ update_region(vc, vc->vc_origin,
|
||||
+ logo_lines * vc->vc_cols);
|
||||
+ }
|
||||
+ logo_shown = FBCON_LOGO_CANSHOW;
|
||||
+ }
|
||||
+ fbcon_cursor(vc, CM_ERASE | CM_SOFTBACK);
|
||||
+ fbcon_redraw_softback(vc, disp, lines);
|
||||
+ fbcon_cursor(vc, CM_DRAW | CM_SOFTBACK);
|
||||
+ return;
|
||||
}
|
||||
+
|
||||
+ if (!scrollback_phys_max)
|
||||
+ return;
|
||||
+
|
||||
+ scrollback_old = scrollback_current;
|
||||
+ scrollback_current -= lines;
|
||||
+ if (scrollback_current < 0)
|
||||
+ scrollback_current = 0;
|
||||
+ else if (scrollback_current > scrollback_max)
|
||||
+ scrollback_current = scrollback_max;
|
||||
+ if (scrollback_current == scrollback_old)
|
||||
+ return;
|
||||
+
|
||||
+ if (fbcon_is_inactive(vc, info))
|
||||
+ return;
|
||||
+
|
||||
+ fbcon_cursor(vc, CM_ERASE);
|
||||
+
|
||||
+ offset = disp->yscroll - scrollback_current;
|
||||
+ limit = disp->vrows;
|
||||
+ switch (disp->scrollmode) {
|
||||
+ case SCROLL_WRAP_MOVE:
|
||||
+ info->var.vmode |= FB_VMODE_YWRAP;
|
||||
+ break;
|
||||
+ case SCROLL_PAN_MOVE:
|
||||
+ case SCROLL_PAN_REDRAW:
|
||||
+ limit -= vc->vc_rows;
|
||||
+ info->var.vmode &= ~FB_VMODE_YWRAP;
|
||||
+ break;
|
||||
+ }
|
||||
+ if (offset < 0)
|
||||
+ offset += limit;
|
||||
+ else if (offset >= limit)
|
||||
+ offset -= limit;
|
||||
+
|
||||
+ ops->var.xoffset = 0;
|
||||
+ ops->var.yoffset = offset * vc->vc_font.height;
|
||||
+ ops->update_start(info);
|
||||
+
|
||||
+ if (!scrollback_current)
|
||||
+ fbcon_cursor(vc, CM_DRAW);
|
||||
}
|
||||
|
||||
static int fbcon_set_origin(struct vc_data *vc)
|
||||
{
|
||||
+ if (softback_lines)
|
||||
+ fbcon_scrolldelta(vc, softback_lines);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2700,6 +3020,8 @@ static void fbcon_modechanged(struct fb_info *info)
|
||||
|
||||
fbcon_set_palette(vc, color_table);
|
||||
update_screen(vc);
|
||||
+ if (softback_buf)
|
||||
+ fbcon_update_softback(vc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3110,6 +3432,7 @@ static const struct consw fb_con = {
|
||||
.con_font_default = fbcon_set_def_font,
|
||||
.con_font_copy = fbcon_copy_font,
|
||||
.con_set_palette = fbcon_set_palette,
|
||||
+ .con_scrolldelta = fbcon_scrolldelta,
|
||||
.con_set_origin = fbcon_set_origin,
|
||||
.con_invert_region = fbcon_invert_region,
|
||||
.con_screen_pos = fbcon_screen_pos,
|
||||
@@ -3344,6 +3667,9 @@ static void fbcon_exit(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
+ kvfree((void *)softback_buf);
|
||||
+ softback_buf = 0UL;
|
||||
+
|
||||
for_each_registered_fb(i) {
|
||||
int pending = 0;
|
||||
|
||||
--
|
||||
2.25.1
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue