kernel: drop dead code & patches from long-disabled kernel-drivers.sh/drivers_network.sh stuff

- this has been dead code (never called) for some 6 months now
- having it there makes it hard to find the actual/real callpoints of non-dead code
This commit is contained in:
Ricardo Pardini
2023-06-13 19:29:46 +02:00
committed by Igor
parent 92aa7b3de2
commit 5ebbe5c4f6
36 changed files with 1 additions and 5837 deletions

View File

@@ -16,7 +16,7 @@ function kernel_drivers_create_patches() {
kernel_drivers_patch_file="undetermined" # outer scope
declare hash_files # any changes in these files will trigger a cache miss; also any changes in misc .patch with "wireless" at start or "wifi" anywhere in the name
calculate_hash_for_files "${SRC}/lib/functions/compilation/patch/drivers_network.sh" "${SRC}/lib/functions/compilation/patch/drivers-harness.sh" "${SRC}"/patch/misc/wireless*.patch "${SRC}"/patch/misc/*wifi*.patch
calculate_hash_for_files "${SRC}/lib/functions/compilation/patch/drivers_network.sh" "${SRC}/lib/functions/compilation/patch/drivers-harness.sh" "${SRC}"/patch/misc/wireless*.patch
declare cache_key_base="${KERNEL_MAJOR_MINOR}_${LINUXFAMILY}"
declare cache_key="${cache_key_base}_${hash_files}"

View File

@@ -688,28 +688,3 @@ driver_rtl8723cs() {
fi
}
patch_drivers_network() {
display_alert "Patching network related drivers"
driver_generic_bring_back_ipx
driver_rtl8152_rtl8153
driver_rtl8189ES
driver_rtl8189FS
driver_rtl8192EU
driver_rtl8811_rtl8812_rtl8814_rtl8821
driver_xradio_xr819
driver_rtl8811CU_rtl8821C
driver_rtl8188EU_rtl8188ETV
driver_rtl88x2bu
driver_rtw88
driver_rtl88x2cs
driver_rtl8822cs_bt
driver_rtl8723DS
driver_rtl8723DU
driver_rtl8822BS
driver_uwe5622_allwinner
driver_rtl8723cs
display_alert "Network related drivers patched" "" "info"
}

View File

@@ -1,288 +0,0 @@
#!/usr/bin/env bash
#
# SPDX-License-Identifier: GPL-2.0
#
# Copyright (c) 2013-2023 Igor Pecovnik, igor@armbian.com
#
# This file is a part of the Armbian Build Framework
# https://github.com/armbian/build/
# @TODO: armbian-next: THIS IS DEAD CODE. no-one calls it. a JIRA for volunteers to fix it, or it will be removed.
function prepare_extra_kernel_drivers() {
source ${SRC}/lib/functions/compilation/patch/drivers_network.sh
# Packaging patch for modern kernels should be one for all.
# Currently we have it per kernel family since we can't have one
# Maintaining one from central location starting with 5.3+
# Temporally set for new "default->legacy,next->current" family naming
if linux-version compare "${version}" ge 5.10; then
if linux-version compare "${version}" le 5.11; then
# Patch python2 path for legacy kernels running on newer Debian Bulleys / Ubuntu Kinetic
# Debian has a deb package the symlinks /usr/bin/python3 to /usr/bin/python so better off to Patch older Kernels
display_alert "Patching" "python" "info"
process_patch_file "${SRC}/patch/misc/general-kernel-python2-5.10.y.patch" "applying"
fi
if test -d ${kerneldir}/debian; then
rm -rf ${kerneldir}/debian/*
fi
sed -i -e '
s/^KBUILD_IMAGE := \$(boot)\/Image\.gz$/KBUILD_IMAGE := \$(boot)\/Image/
' ${kerneldir}/arch/arm64/Makefile
rm -f ${kerneldir}/scripts/package/{builddeb,mkdebian}
cp ${SRC}/packages/armbian/builddeb ${kerneldir}/scripts/package/builddeb
cp ${SRC}/packages/armbian/mkdebian ${kerneldir}/scripts/package/mkdebian
chmod 755 ${kerneldir}/scripts/package/{builddeb,mkdebian}
elif linux-version compare "${version}" ge 5.8.17 &&
linux-version compare "${version}" le 5.9 ||
linux-version compare "${version}" ge 5.9.2; then
display_alert "Adjusting" "packaging" "info"
cd "$kerneldir" || exit
process_patch_file "${SRC}/patch/misc/general-packaging-5.8-9.y.patch" "applying"
elif linux-version compare "${version}" ge 5.6; then
display_alert "Adjusting" "packaging" "info"
cd "$kerneldir" || exit
process_patch_file "${SRC}/patch/misc/general-packaging-5.6.y.patch" "applying"
elif linux-version compare "${version}" ge 5.3; then
display_alert "Adjusting" "packaging" "info"
cd "$kerneldir" || exit
process_patch_file "${SRC}/patch/misc/general-packaging-5.3.y.patch" "applying"
fi
if [[ "${version}" == "4.19."* ]] && [[ "$LINUXFAMILY" == sunxi* || "$LINUXFAMILY" == meson64 ||
"$LINUXFAMILY" == mvebu64 || "$LINUXFAMILY" == mt7623 || "$LINUXFAMILY" == mvebu ]]; then
display_alert "Adjusting" "packaging" "info"
cd "$kerneldir" || exit
process_patch_file "${SRC}/patch/misc/general-packaging-4.19.y.patch" "applying"
fi
if [[ "${version}" == "4.19."* ]] && [[ "$LINUXFAMILY" == rk35xx ]]; then
display_alert "Adjusting" "packaging" "info"
cd "$kerneldir" || exit
process_patch_file "${SRC}/patch/misc/general-packaging-4.19.y-rk35xx.patch" "applying"
fi
if [[ "${version}" == "4.14."* ]] && [[ "$LINUXFAMILY" == s5p6818 || "$LINUXFAMILY" == mvebu64 ||
"$LINUXFAMILY" == imx7d || "$LINUXFAMILY" == odroidxu4 || "$LINUXFAMILY" == mvebu ]]; then
display_alert "Adjusting" "packaging" "info"
cd "$kerneldir" || exit
process_patch_file "${SRC}/patch/misc/general-packaging-4.14.y.patch" "applying"
fi
if [[ "${version}" == "4.4."* || "${version}" == "4.9."* ]] &&
[[ "$LINUXFAMILY" == rockpis || "$LINUXFAMILY" == rk3399 ]]; then
display_alert "Adjusting" "packaging" "info"
cd "$kerneldir" || exit
process_patch_file "${SRC}/patch/misc/general-packaging-4.4.y-rk3399.patch" "applying"
fi
if [[ "${version}" == "4.4."* ]] &&
[[ "$LINUXFAMILY" == rockchip64 || "$LINUXFAMILY" == media* ]]; then
display_alert "Adjusting" "packaging" "info"
cd "$kerneldir" || exit
if [[ $BOARD == nanopct4 ]]; then
process_patch_file "${SRC}/patch/misc/general-packaging-4.4.y-rk3399.patch" "applying"
else
process_patch_file "${SRC}/patch/misc/general-packaging-4.4.y-rockchip64.patch" "applying"
fi
fi
if [[ "${version}" == "4.4."* ]] && [[ "$LINUXFAMILY" == rockchip || "$LINUXFAMILY" == rk322x ]]; then
display_alert "Adjusting" "packaging" "info"
cd "$kerneldir" || exit
process_patch_file "${SRC}/patch/misc/general-packaging-4.4.y.patch" "applying"
fi
if [[ "${version}" == "4.9."* ]] && [[ "$LINUXFAMILY" == meson64 || "$LINUXFAMILY" == odroidc4 ]]; then
display_alert "Adjusting" "packaging" "info"
cd "$kerneldir" || exit
process_patch_file "${SRC}/patch/misc/general-packaging-4.9.y.patch" "applying"
fi
# After the patches have been applied,
# check and add debian package compression if required.
#
if [ "$(awk '/dpkg --build/{print $1}' $kerneldir/scripts/package/builddeb)" == "dpkg" ]; then
sed -i -e '
s/dpkg --build/dpkg-deb \${KDEB_COMPRESS:+-Z\$KDEB_COMPRESS} --build/
' "$kerneldir"/scripts/package/builddeb
fi
#
# Linux splash file (legacy)
#
# since plymouth introduction, boot scripts are not supporting this method anymore.
# In order to enable it, you need to use this: setenv consoleargs "bootsplash.bootfile=bootsplash.armbian ${consoleargs}"
if linux-version compare "${version}" ge 5.15 && linux-version compare "${version}" lt 6.1 && [ "${SKIP_BOOTSPLASH}" != yes ]; then
display_alert "Adding" "Kernel splash file" "info"
if linux-version compare "${version}" ge 5.19.6 ||
(linux-version compare "${version}" ge 5.15.64 && linux-version compare "${version}" lt 5.16); then
process_patch_file "${SRC}/patch/misc/bootsplash-5.19.y-Revert-fbdev-fbcon-release-buffer-when-fbcon_do_set.patch" "applying"
process_patch_file "${SRC}/patch/misc/bootsplash-5.19.y-Revert-fbdev-fbcon-Properly-revert-changes-when-vc_r.patch" "applying"
fi
process_patch_file "${SRC}/patch/misc/bootsplash-5.16.y-0000-Revert-fbcon-Avoid-cap-set-but-not-used-warning.patch" "applying"
process_patch_file "${SRC}/patch/misc/bootsplash-5.16.y-Revert-fbcon-Fix-accelerated-fbdev-scrolling-while-logo-is-still-shown.patch" "applying"
process_patch_file "${SRC}/patch/misc/bootsplash-5.16.y-0001-Revert-fbcon-Add-option-to-enable-legacy-hardware-ac.patch" "applying"
process_patch_file "${SRC}/patch/misc/bootsplash-5.16.y-0002-Revert-vgacon-drop-unused-vga_init_done.patch" "applying"
process_patch_file "${SRC}/patch/misc/bootsplash-5.16.y-0003-Revert-vgacon-remove-software-scrollback-support.patch" "applying"
process_patch_file "${SRC}/patch/misc/bootsplash-5.16.y-0004-Revert-drivers-video-fbcon-fix-NULL-dereference-in-f.patch" "applying"
process_patch_file "${SRC}/patch/misc/bootsplash-5.16.y-0005-Revert-fbcon-remove-no-op-fbcon_set_origin.patch" "applying"
process_patch_file "${SRC}/patch/misc/bootsplash-5.16.y-0006-Revert-fbcon-remove-now-unusued-softback_lines-curso.patch" "applying"
process_patch_file "${SRC}/patch/misc/bootsplash-5.16.y-0007-Revert-fbcon-remove-soft-scrollback-code.patch" "applying"
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"
process_patch_file "${SRC}/patch/misc/0005-bootsplash.patch" "applying"
process_patch_file "${SRC}/patch/misc/0006-bootsplash.patch" "applying"
process_patch_file "${SRC}/patch/misc/0007-bootsplash.patch" "applying"
process_patch_file "${SRC}/patch/misc/0008-bootsplash.patch" "applying"
process_patch_file "${SRC}/patch/misc/0009-bootsplash.patch" "applying"
process_patch_file "${SRC}/patch/misc/0010-bootsplash.patch" "applying"
process_patch_file "${SRC}/patch/misc/0011-bootsplash.patch" "applying"
process_patch_file "${SRC}/patch/misc/0012-bootsplash.patch" "applying"
fi
#
# mac80211 wireless driver injection features from Kali Linux
#
if linux-version compare "${version}" ge 5.4 && [ $EXTRAWIFI == yes ]; then
display_alert "Adding" "Wireless package injections for mac80211 compatible chipsets" "info"
if linux-version compare "${version}" ge 5.9; then
process_patch_file "${SRC}/patch/misc/kali-wifi-injection-1-v5.9-post.patch" "applying"
else
process_patch_file "${SRC}/patch/misc/kali-wifi-injection-1-pre-v5.9.patch" "applying"
fi
process_patch_file "${SRC}/patch/misc/kali-wifi-injection-2.patch" "applying"
process_patch_file "${SRC}/patch/misc/kali-wifi-injection-3.patch" "applying"
fi
# AUFS - advanced multi layered unification filesystem for Kernel > 5.1
#
# Older versions have AUFS support with a patch
if linux-version compare "${version}" gt 5.11 && linux-version compare "${version}" lt 6.2 && [ "$AUFS" == yes ]; then
# attach to specifics tag or branch
local aufstag
aufstag=$(echo "${version}" | cut -f 1-2 -d ".")
aufsmajor=$(echo "${aufstag}" | cut -f 1 -d ".")
# manual overrides
if linux-version compare "${version}" ge 5.10.82 && linux-version compare "${version}" le 5.11; then aufstag="5.10.82"; fi
if linux-version compare "${version}" ge 5.15.41 && linux-version compare "${version}" le 5.16; then aufstag="5.15.41"; fi
if linux-version compare "${version}" ge 5.17.3 && linux-version compare "${version}" le 5.18; then aufstag="5.17.3"; fi
# check if Mr. Okajima already made a branch for this version
improved_git ls-remote --exit-code --heads $GITHUB_SOURCE/sfjro/aufs5-standalone "aufs${aufstag}" > /dev/null
if [ "$?" -ne "0" ]; then
# then use rc branch
aufstag="5.x-rcN"
improved_git ls-remote --exit-code --heads $GITHUB_SOURCE/sfjro/aufs5-standalone "aufs${aufstag}" > /dev/null
fi
if [ "$?" -eq "0" ]; then
display_alert "Adding" "AUFS ${aufstag}" "info"
local aufsver="branch:aufs${aufstag}"
fetch_from_repo "$GITHUB_SOURCE/sfjro/aufs5-standalone" "aufs5" "branch:${aufsver}" "yes"
cd "$kerneldir" || exit
process_patch_file "${SRC}/cache/sources/aufs5/${aufsver#*:}/aufs${aufsmajor}-kbuild.patch" "applying"
process_patch_file "${SRC}/cache/sources/aufs5/${aufsver#*:}/aufs${aufsmajor}-base.patch" "applying"
process_patch_file "${SRC}/cache/sources/aufs5/${aufsver#*:}/aufs${aufsmajor}-mmap.patch" "applying"
process_patch_file "${SRC}/cache/sources/aufs5/${aufsver#*:}/aufs${aufsmajor}-standalone.patch" "applying"
cp -R "${SRC}/cache/sources/aufs5/${aufsver#*:}"/{Documentation,fs} .
cp "${SRC}/cache/sources/aufs5/${aufsver#*:}"/include/uapi/linux/aufs_type.h include/uapi/linux/
fi
fi
# WireGuard VPN for Linux 3.10 - 5.5
if linux-version compare "${version}" ge 3.10 && linux-version compare "${version}" le 5.5 && [ "${WIREGUARD}" == yes ]; then
# attach to specifics tag or branch
local wirever="branch:master"
display_alert "Adding" "WireGuard VPN for Linux 3.10 - 5.5 ${wirever} " "info"
fetch_from_repo "https://git.zx2c4.com/wireguard-linux-compat" "wireguard" "${wirever}" "yes"
cd "$kerneldir" || exit
rm -rf "$kerneldir/net/wireguard"
cp -R "${SRC}/cache/sources/wireguard/${wirever#*:}/src/" "$kerneldir/net/wireguard"
sed -i "/^obj-\\\$(CONFIG_NETFILTER).*+=/a obj-\$(CONFIG_WIREGUARD) += wireguard/" \
"$kerneldir/net/Makefile"
sed -i "/^if INET\$/a source \"net/wireguard/Kconfig\"" \
"$kerneldir/net/Kconfig"
# remove duplicates
[[ $(grep -c wireguard "$kerneldir/net/Makefile") -gt 1 ]] &&
sed -i '0,/wireguard/{/wireguard/d;}' "$kerneldir/net/Makefile"
[[ $(grep -c wireguard "$kerneldir/net/Kconfig") -gt 1 ]] &&
sed -i '0,/wireguard/{/wireguard/d;}' "$kerneldir/net/Kconfig"
# headers workaround
display_alert "Patching WireGuard" "Applying workaround for headers compilation" "info"
sed -i '/mkdir -p "$destdir"/a mkdir -p "$destdir"/net/wireguard; \
touch "$destdir"/net/wireguard/{Kconfig,Makefile} # workaround for Wireguard' \
"$kerneldir/scripts/package/builddeb"
fi
patch_drivers_network
# Exfat driver
if linux-version compare "${version}" ge 4.9 && linux-version compare "${version}" le 5.4; then
# attach to specifics tag or branch
display_alert "Adding" "exfat driver ${exfatsver}" "info"
local exfatsver="branch:master"
fetch_from_repo "$GITHUB_SOURCE/arter97/exfat-linux" "exfat" "${exfatsver}" "yes"
cd "$kerneldir" || exit
mkdir -p $kerneldir/fs/exfat/
cp -R "${SRC}/cache/sources/exfat/${exfatsver#*:}"/{*.c,*.h} \
$kerneldir/fs/exfat/
# Add to section Makefile
echo "obj-\$(CONFIG_EXFAT_FS) += exfat/" >> $kerneldir/fs/Makefile
# Makefile
cat <<- EOF > "$kerneldir/fs/exfat/Makefile"
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Makefile for the linux exFAT filesystem support.
#
obj-\$(CONFIG_EXFAT_FS) += exfat.o
exfat-y := inode.o namei.o dir.o super.o fatent.o cache.o nls.o misc.o file.o balloc.o xattr.o
EOF
# Kconfig
sed -i '$i\source "fs\/exfat\/Kconfig"' $kerneldir/fs/Kconfig
cp "${SRC}/cache/sources/exfat/${exfatsver#*:}/Kconfig" \
"$kerneldir/fs/exfat/Kconfig"
fi
if linux-version compare $version ge 4.4 && linux-version compare $version lt 5.8; then
display_alert "Adjusting" "Framebuffer driver for ST7789 IPS display" "info"
process_patch_file "${SRC}/patch/misc/fbtft-st7789v-invert-color.patch" "applying"
fi
}

View File

@@ -478,15 +478,6 @@ set -o errexit ## set -e : exit the script if any statement returns a non-true
# shellcheck source=lib/functions/compilation/patch/drivers_network.sh
source "${SRC}"/lib/functions/compilation/patch/drivers_network.sh
# no errors tolerated. invoked before each sourced file to make sure.
#set -o pipefail # trace ERR through pipes - will be enabled "soon"
#set -o nounset ## set -u : exit the script if you try to use an uninitialised variable - one day will be enabled
set -o errtrace # trace ERR through - enabled
set -o errexit ## set -e : exit the script if any statement returns a non-true return value - enabled
### lib/functions/compilation/patch/kernel-drivers.sh
# shellcheck source=lib/functions/compilation/patch/kernel-drivers.sh
source "${SRC}"/lib/functions/compilation/patch/kernel-drivers.sh
# no errors tolerated. invoked before each sourced file to make sure.
#set -o pipefail # trace ERR through pipes - will be enabled "soon"
#set -o nounset ## set -u : exit the script if you try to use an uninitialised variable - one day will be enabled

View File

@@ -1,727 +0,0 @@
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 softback_lines, 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

View File

@@ -1,657 +0,0 @@
diff --git a/drivers/video/fbdev/core/Makefile b/drivers/video/fbdev/core/Makefile
index 66895321928e..6a8d1bab8a01 100644
--- a/drivers/video/fbdev/core/Makefile
+++ b/drivers/video/fbdev/core/Makefile
@@ -31,4 +31,4 @@ obj-$(CONFIG_FB_SVGALIB) += svgalib.o
obj-$(CONFIG_FB_DDC) += fb_ddc.o
obj-$(CONFIG_BOOTSPLASH) += bootsplash.o bootsplash_render.o \
- dummyblit.o
+ bootsplash_load.o dummyblit.o
diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
index e449755af268..843c5400fefc 100644
--- a/drivers/video/fbdev/core/bootsplash.c
+++ b/drivers/video/fbdev/core/bootsplash.c
@@ -32,6 +32,7 @@
#include <linux/workqueue.h>
#include "bootsplash_internal.h"
+#include "uapi/linux/bootsplash_file.h"
/*
@@ -102,10 +103,17 @@ static bool is_fb_compatible(const struct fb_info *info)
*/
void bootsplash_render_full(struct fb_info *info)
{
+ mutex_lock(&splash_state.data_lock);
+
if (!is_fb_compatible(info))
- return;
+ goto out;
+
+ bootsplash_do_render_background(info, splash_state.file);
+
+ bootsplash_do_render_pictures(info, splash_state.file);
- bootsplash_do_render_background(info);
+out:
+ mutex_unlock(&splash_state.data_lock);
}
@@ -116,6 +124,7 @@ bool bootsplash_would_render_now(void)
{
return !oops_in_progress
&& !console_blanked
+ && splash_state.file
&& bootsplash_is_enabled();
}
@@ -252,6 +261,7 @@ static struct platform_driver splash_driver = {
void bootsplash_init(void)
{
int ret;
+ struct splash_file_priv *fp;
/* Initialized already? */
if (splash_state.splash_device)
@@ -280,8 +290,26 @@ void bootsplash_init(void)
}
+ mutex_init(&splash_state.data_lock);
+ set_bit(0, &splash_state.enabled);
+
INIT_WORK(&splash_state.work_redraw_vc, splash_callback_redraw_vc);
+
+ if (!splash_state.bootfile || !strlen(splash_state.bootfile))
+ return;
+
+ fp = bootsplash_load_firmware(&splash_state.splash_device->dev,
+ splash_state.bootfile);
+
+ if (!fp)
+ goto err;
+
+ mutex_lock(&splash_state.data_lock);
+ splash_state.splash_fb = NULL;
+ splash_state.file = fp;
+ mutex_unlock(&splash_state.data_lock);
+
return;
err_device:
@@ -292,3 +320,7 @@ void bootsplash_init(void)
err:
pr_err("Failed to initialize.\n");
}
+
+
+module_param_named(bootfile, splash_state.bootfile, charp, 0444);
+MODULE_PARM_DESC(bootfile, "Bootsplash file to load on boot");
diff --git a/drivers/video/fbdev/core/bootsplash_internal.h b/drivers/video/fbdev/core/bootsplash_internal.h
index b11da5cb90bf..71e2a27ac0b8 100644
--- a/drivers/video/fbdev/core/bootsplash_internal.h
+++ b/drivers/video/fbdev/core/bootsplash_internal.h
@@ -15,15 +15,43 @@
#include <linux/types.h>
#include <linux/fb.h>
+#include <linux/firmware.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
+#include "uapi/linux/bootsplash_file.h"
+
/*
* Runtime types
*/
+struct splash_blob_priv {
+ struct splash_blob_header *blob_header;
+ const void *data;
+};
+
+
+struct splash_pic_priv {
+ const struct splash_pic_header *pic_header;
+
+ struct splash_blob_priv *blobs;
+ u16 blobs_loaded;
+};
+
+
+struct splash_file_priv {
+ const struct firmware *fw;
+ const struct splash_file_header *header;
+
+ struct splash_pic_priv *pics;
+};
+
+
struct splash_priv {
+ /* Bootup and runtime state */
+ char *bootfile;
+
/*
* Enabled/disabled state, to be used with atomic bit operations.
* Bit 0: 0 = Splash hidden
@@ -43,6 +71,13 @@ struct splash_priv {
struct platform_device *splash_device;
struct work_struct work_redraw_vc;
+
+ /* Splash data structures including lock for everything below */
+ struct mutex data_lock;
+
+ struct fb_info *splash_fb;
+
+ struct splash_file_priv *file;
};
@@ -50,6 +85,14 @@ struct splash_priv {
/*
* Rendering functions
*/
-void bootsplash_do_render_background(struct fb_info *info);
+void bootsplash_do_render_background(struct fb_info *info,
+ const struct splash_file_priv *fp);
+void bootsplash_do_render_pictures(struct fb_info *info,
+ const struct splash_file_priv *fp);
+
+
+void bootsplash_free_file(struct splash_file_priv *fp);
+struct splash_file_priv *bootsplash_load_firmware(struct device *device,
+ const char *path);
#endif
diff --git a/drivers/video/fbdev/core/bootsplash_load.c b/drivers/video/fbdev/core/bootsplash_load.c
new file mode 100644
index 000000000000..fd807571ab7d
--- /dev/null
+++ b/drivers/video/fbdev/core/bootsplash_load.c
@@ -0,0 +1,225 @@
+/*
+ * Kernel based bootsplash.
+ *
+ * (Loading and freeing 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/firmware.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/printk.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+
+#include "bootsplash_internal.h"
+#include "uapi/linux/bootsplash_file.h"
+
+
+
+
+/*
+ * Free all vmalloc()'d resources describing a splash file.
+ */
+void bootsplash_free_file(struct splash_file_priv *fp)
+{
+ if (!fp)
+ return;
+
+ if (fp->pics) {
+ unsigned int i;
+
+ for (i = 0; i < fp->header->num_pics; i++) {
+ struct splash_pic_priv *pp = &fp->pics[i];
+
+ if (pp->blobs)
+ vfree(pp->blobs);
+ }
+
+ vfree(fp->pics);
+ }
+
+ release_firmware(fp->fw);
+ vfree(fp);
+}
+
+
+
+
+/*
+ * Load a splash screen from a "firmware" file.
+ *
+ * Parsing, and sanity checks.
+ */
+#ifdef __BIG_ENDIAN
+ #define BOOTSPLASH_MAGIC BOOTSPLASH_MAGIC_BE
+#else
+ #define BOOTSPLASH_MAGIC BOOTSPLASH_MAGIC_LE
+#endif
+
+struct splash_file_priv *bootsplash_load_firmware(struct device *device,
+ const char *path)
+{
+ const struct firmware *fw;
+ struct splash_file_priv *fp;
+ unsigned int i;
+ const u8 *walker;
+
+ if (request_firmware(&fw, path, device))
+ return NULL;
+
+ if (fw->size < sizeof(struct splash_file_header)
+ || memcmp(fw->data, BOOTSPLASH_MAGIC, sizeof(fp->header->id))) {
+ pr_err("Not a bootsplash file.\n");
+
+ release_firmware(fw);
+ return NULL;
+ }
+
+ fp = vzalloc(sizeof(struct splash_file_priv));
+ if (!fp) {
+ release_firmware(fw);
+ return NULL;
+ }
+
+ pr_info("Loading splash file (%li bytes)\n", fw->size);
+
+ fp->fw = fw;
+ fp->header = (struct splash_file_header *)fw->data;
+
+ /* Sanity checks */
+ if (fp->header->version != BOOTSPLASH_VERSION) {
+ pr_err("Loaded v%d file, but we only support version %d\n",
+ fp->header->version,
+ BOOTSPLASH_VERSION);
+
+ goto err;
+ }
+
+ if (fw->size < sizeof(struct splash_file_header)
+ + fp->header->num_pics
+ * sizeof(struct splash_pic_header)
+ + fp->header->num_blobs
+ * sizeof(struct splash_blob_header)) {
+ pr_err("File incomplete.\n");
+
+ goto err;
+ }
+
+ /* Read picture headers */
+ if (fp->header->num_pics) {
+ fp->pics = vzalloc(fp->header->num_pics
+ * sizeof(struct splash_pic_priv));
+ if (!fp->pics)
+ goto err;
+ }
+
+ walker = fw->data + sizeof(struct splash_file_header);
+ for (i = 0; i < fp->header->num_pics; i++) {
+ struct splash_pic_priv *pp = &fp->pics[i];
+ struct splash_pic_header *ph = (void *)walker;
+
+ pr_debug("Picture %u: Size %ux%u\n", i, ph->width, ph->height);
+
+ if (ph->num_blobs < 1) {
+ pr_err("Picture %u: Zero blobs? Aborting load.\n", i);
+ goto err;
+ }
+
+ pp->pic_header = ph;
+ pp->blobs = vzalloc(ph->num_blobs
+ * sizeof(struct splash_blob_priv));
+ if (!pp->blobs)
+ goto err;
+
+ walker += sizeof(struct splash_pic_header);
+ }
+
+ /* Read blob headers */
+ for (i = 0; i < fp->header->num_blobs; i++) {
+ struct splash_blob_header *bh = (void *)walker;
+ struct splash_pic_priv *pp;
+
+ if (walker + sizeof(struct splash_blob_header)
+ > fw->data + fw->size)
+ goto err;
+
+ walker += sizeof(struct splash_blob_header);
+
+ if (walker + bh->length > fw->data + fw->size)
+ goto err;
+
+ if (bh->picture_id >= fp->header->num_pics)
+ goto nextblob;
+
+ pp = &fp->pics[bh->picture_id];
+
+ pr_debug("Blob %u, pic %u, blobs_loaded %u, num_blobs %u.\n",
+ i, bh->picture_id,
+ pp->blobs_loaded, pp->pic_header->num_blobs);
+
+ if (pp->blobs_loaded >= pp->pic_header->num_blobs)
+ goto nextblob;
+
+ switch (bh->type) {
+ case 0:
+ /* Raw 24-bit packed pixels */
+ if (bh->length != pp->pic_header->width
+ * pp->pic_header->height * 3) {
+ pr_err("Blob %u, type 1: Length doesn't match picture.\n",
+ i);
+
+ goto err;
+ }
+ break;
+ default:
+ pr_warn("Blob %u, unknown type %u.\n", i, bh->type);
+ goto nextblob;
+ }
+
+ pp->blobs[pp->blobs_loaded].blob_header = bh;
+ pp->blobs[pp->blobs_loaded].data = walker;
+ pp->blobs_loaded++;
+
+nextblob:
+ walker += bh->length;
+ if (bh->length % 16)
+ walker += 16 - (bh->length % 16);
+ }
+
+ if (walker != fw->data + fw->size)
+ pr_warn("Trailing data in splash file.\n");
+
+ /* Walk over pictures and ensure all blob slots are filled */
+ for (i = 0; i < fp->header->num_pics; i++) {
+ struct splash_pic_priv *pp = &fp->pics[i];
+
+ if (pp->blobs_loaded != pp->pic_header->num_blobs) {
+ pr_err("Picture %u doesn't have all blob slots filled.\n",
+ i);
+
+ goto err;
+ }
+ }
+
+ pr_info("Loaded (%ld bytes, %u pics, %u blobs).\n",
+ fw->size,
+ fp->header->num_pics,
+ fp->header->num_blobs);
+
+ return fp;
+
+
+err:
+ bootsplash_free_file(fp);
+ return NULL;
+}
diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c
index 4d7e0117f653..2ae36949d0e3 100644
--- a/drivers/video/fbdev/core/bootsplash_render.c
+++ b/drivers/video/fbdev/core/bootsplash_render.c
@@ -19,6 +19,7 @@
#include <linux/types.h>
#include "bootsplash_internal.h"
+#include "uapi/linux/bootsplash_file.h"
@@ -70,16 +71,69 @@ static inline u32 pack_pixel(const struct fb_var_screeninfo *dst_var,
}
-void bootsplash_do_render_background(struct fb_info *info)
+/*
+ * Copy from source and blend into the destination picture.
+ * Currently assumes that the source picture is 24bpp.
+ * Currently assumes that the destination is <= 32bpp.
+ */
+static int splash_convert_to_fb(u8 *dst,
+ const struct fb_var_screeninfo *dst_var,
+ unsigned int dst_stride,
+ unsigned int dst_xoff,
+ unsigned int dst_yoff,
+ const u8 *src,
+ unsigned int src_width,
+ unsigned int src_height)
+{
+ unsigned int x, y;
+ unsigned int src_stride = 3 * src_width; /* Assume 24bpp packed */
+ u32 dst_octpp = dst_var->bits_per_pixel / 8;
+
+ dst_xoff += dst_var->xoffset;
+ dst_yoff += dst_var->yoffset;
+
+ /* Copy with stride and pixel size adjustment */
+ for (y = 0;
+ y < src_height && y + dst_yoff < dst_var->yres_virtual;
+ y++) {
+ const u8 *srcline = src + (y * src_stride);
+ u8 *dstline = dst + ((y + dst_yoff) * dst_stride)
+ + (dst_xoff * dst_octpp);
+
+ for (x = 0;
+ x < src_width && x + dst_xoff < dst_var->xres_virtual;
+ x++) {
+ u8 red, green, blue;
+ u32 dstpix;
+
+ /* Read pixel */
+ red = *srcline++;
+ green = *srcline++;
+ blue = *srcline++;
+
+ /* Write pixel */
+ dstpix = pack_pixel(dst_var, red, green, blue);
+ memcpy(dstline, &dstpix, dst_octpp);
+
+ dstline += dst_octpp;
+ }
+ }
+
+ return 0;
+}
+
+
+void bootsplash_do_render_background(struct fb_info *info,
+ const struct splash_file_priv *fp)
{
unsigned int x, y;
u32 dstpix;
u32 dst_octpp = info->var.bits_per_pixel / 8;
dstpix = pack_pixel(&info->var,
- 0,
- 0,
- 0);
+ fp->header->bg_red,
+ fp->header->bg_green,
+ fp->header->bg_blue);
for (y = 0; y < info->var.yres_virtual; y++) {
u8 *dstline = info->screen_buffer + (y * info->fix.line_length);
@@ -91,3 +145,44 @@ void bootsplash_do_render_background(struct fb_info *info)
}
}
}
+
+
+void bootsplash_do_render_pictures(struct fb_info *info,
+ const struct splash_file_priv *fp)
+{
+ unsigned int i;
+
+ for (i = 0; i < fp->header->num_pics; i++) {
+ struct splash_blob_priv *bp;
+ struct splash_pic_priv *pp = &fp->pics[i];
+ long dst_xoff, dst_yoff;
+
+ if (pp->blobs_loaded < 1)
+ continue;
+
+ bp = &pp->blobs[0];
+
+ if (!bp || bp->blob_header->type != 0)
+ continue;
+
+ dst_xoff = (info->var.xres - pp->pic_header->width) / 2;
+ dst_yoff = (info->var.yres - pp->pic_header->height) / 2;
+
+ if (dst_xoff < 0
+ || dst_yoff < 0
+ || dst_xoff + pp->pic_header->width > info->var.xres
+ || dst_yoff + pp->pic_header->height > info->var.yres) {
+ pr_info_once("Picture %u is out of bounds at current resolution: %dx%d\n"
+ "(this will only be printed once every reboot)\n",
+ i, info->var.xres, info->var.yres);
+
+ continue;
+ }
+
+ /* Draw next splash frame */
+ splash_convert_to_fb(info->screen_buffer, &info->var,
+ info->fix.line_length, dst_xoff, dst_yoff,
+ bp->data,
+ pp->pic_header->width, pp->pic_header->height);
+ }
+}
diff --git a/include/uapi/linux/bootsplash_file.h b/include/uapi/linux/bootsplash_file.h
new file mode 100644
index 000000000000..89dc9cca8f0c
--- /dev/null
+++ b/include/uapi/linux/bootsplash_file.h
@@ -0,0 +1,118 @@
+/*
+ * Kernel based bootsplash.
+ *
+ * (File format)
+ *
+ * Authors:
+ * Max Staudt <mstaudt@suse.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+ */
+
+#ifndef __BOOTSPLASH_FILE_H
+#define __BOOTSPLASH_FILE_H
+
+
+#define BOOTSPLASH_VERSION 55561
+
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+
+/*
+ * On-disk types
+ *
+ * A splash file consists of:
+ * - One single 'struct splash_file_header'
+ * - An array of 'struct splash_pic_header'
+ * - An array of raw data blocks, each padded to 16 bytes and
+ * preceded by a 'struct splash_blob_header'
+ *
+ * A single-frame splash may look like this:
+ *
+ * +--------------------+
+ * | |
+ * | splash_file_header |
+ * | -> num_blobs = 1 |
+ * | -> num_pics = 1 |
+ * | |
+ * +--------------------+
+ * | |
+ * | splash_pic_header |
+ * | |
+ * +--------------------+
+ * | |
+ * | splash_blob_header |
+ * | -> type = 0 |
+ * | -> picture_id = 0 |
+ * | |
+ * | (raw RGB data) |
+ * | (pad to 16 bytes) |
+ * | |
+ * +--------------------+
+ *
+ * All multi-byte values are stored on disk in the native format
+ * expected by the system the file will be used on.
+ */
+#define BOOTSPLASH_MAGIC_BE "Linux bootsplash"
+#define BOOTSPLASH_MAGIC_LE "hsalpstoob xuniL"
+
+struct splash_file_header {
+ uint8_t id[16]; /* "Linux bootsplash" (no trailing NUL) */
+
+ /* Splash file format version to avoid clashes */
+ uint16_t version;
+
+ /* The background color */
+ uint8_t bg_red;
+ uint8_t bg_green;
+ uint8_t bg_blue;
+ uint8_t bg_reserved;
+
+ /*
+ * Number of pic/blobs so we can allocate memory for internal
+ * structures ahead of time when reading the file
+ */
+ uint16_t num_blobs;
+ uint8_t num_pics;
+
+ uint8_t padding[103];
+} __attribute__((__packed__));
+
+
+struct splash_pic_header {
+ uint16_t width;
+ uint16_t height;
+
+ /*
+ * Number of data packages associated with this picture.
+ * Currently, the only use for more than 1 is for animations.
+ */
+ uint8_t num_blobs;
+
+ uint8_t padding[27];
+} __attribute__((__packed__));
+
+
+struct splash_blob_header {
+ /* Length of the data block in bytes. */
+ uint32_t length;
+
+ /*
+ * Type of the contents.
+ * 0 - Raw RGB data.
+ */
+ uint16_t type;
+
+ /*
+ * Picture this blob is associated with.
+ * Blobs will be added to a picture in the order they are
+ * found in the file.
+ */
+ uint8_t picture_id;
+
+ uint8_t padding[9];
+} __attribute__((__packed__));
+
+#endif

