summarylogtreecommitdiffstats
path: root/0007-bootsplash.patch
diff options
context:
space:
mode:
Diffstat (limited to '0007-bootsplash.patch')
-rw-r--r--0007-bootsplash.patch838
1 files changed, 248 insertions, 590 deletions
diff --git a/0007-bootsplash.patch b/0007-bootsplash.patch
index 92d62caa703..2785c5e6527 100644
--- a/0007-bootsplash.patch
+++ b/0007-bootsplash.patch
@@ -1,669 +1,327 @@
-diff --git a/MAINTAINERS b/MAINTAINERS
-index b5633b56391e..5c237445761e 100644
---- a/MAINTAINERS
-+++ b/MAINTAINERS
-@@ -2712,6 +2712,7 @@ S: Maintained
- F: drivers/video/fbdev/core/bootsplash*.*
- F: drivers/video/fbdev/core/dummycon.c
- F: include/linux/bootsplash.h
-+F: include/uapi/linux/bootsplash_file.h
-
- BPF (Safe dynamic programs and tools)
- M: Alexei Starovoitov <ast@kernel.org>
-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
+index 815b007f81ca..c8642142cfea 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"
+@@ -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);
++ }
++}
++
- /*
-@@ -102,10 +103,17 @@ static bool is_fb_compatible(const struct fb_info *info)
+ 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)
{
-+ mutex_lock(&splash_state.data_lock);
++ bool is_update = false;
+
- if (!is_fb_compatible(info))
-- return;
-+ goto out;
+ 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;
+
-+ bootsplash_do_render_background(info, splash_state.file);
+
-+ bootsplash_do_render_pictures(info, splash_state.file);
++ 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);
-+out:
-+ mutex_unlock(&splash_state.data_lock);
- }
+- 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);
-@@ -116,6 +124,7 @@ bool bootsplash_would_render_now(void)
- {
- return !oops_in_progress
- && !console_blanked
-+ && splash_state.file
- && bootsplash_is_enabled();
- }
+ bootsplash_do_render_flush(info);
-@@ -252,6 +261,7 @@ static struct platform_driver splash_driver = {
- void bootsplash_init(void)
- {
- int ret;
-+ struct splash_file_priv *fp;
++ 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)
- /* Initialized already? */
- if (splash_state.splash_device)
-@@ -280,8 +290,26 @@ void bootsplash_init(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);
++ }
+ }
-+ 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;
-+
+@@ -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;
-+ splash_state.file = fp;
+ mutex_unlock(&splash_state.data_lock);
+
- return;
+ if (bootsplash_would_render_now())
+ schedule_work(&splash_state.work_redraw_vc);
- 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");
+@@ -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 b11da5cb90bf..71e2a27ac0b8 100644
+index 0acb383aa4e3..b3a74835d90f 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>
+@@ -37,6 +37,8 @@ struct splash_pic_priv {
-+#include "uapi/linux/bootsplash_file.h"
+ struct splash_blob_priv *blobs;
+ u16 blobs_loaded;
+
++ u16 anim_nextframe;
+ };
- /*
- * 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;
+
+@@ -45,6 +47,12 @@ struct splash_file_priv {
+ const struct splash_file_header *header;
+
+ struct splash_pic_priv *pics;
+
- /*
- * Enabled/disabled state, to be used with atomic bit operations.
- * Bit 0: 0 = Splash hidden
-@@ -43,6 +71,13 @@ struct splash_priv {
++ /*
++ * 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;
-+
-+ /* Splash data structures including lock for everything below */
-+ struct mutex data_lock;
-+
-+ struct fb_info *splash_fb;
-+
-+ struct splash_file_priv *file;
- };
++ 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);
-@@ -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
+ 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
-new file mode 100644
-index 000000000000..fd807571ab7d
---- /dev/null
+index fd807571ab7d..1f661b2d4cc9 100644
+--- a/drivers/video/fbdev/core/bootsplash_load.c
+++ 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);
+@@ -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);
+
-+ goto err;
++ ph->anim_type = SPLASH_ANIM_NONE;
+ }
-+ }
-+
-+ pr_info("Loaded (%ld bytes, %u pics, %u blobs).\n",
-+ fw->size,
-+ fp->header->num_pics,
-+ fp->header->num_blobs);
-+
-+ return fp;
+
+ 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;
+ }
+
-+err:
-+ bootsplash_free_file(fp);
-+ return NULL;
-+}
++ 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 4d7e0117f653..2ae36949d0e3 100644
+index 07e3a4eab811..76033606ca8a 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"
+@@ -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;
-@@ -70,16 +71,69 @@ static inline u32 pack_pixel(const struct fb_var_screeninfo *dst_var,
- }
-
+@@ -161,7 +162,11 @@ void bootsplash_do_render_pictures(struct fb_info *info,
+ if (pp->blobs_loaded < 1)
+ continue;
--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;
-+}
-+
+- bp = &pp->blobs[0];
++ /* Skip static pictures when refreshing animations */
++ if (ph->anim_type == SPLASH_ANIM_NONE && is_update)
++ continue;
+
-+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)
- }
++ 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_render_pictures(struct fb_info *info,
-+ const struct splash_file_priv *fp)
++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_blob_priv *bp;
+ struct splash_pic_priv *pp = &fp->pics[i];
-+ long dst_xoff, dst_yoff;
+
-+ if (pp->blobs_loaded < 1)
++ if (pp->blobs_loaded < 2
++ || pp->pic_header->anim_loop > pp->blobs_loaded)
+ 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;
++ 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;
+ }
-+
-+ /* 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
+index 71cedcc68933..b3af0a3c6487 100644
+--- a/include/uapi/linux/bootsplash_file.h
+++ 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;
+@@ -77,7 +77,17 @@ struct splash_file_header {
+ uint16_t num_blobs;
+ uint8_t num_pics;
+
+- uint8_t padding[103];
++ uint8_t unused_1;
+
+ /*
-+ * Number of data packages associated with this picture.
-+ * Currently, the only use for more than 1 is for animations.
++ * 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.
+ */
-+ uint8_t num_blobs;
-+
-+ uint8_t padding[27];
-+} __attribute__((__packed__));
-+
-+
-+struct splash_blob_header {
-+ /* Length of the data block in bytes. */
-+ uint32_t length;
++ 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];
+ /*
-+ * Type of the contents.
-+ * 0 - Raw RGB data.
++ * Animation type.
++ * 0 - off
++ * 1 - forward loop
+ */
-+ uint16_t type;
++ uint8_t anim_type;
+
+ /*
-+ * Picture this blob is associated with.
-+ * Blobs will be added to a picture in the order they are
-+ * found in the file.
++ * 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 picture_id;
++ uint8_t anim_loop;
+
-+ uint8_t padding[9];
-+} __attribute__((__packed__));
++ 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
+ #endif