You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
qubes-linux-kernel/patches.suse/bootsplash-keep-multiple-data

322 lines
11 KiB

From: Takashi Iwai <tiwai@suse.de>
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 <tiwai@suse.de>
---
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