From: Takashi Iwai Subject: Keep multiple splash screens for KMS Patch-mainline: Never References: bnc#570082 Keep multiple splash screens for reloading splash again when KMS is kicked off. Signed-off-by: Takashi Iwai --- drivers/video/bootsplash/bootsplash.c | 148 ++++++++++++++++++++++------------ drivers/video/bootsplash/decode-jpg.c | 7 - drivers/video/bootsplash/decode-jpg.h | 2 drivers/video/console/fbcon.c | 11 ++ drivers/video/console/fbcon.h | 1 5 files changed, 115 insertions(+), 54 deletions(-) --- a/drivers/video/bootsplash/bootsplash.c +++ b/drivers/video/bootsplash/bootsplash.c @@ -331,12 +331,14 @@ static int splash_check_jpeg(unsigned ch static void splash_free(struct vc_data *vc, struct fb_info *info) { + struct splash_data *sd; + struct splash_data *next; SPLASH_DEBUG(); - if (!vc->vc_splash_data) - return; - if (vc->vc_splash_data->splash_silentjpeg) - vfree(vc->vc_splash_data->splash_sboxes); - vfree(vc->vc_splash_data); + for (sd = vc->vc_splash_data; sd; sd = next) { + next = sd->next; + vfree(sd->splash_sboxes); + vfree(sd); + } vc->vc_splash_data = 0; info->splash_data = 0; } @@ -418,6 +420,32 @@ static inline int splash_geti(unsigned c pos[off] | pos[off + 1] << 8 | pos[off + 2] << 16 | pos[off + 3] << 24; } +/* move the given splash_data to the current one */ +static void splash_pivot_current(struct vc_data *vc, struct splash_data *new) +{ + struct splash_data *sd; + int state, percent, silent; + + sd = vc->vc_splash_data; + if (!sd || sd == new) + return; + state = sd->splash_state; + percent = sd->splash_percent; + silent = sd->splash_dosilent; + for (; sd->next; sd = sd->next) { + if (sd->next == new) { + sd->next = new->next; + new->next = vc->vc_splash_data; + vc->vc_splash_data = new; + /* copy the current states */ + new->splash_state = state; + new->splash_percent = percent; + new->splash_dosilent = silent; + return; + } + } +} + static int splash_getraw(unsigned char *start, unsigned char *end, int *update) { unsigned char *ndata; @@ -434,6 +462,8 @@ static int splash_getraw(unsigned char * struct vc_data *vc; struct fb_info *info; struct splash_data *sd; + struct splash_data *splash_found = NULL; + int unit_found = -1; int oldpercent, oldsilent; if (update) @@ -442,6 +472,8 @@ static int splash_getraw(unsigned char * if (!update || start[7] < '2' || start[7] > '3' || splash_geti(start, 12) != (int)0xffffffff) printk(KERN_INFO "bootsplash %s: looking for picture...\n", SPLASH_VERSION); + oldpercent = -1; + oldsilent = -1; for (ndata = start; ndata < end; ndata++) { if (ndata[0] != 'B' || ndata[1] != 'O' || ndata[2] != 'O' || ndata[3] != 'T') continue; @@ -522,12 +554,6 @@ static int splash_getraw(unsigned char * printk(KERN_ERR "bootsplash: ...found, but truncated!\n"); return -1; } - if (!jpeg_check_size(ndata + len + boxcnt * 12 + palcnt, width, height)) { - ndata += len + splash_size - 1; - continue; - } - if (splash_check_jpeg(ndata + len + boxcnt * 12 + palcnt, width, height, info->var.bits_per_pixel)) - return -1; silentsize = splash_geti(ndata, SPLASH_OFF_SSIZE); if (silentsize) printk(KERN_INFO "bootsplash: silentjpeg size %d bytes\n", silentsize); @@ -543,32 +569,21 @@ static int splash_getraw(unsigned char * silentsize = 0; } sboxcnt = splash_gets(ndata, SPLASH_OFF_SBOXCNT); - if (silentsize) { - unsigned char *simage = ndata + len + splash_size + 12 * sboxcnt; - if (!jpeg_check_size(simage, width, height) || - splash_check_jpeg(simage, width, height, info->var.bits_per_pixel)) { - printk(KERN_WARNING "bootsplash: error in silent jpeg.\n"); - silentsize = 0; - } - } - oldpercent = -1; - oldsilent = -1; if (vc->vc_splash_data) { oldpercent = vc->vc_splash_data->splash_percent; oldsilent = vc->vc_splash_data->splash_dosilent; - splash_free(vc, info); } - vc->vc_splash_data = sd = vmalloc(sizeof(*sd) + splash_size + (version < 3 ? 2 * 12 : 0)); + sd = vmalloc(sizeof(*sd) + splash_size + (version < 3 ? 2 * 12 : 0)); if (!sd) break; - sd->splash_silentjpeg = 0; - sd->splash_sboxes = 0; - sd->splash_sboxcount = 0; + memset(sd, 0, sizeof(*sd)); + jpeg_get_size(ndata + len + boxcnt * 12 + palcnt, + &sd->splash_width, &sd->splash_height); if (silentsize) { sd->splash_silentjpeg = vmalloc(silentsize); if (sd->splash_silentjpeg) { memcpy(sd->splash_silentjpeg, ndata + len + splash_size, silentsize); - sd->splash_sboxes = vc->vc_splash_data->splash_silentjpeg; + sd->splash_sboxes = sd->splash_silentjpeg; sd->splash_silentjpeg += 12 * sboxcnt; sd->splash_sboxcount = sboxcnt; } @@ -591,22 +606,6 @@ static int splash_getraw(unsigned char * sd->splash_fg_color = (splash_default >> 4) & 0x0f; sd->splash_state = splash_default & 1; } - if (sd->splash_text_xo + sd->splash_text_wi > width || sd->splash_text_yo + sd->splash_text_he > height) { - splash_free(vc, info); - printk(KERN_ERR "bootsplash: found, but has oversized text area!\n"); - return -1; - } - if (!vc_cons[unit].d || info->fbops->fb_imageblit != cfb_imageblit) { - splash_free(vc, info); - printk(KERN_ERR "bootsplash: found, but framebuffer can't handle it!\n"); - return -1; - } - printk(KERN_INFO "bootsplash: ...found (%dx%d, %d bytes, v%d).\n", width, height, splash_size, version); - if (version == 1) { - printk(KERN_WARNING "bootsplash: Using deprecated v1 header. Updating your splash utility recommended.\n"); - printk(KERN_INFO "bootsplash: Find the latest version at http://www.bootsplash.org/\n"); - } - /* fake penguin box for older formats */ if (version == 1) boxcnt = splash_mkpenguin(sd, sd->splash_text_xo + 10, sd->splash_text_yo + 10, sd->splash_text_wi - 20, sd->splash_text_he - 20, 0xf0, 0xf0, 0xf0); @@ -620,8 +619,38 @@ static int splash_getraw(unsigned char * sd->splash_jpeg = sd->splash_palette + palcnt; sd->splash_palcnt = palcnt / 3; sd->splash_dosilent = sd->splash_silentjpeg != 0 ? (oldsilent == -1 ? 1 : oldsilent) : 0; - return unit; + + sd->next = vc->vc_splash_data; + vc->vc_splash_data = sd; + + if (sd->splash_width != width || sd->splash_height != height) { + ndata += len + splash_size - 1; + continue; + } + if (splash_check_jpeg(ndata + len + boxcnt * 12 + palcnt, width, height, info->var.bits_per_pixel)) { + ndata += len + splash_size - 1; + continue; + } + if (!vc_cons[unit].d || info->fbops->fb_imageblit != cfb_imageblit) { + splash_free(vc, info); + printk(KERN_ERR "bootsplash: found, but framebuffer can't handle it!\n"); + return -1; + } + printk(KERN_INFO "bootsplash: ...found (%dx%d, %d bytes, v%d).\n", width, height, splash_size, version); + if (version == 1) { + printk(KERN_WARNING "bootsplash: Using deprecated v1 header. Updating your splash utility recommended.\n"); + printk(KERN_INFO "bootsplash: Find the latest version at http://www.bootsplash.org/\n"); + } + + splash_found = sd; + unit_found = unit; + } + + if (splash_found) { + splash_pivot_current(vc, splash_found); + return unit_found; } + printk(KERN_ERR "bootsplash: ...no good signature found.\n"); return -1; } @@ -696,6 +725,20 @@ static void splash_off(struct fb_info *i info->splash_pic_size = 0; } +/* look for the splash with the matching size and set it as the current */ +static int splash_look_for_jpeg(struct vc_data *vc, int width, int height) +{ + struct splash_data *sd; + + for (sd = vc->vc_splash_data; sd; sd = sd->next) { + if (sd->splash_width == width && sd->splash_height == height) { + splash_pivot_current(vc, sd); + return 0; + } + } + return -1; +} + int splash_prepare(struct vc_data *vc, struct fb_info *info) { int err; @@ -719,6 +762,12 @@ int splash_prepare(struct vc_data *vc, s splash_off(info); return -2; } + if (splash_look_for_jpeg(vc, width, height) < 0) { + printk(KERN_INFO "bootsplash: no matching splash %dx%d\n", + width, height); + splash_off(info); + return -2; + } sbytes = ((width + 15) & ~15) * octpp; size = sbytes * ((height + 15) & ~15); @@ -1007,11 +1056,14 @@ static int splash_write_proc(struct file if (!strncmp(buffer,"freesilent\n",11)) { SPLASH_DEBUG( " freesilent"); if (vc->vc_splash_data && vc->vc_splash_data->splash_silentjpeg) { + struct splash_data *sd; printk(KERN_INFO "bootsplash: freeing silent jpeg\n"); - vc->vc_splash_data->splash_silentjpeg = 0; - vfree(vc->vc_splash_data->splash_sboxes); - vc->vc_splash_data->splash_sboxes = 0; - vc->vc_splash_data->splash_sboxcount = 0; + for (sd = vc->vc_splash_data; sd; sd = sd->next) { + sd->splash_silentjpeg = 0; + vfree(sd->splash_sboxes); + sd->splash_sboxes = 0; + sd->splash_sboxcount = 0; + } if (vc->vc_splash_data->splash_dosilent) { splash_status(vc); } --- a/drivers/video/bootsplash/decode-jpg.c +++ b/drivers/video/bootsplash/decode-jpg.c @@ -240,7 +240,7 @@ static int dec_checkmarker(void) return 0; } -int jpeg_check_size(unsigned char *buf, int width, int height) +void jpeg_get_size(unsigned char *buf, int *width, int *height) { datap = buf; getbyte(); @@ -248,9 +248,8 @@ int jpeg_check_size(unsigned char *buf, readtables(M_SOF0); getword(); getbyte(); - if (height != getword() || width != getword()) - return 0; - return 1; + *height = getword(); + *width = getword(); } int jpeg_decode(buf, pic, width, height, depth, decdata) --- a/drivers/video/bootsplash/decode-jpg.h +++ b/drivers/video/bootsplash/decode-jpg.h @@ -30,6 +30,6 @@ struct jpeg_decdata { }; extern int jpeg_decode(unsigned char *, unsigned char *, int, int, int, struct jpeg_decdata *); -extern int jpeg_check_size(unsigned char *, int, int); +extern void jpeg_get_size(unsigned char *, int *, int *); #endif --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -2187,7 +2187,16 @@ static int fbcon_switch(struct vc_data * ops = info->fbcon_par; #ifdef CONFIG_BOOTSPLASH - splash_prepare(vc, info); + { + struct splash_data *prev_sd = vc->vc_splash_data; + splash_prepare(vc, info); + if (vc->vc_splash_data && vc->vc_splash_data->splash_state && + vc->vc_splash_data != prev_sd) { + vc_resize(vc, vc->vc_splash_data->splash_text_wi / vc->vc_font.width, + vc->vc_splash_data->splash_text_he / vc->vc_font.height); + con_remap_def_color(vc, vc->vc_splash_data->splash_color << 4 | vc->vc_splash_data->splash_fg_color); + } + } #endif if (softback_top) { --- a/drivers/video/console/fbcon.h +++ b/drivers/video/console/fbcon.h @@ -50,6 +50,7 @@ struct splash_data { unsigned char *splash_silentjpeg; unsigned char *splash_sboxes; int splash_sboxcount; + struct splash_data *next; }; #endif