322 lines
11 KiB
Plaintext
322 lines
11 KiB
Plaintext
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
|
|
@@ -2185,7 +2185,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
|
|
|