View File

@@ -1,66 +0,0 @@
diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
index 843c5400fefc..815b007f81ca 100644
--- a/drivers/video/fbdev/core/bootsplash.c
+++ b/drivers/video/fbdev/core/bootsplash.c
@@ -112,6 +112,8 @@ void bootsplash_render_full(struct fb_info *info)
bootsplash_do_render_pictures(info, splash_state.file);
+ bootsplash_do_render_flush(info);
+
out:
mutex_unlock(&splash_state.data_lock);
}
diff --git a/drivers/video/fbdev/core/bootsplash_internal.h b/drivers/video/fbdev/core/bootsplash_internal.h
index 71e2a27ac0b8..0acb383aa4e3 100644
--- a/drivers/video/fbdev/core/bootsplash_internal.h
+++ b/drivers/video/fbdev/core/bootsplash_internal.h
@@ -89,6 +89,7 @@ void bootsplash_do_render_background(struct fb_info *info,
const struct splash_file_priv *fp);
void bootsplash_do_render_pictures(struct fb_info *info,
const struct splash_file_priv *fp);
+void bootsplash_do_render_flush(struct fb_info *info);
void bootsplash_free_file(struct splash_file_priv *fp);
diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c
index 2ae36949d0e3..8c09c306ff67 100644
--- a/drivers/video/fbdev/core/bootsplash_render.c
+++ b/drivers/video/fbdev/core/bootsplash_render.c
@@ -186,3 +186,36 @@ void bootsplash_do_render_pictures(struct fb_info *info,
pp->pic_header->width, pp->pic_header->height);
}
}
+
+
+void bootsplash_do_render_flush(struct fb_info *info)
+{
+ /*
+ * FB drivers using deferred_io (such as Xen) need to sync the
+ * screen after modifying its contents. When the FB is mmap()ed
+ * from userspace, this happens via a dirty pages callback, but
+ * when modifying the FB from the kernel, there is no such thing.
+ *
+ * So let's issue a fake fb_copyarea (copying the FB onto itself)
+ * to trick the FB driver into syncing the screen.
+ *
+ * A few DRM drivers' FB implementations are broken by not using
+ * deferred_io when they really should - we match on the known
+ * bad ones manually for now.
+ */
+ if (info->fbdefio
+ || !strcmp(info->fix.id, "astdrmfb")
+ || !strcmp(info->fix.id, "cirrusdrmfb")
+ || !strcmp(info->fix.id, "mgadrmfb")) {
+ struct fb_copyarea area;
+
+ area.dx = 0;
+ area.dy = 0;
+ area.width = info->var.xres;
+ area.height = info->var.yres;
+ area.sx = 0;
+ area.sy = 0;
+
+ info->fbops->fb_copyarea(info, &area);
+ }
+}

