diff options
Diffstat (limited to '0007-bootsplash.patch')
-rw-r--r-- | 0007-bootsplash.patch | 838 |
1 files changed, 248 insertions, 590 deletions
diff --git a/0007-bootsplash.patch b/0007-bootsplash.patch index 92d62caa7031..2785c5e65277 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 |