View File

@@ -1,215 +0,0 @@
diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c
index 8c09c306ff67..07e3a4eab811 100644
--- a/drivers/video/fbdev/core/bootsplash_render.c
+++ b/drivers/video/fbdev/core/bootsplash_render.c
@@ -155,6 +155,7 @@ void bootsplash_do_render_pictures(struct fb_info *info,
for (i = 0; i < fp->header->num_pics; i++) {
struct splash_blob_priv *bp;
struct splash_pic_priv *pp = &fp->pics[i];
+ const struct splash_pic_header *ph = pp->pic_header;
long dst_xoff, dst_yoff;
if (pp->blobs_loaded < 1)
@@ -165,8 +166,139 @@ void bootsplash_do_render_pictures(struct fb_info *info,
if (!bp || bp->blob_header->type != 0)
continue;
- dst_xoff = (info->var.xres - pp->pic_header->width) / 2;
- dst_yoff = (info->var.yres - pp->pic_header->height) / 2;
+ switch (ph->position) {
+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_TOP_LEFT:
+ dst_xoff = 0;
+ dst_yoff = 0;
+
+ dst_xoff += ph->position_offset;
+ dst_yoff += ph->position_offset;
+ break;
+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_TOP:
+ dst_xoff = info->var.xres - pp->pic_header->width;
+ dst_xoff /= 2;
+ dst_yoff = 0;
+
+ dst_yoff += ph->position_offset;
+ break;
+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_TOP_RIGHT:
+ dst_xoff = info->var.xres - pp->pic_header->width;
+ dst_yoff = 0;
+
+ dst_xoff -= ph->position_offset;
+ dst_yoff += ph->position_offset;
+ break;
+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_RIGHT:
+ dst_xoff = info->var.xres - pp->pic_header->width;
+ dst_yoff = info->var.yres - pp->pic_header->height;
+ dst_yoff /= 2;
+
+ dst_xoff -= ph->position_offset;
+ break;
+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_BOTTOM_RIGHT:
+ dst_xoff = info->var.xres - pp->pic_header->width;
+ dst_yoff = info->var.yres - pp->pic_header->height;
+
+ dst_xoff -= ph->position_offset;
+ dst_yoff -= ph->position_offset;
+ break;
+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_BOTTOM:
+ dst_xoff = info->var.xres - pp->pic_header->width;
+ dst_xoff /= 2;
+ dst_yoff = info->var.yres - pp->pic_header->height;
+
+ dst_yoff -= ph->position_offset;
+ break;
+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_BOTTOM_LEFT:
+ dst_xoff = 0 + ph->position_offset;
+ dst_yoff = info->var.yres - pp->pic_header->height
+ - ph->position_offset;
+ break;
+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_LEFT:
+ dst_xoff = 0;
+ dst_yoff = info->var.yres - pp->pic_header->height;
+ dst_yoff /= 2;
+
+ dst_xoff += ph->position_offset;
+ break;
+
+ case SPLASH_CORNER_TOP_LEFT:
+ dst_xoff = info->var.xres - pp->pic_header->width;
+ dst_xoff /= 2;
+ dst_yoff = info->var.yres - pp->pic_header->height;
+ dst_yoff /= 2;
+
+ dst_xoff -= ph->position_offset;
+ dst_yoff -= ph->position_offset;
+ break;
+ case SPLASH_CORNER_TOP:
+ dst_xoff = info->var.xres - pp->pic_header->width;
+ dst_xoff /= 2;
+ dst_yoff = info->var.yres - pp->pic_header->height;
+ dst_yoff /= 2;
+
+ dst_yoff -= ph->position_offset;
+ break;
+ case SPLASH_CORNER_TOP_RIGHT:
+ dst_xoff = info->var.xres - pp->pic_header->width;
+ dst_xoff /= 2;
+ dst_yoff = info->var.yres - pp->pic_header->height;
+ dst_yoff /= 2;
+
+ dst_xoff += ph->position_offset;
+ dst_yoff -= ph->position_offset;
+ break;
+ case SPLASH_CORNER_RIGHT:
+ dst_xoff = info->var.xres - pp->pic_header->width;
+ dst_xoff /= 2;
+ dst_yoff = info->var.yres - pp->pic_header->height;
+ dst_yoff /= 2;
+
+ dst_xoff += ph->position_offset;
+ break;
+ case SPLASH_CORNER_BOTTOM_RIGHT:
+ dst_xoff = info->var.xres - pp->pic_header->width;
+ dst_xoff /= 2;
+ dst_yoff = info->var.yres - pp->pic_header->height;
+ dst_yoff /= 2;
+
+ dst_xoff += ph->position_offset;
+ dst_yoff += ph->position_offset;
+ break;
+ case SPLASH_CORNER_BOTTOM:
+ dst_xoff = info->var.xres - pp->pic_header->width;
+ dst_xoff /= 2;
+ dst_yoff = info->var.yres - pp->pic_header->height;
+ dst_yoff /= 2;
+
+ dst_yoff += ph->position_offset;
+ break;
+ case SPLASH_CORNER_BOTTOM_LEFT:
+ dst_xoff = info->var.xres - pp->pic_header->width;
+ dst_xoff /= 2;
+ dst_yoff = info->var.yres - pp->pic_header->height;
+ dst_yoff /= 2;
+
+ dst_xoff -= ph->position_offset;
+ dst_yoff += ph->position_offset;
+ break;
+ case SPLASH_CORNER_LEFT:
+ dst_xoff = info->var.xres - pp->pic_header->width;
+ dst_xoff /= 2;
+ dst_yoff = info->var.yres - pp->pic_header->height;
+ dst_yoff /= 2;
+
+ dst_xoff -= ph->position_offset;
+ break;
+
+ default:
+ /* As a fallback, center the picture. */
+ dst_xoff = info->var.xres - pp->pic_header->width;
+ dst_xoff /= 2;
+ dst_yoff = info->var.yres - pp->pic_header->height;
+ dst_yoff /= 2;
+ break;
+ }
if (dst_xoff < 0
|| dst_yoff < 0
diff --git a/include/uapi/linux/bootsplash_file.h b/include/uapi/linux/bootsplash_file.h
index 89dc9cca8f0c..71cedcc68933 100644
--- a/include/uapi/linux/bootsplash_file.h
+++ b/include/uapi/linux/bootsplash_file.h
@@ -91,7 +91,32 @@ struct splash_pic_header {
*/
uint8_t num_blobs;
- uint8_t padding[27];
+ /*
+ * Corner to move the picture to / from.
+ * 0x00 - Top left
+ * 0x01 - Top
+ * 0x02 - Top right
+ * 0x03 - Right
+ * 0x04 - Bottom right
+ * 0x05 - Bottom
+ * 0x06 - Bottom left
+ * 0x07 - Left
+ *
+ * Flags:
+ * 0x10 - Calculate offset from the corner towards the center,
+ * rather than from the center towards the corner
+ */
+ uint8_t position;
+
+ /*
+ * Pixel offset from the selected position.
+ * Example: If the picture is in the top right corner, it will
+ * be placed position_offset pixels from the top and
+ * position_offset pixels from the right margin.
+ */
+ uint16_t position_offset;
+
+ uint8_t padding[24];
} __attribute__((__packed__));
@@ -115,4 +140,22 @@ struct splash_blob_header {
uint8_t padding[9];
} __attribute__((__packed__));
+
+
+
+/*
+ * Enums for on-disk types
+ */
+enum splash_position {
+ SPLASH_CORNER_TOP_LEFT = 0,
+ SPLASH_CORNER_TOP = 1,
+ SPLASH_CORNER_TOP_RIGHT = 2,
+ SPLASH_CORNER_RIGHT = 3,
+ SPLASH_CORNER_BOTTOM_RIGHT = 4,
+ SPLASH_CORNER_BOTTOM = 5,
+ SPLASH_CORNER_BOTTOM_LEFT = 6,
+ SPLASH_CORNER_LEFT = 7,
+ SPLASH_POS_FLAG_CORNER = 0x10,
+};
+
#endif

View File

@@ -1,327 +0,0 @@
diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
index 815b007f81ca..c8642142cfea 100644
--- a/drivers/video/fbdev/core/bootsplash.c
+++ b/drivers/video/fbdev/core/bootsplash.c
@@ -53,6 +53,14 @@ static void splash_callback_redraw_vc(struct work_struct *ignored)
console_unlock();
}
+static void splash_callback_animation(struct work_struct *ignored)
+{
+ if (bootsplash_would_render_now()) {
+ /* This will also re-schedule this delayed worker */
+ splash_callback_redraw_vc(ignored);
+ }
+}
+
static bool is_fb_compatible(const struct fb_info *info)
{
@@ -103,17 +111,44 @@ static bool is_fb_compatible(const struct fb_info *info)
*/
void bootsplash_render_full(struct fb_info *info)
{
+ bool is_update = false;
+
mutex_lock(&splash_state.data_lock);
- if (!is_fb_compatible(info))
- goto out;
+ /*
+ * If we've painted on this FB recently, we don't have to do
+ * the sanity checks and background drawing again.
+ */
+ if (splash_state.splash_fb == info)
+ is_update = true;
+
+
+ if (!is_update) {
+ /* Check whether we actually support this FB. */
+ splash_state.splash_fb = NULL;
+
+ if (!is_fb_compatible(info))
+ goto out;
+
+ /* Draw the background only once */
+ bootsplash_do_render_background(info, splash_state.file);
- bootsplash_do_render_background(info, splash_state.file);
+ /* Mark this FB as last seen */
+ splash_state.splash_fb = info;
+ }
- bootsplash_do_render_pictures(info, splash_state.file);
+ bootsplash_do_render_pictures(info, splash_state.file, is_update);
bootsplash_do_render_flush(info);
+ bootsplash_do_step_animations(splash_state.file);
+
+ /* Schedule update for animated splash screens */
+ if (splash_state.file->frame_ms > 0)
+ schedule_delayed_work(&splash_state.dwork_animation,
+ msecs_to_jiffies(
+ splash_state.file->frame_ms));
+
out:
mutex_unlock(&splash_state.data_lock);
}
@@ -169,8 +204,14 @@ void bootsplash_enable(void)
was_enabled = test_and_set_bit(0, &splash_state.enabled);
- if (!was_enabled)
+ if (!was_enabled) {
+ /* Force a full redraw when the splash is re-activated */
+ mutex_lock(&splash_state.data_lock);
+ splash_state.splash_fb = NULL;
+ mutex_unlock(&splash_state.data_lock);
+
schedule_work(&splash_state.work_redraw_vc);
+ }
}
@@ -227,6 +268,14 @@ ATTRIBUTE_GROUPS(splash_dev);
*/
static int splash_resume(struct device *device)
{
+ /*
+ * Force full redraw on resume since we've probably lost the
+ * framebuffer's contents meanwhile
+ */
+ mutex_lock(&splash_state.data_lock);
+ splash_state.splash_fb = NULL;
+ mutex_unlock(&splash_state.data_lock);
+
if (bootsplash_would_render_now())
schedule_work(&splash_state.work_redraw_vc);
@@ -235,6 +284,7 @@ static int splash_resume(struct device *device)
static int splash_suspend(struct device *device)
{
+ cancel_delayed_work_sync(&splash_state.dwork_animation);
cancel_work_sync(&splash_state.work_redraw_vc);
return 0;
@@ -296,6 +346,8 @@ void bootsplash_init(void)
set_bit(0, &splash_state.enabled);
INIT_WORK(&splash_state.work_redraw_vc, splash_callback_redraw_vc);
+ INIT_DELAYED_WORK(&splash_state.dwork_animation,
+ splash_callback_animation);
if (!splash_state.bootfile || !strlen(splash_state.bootfile))
diff --git a/drivers/video/fbdev/core/bootsplash_internal.h b/drivers/video/fbdev/core/bootsplash_internal.h
index 0acb383aa4e3..b3a74835d90f 100644
--- a/drivers/video/fbdev/core/bootsplash_internal.h
+++ b/drivers/video/fbdev/core/bootsplash_internal.h
@@ -37,6 +37,8 @@ struct splash_pic_priv {
struct splash_blob_priv *blobs;
u16 blobs_loaded;
+
+ u16 anim_nextframe;
};
@@ -45,6 +47,12 @@ struct splash_file_priv {
const struct splash_file_header *header;
struct splash_pic_priv *pics;
+
+ /*
+ * A local copy of the frame delay in the header.
+ * We modify it to keep the code simple.
+ */
+ u16 frame_ms;
};
@@ -71,6 +79,7 @@ struct splash_priv {
struct platform_device *splash_device;
struct work_struct work_redraw_vc;
+ struct delayed_work dwork_animation;
/* Splash data structures including lock for everything below */
struct mutex data_lock;
@@ -88,8 +97,10 @@ struct splash_priv {
void bootsplash_do_render_background(struct fb_info *info,
const struct splash_file_priv *fp);
void bootsplash_do_render_pictures(struct fb_info *info,
- const struct splash_file_priv *fp);
+ const struct splash_file_priv *fp,
+ bool is_update);
void bootsplash_do_render_flush(struct fb_info *info);
+void bootsplash_do_step_animations(struct splash_file_priv *fp);
void bootsplash_free_file(struct splash_file_priv *fp);
diff --git a/drivers/video/fbdev/core/bootsplash_load.c b/drivers/video/fbdev/core/bootsplash_load.c
index fd807571ab7d..1f661b2d4cc9 100644
--- a/drivers/video/fbdev/core/bootsplash_load.c
+++ b/drivers/video/fbdev/core/bootsplash_load.c
@@ -71,6 +71,7 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device,
{
const struct firmware *fw;
struct splash_file_priv *fp;
+ bool have_anim = false;
unsigned int i;
const u8 *walker;
@@ -135,6 +136,13 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device,
goto err;
}
+ if (ph->anim_type > SPLASH_ANIM_LOOP_FORWARD) {
+ pr_warn("Picture %u: Unsupported animation type %u.\n",
+ i, ph->anim_type);
+
+ ph->anim_type = SPLASH_ANIM_NONE;
+ }
+
pp->pic_header = ph;
pp->blobs = vzalloc(ph->num_blobs
* sizeof(struct splash_blob_priv));
@@ -202,6 +210,7 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device,
/* Walk over pictures and ensure all blob slots are filled */
for (i = 0; i < fp->header->num_pics; i++) {
struct splash_pic_priv *pp = &fp->pics[i];
+ const struct splash_pic_header *ph = pp->pic_header;
if (pp->blobs_loaded != pp->pic_header->num_blobs) {
pr_err("Picture %u doesn't have all blob slots filled.\n",
@@ -209,8 +218,20 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device,
goto err;
}
+
+ if (ph->anim_type
+ && ph->num_blobs > 1
+ && ph->anim_loop < pp->blobs_loaded)
+ have_anim = true;
}
+ if (!have_anim)
+ /* Disable animation timer if there is nothing to animate */
+ fp->frame_ms = 0;
+ else
+ /* Enforce minimum delay between frames */
+ fp->frame_ms = max((u16)20, fp->header->frame_ms);
+
pr_info("Loaded (%ld bytes, %u pics, %u blobs).\n",
fw->size,
fp->header->num_pics,
diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c
index 07e3a4eab811..76033606ca8a 100644
--- a/drivers/video/fbdev/core/bootsplash_render.c
+++ b/drivers/video/fbdev/core/bootsplash_render.c
@@ -148,7 +148,8 @@ void bootsplash_do_render_background(struct fb_info *info,
void bootsplash_do_render_pictures(struct fb_info *info,
- const struct splash_file_priv *fp)
+ const struct splash_file_priv *fp,
+ bool is_update)
{
unsigned int i;
@@ -161,7 +162,11 @@ void bootsplash_do_render_pictures(struct fb_info *info,
if (pp->blobs_loaded < 1)
continue;
- bp = &pp->blobs[0];
+ /* Skip static pictures when refreshing animations */
+ if (ph->anim_type == SPLASH_ANIM_NONE && is_update)
+ continue;
+
+ bp = &pp->blobs[pp->anim_nextframe];
if (!bp || bp->blob_header->type != 0)
continue;
@@ -351,3 +356,24 @@ void bootsplash_do_render_flush(struct fb_info *info)
info->fbops->fb_copyarea(info, &area);
}
}
+
+
+void bootsplash_do_step_animations(struct splash_file_priv *fp)
+{
+ unsigned int i;
+
+ /* Step every animation once */
+ for (i = 0; i < fp->header->num_pics; i++) {
+ struct splash_pic_priv *pp = &fp->pics[i];
+
+ if (pp->blobs_loaded < 2
+ || pp->pic_header->anim_loop > pp->blobs_loaded)
+ continue;
+
+ if (pp->pic_header->anim_type == SPLASH_ANIM_LOOP_FORWARD) {
+ pp->anim_nextframe++;
+ if (pp->anim_nextframe >= pp->pic_header->num_blobs)
+ pp->anim_nextframe = pp->pic_header->anim_loop;
+ }
+ }
+}
diff --git a/include/uapi/linux/bootsplash_file.h b/include/uapi/linux/bootsplash_file.h
index 71cedcc68933..b3af0a3c6487 100644
--- a/include/uapi/linux/bootsplash_file.h
+++ b/include/uapi/linux/bootsplash_file.h
@@ -77,7 +77,17 @@ struct splash_file_header {
uint16_t num_blobs;
uint8_t num_pics;
- uint8_t padding[103];
+ uint8_t unused_1;
+
+ /*
+ * Milliseconds to wait before painting the next frame in
+ * an animation.
+ * This is actually a minimum, as the system is allowed to
+ * stall for longer between frames.
+ */
+ uint16_t frame_ms;
+
+ uint8_t padding[100];
} __attribute__((__packed__));
@@ -116,7 +126,23 @@ struct splash_pic_header {
*/
uint16_t position_offset;
- uint8_t padding[24];
+ /*
+ * Animation type.
+ * 0 - off
+ * 1 - forward loop
+ */
+ uint8_t anim_type;
+
+ /*
+ * Animation loop point.
+ * Actual meaning depends on animation type:
+ * Type 0 - Unused
+ * 1 - Frame at which to restart the forward loop
+ * (allowing for "intro" frames)
+ */
+ uint8_t anim_loop;
+
+ uint8_t padding[22];
} __attribute__((__packed__));
@@ -158,4 +184,9 @@ enum splash_position {
SPLASH_POS_FLAG_CORNER = 0x10,
};
+enum splash_anim_type {
+ SPLASH_ANIM_NONE = 0,
+ SPLASH_ANIM_LOOP_FORWARD = 1,
+};
+
#endif

View File

@@ -1,82 +0,0 @@
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 2ebaba16f785..416735ab6dc1 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -105,6 +105,7 @@
#include <linux/ctype.h>
#include <linux/bsearch.h>
#include <linux/gcd.h>
+#include <linux/bootsplash.h>
#define MAX_NR_CON_DRIVER 16
@@ -4235,6 +4236,7 @@ void do_unblank_screen(int leaving_gfx)
}
console_blanked = 0;
+ bootsplash_mark_dirty();
if (vc->vc_sw->con_blank(vc, 0, leaving_gfx))
/* Low-level driver cannot restore -> do it ourselves */
update_screen(vc);
diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
index c8642142cfea..13fcaabbc2ca 100644
--- a/drivers/video/fbdev/core/bootsplash.c
+++ b/drivers/video/fbdev/core/bootsplash.c
@@ -165,6 +165,13 @@ bool bootsplash_would_render_now(void)
&& bootsplash_is_enabled();
}
+void bootsplash_mark_dirty(void)
+{
+ mutex_lock(&splash_state.data_lock);
+ splash_state.splash_fb = NULL;
+ mutex_unlock(&splash_state.data_lock);
+}
+
bool bootsplash_is_enabled(void)
{
bool was_enabled;
@@ -206,9 +213,7 @@ void bootsplash_enable(void)
if (!was_enabled) {
/* Force a full redraw when the splash is re-activated */
- mutex_lock(&splash_state.data_lock);
- splash_state.splash_fb = NULL;
- mutex_unlock(&splash_state.data_lock);
+ bootsplash_mark_dirty();
schedule_work(&splash_state.work_redraw_vc);
}
@@ -272,9 +277,7 @@ static int splash_resume(struct device *device)
* Force full redraw on resume since we've probably lost the
* framebuffer's contents meanwhile
*/
- mutex_lock(&splash_state.data_lock);
- splash_state.splash_fb = NULL;
- mutex_unlock(&splash_state.data_lock);
+ bootsplash_mark_dirty();
if (bootsplash_would_render_now())
schedule_work(&splash_state.work_redraw_vc);
diff --git a/include/linux/bootsplash.h b/include/linux/bootsplash.h
index c6dd0b43180d..4075098aaadd 100644
--- a/include/linux/bootsplash.h
+++ b/include/linux/bootsplash.h
@@ -19,6 +19,8 @@ extern void bootsplash_render_full(struct fb_info *info);
extern bool bootsplash_would_render_now(void);
+extern void bootsplash_mark_dirty(void);
+
extern bool bootsplash_is_enabled(void);
extern void bootsplash_disable(void);
extern void bootsplash_enable(void);
@@ -31,6 +33,8 @@ extern void bootsplash_init(void);
#define bootsplash_would_render_now() (false)
+#define bootsplash_mark_dirty()
+
#define bootsplash_is_enabled() (false)
#define bootsplash_disable()
#define bootsplash_enable()

View File

@@ -1,41 +0,0 @@
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index f4166263bb3a..a248429194bb 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -28,6 +28,7 @@
* 21-08-02: Converted to input API, major cleanup. (Vojtech Pavlik)
*/
+#include <linux/bootsplash.h>
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/consolemap.h>
@@ -1353,6 +1355,28 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
}
#endif
+ /* Trap keys when bootsplash is shown */
+ if (bootsplash_would_render_now()) {
+ /* Deactivate bootsplash on ESC or Alt+Fxx VT switch */
+ if (keycode >= KEY_F1 && keycode <= KEY_F12) {
+ bootsplash_disable();
+
+ /*
+ * No return here since we want to actually
+ * perform the VT switch.
+ */
+ } else {
+ if (keycode == KEY_ESC)
+ bootsplash_disable();
+
+ /*
+ * Just drop any other keys.
+ * Their effect would be hidden by the splash.
+ */
+ return;
+ }
+ }
+
if (kbd->kbdmode == VC_MEDIUMRAW) {
/*
* This is extended medium raw mode, with keys above 127

View File

@@ -1,21 +0,0 @@
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index 3ffc1ce29023..bc6a24c9dfa8 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -49,6 +49,7 @@
#include <linux/syscalls.h>
#include <linux/of.h>
#include <linux/rcupdate.h>
+#include <linux/bootsplash.h>
#include <asm/ptrace.h>
#include <asm/irq_regs.h>
@@ -104,6 +105,8 @@ static void sysrq_handle_SAK(int key)
{
struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work;
schedule_work(SAK_work);
+
+ bootsplash_disable();
}
static struct sysrq_key_op sysrq_SAK_op = {
.handler = sysrq_handle_SAK,

View File

@@ -1,21 +0,0 @@
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 9a39a6fcfe98..8a9c67e1c5d8 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -1343,6 +1343,16 @@ static void fbcon_cursor(struct vc_data *vc, int mode)
int y;
int c = scr_readw((u16 *) vc->vc_pos);
+ /*
+ * Disable the splash here so we don't have to hook into
+ * vt_console_print() in drivers/tty/vt/vt.c
+ *
+ * We'd disable the splash just before the call to
+ * hide_cursor() anyway, so this spot is just fine.
+ */
+ if (oops_in_progress)
+ bootsplash_disable();
+
ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1)

View File

@@ -1,308 +0,0 @@
diff --git a/Documentation/ABI/testing/sysfs-platform-bootsplash b/Documentation/ABI/testing/sysfs-platform-bootsplash
new file mode 100644
index 000000000000..742c7b035ded
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-platform-bootsplash
@@ -0,0 +1,11 @@
+What: /sys/devices/platform/bootsplash.0/enabled
+Date: Oct 2017
+KernelVersion: 4.14
+Contact: Max Staudt <mstaudt@suse.de>
+Description:
+ Can be set and read.
+
+ 0: Splash is disabled.
+ 1: Splash is shown whenever fbcon would show a text console
+ (i.e. no graphical application is running), and a splash
+ file is loaded.
diff --git a/Documentation/bootsplash.rst b/Documentation/bootsplash.rst
new file mode 100644
index 000000000000..611f0c558925
--- /dev/null
+++ b/Documentation/bootsplash.rst
@@ -0,0 +1,285 @@
+====================
+The Linux bootsplash
+====================
+
+:Date: November, 2017
+:Author: Max Staudt <mstaudt@suse.de>
+
+
+The Linux bootsplash is a graphical replacement for the '``quiet``' boot
+option, typically showing a logo and a spinner animation as the system starts.
+
+Currently, it is a part of the Framebuffer Console support, and can be found
+as ``CONFIG_BOOTSPLASH`` in the kernel configuration. This means that as long
+as it is enabled, it hijacks fbcon's output and draws a splash screen instead.
+
+Purely compiling in the bootsplash will not render it functional - to actually
+render a splash, you will also need a splash theme file. See the example
+utility and script in ``tools/bootsplash`` for a live demo.
+
+
+
+Motivation
+==========
+
+- The '``quiet``' boot option only suppresses most messages during boot, but
+ errors are still shown.
+
+- A user space implementation can only show a logo once user space has been
+ initialized far enough to allow this. A kernel splash can display a splash
+ immediately as soon as fbcon can be displayed.
+
+- Implementing a splash screen in user space (e.g. Plymouth) is problematic
+ due to resource conflicts.
+
+ For example, if Plymouth is keeping ``/dev/fb0`` (provided via vesafb/efifb)
+ open, then most DRM drivers can't replace it because the address space is
+ still busy - thus leading to a VRAM reservation error.
+
+ See: https://bugzilla.opensuse.org/show_bug.cgi?id=980750
+
+
+
+Command line arguments
+======================
+
+``bootsplash.bootfile``
+ Which file in the initramfs to load.
+
+ The splash theme is loaded via request_firmware(), thus to load
+ ``/lib/firmware/bootsplash/mytheme`` pass the command line:
+
+ ``bootsplash.bootfile=bootsplash/mytheme``
+
+ Note: The splash file *has to be* in the initramfs, as it needs to be
+ available when the splash is initialized early on.
+
+ Default: none, i.e. a non-functional splash, falling back to showing text.
+
+
+
+sysfs run-time configuration
+============================
+
+``/sys/devices/platform/bootsplash.0/enabled``
+ Enable/disable the bootsplash.
+ The system boots with this set to 1, but will not show a splash unless
+ a splash theme file is also loaded.
+
+
+
+Kconfig
+=======
+
+``BOOTSPLASH``
+ Whether to compile in bootsplash support
+ (depends on fbcon compiled in, i.e. ``FRAMEBUFFER_CONSOLE=y``)
+
+
+
+Bootsplash file format
+======================
+
+A file specified in the kernel configuration as ``CONFIG_BOOTSPLASH_FILE``
+or specified on the command line as ``bootsplash.bootfile`` will be loaded
+and displayed as soon as fbcon is initialized.
+
+
+Main blocks
+-----------
+
+There are 3 main blocks in each file:
+
+ - one File header
+ - n Picture headers
+ - m (Blob header + payload) blocks
+
+
+Structures
+----------
+
+The on-disk structures are defined in
+``drivers/video/fbdev/core/bootsplash_file.h`` and represent these blocks:
+
+ - ``struct splash_file_header``
+
+ Represents the file header, with splash-wide information including:
+
+ - The magic string "``Linux bootsplash``" on big-endian platforms
+ (the reverse on little endian)
+ - The file format version (for incompatible updates, hopefully never)
+ - The background color
+ - Number of picture and blob blocks
+ - Animation speed (we only allow one delay for all animations)
+
+ The file header is followed by the first picture header.
+
+
+ - ``struct splash_picture_header``
+
+ Represents an object (picture) drawn on screen, including its immutable
+ properties:
+ - Width, height
+ - Positioning relative to screen corners or in the center
+ - Animation, if any
+ - Animation type
+ - Number of blobs
+
+ The picture header is followed by another picture header, up until n
+ picture headers (as defined in the file header) have been read. Then,
+ the (blob header, payload) pairs follow.
+
+
+ - ``struct splash_blob_header``
+ (followed by payload)
+
+ Represents one raw data stream. So far, only picture data is defined.
+
+ The blob header is followed by a payload, then padding to n*16 bytes,
+ then (if further blobs are defined in the file header) a further blob
+ header.
+
+
+Alignment
+---------
+
+The bootsplash file is designed to be loaded into memory as-is.
+
+All structures are a multiple of 16 bytes long, all elements therein are
+aligned to multiples of their length, and the payloads are always padded
+up to multiples of 16 bytes. This is to allow aligned accesses in all
+cases while still simply mapping the structures over an in-memory copy of
+the bootsplash file.
+
+
+Further information
+-------------------
+
+Please see ``drivers/video/fbdev/core/bootsplash_file.h`` for further
+details and possible values in the file.
+
+
+
+Hooks - how the bootsplash is integrated
+========================================
+
+``drivers/video/fbdev/core/fbcon.c``
+ ``fbcon_init()`` calls ``bootsplash_init()``, which loads the default
+ bootsplash file or the one specified on the kernel command line.
+
+ ``fbcon_switch()`` draws the bootsplash when it's active, and is also
+ one of the callers of ``set_blitting_type()``.
+
+ ``set_blitting_type()`` calls ``fbcon_set_dummyops()`` when the
+ bootsplash is active, overriding the text rendering functions.
+
+ ``fbcon_cursor()`` will call ``bootsplash_disable()`` when an oops is
+ being printed in order to make a kernel panic visible.
+
+``drivers/video/fbdev/core/dummyblit.c``
+ This contains the dummy text rendering functions used to suppress text
+ output while the bootsplash is shown.
+
+``drivers/tty/vt/keyboard.c``
+ ``kbd_keycode()`` can call ``bootsplash_disable()`` when the user
+ presses ESC or F1-F12 (changing VT). This is to provide a built-in way
+ of disabling the splash manually at any time.
+
+
+
+FAQ: Frequently Asked Questions
+===============================
+
+I want to see the log! How do I show the log?
+---------------------------------------------
+
+Press ESC while the splash is shown, or remove the ``bootsplash.bootfile``
+parameter from the kernel cmdline. Without that parameter, the bootsplash
+will boot disabled.
+
+
+Why use FB instead of modern DRM/KMS?
+-------------------------------------
+
+This is a semantic problem:
+ - What memory to draw the splash to?
+ - And what mode will the screen be set to?
+
+Using the fbdev emulation solves these issues.
+
+Let's start from a bare KMS system, without fbcon, and without fbdev
+emulation. In this case, as long as userspace doesn't open the KMS
+device, the state of the screen is undefined. No framebuffer is
+allocated in video RAM, and no particular mode is set.
+
+In this case, we'd have to allocate a framebuffer to show the splash,
+and set our mode ourselves. This either wastes a screenful of video RAM
+if the splash is to co-exist with the userspace program's own allocated
+framebuffer, or there is a flicker as we deactivate and delete the
+bootsplash's framebuffer and hand control over to userspace. Since we
+may set a different mode than userspace, we'd also have flicker due
+to mode switching.
+
+This logic is already contained in every KMS driver that performs fbdev
+emulation. So we might as well use that. And the correct API to do so is
+fbdev. Plus, we get compatibility with old, pure fbdev drivers for free.
+With the fbdev emulation, there is *always* a well-defined framebuffer
+to draw on. And the selection of mode has already been done by the
+graphics driver, so we don't need to reinvent that wheel, either.
+Finally, if userspace decides to use /dev/fbX, we don't have to worry
+about wasting video RAM, either.
+
+
+Why is the bootsplash integrated in fbcon?
+------------------------------------------
+
+Right now, the bootsplash is drawn from within fbcon, as this allows us
+to easily know *when* to draw - i.e. when we're safe from fbcon and
+userspace drawing all over our beautiful splash logo.
+
+Separating them is not easy - see the to-do list below.
+
+
+
+TO DO list for future development
+=================================
+
+Second enable/disable switch for the system
+-------------------------------------------
+
+It may be helpful to differentiate between the system and the user
+switching off the bootsplash. Thus, the system may make it disappear and
+reappear e.g. for a password prompt, yet once the user has pressed ESC,
+it could stay gone.
+
+
+Fix buggy DRM/KMS drivers
+-------------------------
+
+Currently, the splash code manually checks for fbdev emulation provided by
+the ast, cirrus, and mgag200 DRM/KMS drivers.
+These drivers use a manual mechanism similar to deferred I/O for their FB
+emulation, and thus need to be manually flushed onto the screen in the same
+way.
+
+This may be improved upon in several ways:
+
+1. Changing these drivers to expose the fbdev BO's memory directly, like
+ bochsdrmfb does.
+2. Creating a new fb_ops->fb_flush() API to allow the kernel to flush the
+ framebuffer once the bootsplash has been drawn into it.
+
+
+Separating from fbcon
+---------------------
+
+Separating these two components would yield independence from fbcon being
+compiled into the kernel, and thus lowering code size in embedded
+applications.
+
+To do this cleanly will involve a clean separation of users of an FB device
+within the kernel, i.e. fbcon, bootsplash, and userspace. Right now, the
+legacy fbcon code and VT code co-operate to switch between fbcon and
+userspace (by setting the VT into KD_GRAPHICS mode). Installing a muxer
+between these components ensues refactoring of old code and checking for
+correct locking.

View File

@@ -1,129 +0,0 @@
diff --git a/Documentation/ABI/testing/sysfs-platform-bootsplash b/Documentation/ABI/testing/sysfs-platform-bootsplash
index 742c7b035ded..f8f4b259220e 100644
--- a/Documentation/ABI/testing/sysfs-platform-bootsplash
+++ b/Documentation/ABI/testing/sysfs-platform-bootsplash
@@ -9,3 +9,35 @@ Description:
1: Splash is shown whenever fbcon would show a text console
(i.e. no graphical application is running), and a splash
file is loaded.
+
+What: /sys/devices/platform/bootsplash.0/drop_splash
+Date: Oct 2017
+KernelVersion: 4.14
+Contact: Max Staudt <mstaudt@suse.de>
+Description:
+ Can only be set.
+
+ Any value written will cause the current splash theme file
+ to be unloaded and the text console to be redrawn.
+
+What: /sys/devices/platform/bootsplash.0/load_file
+Date: Oct 2017
+KernelVersion: 4.14
+Contact: Max Staudt <mstaudt@suse.de>
+Description:
+ Can only be set.
+
+ Any value written will cause the splash to be disabled and
+ internal memory structures to be freed.
+
+ A firmware path written will cause a new theme file to be
+ loaded and the current bootsplash to be replaced.
+ The current enabled/disabled status is not touched.
+ If the splash is already active, it will be redrawn.
+
+ The path has to be a path in /lib/firmware since
+ request_firmware() is used to fetch the data.
+
+ When setting the splash from the shell, echo -n has to be
+ used as any trailing '\n' newline will be interpreted as
+ part of the path.
diff --git a/Documentation/bootsplash.rst b/Documentation/bootsplash.rst
index 611f0c558925..b35aba5093e8 100644
--- a/Documentation/bootsplash.rst
+++ b/Documentation/bootsplash.rst
@@ -67,6 +67,14 @@ sysfs run-time configuration
a splash theme file is also loaded.
+``/sys/devices/platform/bootsplash.0/drop_splash``
+ Unload splash data and free memory.
+
+``/sys/devices/platform/bootsplash.0/load_file``
+ Load a splash file from ``/lib/firmware/``.
+ Note that trailing newlines will be interpreted as part of the file name.
+
+
Kconfig
=======
diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
index 13fcaabbc2ca..16cb0493629d 100644
--- a/drivers/video/fbdev/core/bootsplash.c
+++ b/drivers/video/fbdev/core/bootsplash.c
@@ -251,11 +251,65 @@ static ssize_t splash_store_enabled(struct device *device,
return count;
}
+static ssize_t splash_store_drop_splash(struct device *device,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct splash_file_priv *fp;
+
+ if (!buf || !count || !splash_state.file)
+ return count;
+
+ mutex_lock(&splash_state.data_lock);
+ fp = splash_state.file;
+ splash_state.file = NULL;
+ mutex_unlock(&splash_state.data_lock);
+
+ /* Redraw the text console */
+ schedule_work(&splash_state.work_redraw_vc);
+
+ bootsplash_free_file(fp);
+
+ return count;
+}
+
+static ssize_t splash_store_load_file(struct device *device,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct splash_file_priv *fp, *fp_old;
+
+ if (!count)
+ return 0;
+
+ fp = bootsplash_load_firmware(&splash_state.splash_device->dev,
+ buf);
+
+ if (!fp)
+ return -ENXIO;
+
+ mutex_lock(&splash_state.data_lock);
+ fp_old = splash_state.file;
+ splash_state.splash_fb = NULL;
+ splash_state.file = fp;
+ mutex_unlock(&splash_state.data_lock);
+
+ /* Update the splash or text console */
+ schedule_work(&splash_state.work_redraw_vc);
+
+ bootsplash_free_file(fp_old);
+ return count;
+}
+
static DEVICE_ATTR(enabled, 0644, splash_show_enabled, splash_store_enabled);
+static DEVICE_ATTR(drop_splash, 0200, NULL, splash_store_drop_splash);
+static DEVICE_ATTR(load_file, 0200, NULL, splash_store_load_file);
static struct attribute *splash_dev_attrs[] = {
&dev_attr_enabled.attr,
+ &dev_attr_drop_splash.attr,
+ &dev_attr_load_file.attr,
NULL
};

View File

@@ -1,499 +0,0 @@
diff --git a/tools/bootsplash/.gitignore b/tools/bootsplash/.gitignore
new file mode 100644
index 000000000000..091b99a17567
--- /dev/null
+++ b/tools/bootsplash/.gitignore
@@ -0,0 +1 @@
+bootsplash-packer
diff --git a/tools/bootsplash/Makefile b/tools/bootsplash/Makefile
new file mode 100644
index 000000000000..0ad8e8a84942
--- /dev/null
+++ b/tools/bootsplash/Makefile
@@ -0,0 +1,9 @@
+CC := $(CROSS_COMPILE)gcc
+CFLAGS := -I../../usr/include
+
+PROGS := bootsplash-packer
+
+all: $(PROGS)
+
+clean:
+ rm -fr $(PROGS)
diff --git a/tools/bootsplash/bootsplash-packer.c b/tools/bootsplash/bootsplash-packer.c
new file mode 100644
index 000000000000..ffb6a8b69885
--- /dev/null
+++ b/tools/bootsplash/bootsplash-packer.c
@@ -0,0 +1,471 @@
+/*
+ * Kernel based bootsplash.
+ *
+ * (Splash file packer tool)
+ *
+ * Authors:
+ * Max Staudt <mstaudt@suse.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <endian.h>
+#include <getopt.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <linux/bootsplash_file.h>
+
+
+static void print_help(char *progname)
+{
+ printf("Usage: %s [OPTIONS] outfile\n", progname);
+ printf("\n"
+ "Options, executed in order given:\n"
+ " -h, --help Print this help message\n"
+ "\n"
+ " --bg_red <u8> Background color (red part)\n"
+ " --bg_green <u8> Background color (green part)\n"
+ " --bg_blue <u8> Background color (blue part)\n"
+ " --bg_reserved <u8> (do not use)\n"
+ " --frame_ms <u16> Minimum milliseconds between animation steps\n"
+ "\n"
+ " --picture Start describing the next picture\n"
+ " --pic_width <u16> Picture width in pixels\n"
+ " --pic_height <u16> Picture height in pixels\n"
+ " --pic_position <u8> Coarse picture placement:\n"
+ " 0x00 - Top left\n"
+ " 0x01 - Top\n"
+ " 0x02 - Top right\n"
+ " 0x03 - Right\n"
+ " 0x04 - Bottom right\n"
+ " 0x05 - Bottom\n"
+ " 0x06 - Bottom left\n"
+ " 0x07 - Left\n"
+ "\n"
+ " Flags:\n"
+ " 0x10 - Calculate offset from corner towards center,\n"
+ " rather than from center towards corner\n"
+ " --pic_position_offset <u16> Distance from base position in pixels\n"
+ " --pic_anim_type <u8> Animation type:\n"
+ " 0 - None\n"
+ " 1 - Forward loop\n"
+ " --pic_anim_loop <u8> Loop point for animation\n"
+ "\n"
+ " --blob <filename> Include next data stream\n"
+ " --blob_type <u16> Type of data\n"
+ " --blob_picture_id <u8> Picture to associate this blob with, starting at 0\n"
+ " (default: number of last --picture)\n"
+ "\n");
+ printf("This tool will write %s files.\n\n",
+#if __BYTE_ORDER == __BIG_ENDIAN
+ "Big Endian (BE)");
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+ "Little Endian (LE)");
+#else
+#error
+#endif
+}
+
+
+struct blob_entry {
+ struct blob_entry *next;
+
+ char *fn;
+
+ struct splash_blob_header header;
+};
+
+
+static void dump_file_header(struct splash_file_header *h)
+{
+ printf(" --- File header ---\n");
+ printf("\n");
+ printf(" version: %5u\n", h->version);
+ printf("\n");
+ printf(" bg_red: %5u\n", h->bg_red);
+ printf(" bg_green: %5u\n", h->bg_green);
+ printf(" bg_blue: %5u\n", h->bg_blue);
+ printf(" bg_reserved: %5u\n", h->bg_reserved);
+ printf("\n");
+ printf(" num_blobs: %5u\n", h->num_blobs);
+ printf(" num_pics: %5u\n", h->num_pics);
+ printf("\n");
+ printf(" frame_ms: %5u\n", h->frame_ms);
+ printf("\n");
+}
+
+static void dump_pic_header(struct splash_pic_header *ph)
+{
+ printf(" --- Picture header ---\n");
+ printf("\n");
+ printf(" width: %5u\n", ph->width);
+ printf(" height: %5u\n", ph->height);
+ printf("\n");
+ printf(" num_blobs: %5u\n", ph->num_blobs);
+ printf("\n");
+ printf(" position: %0x3x\n", ph->position);
+ printf(" position_offset: %5u\n", ph->position_offset);
+ printf("\n");
+ printf(" anim_type: %5u\n", ph->anim_type);
+ printf(" anim_loop: %5u\n", ph->anim_loop);
+ printf("\n");
+}
+
+static void dump_blob(struct blob_entry *b)
+{
+ printf(" --- Blob header ---\n");
+ printf("\n");
+ printf(" length: %7u\n", b->header.length);
+ printf(" type: %7u\n", b->header.type);
+ printf("\n");
+ printf(" picture_id: %7u\n", b->header.picture_id);
+ printf("\n");
+}
+
+
+#define OPT_MAX(var, max) \
+ do { \
+ if ((var) > max) { \
+ fprintf(stderr, "--%s: Invalid value\n", \
+ long_options[option_index].name); \
+ break; \
+ } \
+ } while (0)
+
+static struct option long_options[] = {
+ {"help", 0, 0, 'h'},
+ {"bg_red", 1, 0, 10001},
+ {"bg_green", 1, 0, 10002},
+ {"bg_blue", 1, 0, 10003},
+ {"bg_reserved", 1, 0, 10004},
+ {"frame_ms", 1, 0, 10005},
+ {"picture", 0, 0, 20000},
+ {"pic_width", 1, 0, 20001},
+ {"pic_height", 1, 0, 20002},
+ {"pic_position", 1, 0, 20003},
+ {"pic_position_offset", 1, 0, 20004},
+ {"pic_anim_type", 1, 0, 20005},
+ {"pic_anim_loop", 1, 0, 20006},
+ {"blob", 1, 0, 30000},
+ {"blob_type", 1, 0, 30001},
+ {"blob_picture_id", 1, 0, 30002},
+ {NULL, 0, NULL, 0}
+};
+
+
+int main(int argc, char **argv)
+{
+ FILE *of;
+ char *ofn;
+ int c;
+ int option_index = 0;
+
+ unsigned long ul;
+ struct splash_file_header fh = {};
+ struct splash_pic_header ph[255];
+ struct blob_entry *blob_first = NULL;
+ struct blob_entry *blob_last = NULL;
+ struct blob_entry *blob_cur = NULL;
+
+ if (argc < 2) {
+ print_help(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+
+ /* Parse and and execute user commands */
+ while ((c = getopt_long(argc, argv, "h",
+ long_options, &option_index)) != -1) {
+ switch (c) {
+ case 10001: /* bg_red */
+ ul = strtoul(optarg, NULL, 0);
+ OPT_MAX(ul, 255);
+ fh.bg_red = ul;
+ break;
+ case 10002: /* bg_green */
+ ul = strtoul(optarg, NULL, 0);
+ OPT_MAX(ul, 255);
+ fh.bg_green = ul;
+ break;
+ case 10003: /* bg_blue */
+ ul = strtoul(optarg, NULL, 0);
+ OPT_MAX(ul, 255);
+ fh.bg_blue = ul;
+ break;
+ case 10004: /* bg_reserved */
+ ul = strtoul(optarg, NULL, 0);
+ OPT_MAX(ul, 255);
+ fh.bg_reserved = ul;
+ break;
+ case 10005: /* frame_ms */
+ ul = strtoul(optarg, NULL, 0);
+ OPT_MAX(ul, 65535);
+ fh.frame_ms = ul;
+ break;
+
+
+ case 20000: /* picture */
+ if (fh.num_pics >= 255) {
+ fprintf(stderr, "--%s: Picture array full\n",
+ long_options[option_index].name);
+ break;
+ }
+
+ fh.num_pics++;
+ break;
+
+ case 20001: /* pic_width */
+ ul = strtoul(optarg, NULL, 0);
+ OPT_MAX(ul, 65535);
+ ph[fh.num_pics - 1].width = ul;
+ break;
+
+ case 20002: /* pic_height */
+ ul = strtoul(optarg, NULL, 0);
+ OPT_MAX(ul, 65535);
+ ph[fh.num_pics - 1].height = ul;
+ break;
+
+ case 20003: /* pic_position */
+ ul = strtoul(optarg, NULL, 0);
+ OPT_MAX(ul, 255);
+ ph[fh.num_pics - 1].position = ul;
+ break;
+
+ case 20004: /* pic_position_offset */
+ ul = strtoul(optarg, NULL, 0);
+ OPT_MAX(ul, 255);
+ ph[fh.num_pics - 1].position_offset = ul;
+ break;
+
+ case 20005: /* pic_anim_type */
+ ul = strtoul(optarg, NULL, 0);
+ OPT_MAX(ul, 255);
+ ph[fh.num_pics - 1].anim_type = ul;
+ break;
+
+ case 20006: /* pic_anim_loop */
+ ul = strtoul(optarg, NULL, 0);
+ OPT_MAX(ul, 255);
+ ph[fh.num_pics - 1].anim_loop = ul;
+ break;
+
+
+ case 30000: /* blob */
+ if (fh.num_blobs >= 65535) {
+ fprintf(stderr, "--%s: Blob array full\n",
+ long_options[option_index].name);
+ break;
+ }
+
+ blob_cur = calloc(1, sizeof(struct blob_entry));
+ if (!blob_cur) {
+ fprintf(stderr, "--%s: Out of memory\n",
+ long_options[option_index].name);
+ break;
+ }
+
+ blob_cur->fn = optarg;
+ if (fh.num_pics)
+ blob_cur->header.picture_id = fh.num_pics - 1;
+
+ if (!blob_first)
+ blob_first = blob_cur;
+ if (blob_last)
+ blob_last->next = blob_cur;
+ blob_last = blob_cur;
+ fh.num_blobs++;
+ break;
+
+ case 30001: /* blob_type */
+ if (!blob_cur) {
+ fprintf(stderr, "--%s: No blob selected\n",
+ long_options[option_index].name);
+ break;
+ }
+
+ ul = strtoul(optarg, NULL, 0);
+ OPT_MAX(ul, 255);
+ blob_cur->header.type = ul;
+ break;
+
+ case 30002: /* blob_picture_id */
+ if (!blob_cur) {
+ fprintf(stderr, "--%s: No blob selected\n",
+ long_options[option_index].name);
+ break;
+ }
+
+ ul = strtoul(optarg, NULL, 0);
+ OPT_MAX(ul, 255);
+ blob_cur->header.picture_id = ul;
+ break;
+
+
+
+ case 'h':
+ case '?':
+ default:
+ print_help(argv[0]);
+ goto EXIT;
+ } /* switch (c) */
+ } /* while ((c = getopt_long(...)) != -1) */
+
+ /* Consume and drop lone arguments */
+ while (optind < argc) {
+ ofn = argv[optind];
+ optind++;
+ }
+
+
+ /* Read file lengths */
+ for (blob_cur = blob_first; blob_cur; blob_cur = blob_cur->next) {
+ FILE *f;
+ long pos;
+ int i;
+
+ if (!blob_cur->fn)
+ continue;
+
+ f = fopen(blob_cur->fn, "rb");
+ if (!f)
+ goto ERR_FILE_LEN;
+
+ if (fseek(f, 0, SEEK_END))
+ goto ERR_FILE_LEN;
+
+ pos = ftell(f);
+ if (pos < 0 || pos > (1 << 30))
+ goto ERR_FILE_LEN;
+
+ blob_cur->header.length = pos;
+
+ fclose(f);
+ continue;
+
+ERR_FILE_LEN:
+ fprintf(stderr, "Error getting file length (or too long): %s\n",
+ blob_cur->fn);
+ if (f)
+ fclose(f);
+ continue;
+ }
+
+
+ /* Set magic headers */
+#if __BYTE_ORDER == __BIG_ENDIAN
+ memcpy(&fh.id[0], BOOTSPLASH_MAGIC_BE, 16);
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+ memcpy(&fh.id[0], BOOTSPLASH_MAGIC_LE, 16);
+#else
+#error
+#endif
+ fh.version = BOOTSPLASH_VERSION;
+
+ /* Set blob counts */
+ for (blob_cur = blob_first; blob_cur; blob_cur = blob_cur->next) {
+ if (blob_cur->header.picture_id < fh.num_pics)
+ ph[blob_cur->header.picture_id].num_blobs++;
+ }
+
+
+ /* Dump structs */
+ dump_file_header(&fh);
+
+ for (ul = 0; ul < fh.num_pics; ul++)
+ dump_pic_header(&ph[ul]);
+
+ for (blob_cur = blob_first; blob_cur; blob_cur = blob_cur->next)
+ dump_blob(blob_cur);
+
+
+ /* Write to file */
+ printf("Writing splash to file: %s\n", ofn);
+ of = fopen(ofn, "wb");
+ if (!of)
+ goto ERR_WRITING;
+
+ if (fwrite(&fh, sizeof(struct splash_file_header), 1, of) != 1)
+ goto ERR_WRITING;
+
+ for (ul = 0; ul < fh.num_pics; ul++) {
+ if (fwrite(&ph[ul], sizeof(struct splash_pic_header), 1, of)
+ != 1)
+ goto ERR_WRITING;
+ }
+
+ blob_cur = blob_first;
+ while (blob_cur) {
+ struct blob_entry *blob_old = blob_cur;
+ FILE *f;
+ char *buf[256];
+ uint32_t left;
+
+ if (fwrite(&blob_cur->header,
+ sizeof(struct splash_blob_header), 1, of) != 1)
+ goto ERR_WRITING;
+
+ if (!blob_cur->header.length || !blob_cur->fn)
+ continue;
+
+ f = fopen(blob_cur->fn, "rb");
+ if (!f)
+ goto ERR_FILE_COPY;
+
+ left = blob_cur->header.length;
+ while (left >= sizeof(buf)) {
+ if (fread(buf, sizeof(buf), 1, f) != 1)
+ goto ERR_FILE_COPY;
+ if (fwrite(buf, sizeof(buf), 1, of) != 1)
+ goto ERR_FILE_COPY;
+ left -= sizeof(buf);
+ }
+ if (left) {
+ if (fread(buf, left, 1, f) != 1)
+ goto ERR_FILE_COPY;
+ if (fwrite(buf, left, 1, of) != 1)
+ goto ERR_FILE_COPY;
+ }
+
+ /* Pad data stream to 16 bytes */
+ if (left % 16) {
+ if (fwrite("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
+ 16 - (left % 16), 1, of) != 1)
+ goto ERR_FILE_COPY;
+ }
+
+ fclose(f);
+ blob_cur = blob_cur->next;
+ free(blob_old);
+ continue;
+
+ERR_FILE_COPY:
+ if (f)
+ fclose(f);
+ goto ERR_WRITING;
+ }
+
+ fclose(of);
+
+EXIT:
+ return EXIT_SUCCESS;
+
+
+ERR_WRITING:
+ fprintf(stderr, "Error writing splash.\n");
+ fprintf(stderr, "The output file is probably corrupt.\n");
+ if (of)
+ fclose(of);
+
+ while (blob_cur) {
+ struct blob_entry *blob_old = blob_cur;
+
+ blob_cur = blob_cur->next;
+ free(blob_old);
+ }
+
+ return EXIT_FAILURE;
+}

View File

@@ -1,10 +0,0 @@
--- a/fbtft-core.c
+++ b/fbtft-core.c
@@ -52,7 +52,7 @@
module_param(debug, ulong , 0);
MODULE_PARM_DESC(debug, "override device debug level");
-static bool dma = true;
+static bool dma = false;
module_param(dma, bool, 0);
MODULE_PARM_DESC(dma, "Use DMA buffer");

View File

@@ -1,37 +0,0 @@
From 27517cde069da44a218ce13b5d46fee19c1bcc77 Mon Sep 17 00:00:00 2001
From: Helge Deller <deller@gmx.de>
Date: Mon, 7 Feb 2022 16:59:31 +0100
Subject: [PATCH] Revert "fbcon: Avoid 'cap' set but not used warning"
This reverts commit 3523167d665852fc5f92971aefea8f3bd4e2f6fd.
---
drivers/video/fbdev/core/fbcon.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index a53c1f6906f0..f7b7d35953e8 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -1025,7 +1025,7 @@ static void fbcon_init(struct vc_data *vc, int init)
struct vc_data *svc = *default_mode;
struct fbcon_display *t, *p = &fb_display[vc->vc_num];
int logo = 1, new_rows, new_cols, rows, cols;
- int ret;
+ int cap, ret;
if (WARN_ON(info_idx == -1))
return;
@@ -1136,8 +1137,8 @@ static void fbcon_init(struct vc_data *vc, int init)
ops->graphics = 0;
#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
- if ((info->flags & FBINFO_HWACCEL_COPYAREA) &&
- !(info->flags & FBINFO_HWACCEL_DISABLED))
+ if ((cap & FBINFO_HWACCEL_COPYAREA) &&
+ !(cap & FBINFO_HWACCEL_DISABLED))
p->scrollmode = SCROLL_MOVE;
else /* default to something safe */
p->scrollmode = SCROLL_REDRAW;
--
2.25.1

View File

@@ -1,360 +0,0 @@
From b205b9e8c05a4e9ea136036f36739e3385878477 Mon Sep 17 00:00:00 2001
From: Igor Pecovnik <igor.pecovnik@gmail.com>
Date: Thu, 10 Feb 2022 16:48:05 +0100
Subject: [PATCH 1/2] Revert "fbcon: Add option to enable legacy hardware
acceleration"
This reverts commit 72c4cec1d21ab6fa1b7b6ed5a60a85b421028b89.
---
drivers/video/console/Kconfig | 20 -------------
drivers/video/fbdev/core/fbcon.c | 39 +++++++------------------
drivers/video/fbdev/core/fbcon.h | 15 +---------
drivers/video/fbdev/core/fbcon_ccw.c | 10 +++----
drivers/video/fbdev/core/fbcon_cw.c | 10 +++----
drivers/video/fbdev/core/fbcon_rotate.h | 4 +--
drivers/video/fbdev/core/fbcon_ud.c | 20 ++++++-------
7 files changed, 34 insertions(+), 84 deletions(-)
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index fcc46380e7c9..840d9813b0bc 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -78,26 +78,6 @@ config FRAMEBUFFER_CONSOLE
help
Low-level framebuffer-based console driver.
-config FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
- bool "Enable legacy fbcon hardware acceleration code"
- depends on FRAMEBUFFER_CONSOLE
- default y if PARISC
- default n
- help
- This option enables the fbcon (framebuffer text-based) hardware
- acceleration for graphics drivers which were written for the fbdev
- graphics interface.
-
- On modern machines, on mainstream machines (like x86-64) or when
- using a modern Linux distribution those fbdev drivers usually aren't used.
- So enabling this option wouldn't have any effect, which is why you want
- to disable this option on such newer machines.
-
- If you compile this kernel for older machines which still require the
- fbdev drivers, you may want to say Y.
-
- If unsure, select n.
-
config FRAMEBUFFER_CONSOLE_DETECT_PRIMARY
bool "Map the console to the primary display device"
depends on FRAMEBUFFER_CONSOLE
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index f36829eeb5a9..0cc2a36b674a 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -1136,13 +1136,11 @@ static void fbcon_init(struct vc_data *vc, int init)
ops->graphics = 0;
-#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
if ((cap & FBINFO_HWACCEL_COPYAREA) &&
!(cap & FBINFO_HWACCEL_DISABLED))
p->scrollmode = SCROLL_MOVE;
else /* default to something safe */
p->scrollmode = SCROLL_REDRAW;
-#endif
/*
* ++guenther: console.c:vc_allocate() relies on initializing
@@ -1707,7 +1705,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
count = vc->vc_rows;
if (logo_shown >= 0)
goto redraw_up;
- switch (fb_scrollmode(p)) {
+ switch (p->scrollmode) {
case SCROLL_MOVE:
fbcon_redraw_blit(vc, info, p, t, b - t - count,
count);
@@ -1797,7 +1795,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
count = vc->vc_rows;
if (logo_shown >= 0)
goto redraw_down;
- switch (fb_scrollmode(p)) {
+ switch (p->scrollmode) {
case SCROLL_MOVE:
fbcon_redraw_blit(vc, info, p, b - 1, b - t - count,
-count);
@@ -1948,12 +1946,12 @@ static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy,
height, width);
}
-static void updatescrollmode_accel(struct fbcon_display *p,
+static void updatescrollmode(struct fbcon_display *p,
struct fb_info *info,
struct vc_data *vc)
{
-#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
struct fbcon_ops *ops = info->fbcon_par;
+ int fh = vc->vc_font.height;
int cap = info->flags;
u16 t = 0;
int ypan = FBCON_SWAP(ops->rotate, info->fix.ypanstep,
@@ -1974,6 +1972,12 @@ static void updatescrollmode_accel(struct fbcon_display *p,
int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) &&
!(cap & FBINFO_HWACCEL_DISABLED);
+ p->vrows = vyres/fh;
+ if (yres > (fh * (vc->vc_rows + 1)))
+ p->vrows -= (yres - (fh * vc->vc_rows)) / fh;
+ if ((yres % fh) && (vyres % fh < yres % fh))
+ p->vrows--;
+
if (good_wrap || good_pan) {
if (reading_fast || fast_copyarea)
p->scrollmode = good_wrap ?
@@ -1987,27 +1991,6 @@ static void updatescrollmode_accel(struct fbcon_display *p,
else
p->scrollmode = SCROLL_REDRAW;
}
-#endif
-}
-
-static void updatescrollmode(struct fbcon_display *p,
- struct fb_info *info,
- struct vc_data *vc)
-{
- struct fbcon_ops *ops = info->fbcon_par;
- int fh = vc->vc_font.height;
- int yres = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
- int vyres = FBCON_SWAP(ops->rotate, info->var.yres_virtual,
- info->var.xres_virtual);
-
- p->vrows = vyres/fh;
- if (yres > (fh * (vc->vc_rows + 1)))
- p->vrows -= (yres - (fh * vc->vc_rows)) / fh;
- if ((yres % fh) && (vyres % fh < yres % fh))
- p->vrows--;
-
- /* update scrollmode in case hardware acceleration is used */
- updatescrollmode_accel(p, info, vc);
}
#define PITCH(w) (((w) + 7) >> 3)
@@ -2165,7 +2148,7 @@ static int fbcon_switch(struct vc_data *vc)
updatescrollmode(p, info, vc);
- switch (fb_scrollmode(p)) {
+ switch (p->scrollmode) {
case SCROLL_WRAP_MOVE:
scrollback_phys_max = p->vrows - vc->vc_rows;
break;
diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h
index 969d41ecede5..5246d0f2574b 100644
--- a/drivers/video/fbdev/core/fbcon.h
+++ b/drivers/video/fbdev/core/fbcon.h
@@ -29,9 +29,7 @@ struct fbcon_display {
/* Filled in by the low-level console driver */
const u_char *fontdata;
int userfont; /* != 0 if fontdata kmalloc()ed */
-#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
- u_short scrollmode; /* Scroll Method, use fb_scrollmode() */
-#endif
+ u_short scrollmode; /* Scroll Method */
u_short inverse; /* != 0 text black on white as default */
short yscroll; /* Hardware scrolling */
int vrows; /* number of virtual rows */
@@ -210,17 +208,6 @@ static inline int attr_col_ec(int shift, struct vc_data *vc,
#define SCROLL_REDRAW 0x004
#define SCROLL_PAN_REDRAW 0x005
-static inline u_short fb_scrollmode(struct fbcon_display *fb)
-{
-#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
- return fb->scrollmode;
-#else
- /* hardcoded to SCROLL_REDRAW if acceleration was disabled. */
- return SCROLL_REDRAW;
-#endif
-}
-
-
#ifdef CONFIG_FB_TILEBLITTING
extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info);
#endif
diff --git a/drivers/video/fbdev/core/fbcon_ccw.c b/drivers/video/fbdev/core/fbcon_ccw.c
index 2789ace79634..9cd2c4b05c32 100644
--- a/drivers/video/fbdev/core/fbcon_ccw.c
+++ b/drivers/video/fbdev/core/fbcon_ccw.c
@@ -65,7 +65,7 @@ static void ccw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
{
struct fbcon_ops *ops = info->fbcon_par;
struct fb_copyarea area;
- u32 vyres = GETVYRES(ops->p, info);
+ u32 vyres = GETVYRES(ops->p->scrollmode, info);
area.sx = sy * vc->vc_font.height;
area.sy = vyres - ((sx + width) * vc->vc_font.width);
@@ -83,7 +83,7 @@ static void ccw_clear(struct vc_data *vc, struct fb_info *info, int sy,
struct fbcon_ops *ops = info->fbcon_par;
struct fb_fillrect region;
int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
- u32 vyres = GETVYRES(ops->p, info);
+ u32 vyres = GETVYRES(ops->p->scrollmode, info);
region.color = attr_bgcol_ec(bgshift,vc,info);
region.dx = sy * vc->vc_font.height;
@@ -140,7 +140,7 @@ static void ccw_putcs(struct vc_data *vc, struct fb_info *info,
u32 cnt, pitch, size;
u32 attribute = get_attribute(info, scr_readw(s));
u8 *dst, *buf = NULL;
- u32 vyres = GETVYRES(ops->p, info);
+ u32 vyres = GETVYRES(ops->p->scrollmode, info);
if (!ops->fontbuffer)
return;
@@ -229,7 +229,7 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
int err = 1, dx, dy;
char *src;
- u32 vyres = GETVYRES(ops->p, info);
+ u32 vyres = GETVYRES(ops->p->scrollmode, info);
if (!ops->fontbuffer)
return;
@@ -387,7 +387,7 @@ static int ccw_update_start(struct fb_info *info)
{
struct fbcon_ops *ops = info->fbcon_par;
u32 yoffset;
- u32 vyres = GETVYRES(ops->p, info);
+ u32 vyres = GETVYRES(ops->p->scrollmode, info);
int err;
yoffset = (vyres - info->var.yres) - ops->var.xoffset;
diff --git a/drivers/video/fbdev/core/fbcon_cw.c b/drivers/video/fbdev/core/fbcon_cw.c
index 86a254c1b2b7..88d89fad3f05 100644
--- a/drivers/video/fbdev/core/fbcon_cw.c
+++ b/drivers/video/fbdev/core/fbcon_cw.c
@@ -50,7 +50,7 @@ static void cw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
{
struct fbcon_ops *ops = info->fbcon_par;
struct fb_copyarea area;
- u32 vxres = GETVXRES(ops->p, info);
+ u32 vxres = GETVXRES(ops->p->scrollmode, info);
area.sx = vxres - ((sy + height) * vc->vc_font.height);
area.sy = sx * vc->vc_font.width;
@@ -68,7 +68,7 @@ static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy,
struct fbcon_ops *ops = info->fbcon_par;
struct fb_fillrect region;
int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
- u32 vxres = GETVXRES(ops->p, info);
+ u32 vxres = GETVXRES(ops->p->scrollmode, info);
region.color = attr_bgcol_ec(bgshift,vc,info);
region.dx = vxres - ((sy + height) * vc->vc_font.height);
@@ -125,7 +125,7 @@ static void cw_putcs(struct vc_data *vc, struct fb_info *info,
u32 cnt, pitch, size;
u32 attribute = get_attribute(info, scr_readw(s));
u8 *dst, *buf = NULL;
- u32 vxres = GETVXRES(ops->p, info);
+ u32 vxres = GETVXRES(ops->p->scrollmode, info);
if (!ops->fontbuffer)
return;
@@ -212,7 +212,7 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
int err = 1, dx, dy;
char *src;
- u32 vxres = GETVXRES(ops->p, info);
+ u32 vxres = GETVXRES(ops->p->scrollmode, info);
if (!ops->fontbuffer)
return;
@@ -369,7 +369,7 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
static int cw_update_start(struct fb_info *info)
{
struct fbcon_ops *ops = info->fbcon_par;
- u32 vxres = GETVXRES(ops->p, info);
+ u32 vxres = GETVXRES(ops->p->scrollmode, info);
u32 xoffset;
int err;
diff --git a/drivers/video/fbdev/core/fbcon_rotate.h b/drivers/video/fbdev/core/fbcon_rotate.h
index 01cbe303b8a2..e233444cda66 100644
--- a/drivers/video/fbdev/core/fbcon_rotate.h
+++ b/drivers/video/fbdev/core/fbcon_rotate.h
@@ -12,11 +12,11 @@
#define _FBCON_ROTATE_H
#define GETVYRES(s,i) ({ \
- (fb_scrollmode(s) == SCROLL_REDRAW || fb_scrollmode(s) == SCROLL_MOVE) ? \
+ (s == SCROLL_REDRAW || s == SCROLL_MOVE) ? \
(i)->var.yres : (i)->var.yres_virtual; })
#define GETVXRES(s,i) ({ \
- (fb_scrollmode(s) == SCROLL_REDRAW || fb_scrollmode(s) == SCROLL_MOVE || !(i)->fix.xpanstep) ? \
+ (s == SCROLL_REDRAW || s == SCROLL_MOVE || !(i)->fix.xpanstep) ? \
(i)->var.xres : (i)->var.xres_virtual; })
diff --git a/drivers/video/fbdev/core/fbcon_ud.c b/drivers/video/fbdev/core/fbcon_ud.c
index 23bc045769d0..8d5e66b1bdfb 100644
--- a/drivers/video/fbdev/core/fbcon_ud.c
+++ b/drivers/video/fbdev/core/fbcon_ud.c
@@ -50,8 +50,8 @@ static void ud_bmove(struct vc_data *vc, struct fb_info *info, int sy,
{
struct fbcon_ops *ops = info->fbcon_par;
struct fb_copyarea area;
- u32 vyres = GETVYRES(ops->p, info);
- u32 vxres = GETVXRES(ops->p, info);
+ u32 vyres = GETVYRES(ops->p->scrollmode, info);
+ u32 vxres = GETVXRES(ops->p->scrollmode, info);
area.sy = vyres - ((sy + height) * vc->vc_font.height);
area.sx = vxres - ((sx + width) * vc->vc_font.width);
@@ -69,8 +69,8 @@ static void ud_clear(struct vc_data *vc, struct fb_info *info, int sy,
struct fbcon_ops *ops = info->fbcon_par;
struct fb_fillrect region;
int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
- u32 vyres = GETVYRES(ops->p, info);
- u32 vxres = GETVXRES(ops->p, info);
+ u32 vyres = GETVYRES(ops->p->scrollmode, info);
+ u32 vxres = GETVXRES(ops->p->scrollmode, info);
region.color = attr_bgcol_ec(bgshift,vc,info);
region.dy = vyres - ((sy + height) * vc->vc_font.height);
@@ -162,8 +162,8 @@ static void ud_putcs(struct vc_data *vc, struct fb_info *info,
u32 mod = vc->vc_font.width % 8, cnt, pitch, size;
u32 attribute = get_attribute(info, scr_readw(s));
u8 *dst, *buf = NULL;
- u32 vyres = GETVYRES(ops->p, info);
- u32 vxres = GETVXRES(ops->p, info);
+ u32 vyres = GETVYRES(ops->p->scrollmode, info);
+ u32 vxres = GETVXRES(ops->p->scrollmode, info);
if (!ops->fontbuffer)
return;
@@ -259,8 +259,8 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode,
int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
int err = 1, dx, dy;
char *src;
- u32 vyres = GETVYRES(ops->p, info);
- u32 vxres = GETVXRES(ops->p, info);
+ u32 vyres = GETVYRES(ops->p->scrollmode, info);
+ u32 vxres = GETVXRES(ops->p->scrollmode, info);
if (!ops->fontbuffer)
return;
@@ -410,8 +410,8 @@ static int ud_update_start(struct fb_info *info)
{
struct fbcon_ops *ops = info->fbcon_par;
int xoffset, yoffset;
- u32 vyres = GETVYRES(ops->p, info);
- u32 vxres = GETVXRES(ops->p, info);
+ u32 vyres = GETVYRES(ops->p->scrollmode, info);
+ u32 vxres = GETVXRES(ops->p->scrollmode, info);
int err;
xoffset = vxres - info->var.xres - ops->var.xoffset;
--
2.25.1

View File

@@ -1,132 +0,0 @@
From abd60692635211581dec506af647ac9295d21d69 Mon Sep 17 00:00:00 2001
From: Igor Pecovnik <igor.pecovnik@gmail.com>
Date: Thu, 10 Feb 2022 16:48:23 +0100
Subject: [PATCH 2/2] Revert "Revert "fbcon: Disable accelerated scrolling""
This reverts commit ba724328faffc640b7772c953bd061bf6c4d39cd.
---
Documentation/gpu/todo.rst | 21 +++++++++++++++
drivers/video/fbdev/core/fbcon.c | 45 ++++++--------------------------
2 files changed, 29 insertions(+), 37 deletions(-)
diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst
index 01fb97dd2dd0..6613543955e9 100644
--- a/Documentation/gpu/todo.rst
+++ b/Documentation/gpu/todo.rst
@@ -311,6 +311,27 @@ Contact: Daniel Vetter, Noralf Tronnes
Level: Advanced
+Garbage collect fbdev scrolling acceleration
+--------------------------------------------
+
+Scroll acceleration is disabled in fbcon by hard-wiring p->scrollmode =
+SCROLL_REDRAW. There's a ton of code this will allow us to remove:
+
+- lots of code in fbcon.c
+
+- a bunch of the hooks in fbcon_ops, maybe the remaining hooks could be called
+ directly instead of the function table (with a switch on p->rotate)
+
+- fb_copyarea is unused after this, and can be deleted from all drivers
+
+Note that not all acceleration code can be deleted, since clearing and cursor
+support is still accelerated, which might be good candidates for further
+deletion projects.
+
+Contact: Daniel Vetter
+
+Level: Intermediate
+
idr_init_base()
---------------
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 0cc2a36b674a..fc34caddf9cf 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -1025,7 +1025,7 @@ static void fbcon_init(struct vc_data *vc, int init)
struct vc_data *svc = *default_mode;
struct fbcon_display *t, *p = &fb_display[vc->vc_num];
int logo = 1, new_rows, new_cols, rows, cols;
- int cap, ret;
+ int ret;
if (WARN_ON(info_idx == -1))
return;
@@ -1034,7 +1034,6 @@ static void fbcon_init(struct vc_data *vc, int init)
con2fb_map[vc->vc_num] = info_idx;
info = registered_fb[con2fb_map[vc->vc_num]];
- cap = info->flags;
if (logo_shown < 0 && console_loglevel <= CONSOLE_LOGLEVEL_QUIET)
logo_shown = FBCON_LOGO_DONTSHOW;
@@ -1136,11 +1135,13 @@ static void fbcon_init(struct vc_data *vc, int init)
ops->graphics = 0;
- if ((cap & FBINFO_HWACCEL_COPYAREA) &&
- !(cap & FBINFO_HWACCEL_DISABLED))
- p->scrollmode = SCROLL_MOVE;
- else /* default to something safe */
- p->scrollmode = SCROLL_REDRAW;
+ /*
+ * No more hw acceleration for fbcon.
+ *
+ * FIXME: Garbage collect all the now dead code after sufficient time
+ * has passed.
+ */
+ p->scrollmode = SCROLL_REDRAW;
/*
* ++guenther: console.c:vc_allocate() relies on initializing
@@ -1952,45 +1953,15 @@ static void updatescrollmode(struct fbcon_display *p,
{
struct fbcon_ops *ops = info->fbcon_par;
int fh = vc->vc_font.height;
- int cap = info->flags;
- u16 t = 0;
- int ypan = FBCON_SWAP(ops->rotate, info->fix.ypanstep,
- info->fix.xpanstep);
- int ywrap = FBCON_SWAP(ops->rotate, info->fix.ywrapstep, t);
int yres = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
int vyres = FBCON_SWAP(ops->rotate, info->var.yres_virtual,
info->var.xres_virtual);
- int good_pan = (cap & FBINFO_HWACCEL_YPAN) &&
- divides(ypan, vc->vc_font.height) && vyres > yres;
- int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) &&
- divides(ywrap, vc->vc_font.height) &&
- divides(vc->vc_font.height, vyres) &&
- divides(vc->vc_font.height, yres);
- int reading_fast = cap & FBINFO_READS_FAST;
- int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) &&
- !(cap & FBINFO_HWACCEL_DISABLED);
- int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) &&
- !(cap & FBINFO_HWACCEL_DISABLED);
p->vrows = vyres/fh;
if (yres > (fh * (vc->vc_rows + 1)))
p->vrows -= (yres - (fh * vc->vc_rows)) / fh;
if ((yres % fh) && (vyres % fh < yres % fh))
p->vrows--;
-
- if (good_wrap || good_pan) {
- if (reading_fast || fast_copyarea)
- p->scrollmode = good_wrap ?
- SCROLL_WRAP_MOVE : SCROLL_PAN_MOVE;
- else
- p->scrollmode = good_wrap ? SCROLL_REDRAW :
- SCROLL_PAN_REDRAW;
- } else {
- if (reading_fast || (fast_copyarea && !fast_imageblit))
- p->scrollmode = SCROLL_MOVE;
- else
- p->scrollmode = SCROLL_REDRAW;
- }
}
#define PITCH(w) (((w) + 7) >> 3)
--
2.25.1

View File

@@ -1,34 +0,0 @@
From d8eb6e5e70ba30717bb8aea4390c112cb8892e1b Mon Sep 17 00:00:00 2001
From: Igor Pecovnik <igor.pecovnik@gmail.com>
Date: Tue, 20 Jul 2021 17:38:53 +0000
Subject: [PATCH] Revert "vgacon: drop unused vga_init_done"
This reverts commit 0ae798fd96f8c28850e09d22d3f0d455071ed8eb.
---
drivers/video/console/vgacon.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index ef9c57ce0906..8cba9f46ddf9 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -79,6 +79,7 @@ static struct uni_pagedir *vgacon_uni_pagedir;
static int vgacon_refcount;
/* Description of the hardware situation */
+static bool vga_init_done;
static unsigned long vga_vram_base __read_mostly; /* Base of video memory */
static unsigned long vga_vram_end __read_mostly; /* End of video memory */
static unsigned int vga_vram_size __read_mostly; /* Size of video memory */
@@ -358,6 +359,8 @@ static const char *vgacon_startup(void)
vgacon_xres = screen_info.orig_video_cols * VGA_FONTWIDTH;
vgacon_yres = vga_scan_lines;
+ vga_init_done = true;
+
return display_desc;
}
--
2.30.2

View File

@@ -1,338 +0,0 @@
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

View File

@@ -1,28 +0,0 @@
From c57a371a7c28e32f0d984a1e0f22ec4e33eea51b Mon Sep 17 00:00:00 2001
From: Igor Pecovnik <igor.pecovnik@gmail.com>
Date: Thu, 10 Feb 2022 19:20:27 +0100
Subject: [PATCH] Revert "drivers: video: fbcon: fix NULL dereference in
fbcon_cursor()"
This reverts commit 61f0c3e8098facbec81dcc32508d58c8611cb799.
---
drivers/video/fbdev/core/fbcon.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 26581194fdf8..8d1ae973041a 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -1344,9 +1344,6 @@ static void fbcon_cursor(struct vc_data *vc, int mode)
ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1;
- if (!ops->cursor)
- return;
-
ops->cursor(vc, info, mode, get_color(vc, info, c, 1),
get_color(vc, info, c, 0));
}
--
2.25.1

View File

@@ -1,46 +0,0 @@
From 1703e0e113025614c66dee8eb575aa67861934cd Mon Sep 17 00:00:00 2001
From: Igor Pecovnik <igor.pecovnik@gmail.com>
Date: Thu, 10 Feb 2022 19:26:33 +0100
Subject: [PATCH] Revert "fbcon: remove no-op fbcon_set_origin()"
This reverts commit bfeb28539d1f61829232883ced0986569218c4de.
---
drivers/video/fbdev/core/fbcon.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index ad0862d6c1a9..6fea22c4642c 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -163,6 +163,8 @@ static const struct consw fb_con;
#define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row)
+static int fbcon_set_origin(struct vc_data *);
+
static int fbcon_cursor_noblink;
#define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1)
@@ -2633,6 +2635,11 @@ static void fbcon_invert_region(struct vc_data *vc, u16 * p, int cnt)
}
}
+static int fbcon_set_origin(struct vc_data *vc)
+{
+ return 0;
+}
+
void fbcon_suspended(struct fb_info *info)
{
struct vc_data *vc = NULL;
@@ -3103,6 +3110,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_set_origin = fbcon_set_origin,
.con_invert_region = fbcon_invert_region,
.con_screen_pos = fbcon_screen_pos,
.con_getxy = fbcon_getxy,
--
2.25.1

View File

@@ -1,184 +0,0 @@
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

View File

@@ -1,502 +0,0 @@
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,
--
2.25.1

View File

@@ -1,32 +0,0 @@
Revert "fbcon: Fix accelerated fbdev scrolling while logo is still shown"
This reverts commit 3866cba87dcd0162fb41e9b3b653d0af68fad5ec.
---
drivers/video/fbdev/core/fbcon.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index cf9ac4da0a82..0636d05c519c 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -1760,6 +1760,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 (logo_shown >= 0)
+ goto redraw_up;
switch (fb_scrollmode(p)) {
case SCROLL_MOVE:
fbcon_redraw_blit(vc, info, p, t, b - t - count,
@@ -1848,6 +1850,8 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
case SM_DOWN:
if (count > vc->vc_rows) /* Maximum realistic size */
count = vc->vc_rows;
+ if (logo_shown >= 0)
+ goto redraw_down;
switch (fb_scrollmode(p)) {
case SCROLL_MOVE:
fbcon_redraw_blit(vc, info, p, b - 1, b - t - count,
--
2.25.1

View File

@@ -1,74 +0,0 @@
From 34329038e08a285761f74d454c2a050788b9323c Mon Sep 17 00:00:00 2001
From: Igor Pecovnik <igor.pecovnik@gmail.com>
Date: Mon, 5 Sep 2022 08:37:35 +0200
Subject: [PATCH] Revert "fbdev: fbcon: Properly revert changes when
vc_resize() failed"
This reverts commit f08ccb792d3eaf1dc62d8cbf6a30d6522329f660.
---
drivers/video/fbdev/core/fbcon.c | 27 ++-------------------------
1 file changed, 2 insertions(+), 25 deletions(-)
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 2efaed36a3ad..b89075f3b6ab 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -2402,21 +2402,15 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
struct fb_info *info = fbcon_info_from_console(vc->vc_num);
struct fbcon_ops *ops = info->fbcon_par;
struct fbcon_display *p = &fb_display[vc->vc_num];
- int resize, ret, old_userfont, old_width, old_height, old_charcount;
+ int resize;
char *old_data = NULL;
resize = (w != vc->vc_font.width) || (h != vc->vc_font.height);
if (p->userfont)
old_data = vc->vc_font.data;
vc->vc_font.data = (void *)(p->fontdata = data);
- old_userfont = p->userfont;
if ((p->userfont = userfont))
REFCOUNT(data)++;
-
- old_width = vc->vc_font.width;
- old_height = vc->vc_font.height;
- old_charcount = vc->vc_font.charcount;
-
vc->vc_font.width = w;
vc->vc_font.height = h;
vc->vc_font.charcount = charcount;
@@ -2432,9 +2426,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
cols /= w;
rows /= h;
- ret = vc_resize(vc, cols, rows);
- if (ret)
- goto err_out;
+ vc_resize(vc, cols, rows);
} else if (con_is_visible(vc)
&& vc->vc_mode == KD_TEXT) {
fbcon_clear_margins(vc, 0);
@@ -2444,21 +2436,6 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
if (old_data && (--REFCOUNT(old_data) == 0))
kfree(old_data - FONT_EXTRA_WORDS * sizeof(int));
return 0;
-
-err_out:
- p->fontdata = old_data;
- vc->vc_font.data = (void *)old_data;
-
- if (userfont) {
- p->userfont = old_userfont;
- REFCOUNT(data)--;
- }
-
- vc->vc_font.width = old_width;
- vc->vc_font.height = old_height;
- vc->vc_font.charcount = old_charcount;
-
- return ret;
}
/*
--
2.34.1

View File

@@ -1,28 +0,0 @@
From 729b2d566888ddc24edd9887098b80af3fc4269f Mon Sep 17 00:00:00 2001
From: Igor Pecovnik <igor.pecovnik@gmail.com>
Date: Sat, 31 Dec 2022 14:27:32 +0100
Subject: [PATCH] Revert "fbdev: fbcon: release buffer when fbcon_do_set_font()
failed"
This reverts commit 88ec6d11052da527eb9268831e7a9bc5bbad02f6.
---
drivers/video/fbdev/core/fbcon.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index df40360e04ff..1f37904b0405 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -2462,8 +2462,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
if (userfont) {
p->userfont = old_userfont;
- if (--REFCOUNT(data) == 0)
- kfree(data - FONT_EXTRA_WORDS * sizeof(int));
+ REFCOUNT(data)--;
}
vc->vc_font.width = old_width;
--
2.34.1

View File

@@ -1,31 +0,0 @@
--- a/arch/arm/kernel/asm-offsets.c
+++ b/arch/arm/kernel/asm-offsets.c
@@ -10,6 +10,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#include <linux/compiler.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/dma-mapping.h>
@@ -39,10 +40,19 @@
* GCC 3.2.x: miscompiles NEW_AUX_ENT in fs/binfmt_elf.c
* (http://gcc.gnu.org/PR8896) and incorrect structure
* initialisation in fs/jffs2/erase.c
+ * GCC 4.8.0-4.8.2: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58854
+ * miscompiles find_get_entry(), and can result in EXT3 and EXT4
+ * filesystem corruption (possibly other FS too).
*/
+#ifdef __GNUC__
#if (__GNUC__ == 3 && __GNUC_MINOR__ < 3)
#error Your compiler is too buggy; it is known to miscompile kernels.
-#error Known good compilers: 3.3
+#error Known good compilers: 3.3, 4.x
+#endif
+#if GCC_VERSION >= 40800 && GCC_VERSION < 40803
+#error Your compiler is too buggy; it is known to miscompile kernels
+#error and result in filesystem corruption and oopses.
+#endif
#endif
int main(void)

View File

@@ -1,82 +0,0 @@
diff --git a/drivers/staging/fbtft/fb_st7789v.c b/drivers/staging/fbtft/fb_st7789v.c
index 3c3f38793..3a280cc18 100644
--- a/drivers/staging/fbtft/fb_st7789v.c
+++ b/drivers/staging/fbtft/fb_st7789v.c
@@ -20,6 +20,12 @@
"70 2C 2E 15 10 09 48 33 53 0B 19 18 20 25\n" \
"70 2C 2E 15 10 09 48 33 53 0B 19 18 20 25"
+#define HSD20_IPS_GAMMA \
+ "D0 05 0A 09 08 05 2E 44 45 0F 17 16 2B 33\n" \
+ "D0 05 0A 09 08 05 2E 43 45 0F 16 16 2B 33"
+
+#define HSD20_IPS 1
+
/**
* enum st7789v_command - ST7789V display controller commands
*
@@ -82,14 +88,20 @@ static int init_display(struct fbtft_par *par)
/* set pixel format to RGB-565 */
write_reg(par, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_16BIT);
+ if (HSD20_IPS)
+ write_reg(par, PORCTRL, 0x05, 0x05, 0x00, 0x33, 0x33);
- write_reg(par, PORCTRL, 0x08, 0x08, 0x00, 0x22, 0x22);
+ else
+ write_reg(par, PORCTRL, 0x08, 0x08, 0x00, 0x22, 0x22);
/*
* VGH = 13.26V
* VGL = -10.43V
*/
- write_reg(par, GCTRL, 0x35);
+ if (HSD20_IPS)
+ write_reg(par, GCTRL, 0x75);
+ else
+ write_reg(par, GCTRL, 0x35);
/*
* VDV and VRH register values come from command write
@@ -101,13 +113,19 @@ static int init_display(struct fbtft_par *par)
* VAP = 4.1V + (VCOM + VCOM offset + 0.5 * VDV)
* VAN = -4.1V + (VCOM + VCOM offset + 0.5 * VDV)
*/
- write_reg(par, VRHS, 0x0B);
+ if (HSD20_IPS)
+ write_reg(par, VRHS, 0x13);
+ else
+ write_reg(par, VRHS, 0x0B);
/* VDV = 0V */
write_reg(par, VDVS, 0x20);
/* VCOM = 0.9V */
- write_reg(par, VCOMS, 0x20);
+ if (HSD20_IPS)
+ write_reg(par, VCOMS, 0x22);
+ else
+ write_reg(par, VCOMS, 0x20);
/* VCOM offset = 0V */
write_reg(par, VCMOFSET, 0x20);
@@ -120,6 +138,10 @@ static int init_display(struct fbtft_par *par)
write_reg(par, PWCTRL1, 0xA4, 0xA1);
write_reg(par, MIPI_DCS_SET_DISPLAY_ON);
+
+ if (HSD20_IPS)
+ write_reg(par, MIPI_DCS_ENTER_INVERT_MODE);
+
return 0;
}
@@ -234,7 +256,7 @@ static struct fbtft_display display = {
.height = 320,
.gamma_num = 2,
.gamma_len = 14,
- .gamma = DEFAULT_GAMMA,
+ .gamma = HSD20_IPS_GAMMA,
.fbtftops = {
.init_display = init_display,
.set_var = set_var,

View File

@@ -1,250 +0,0 @@
diff --git a/Documentation/networking/device_drivers/atm/cxacru-cf.py b/Documentation/networking/device_drivers/atm/cxacru-cf.py
index b41d298398c8..413b97579405 100644
--- a/Documentation/networking/device_drivers/atm/cxacru-cf.py
+++ b/Documentation/networking/device_drivers/atm/cxacru-cf.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python2
# Copyright 2009 Simon Arlott
#
# This program is free software; you can redistribute it and/or modify it
diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py
index dc8fed48d3c2..395a5728d86f 100755
--- a/Documentation/sphinx/maintainers_include.py
+++ b/Documentation/sphinx/maintainers_include.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python2
# SPDX-License-Identifier: GPL-2.0
# -*- coding: utf-8; mode: python -*-
# pylint: disable=R0903, C0330, R0914, R0912, E0401
diff --git a/Documentation/target/tcm_mod_builder.py b/Documentation/target/tcm_mod_builder.py
index 54492aa813b9..277e24566923 100755
--- a/Documentation/target/tcm_mod_builder.py
+++ b/Documentation/target/tcm_mod_builder.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python2
# The TCM v4 multi-protocol fabric module generation script for drivers/target/$NEW_MOD
#
# Copyright (c) 2010 Rising Tide Systems
diff --git a/Documentation/trace/postprocess/decode_msr.py b/Documentation/trace/postprocess/decode_msr.py
index aa9cc7abd5c2..7c9efdc5c353 100644
--- a/Documentation/trace/postprocess/decode_msr.py
+++ b/Documentation/trace/postprocess/decode_msr.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python2
# add symbolic names to read_msr / write_msr in trace
# decode_msr msr-index.h < trace
import sys
diff --git a/Makefile b/Makefile
index 6bbc15bea093..09063da45379 100644
--- a/Makefile
+++ b/Makefile
@@ -468,7 +468,7 @@ AWK = awk
INSTALLKERNEL := installkernel
DEPMOD = depmod
PERL = perl
-PYTHON = python
+PYTHON = python2
PYTHON3 = python3
CHECK = sparse
BASH = bash
diff --git a/arch/ia64/scripts/unwcheck.py b/arch/ia64/scripts/unwcheck.py
index bfd1b671e35f..5f998048d68c 100644
--- a/arch/ia64/scripts/unwcheck.py
+++ b/arch/ia64/scripts/unwcheck.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python2
# SPDX-License-Identifier: GPL-2.0
#
# Usage: unwcheck.py FILE
diff --git a/drivers/staging/greybus/tools/lbtest b/drivers/staging/greybus/tools/lbtest
index 47c481239e98..4b3773b97794 100755
--- a/drivers/staging/greybus/tools/lbtest
+++ b/drivers/staging/greybus/tools/lbtest
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python2
# SPDX-License-Identifier: BSD-3-Clause
# Copyright (c) 2015 Google, Inc.
diff --git a/scripts/bmpconvert b/scripts/bmpconvert
index 9863444da093..2d5b9b3bfe2c 100755
--- a/scripts/bmpconvert
+++ b/scripts/bmpconvert
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python2
# SPDX-License-Identifier: GPL-2.0 */
# -*- coding: utf-8 -*-
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 0ad235ee96f9..3c2f0c1f0bac 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -910,10 +910,10 @@ sub is_maintained_obsolete {
sub is_SPDX_License_valid {
my ($license) = @_;
- return 1 if (!$tree || which("python") eq "" || !(-e "$root/scripts/spdxcheck.py") || !(-e "$gitroot"));
+ return 1 if (!$tree || which("python2") eq "" || !(-e "$root/scripts/spdxcheck.py") || !(-e "$gitroot"));
my $root_path = abs_path($root);
- my $status = `cd "$root_path"; echo "$license" | python scripts/spdxcheck.py -`;
+ my $status = `cd "$root_path"; echo "$license" | python2 scripts/spdxcheck.py -`;
return 0 if ($status ne "");
return 1;
}
diff --git a/scripts/clang-wrapper.py b/scripts/clang-wrapper.py
index 871aa5080bad..c5520905dab0 100755
--- a/scripts/clang-wrapper.py
+++ b/scripts/clang-wrapper.py
@@ -1,4 +1,4 @@
-#! /usr/bin/env python
+#! /usr/bin/env python2
# -*- coding: utf-8 -*-
# Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
diff --git a/scripts/gcc-wrapper.py b/scripts/gcc-wrapper.py
index ea74ea852242..c6853b5ee8b4 100755
--- a/scripts/gcc-wrapper.py
+++ b/scripts/gcc-wrapper.py
@@ -1,4 +1,4 @@
-#! /usr/bin/env python
+#! /usr/bin/env python2
# -*- coding: utf-8 -*-
# Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
diff --git a/scripts/jobserver-exec b/scripts/jobserver-exec
index 0fdb31a790a8..1dd35a8a277d 100755
--- a/scripts/jobserver-exec
+++ b/scripts/jobserver-exec
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python2
# SPDX-License-Identifier: GPL-2.0+
#
# This determines how many parallel tasks "make" is expecting, as it is
diff --git a/scripts/mkbootimg b/scripts/mkbootimg
index 0c6093e19416..0d3464e8bbca 100755
--- a/scripts/mkbootimg
+++ b/scripts/mkbootimg
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python2
# Copyright 2015, The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/scripts/mkmultidtb.py b/scripts/mkmultidtb.py
index 81b814acd304..44ade858a8d0 100755
--- a/scripts/mkmultidtb.py
+++ b/scripts/mkmultidtb.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python2
# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
# Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd
#
diff --git a/scripts/show_delta b/scripts/show_delta
index 28e67e178194..a613571dad27 100755
--- a/scripts/show_delta
+++ b/scripts/show_delta
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python2
# SPDX-License-Identifier: GPL-2.0-only
#
# show_deltas: Read list of printk messages instrumented with
diff --git a/scripts/spdxcheck.py b/scripts/spdxcheck.py
index bc87200f9c7c..9747c64288c4 100755
--- a/scripts/spdxcheck.py
+++ b/scripts/spdxcheck.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python2
# SPDX-License-Identifier: GPL-2.0
# Copyright Thomas Gleixner <tglx@linutronix.de>
diff --git a/scripts/tracing/draw_functrace.py b/scripts/tracing/draw_functrace.py
index 7011fbe003ff..72001a9a9c76 100755
--- a/scripts/tracing/draw_functrace.py
+++ b/scripts/tracing/draw_functrace.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python2
# SPDX-License-Identifier: GPL-2.0-only
"""
diff --git a/scripts/unpack_bootimg b/scripts/unpack_bootimg
index 83c2bbe33d7d..cca9338cacd6 100755
--- a/scripts/unpack_bootimg
+++ b/scripts/unpack_bootimg
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python2
# Copyright 2018, The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/tools/hv/lsvmbus b/tools/hv/lsvmbus
index 099f2c44dbed..cb2f7e27ea37 100644
--- a/tools/hv/lsvmbus
+++ b/tools/hv/lsvmbus
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python2
# SPDX-License-Identifier: GPL-2.0
import os
diff --git a/tools/perf/python/tracepoint.py b/tools/perf/python/tracepoint.py
index 461848c7f57d..ed8377178830 100755
--- a/tools/perf/python/tracepoint.py
+++ b/tools/perf/python/tracepoint.py
@@ -1,4 +1,4 @@
-#! /usr/bin/env python
+#! /usr/bin/env python2
# SPDX-License-Identifier: GPL-2.0
# -*- python -*-
# -*- coding: utf-8 -*-
diff --git a/tools/perf/python/twatch.py b/tools/perf/python/twatch.py
index 04f3db29b9bc..ab0a2970b3fb 100755
--- a/tools/perf/python/twatch.py
+++ b/tools/perf/python/twatch.py
@@ -1,4 +1,4 @@
-#! /usr/bin/env python
+#! /usr/bin/env python2
# SPDX-License-Identifier: GPL-2.0-only
# -*- python -*-
# -*- coding: utf-8 -*-
diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py
index 711d4f9f5645..e27e7a92fdac 100755
--- a/tools/perf/scripts/python/exported-sql-viewer.py
+++ b/tools/perf/scripts/python/exported-sql-viewer.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python2
# SPDX-License-Identifier: GPL-2.0
# exported-sql-viewer.py: view data from sql database
# Copyright (c) 2014-2018, Intel Corporation.
diff --git a/tools/power/x86/intel_pstate_tracer/intel_pstate_tracer.py b/tools/power/x86/intel_pstate_tracer/intel_pstate_tracer.py
index e15e20696d17..c8159fe6d2e8 100755
--- a/tools/power/x86/intel_pstate_tracer/intel_pstate_tracer.py
+++ b/tools/power/x86/intel_pstate_tracer/intel_pstate_tracer.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python2
# SPDX-License-Identifier: GPL-2.0-only
# -*- coding: utf-8 -*-
#
diff --git a/tools/testing/selftests/drivers/net/mlxsw/sharedbuffer_configuration.py b/tools/testing/selftests/drivers/net/mlxsw/sharedbuffer_configuration.py
index 2223337eed0c..81c538732185 100755
--- a/tools/testing/selftests/drivers/net/mlxsw/sharedbuffer_configuration.py
+++ b/tools/testing/selftests/drivers/net/mlxsw/sharedbuffer_configuration.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python2
# SPDX-License-Identifier: GPL-2.0
import subprocess

View File

@@ -1,64 +0,0 @@
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -784,7 +784,8 @@ static int ieee80211_set_monitor_channel
ret = ieee80211_vif_use_channel(sdata, chandef,
IEEE80211_CHANCTX_EXCLUSIVE);
}
- } else if (local->open_count == local->monitors) {
+ // Patch: Always allow channel change, even if a normal virtual interface is present
+ } else /*if (local->open_count == local->monitors)*/ {
local->_oper_chandef = *chandef;
ieee80211_hw_config(local, 0);
}
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -803,11 +803,19 @@ ieee80211_tx_h_sequence(struct ieee80211
/*
* Packet injection may want to control the sequence
- * number, if we have no matching interface then we
- * neither assign one ourselves nor ask the driver to.
+ * number, so if an injected packet is found, skip
+ * renumbering it. Also make the packet NO_ACK to avoid
+ * excessive retries (ACKing and retrying should be
+ * handled by the injecting application).
+ * FIXME This may break hostapd and some other injectors.
+ * This should be done using a radiotap flag.
*/
- if (unlikely(info->control.vif->type == NL80211_IFTYPE_MONITOR))
+ if (unlikely((info->flags & IEEE80211_TX_CTL_INJECTED) &&
+ !(tx->sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES))) {
+ if (!ieee80211_has_morefrags(hdr->frame_control))
+ info->flags |= IEEE80211_TX_CTL_NO_ACK;
return TX_CONTINUE;
+ }
if (unlikely(ieee80211_is_ctl(hdr->frame_control)))
return TX_CONTINUE;
@@ -2012,7 +2020,10 @@ void ieee80211_xmit(struct ieee80211_sub
}
}
- ieee80211_set_qos_hdr(sdata, skb);
+ // Don't overwrite QoS header in monitor mode
+ if (likely(info->control.vif->type != NL80211_IFTYPE_MONITOR)) {
+ ieee80211_set_qos_hdr(sdata, skb);
+ }
ieee80211_tx(sdata, sta, skb, false, txdata_flags);
}
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -1148,8 +1148,10 @@ int cfg80211_set_monitor_channel(struct
{
if (!rdev->ops->set_monitor_channel)
return -EOPNOTSUPP;
- if (!cfg80211_has_monitors_only(rdev))
- return -EBUSY;
+ // Always allow user to change channel, even if there is another normal
+ // virtual interface using the device.
+ //if (!cfg80211_has_monitors_only(rdev))
+ // return -EBUSY;
return rdev_set_monitor_channel(rdev, chandef);
}

View File

@@ -1,64 +0,0 @@
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -784,7 +784,8 @@ static int ieee80211_set_monitor_channel
ret = ieee80211_vif_use_channel(sdata, chandef,
IEEE80211_CHANCTX_EXCLUSIVE);
}
- } else if (local->open_count == local->monitors) {
+ // Patch: Always allow channel change, even if a normal virtual interface is present
+ } else /*if (local->open_count == local->monitors)*/ {
local->_oper_chandef = *chandef;
ieee80211_hw_config(local, 0);
}
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -810,11 +810,19 @@
/*
* Packet injection may want to control the sequence
- * number, if we have no matching interface then we
- * neither assign one ourselves nor ask the driver to.
+ * number, so if an injected packet is found, skip
+ * renumbering it. Also make the packet NO_ACK to avoid
+ * excessive retries (ACKing and retrying should be
+ * handled by the injecting application).
+ * FIXME This may break hostapd and some other injectors.
+ * This should be done using a radiotap flag.
*/
- if (unlikely(info->control.vif->type == NL80211_IFTYPE_MONITOR))
+ if (unlikely((info->flags & IEEE80211_TX_CTL_INJECTED) &&
+ !(tx->sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES))) {
+ if (!ieee80211_has_morefrags(hdr->frame_control))
+ info->flags |= IEEE80211_TX_CTL_NO_ACK;
return TX_CONTINUE;
+ }
if (unlikely(ieee80211_is_ctl(hdr->frame_control)))
return TX_CONTINUE;
@@ -2011,7 +2019,10 @@
}
}
- ieee80211_set_qos_hdr(sdata, skb);
+ // Don't overwrite QoS header in monitor mode
+ if (likely(info->control.vif->type != NL80211_IFTYPE_MONITOR)) {
+ ieee80211_set_qos_hdr(sdata, skb);
+ }
ieee80211_tx(sdata, sta, skb, false);
}
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -1148,8 +1148,10 @@ int cfg80211_set_monitor_channel(struct
{
if (!rdev->ops->set_monitor_channel)
return -EOPNOTSUPP;
- if (!cfg80211_has_monitors_only(rdev))
- return -EBUSY;
+ // Always allow user to change channel, even if there is another normal
+ // virtual interface using the device.
+ //if (!cfg80211_has_monitors_only(rdev))
+ // return -EBUSY;
return rdev_set_monitor_channel(rdev, chandef);
}

View File

@@ -1,66 +0,0 @@
--- a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c
@@ -229,14 +229,19 @@ void zd_mac_clear(struct zd_mac *mac)
static int set_rx_filter(struct zd_mac *mac)
{
unsigned long flags;
- u32 filter = STA_RX_FILTER;
+ struct zd_ioreq32 ioreqs[] = {
+ {CR_RX_FILTER, STA_RX_FILTER},
+ { CR_SNIFFER_ON, 0U },
+ };
spin_lock_irqsave(&mac->lock, flags);
- if (mac->pass_ctrl)
- filter |= RX_FILTER_CTRL;
+ if (mac->pass_ctrl) {
+ ioreqs[0].value |= 0xFFFFFFFF;
+ ioreqs[1].value = 0x1;
+ }
spin_unlock_irqrestore(&mac->lock, flags);
- return zd_iowrite32(&mac->chip, CR_RX_FILTER, filter);
+ return zd_iowrite32a(&mac->chip, ioreqs, ARRAY_SIZE(ioreqs));
}
static int set_mac_and_bssid(struct zd_mac *mac)
@@ -1043,7 +1048,8 @@ int zd_mac_rx(struct ieee80211_hw *hw, c
/* Caller has to ensure that length >= sizeof(struct rx_status). */
status = (struct rx_status *)
(buffer + (length - sizeof(struct rx_status)));
- if (status->frame_status & ZD_RX_ERROR) {
+ if ((status->frame_status & ZD_RX_ERROR) ||
+ (status->frame_status & ~0x21)) {
if (mac->pass_failed_fcs &&
(status->frame_status & ZD_RX_CRC32_ERROR)) {
stats.flag |= RX_FLAG_FAILED_FCS_CRC;
@@ -1386,7 +1392,7 @@ struct ieee80211_hw *zd_mac_alloc_hw(str
ieee80211_hw_set(hw, MFP_CAPABLE);
ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
ieee80211_hw_set(hw, RX_INCLUDES_FCS);
- ieee80211_hw_set(hw, SIGNAL_UNSPEC);
+ ieee80211_hw_set(hw, SIGNAL_DBM);
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_MESH_POINT) |
--- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
+++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
@@ -248,8 +248,17 @@ static void rtl8187_tx(struct ieee80211_
flags |= RTL818X_TX_DESC_FLAG_NO_ENC;
flags |= ieee80211_get_tx_rate(dev, info)->hw_value << 24;
+
+ // When this flag is set the firmware waits untill ALL fragments have
+ // reached the USB device. Then it sends the first fragment and waits
+ // for ACKS's. Of course in monitor mode it won't detect these ACK's.
if (ieee80211_has_morefrags(tx_hdr->frame_control))
- flags |= RTL818X_TX_DESC_FLAG_MOREFRAG;
+ {
+ // If info->control.vif is NULL it's most likely in monitor mode
+ if (likely(info->control.vif != NULL && info->control.vif->type != NL80211_IFTYPE_MONITOR)) {
+ flags |= RTL818X_TX_DESC_FLAG_MOREFRAG;
+ }
+ }
/* HW will perform RTS-CTS when only RTS flags is set.
* HW will perform CTS-to-self when both RTS and CTS flags are set.

View File

@@ -1,59 +0,0 @@
From c46a994dd78befbe94e66771db41c18351be2aae Mon Sep 17 00:00:00 2001
From: Steve deRosier <derosier@cal-sierra.com>
Date: Fri, 29 Sep 2017 10:48:19 -0700
Subject: [PATCH] wireless: carl9170: Enable sniffer mode promisc flag to fix
injection
The removal of the AR9170_MAC_SNIFFER_ENABLE_PROMISC flag to fix an issue
many years ago caused the AR9170 to not be able to pass probe response
packets with different MAC addresses back up to the driver. In general
operation, this doesn't matter, but in the case of packet injection with
aireplay-ng it is important. aireplay-ng specifically injects packets with
spoofed MAC addresses on the probe requests and looks for probe responses
back to those addresses. No other combination of filter flags seem to fix
this issue and so AR9170_MAC_SNIFFER_ENABLE is required to get these packets.
This was originally caused by commit e0509d3bdd7365d06c9bf570bf9f11 which
removed this flag in order to avoid spurious ack noise from the hardware.
In testing for this issue, keeping this flag but not restoring the
AR9170_MAC_RX_CTRL_ACK_IN_SNIFFER flag on the rc_ctrl seems to solve this
issue, at least with the most current firmware v1.9.9.
Signed-off-by: Steve deRosier <derosier@cal-sierra.com>
---
drivers/net/wireless/ath/carl9170/mac.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/net/wireless/ath/carl9170/mac.c b/drivers/net/wireless/ath/carl9170/mac.c
index 7d4a72dc98db..c617e883f47a 100644
--- a/drivers/net/wireless/ath/carl9170/mac.c
+++ b/drivers/net/wireless/ath/carl9170/mac.c
@@ -309,6 +309,7 @@ int carl9170_set_operating_mode(struct ar9170 *ar)
u32 rx_ctrl = AR9170_MAC_RX_CTRL_DEAGG |
AR9170_MAC_RX_CTRL_SHORT_FILTER;
u32 sniffer = AR9170_MAC_SNIFFER_DEFAULTS;
+ u32 mac_ftf = AR9170_MAC_FTF_DEFAULTS;
int err = 0;
rcu_read_lock();
@@ -373,6 +374,9 @@ int carl9170_set_operating_mode(struct ar9170 *ar)
if (ar->sniffer_enabled) {
enc_mode |= AR9170_MAC_ENCRYPTION_RX_SOFTWARE;
+ mac_ftf = AR9170_MAC_FTF_MONITOR;
+ sniffer |= AR9170_MAC_SNIFFER_ENABLE_PROMISC;
+ mac_addr = NULL;
}
err = carl9170_set_mac_reg(ar, AR9170_MAC_REG_MAC_ADDR_L, mac_addr);
@@ -384,6 +388,7 @@ int carl9170_set_operating_mode(struct ar9170 *ar)
return err;
carl9170_regwrite_begin(ar);
+ carl9170_regwrite(AR9170_MAC_REG_FRAMETYPE_FILTER, mac_ftf);
carl9170_regwrite(AR9170_MAC_REG_SNIFFER, sniffer);
carl9170_regwrite(AR9170_MAC_REG_CAM_MODE, cam_mode);
carl9170_regwrite(AR9170_MAC_REG_ENCRYPTION, enc_mode);
--
2.14.1