1293 lines
41 KiB
Plaintext
1293 lines
41 KiB
Plaintext
|
From: Egbert Eich <eich@suse.de>
|
||
|
Subject: Add bootsplash image scaler
|
||
|
Patch-mainline: Never
|
||
|
References: bnc#570082
|
||
|
|
||
|
The initrd most often contains a single fixed size boot image which is of the
|
||
|
size of the VESA framebuffer used for boot. If the size of the framebuffer
|
||
|
changes when KMS is initialized for example the boot splash is turned off.
|
||
|
Takashi Iwai has provided a patch which allows to add multiple images to initrd
|
||
|
so that the kernel can select the appropriate size. This is only feasible for
|
||
|
mobile devices with a build in panel of a fixed resolution in which case one
|
||
|
would have to ship two images at the most: the one of the VESA resolution at
|
||
|
boot time and the one of the panel as used by KMS.
|
||
|
The attached patch adds a boot splash scaler which allows the down scaling of
|
||
|
bootsplash image which is bigger than the screen size. This way by supplying a
|
||
|
single image large enough to accomodate the largest screens possible all
|
||
|
resolutions can be derived from it.
|
||
|
|
||
|
Acked-by: Michal Marek <mmarek@suse.cz>
|
||
|
|
||
|
---
|
||
|
drivers/video/bootsplash/bootsplash.c | 858 +++++++++++++++++++++++++++++++---
|
||
|
drivers/video/bootsplash/decode-jpg.c | 4
|
||
|
drivers/video/bootsplash/render.c | 16
|
||
|
drivers/video/console/fbcon.h | 11
|
||
|
include/linux/fb.h | 3
|
||
|
5 files changed, 810 insertions(+), 82 deletions(-)
|
||
|
|
||
|
--- a/drivers/video/bootsplash/bootsplash.c
|
||
|
+++ b/drivers/video/bootsplash/bootsplash.c
|
||
|
@@ -6,6 +6,7 @@
|
||
|
* Stefan Reinauer, <stepan@suse.de>,
|
||
|
* Steffen Winterfeldt, <snwint@suse.de>,
|
||
|
* Michael Schroeder <mls@suse.de>
|
||
|
+ * 2009, 2010 Egbert Eich <eich@suse.de>
|
||
|
*
|
||
|
* Ideas & SuSE screen work by Ken Wimer, <wimer@suse.de>
|
||
|
*
|
||
|
@@ -55,7 +56,9 @@ static unsigned char *jpg_errors[] = {
|
||
|
"wrong marker",
|
||
|
"no EOI",
|
||
|
"bad tables",
|
||
|
- "depth mismatch"
|
||
|
+ "depth mismatch",
|
||
|
+ "scale error",
|
||
|
+ "out of memory"
|
||
|
};
|
||
|
|
||
|
static struct jpeg_decdata *decdata = 0; /* private decoder data */
|
||
|
@@ -64,7 +67,9 @@ static int splash_registered = 0;
|
||
|
static int splash_usesilent = 0; /* shall we display the silentjpeg? */
|
||
|
int splash_default = 0xf01;
|
||
|
|
||
|
-static int splash_check_jpeg(unsigned char *jpeg, int width, int height, int depth);
|
||
|
+static int jpeg_get(unsigned char *buf, unsigned char *pic, int width, int height, int depth,
|
||
|
+ struct jpeg_decdata *decdata);
|
||
|
+static int splash_look_for_jpeg(struct vc_data *vc, int width, int height);
|
||
|
|
||
|
static int __init splash_setup(char *options)
|
||
|
{
|
||
|
@@ -120,7 +125,8 @@ static int boxextract(unsigned char *buf
|
||
|
return 12;
|
||
|
}
|
||
|
|
||
|
-static void boxit(unsigned char *pic, int bytes, unsigned char *buf, int num, int percent, int overpaint, int octpp)
|
||
|
+static void boxit(unsigned char *pic, int bytes, unsigned char *buf, int num,
|
||
|
+ int percent, int xoff, int yoff, int overpaint, int octpp)
|
||
|
{
|
||
|
int x, y, p, doblend, r, g, b, a, add;
|
||
|
unsigned int i = 0;
|
||
|
@@ -245,7 +251,7 @@ static void boxit(unsigned char *pic, in
|
||
|
}
|
||
|
add = (xs & 1);
|
||
|
add ^= (add ^ y) & 1 ? 1 : 3; /* 2x2 ordered dithering */
|
||
|
- picp.ub = (pic + xs * octpp + y * bytes);
|
||
|
+ picp.ub = (pic + (xs + xoff) * octpp + (y + yoff) * bytes);
|
||
|
for (x = xs; x <= xe; x++) {
|
||
|
if (!(sti & 0x80000000)) {
|
||
|
sti <<= 1;
|
||
|
@@ -310,19 +316,172 @@ static void boxit(unsigned char *pic, in
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+static void box_offsets(unsigned char *buf, int num,
|
||
|
+ int screen_w, int screen_h, int pic_w, int pic_h,
|
||
|
+ int *x_off, int *y_off)
|
||
|
+{
|
||
|
+ int a, doblend;
|
||
|
+ int x_min = pic_w, x_max = 0;
|
||
|
+ int y_min = pic_h, y_max = 0;
|
||
|
+ unsigned int i = 0;
|
||
|
+ unsigned short data1[4];
|
||
|
+ unsigned char cols1[16];
|
||
|
+ unsigned short data2[4];
|
||
|
+ unsigned char cols2[16];
|
||
|
+ unsigned char *bufend;
|
||
|
+ unsigned int stin, stinn, stixs, stixe, stiys, stiye;
|
||
|
+ int xs, xe, ys, ye;
|
||
|
+
|
||
|
+ SPLASH_DEBUG();
|
||
|
+
|
||
|
+ if ((screen_w == pic_w && screen_h == pic_h) || num == 0)
|
||
|
+ *x_off = *y_off = 0;
|
||
|
+
|
||
|
+ bufend = buf + num * 12;
|
||
|
+ stin = 1;
|
||
|
+ stinn = 0;
|
||
|
+ stixs = stixe = 0;
|
||
|
+ stiys = stiye = 0;
|
||
|
+
|
||
|
+ while(buf < bufend) {
|
||
|
+ doblend = 0;
|
||
|
+ buf += boxextract(buf, data1, cols1, &doblend);
|
||
|
+ if (data1[0] == 32767 && data1[1] == 32767) {
|
||
|
+ /* box stipple */
|
||
|
+ if (stinn == 32)
|
||
|
+ continue;
|
||
|
+ if (stinn == 0) {
|
||
|
+ stixs = data1[2];
|
||
|
+ stixe = data1[3];
|
||
|
+ stiys = stiye = 0;
|
||
|
+ } else if (stinn == 4) {
|
||
|
+ stiys = data1[2];
|
||
|
+ stiye = data1[3];
|
||
|
+ }
|
||
|
+ stin = stinn;
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+ stinn = 0;
|
||
|
+ if (data1[0] > 32767)
|
||
|
+ buf += boxextract(buf, data2, cols2, &doblend);
|
||
|
+ if (data1[0] == 32767 && data1[1] == 32766) {
|
||
|
+ /* box copy */
|
||
|
+ i = 12 * (short)data1[3];
|
||
|
+ doblend = 0;
|
||
|
+ i += boxextract(buf + i, data1, cols1, &doblend);
|
||
|
+ if (data1[0] > 32767)
|
||
|
+ boxextract(buf + i, data2, cols2, &doblend);
|
||
|
+ }
|
||
|
+ if (data1[0] == 32767)
|
||
|
+ continue;
|
||
|
+ if (data1[2] > 32767) {
|
||
|
+ data1[2] = ~data1[2];
|
||
|
+ }
|
||
|
+ if (data1[3] > 32767) {
|
||
|
+ data1[3] = ~data1[3];
|
||
|
+ }
|
||
|
+ if (data1[0] > 32767) {
|
||
|
+ data1[0] = ~data1[0];
|
||
|
+ for (i = 0; i < 4; i++)
|
||
|
+ data1[i] = (data1[i] * (65536 - 1) + data2[i] * 1) >> 16;
|
||
|
+ }
|
||
|
+ *(unsigned int *)cols2 = *(unsigned int *)cols1;
|
||
|
+ a = cols2[3];
|
||
|
+ if (a == 0 && !doblend)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if (stixs >= 32768) {
|
||
|
+ xs = (stixs ^ 65535) + data1[0];
|
||
|
+ xe = stixe ? stixe + data1[0] : data1[2];
|
||
|
+ } else if (stixe >= 32768) {
|
||
|
+ xs = stixs ? data1[2] - stixs : data1[0];
|
||
|
+ xe = data1[2] - (stixe ^ 65535);
|
||
|
+ } else {
|
||
|
+ xs = stixs;
|
||
|
+ xe = stixe ? stixe : data1[2];
|
||
|
+ }
|
||
|
+ if (stiys >= 32768) {
|
||
|
+ ys = (stiys ^ 65535) + data1[1];
|
||
|
+ ye = stiye ? stiye + data1[1] : data1[3];
|
||
|
+ } else if (stiye >= 32768) {
|
||
|
+ ys = stiys ? data1[3] - stiys : data1[1];
|
||
|
+ ye = data1[3] - (stiye ^ 65535);
|
||
|
+ } else {
|
||
|
+ ys = stiys;
|
||
|
+ ye = stiye ? stiye : data1[3];
|
||
|
+ }
|
||
|
+ if (xs < data1[0])
|
||
|
+ xs = data1[0];
|
||
|
+ if (xe > data1[2])
|
||
|
+ xe = data1[2];
|
||
|
+ if (ys < data1[1])
|
||
|
+ ys = data1[1];
|
||
|
+ if (ye > data1[3])
|
||
|
+ ye = data1[3];
|
||
|
+
|
||
|
+ if (xs < x_min)
|
||
|
+ x_min = xs;
|
||
|
+ if (xe > x_max)
|
||
|
+ x_max = xe;
|
||
|
+ if (ys < y_min)
|
||
|
+ y_min = ys;
|
||
|
+ if (ye > y_max)
|
||
|
+ y_max = ye;
|
||
|
+ }
|
||
|
+ {
|
||
|
+ int x_center = (x_min + x_max) / 2;
|
||
|
+ int y_center = (y_min + y_max) / 2;
|
||
|
+
|
||
|
+ if (screen_w == pic_w)
|
||
|
+ *x_off = 0;
|
||
|
+ else {
|
||
|
+ if (x_center < (pic_w + pic_w / 10) >> 1 && x_center > (pic_w - pic_w / 10) >> 1)
|
||
|
+ *x_off = (screen_w - pic_w) >> 1;
|
||
|
+ else {
|
||
|
+ int x = x_center * screen_w / pic_w;
|
||
|
+ *x_off = x - x_center;
|
||
|
+ if (x_min + x_off > 0)
|
||
|
+ *x_off = 0;
|
||
|
+ if (x_max + *x_off > screen_w)
|
||
|
+ *x_off = screen_w - pic_w;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ if (screen_h == pic_h)
|
||
|
+ *y_off = 0;
|
||
|
+ else {
|
||
|
+ if (y_center < (pic_h + pic_h / 10) >> 1 && y_center > (pic_h - pic_h / 10) >> 1)
|
||
|
+ *y_off = (screen_h - pic_h) >> 1;
|
||
|
+ else {
|
||
|
+ int x = y_center * screen_h / pic_h;
|
||
|
+ *y_off = x - y_center;
|
||
|
+ if (y_min + y_off > 0)
|
||
|
+ *y_off = 0;
|
||
|
+ if (y_max + *x_off > screen_h)
|
||
|
+ *y_off = screen_h - pic_h;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
static int splash_check_jpeg(unsigned char *jpeg, int width, int height, int depth)
|
||
|
{
|
||
|
int size, err;
|
||
|
unsigned char *mem;
|
||
|
|
||
|
- size = ((width + 15) & ~15) * ((height + 15) & ~15) * (depth >> 3);
|
||
|
+ size = ((width + 15) & ~15) * ((height + 15) & ~15) * ((depth + 1) >> 3);
|
||
|
mem = vmalloc(size);
|
||
|
if (!mem) {
|
||
|
printk(KERN_INFO "bootsplash: no memory for decoded picture.\n");
|
||
|
return -1;
|
||
|
}
|
||
|
- if (!decdata)
|
||
|
- decdata = vmalloc(sizeof(*decdata));
|
||
|
+ if (!decdata) {
|
||
|
+ decdata = vmalloc(sizeof(*decdata));
|
||
|
+ if (!decdata) {
|
||
|
+ printk(KERN_INFO "bootsplash: not enough memory.\n");
|
||
|
+ vfree(mem);
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ }
|
||
|
if ((err = jpeg_decode(jpeg, mem, ((width + 15) & ~15), ((height + 15) & ~15), depth, decdata)))
|
||
|
printk(KERN_INFO "bootsplash: error while decompressing picture: %s (%d)\n",jpg_errors[err - 1], err);
|
||
|
vfree(mem);
|
||
|
@@ -337,6 +496,7 @@ static void splash_free(struct vc_data *
|
||
|
for (sd = vc->vc_splash_data; sd; sd = next) {
|
||
|
next = sd->next;
|
||
|
vfree(sd->splash_sboxes);
|
||
|
+ vfree(sd->splash_pic);
|
||
|
vfree(sd);
|
||
|
}
|
||
|
vc->vc_splash_data = 0;
|
||
|
@@ -432,6 +592,11 @@ static void splash_pivot_current(struct
|
||
|
state = sd->splash_state;
|
||
|
percent = sd->splash_percent;
|
||
|
silent = sd->splash_dosilent;
|
||
|
+ vfree(sd->splash_pic);
|
||
|
+ sd->splash_pic_size = 0;
|
||
|
+ sd->splash_pic = NULL;
|
||
|
+ sd->splash_text_wi = sd->splash_jpg_text_wi;
|
||
|
+ sd->splash_text_he = sd->splash_jpg_text_he;
|
||
|
for (; sd->next; sd = sd->next) {
|
||
|
if (sd->next == new) {
|
||
|
sd->next = new->next;
|
||
|
@@ -441,6 +606,17 @@ static void splash_pivot_current(struct
|
||
|
new->splash_state = state;
|
||
|
new->splash_percent = percent;
|
||
|
new->splash_dosilent = silent;
|
||
|
+ new->splash_text_wi = new->splash_jpg_text_wi;
|
||
|
+ new->splash_text_he = new->splash_jpg_text_he;
|
||
|
+
|
||
|
+ vfree(new->splash_pic);
|
||
|
+ new->splash_pic = NULL;
|
||
|
+ new->splash_pic_size = 0;
|
||
|
+
|
||
|
+ new->splash_boxes_xoff = 0;
|
||
|
+ new->splash_boxes_yoff = 0;
|
||
|
+ new->splash_sboxes_xoff = 0;
|
||
|
+ new->splash_sboxes_yoff = 0;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
@@ -459,7 +635,7 @@ static int splash_getraw(unsigned char *
|
||
|
int palcnt;
|
||
|
int i, len;
|
||
|
const int *offsets;
|
||
|
- struct vc_data *vc;
|
||
|
+ struct vc_data *vc = NULL;
|
||
|
struct fb_info *info;
|
||
|
struct splash_data *sd;
|
||
|
struct splash_data *splash_found = NULL;
|
||
|
@@ -489,7 +665,16 @@ static int splash_getraw(unsigned char *
|
||
|
vc_allocate(unit);
|
||
|
}
|
||
|
vc = vc_cons[unit].d;
|
||
|
+ if (!vc)
|
||
|
+ continue;
|
||
|
+
|
||
|
info = registered_fb[(int)con2fb_map[unit]];
|
||
|
+
|
||
|
+ if (info->fbops->fb_imageblit != cfb_imageblit) {
|
||
|
+ splash_free(vc, info);
|
||
|
+ printk(KERN_ERR "bootsplash: found, but framebuffer can't handle it!\n");
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
width = info->var.xres;
|
||
|
height = info->var.yres;
|
||
|
splash_size = splash_geti(ndata, SPLASH_OFF_SIZE);
|
||
|
@@ -539,6 +724,9 @@ static int splash_getraw(unsigned char *
|
||
|
}
|
||
|
if (update)
|
||
|
*update = up;
|
||
|
+ vfree(sd->splash_pic);
|
||
|
+ sd->splash_pic = NULL;
|
||
|
+ sd->splash_pic_size = 0;
|
||
|
}
|
||
|
return unit;
|
||
|
}
|
||
|
@@ -579,6 +767,12 @@ static int splash_getraw(unsigned char *
|
||
|
memset(sd, 0, sizeof(*sd));
|
||
|
jpeg_get_size(ndata + len + boxcnt * 12 + palcnt,
|
||
|
&sd->splash_width, &sd->splash_height);
|
||
|
+ if (splash_check_jpeg(ndata + len + boxcnt * 12 + palcnt,
|
||
|
+ sd->splash_width, sd->splash_height, info->var.bits_per_pixel)) {
|
||
|
+ ndata += len + splash_size - 1;
|
||
|
+ vfree(sd);
|
||
|
+ continue;
|
||
|
+ }
|
||
|
if (silentsize) {
|
||
|
sd->splash_silentjpeg = vmalloc(silentsize);
|
||
|
if (sd->splash_silentjpeg) {
|
||
|
@@ -596,6 +790,8 @@ static int splash_getraw(unsigned char *
|
||
|
sd->splash_text_yo = splash_gets(ndata, SPLASH_OFF_YO);
|
||
|
sd->splash_text_wi = splash_gets(ndata, SPLASH_OFF_WI);
|
||
|
sd->splash_text_he = splash_gets(ndata, SPLASH_OFF_HE);
|
||
|
+ sd->splash_pic = NULL;
|
||
|
+ sd->splash_pic_size = 0;
|
||
|
sd->splash_percent = oldpercent == -1 ? splash_gets(ndata, SPLASH_OFF_PERCENT) : oldpercent;
|
||
|
if (version == 1) {
|
||
|
sd->splash_text_xo *= 8;
|
||
|
@@ -606,6 +802,9 @@ static int splash_getraw(unsigned char *
|
||
|
sd->splash_fg_color = (splash_default >> 4) & 0x0f;
|
||
|
sd->splash_state = splash_default & 1;
|
||
|
}
|
||
|
+ sd->splash_jpg_text_wi = sd->splash_text_wi;
|
||
|
+ sd->splash_jpg_text_he = sd->splash_text_he;
|
||
|
+
|
||
|
/* 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);
|
||
|
@@ -627,15 +826,6 @@ static int splash_getraw(unsigned char *
|
||
|
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");
|
||
|
@@ -649,6 +839,16 @@ static int splash_getraw(unsigned char *
|
||
|
if (splash_found) {
|
||
|
splash_pivot_current(vc, splash_found);
|
||
|
return unit_found;
|
||
|
+ } else {
|
||
|
+ vc = vc_cons[0].d;
|
||
|
+ if (vc) {
|
||
|
+ info = registered_fb[(int)con2fb_map[0]];
|
||
|
+ width = info->var.xres;
|
||
|
+ height = info->var.yres;
|
||
|
+ if (!splash_look_for_jpeg(vc, width, height))
|
||
|
+ return -1;
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
printk(KERN_ERR "bootsplash: ...no good signature found.\n");
|
||
|
@@ -715,27 +915,71 @@ int splash_verbose(void)
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
-static void splash_off(struct fb_info *info)
|
||
|
+static void splash_off(struct vc_data *vc,struct fb_info *info)
|
||
|
{
|
||
|
+ int rows = info->var.xres / vc->vc_font.width;
|
||
|
+ int cols = info->var.yres / vc->vc_font.height;
|
||
|
SPLASH_DEBUG();
|
||
|
+
|
||
|
info->splash_data = 0;
|
||
|
- if (info->splash_pic)
|
||
|
- vfree(info->splash_pic);
|
||
|
- info->splash_pic = 0;
|
||
|
- info->splash_pic_size = 0;
|
||
|
+ if (rows != vc->vc_rows || cols != vc->vc_cols)
|
||
|
+ vc_resize(vc, rows, cols);
|
||
|
+ if (vc->vc_def_color != 0x07)
|
||
|
+ con_remap_def_color(vc, 0x07);
|
||
|
}
|
||
|
|
||
|
/* 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;
|
||
|
+ struct splash_data *sd, *found = NULL;
|
||
|
+ int found_delta_x = INT_MAX, found_delta_y = INT_MAX;
|
||
|
|
||
|
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;
|
||
|
+ int delta_x = abs(sd->splash_width - width) * height;
|
||
|
+ int delta_y = abs(sd->splash_height - height) * width;
|
||
|
+ if (!found || (found_delta_x + found_delta_y > delta_x + delta_y)) {
|
||
|
+ found = sd;
|
||
|
+ found_delta_x = delta_x;
|
||
|
+ found_delta_y = delta_y;
|
||
|
}
|
||
|
}
|
||
|
+
|
||
|
+ if (found) {
|
||
|
+ SPLASH_DEBUG("bootsplash: scalable image found (%dx%d scaled to %dx%d).",
|
||
|
+ found->splash_width, found->splash_height, width, height);
|
||
|
+
|
||
|
+ splash_pivot_current(vc, found);
|
||
|
+
|
||
|
+ /* textarea margins are constant independent from image size */
|
||
|
+ if (found->splash_height != height)
|
||
|
+ found->splash_text_he = height - (found->splash_height - found->splash_jpg_text_he);
|
||
|
+ else
|
||
|
+ found->splash_text_he = found->splash_jpg_text_he;
|
||
|
+ if (found->splash_width != width)
|
||
|
+ found->splash_text_wi = width - (found->splash_width - found->splash_jpg_text_wi);
|
||
|
+ else
|
||
|
+ found->splash_text_wi = found->splash_jpg_text_wi;
|
||
|
+
|
||
|
+ if (found->splash_width != width || found->splash_height != height) {
|
||
|
+ box_offsets(found->splash_boxes, found->splash_boxcount,
|
||
|
+ width, height, found->splash_width, found->splash_height,
|
||
|
+ &found->splash_boxes_xoff, &found->splash_boxes_yoff);
|
||
|
+ SPLASH_DEBUG("bootsplash: offsets for boxes: x=%d y=%d",
|
||
|
+ found->splash_boxes_xoff,found->splash_boxes_yoff);
|
||
|
+
|
||
|
+ if (found->splash_sboxes) {
|
||
|
+ box_offsets(found->splash_sboxes, found->splash_sboxcount,
|
||
|
+ width, height, found->splash_width, found->splash_height,
|
||
|
+ &found->splash_sboxes_xoff, &found->splash_sboxes_yoff);
|
||
|
+ SPLASH_DEBUG("bootsplash: offsets sboxes: x=%d y=%d",
|
||
|
+ found->splash_sboxes_xoff,found->splash_sboxes_yoff);
|
||
|
+ }
|
||
|
+ } else {
|
||
|
+ found->splash_sboxes_xoff = 0;
|
||
|
+ found->splash_sboxes_yoff = 0;
|
||
|
+ }
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
@@ -743,13 +987,14 @@ int splash_prepare(struct vc_data *vc, s
|
||
|
{
|
||
|
int err;
|
||
|
int width, height, depth, octpp, size, sbytes;
|
||
|
+ int pic_update = 0;
|
||
|
|
||
|
SPLASH_DEBUG("vc_num: %i", vc->vc_num);
|
||
|
if (!vc->vc_splash_data || !vc->vc_splash_data->splash_state) {
|
||
|
if (decdata)
|
||
|
vfree(decdata);
|
||
|
decdata = 0;
|
||
|
- splash_off(info);
|
||
|
+ splash_off(vc,info);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
@@ -759,52 +1004,62 @@ int splash_prepare(struct vc_data *vc, s
|
||
|
octpp = (depth + 1) >> 3;
|
||
|
|
||
|
if (depth == 24 || depth < 15) { /* Other targets might need fixing */
|
||
|
- splash_off(info);
|
||
|
+ splash_off(vc,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);
|
||
|
+ splash_off(vc,info);
|
||
|
return -2;
|
||
|
}
|
||
|
|
||
|
sbytes = ((width + 15) & ~15) * octpp;
|
||
|
size = sbytes * ((height + 15) & ~15);
|
||
|
- if (size != info->splash_pic_size) {
|
||
|
- vfree(info->splash_pic);
|
||
|
- info->splash_pic = NULL;
|
||
|
- }
|
||
|
- if (!info->splash_pic)
|
||
|
- info->splash_pic = vmalloc(size);
|
||
|
|
||
|
- if (!info->splash_pic) {
|
||
|
+ if (size != vc->vc_splash_data->splash_pic_size) {
|
||
|
+ vfree(vc->vc_splash_data->splash_pic);
|
||
|
+ vc->vc_splash_data->splash_pic = NULL;
|
||
|
+ }
|
||
|
+ if (!vc->vc_splash_data->splash_pic) {
|
||
|
+ vc->vc_splash_data->splash_pic = vmalloc(size);
|
||
|
+ pic_update = 1;
|
||
|
+ }
|
||
|
+ if (!vc->vc_splash_data->splash_pic) {
|
||
|
printk(KERN_INFO "bootsplash: not enough memory.\n");
|
||
|
- splash_off(info);
|
||
|
+ splash_off(vc,info);
|
||
|
return -3;
|
||
|
}
|
||
|
|
||
|
- if (!decdata)
|
||
|
+ if (!decdata) {
|
||
|
decdata = vmalloc(sizeof(*decdata));
|
||
|
+ if (!decdata) {
|
||
|
+ printk(KERN_INFO "bootsplash: not enough memory.\n");
|
||
|
+ splash_off(vc,info);
|
||
|
+ return -3;
|
||
|
+ }
|
||
|
+ }
|
||
|
|
||
|
if (vc->vc_splash_data->splash_silentjpeg && vc->vc_splash_data->splash_dosilent) {
|
||
|
- /* fill area after framebuffer with other jpeg */
|
||
|
- if ((err = jpeg_decode(vc->vc_splash_data->splash_silentjpeg, info->splash_pic,
|
||
|
- ((width + 15) & ~15), ((height + 15) & ~15), depth, decdata))) {
|
||
|
+ pic_update = 1;
|
||
|
+ if ((err = jpeg_get(vc->vc_splash_data->splash_silentjpeg, vc->vc_splash_data->splash_pic,
|
||
|
+ width, height, depth, decdata))) {
|
||
|
printk(KERN_INFO "bootsplash: error while decompressing silent picture: %s (%d)\n",
|
||
|
jpg_errors[err - 1], err);
|
||
|
vc->vc_splash_data->splash_dosilent = 0;
|
||
|
} else {
|
||
|
if (vc->vc_splash_data->splash_sboxcount)
|
||
|
- boxit(info->splash_pic,
|
||
|
+ boxit(vc->vc_splash_data->splash_pic,
|
||
|
sbytes,
|
||
|
vc->vc_splash_data->splash_sboxes,
|
||
|
vc->vc_splash_data->splash_sboxcount,
|
||
|
vc->vc_splash_data->splash_percent,
|
||
|
+ vc->vc_splash_data->splash_sboxes_xoff,
|
||
|
+ vc->vc_splash_data->splash_sboxes_yoff,
|
||
|
0,
|
||
|
octpp);
|
||
|
splashcopy(info->screen_base,
|
||
|
- info->splash_pic,
|
||
|
+ vc->vc_splash_data->splash_pic,
|
||
|
info->var.yres,
|
||
|
info->var.xres,
|
||
|
info->fix.line_length, sbytes,
|
||
|
@@ -813,27 +1068,43 @@ int splash_prepare(struct vc_data *vc, s
|
||
|
} else
|
||
|
vc->vc_splash_data->splash_dosilent = 0;
|
||
|
|
||
|
- if ((err = jpeg_decode(vc->vc_splash_data->splash_jpeg, info->splash_pic,
|
||
|
- ((width + 15) & ~15), ((height + 15) & ~15), depth, decdata))) {
|
||
|
- printk(KERN_INFO "bootsplash: error while decompressing picture: %s (%d) .\n",
|
||
|
- jpg_errors[err - 1], err);
|
||
|
- splash_off(info);
|
||
|
- return -4;
|
||
|
+ if (pic_update) {
|
||
|
+ if ((err = jpeg_get(vc->vc_splash_data->splash_jpeg, vc->vc_splash_data->splash_pic,
|
||
|
+ width, height, depth, decdata))) {
|
||
|
+ printk(KERN_INFO "bootsplash: error while decompressing picture: %s (%d) .\n",
|
||
|
+ jpg_errors[err - 1], err);
|
||
|
+ splash_off(vc,info);
|
||
|
+ return -4;
|
||
|
+ }
|
||
|
}
|
||
|
- info->splash_pic_size = size;
|
||
|
- info->splash_pic_stride = sbytes;
|
||
|
+
|
||
|
+ vc->vc_splash_data->splash_pic_size = size;
|
||
|
+ vc->vc_splash_data->splash_pic_stride = sbytes;
|
||
|
+
|
||
|
if (vc->vc_splash_data->splash_boxcount)
|
||
|
- boxit(info->splash_pic,
|
||
|
+ boxit(vc->vc_splash_data->splash_pic,
|
||
|
sbytes,
|
||
|
vc->vc_splash_data->splash_boxes,
|
||
|
vc->vc_splash_data->splash_boxcount,
|
||
|
vc->vc_splash_data->splash_percent,
|
||
|
+ vc->vc_splash_data->splash_boxes_xoff,
|
||
|
+ vc->vc_splash_data->splash_boxes_yoff,
|
||
|
0,
|
||
|
octpp);
|
||
|
- if (vc->vc_splash_data->splash_state)
|
||
|
+ if (vc->vc_splash_data->splash_state) {
|
||
|
+ int cols = vc->vc_splash_data->splash_text_wi / vc->vc_font.width;
|
||
|
+ int rows = vc->vc_splash_data->splash_text_he / vc->vc_font.height;
|
||
|
+ int color = vc->vc_splash_data->splash_color << 4 | vc->vc_splash_data->splash_fg_color;
|
||
|
info->splash_data = vc->vc_splash_data;
|
||
|
- else {
|
||
|
- splash_off(info);
|
||
|
+
|
||
|
+ /* vc_resize also calls con_switch which resets yscroll */
|
||
|
+ if (rows != vc->vc_rows || cols != vc->vc_cols)
|
||
|
+ vc_resize(vc, cols, rows);
|
||
|
+ if (vc->vc_def_color != color)
|
||
|
+ con_remap_def_color(vc, color);
|
||
|
+
|
||
|
+ } else {
|
||
|
+ splash_off(vc,info);
|
||
|
return -5;
|
||
|
}
|
||
|
return 0;
|
||
|
@@ -856,12 +1127,16 @@ static struct proc_dir_entry *proc_splas
|
||
|
|
||
|
static int splash_recolor(struct vc_data *vc)
|
||
|
{
|
||
|
+ int color;
|
||
|
+
|
||
|
SPLASH_DEBUG();
|
||
|
if (!vc->vc_splash_data)
|
||
|
return -1;
|
||
|
if (!vc->vc_splash_data->splash_state)
|
||
|
return 0;
|
||
|
- con_remap_def_color(vc, vc->vc_splash_data->splash_color << 4 | vc->vc_splash_data->splash_fg_color);
|
||
|
+ color = vc->vc_splash_data->splash_color << 4 | vc->vc_splash_data->splash_fg_color;
|
||
|
+ if (vc->vc_def_color != color)
|
||
|
+ con_remap_def_color(vc, color);
|
||
|
if (fg_console == vc->vc_num) {
|
||
|
update_region(vc,
|
||
|
vc->vc_origin + vc->vc_size_row * vc->vc_top,
|
||
|
@@ -884,10 +1159,6 @@ static int splash_status(struct vc_data
|
||
|
splash_prepare(vc, info);
|
||
|
if (vc->vc_splash_data && vc->vc_splash_data->splash_state) {
|
||
|
if (info->splash_data) {
|
||
|
- con_remap_def_color(vc, info->splash_data->splash_color << 4 | info->splash_data->splash_fg_color);
|
||
|
- /* vc_resize also calls con_switch which resets yscroll */
|
||
|
- vc_resize(vc, info->splash_data->splash_text_wi / vc->vc_font.width,
|
||
|
- info->splash_data->splash_text_he / vc->vc_font.height);
|
||
|
if (fg_console == vc->vc_num) {
|
||
|
update_region(vc,
|
||
|
vc->vc_origin + vc->vc_size_row * vc->vc_top,
|
||
|
@@ -895,11 +1166,9 @@ static int splash_status(struct vc_data
|
||
|
splash_clear_margins(vc, info, 0);
|
||
|
}
|
||
|
}
|
||
|
- } else {
|
||
|
- /* Switch bootsplash off */
|
||
|
- con_remap_def_color(vc, 0x07);
|
||
|
- vc_resize(vc, info->var.xres / vc->vc_font.width, info->var.yres / vc->vc_font.height);
|
||
|
- }
|
||
|
+ } else
|
||
|
+ splash_off(vc,info);
|
||
|
+
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -956,10 +1225,9 @@ void splash_set_percent(struct vc_data *
|
||
|
|| pe < oldpe) {
|
||
|
if (splash_hasinter(vc->vc_splash_data->splash_boxes,
|
||
|
vc->vc_splash_data->splash_boxcount)) {
|
||
|
- splash_status(vc);
|
||
|
- }
|
||
|
- else
|
||
|
- splash_prepare(vc, info);
|
||
|
+ splash_status(vc);
|
||
|
+ } else
|
||
|
+ splash_prepare(vc, info);
|
||
|
} else {
|
||
|
int octpp = (info->var.bits_per_pixel + 1) >> 3;
|
||
|
if (info->splash_data) {
|
||
|
@@ -970,6 +1238,8 @@ void splash_set_percent(struct vc_data *
|
||
|
info->splash_data->splash_sboxes,
|
||
|
info->splash_data->splash_sboxcount,
|
||
|
info->splash_data->splash_percent,
|
||
|
+ info->splash_data->splash_sboxes_xoff,
|
||
|
+ info->splash_data->splash_sboxes_yoff,
|
||
|
1,
|
||
|
octpp);
|
||
|
#if 0
|
||
|
@@ -979,6 +1249,8 @@ void splash_set_percent(struct vc_data *
|
||
|
info->splash_data->splash_boxes,
|
||
|
info->splash_data->splash_boxcount,
|
||
|
info->splash_data->splash_percent,
|
||
|
+ info->splash_data->splash_boxes_xoff,
|
||
|
+ info->splash_data->splash_boxes_yoff,
|
||
|
1,
|
||
|
octpp);
|
||
|
#endif
|
||
|
@@ -1100,6 +1372,8 @@ static int splash_write_proc(struct file
|
||
|
info->splash_data->splash_sboxes,
|
||
|
info->splash_data->splash_sboxcount,
|
||
|
info->splash_data->splash_percent,
|
||
|
+ info->splash_data->splash_sboxes_xoff,
|
||
|
+ info->splash_data->splash_sboxes_yoff,
|
||
|
1,
|
||
|
octpp);
|
||
|
} else if ((up & 1) != 0) {
|
||
|
@@ -1108,6 +1382,8 @@ static int splash_write_proc(struct file
|
||
|
info->splash_data->splash_boxes,
|
||
|
info->splash_data->splash_boxcount,
|
||
|
info->splash_data->splash_percent,
|
||
|
+ info->splash_data->splash_boxes_xoff,
|
||
|
+ info->splash_data->splash_boxes_yoff,
|
||
|
1,
|
||
|
octpp);
|
||
|
}
|
||
|
@@ -1226,3 +1502,447 @@ void splash_init(void)
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
+#define SPLASH_ALIGN 15
|
||
|
+
|
||
|
+static u32 *do_coefficients(u32 from, u32 to, u32 *shift)
|
||
|
+{
|
||
|
+ u32 *coefficients;
|
||
|
+ u32 left = to;
|
||
|
+ int n = 1;
|
||
|
+ u32 upper = 31;
|
||
|
+ int col_cnt = 0;
|
||
|
+ int row_cnt = 0;
|
||
|
+ int m;
|
||
|
+ u32 rnd = from >> 1;
|
||
|
+
|
||
|
+ if (from > to) {
|
||
|
+ left = to;
|
||
|
+ rnd = from >> 1;
|
||
|
+
|
||
|
+ while (upper > 0) {
|
||
|
+ if ((1 << upper) & from)
|
||
|
+ break;
|
||
|
+ upper--;
|
||
|
+ }
|
||
|
+ upper++;
|
||
|
+
|
||
|
+ *shift = 32 - 8 - 1 - upper;
|
||
|
+
|
||
|
+ coefficients = vmalloc(sizeof (u32) * (from / to + 2) * from + 1);
|
||
|
+ if (!coefficients)
|
||
|
+ return NULL;
|
||
|
+
|
||
|
+ n = 1;
|
||
|
+ while (1) {
|
||
|
+ u32 sum = left;
|
||
|
+ col_cnt = 0;
|
||
|
+ m = n++;
|
||
|
+ while (sum < from) {
|
||
|
+ coefficients[n++] = ((left << *shift) + rnd) / from;
|
||
|
+ col_cnt++;
|
||
|
+ left = to;
|
||
|
+ sum += left;
|
||
|
+ }
|
||
|
+ left = sum - from;
|
||
|
+ coefficients[n++] = (((to - left) << *shift) + rnd) / from;
|
||
|
+ col_cnt++;
|
||
|
+ coefficients[m] = col_cnt;
|
||
|
+ row_cnt++;
|
||
|
+ if (!left) {
|
||
|
+ coefficients[0] = row_cnt;
|
||
|
+ return coefficients;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ } else {
|
||
|
+ left = 0;
|
||
|
+ rnd = to >> 1;
|
||
|
+
|
||
|
+ while (upper > 0) {
|
||
|
+ if ((1 << upper) & to)
|
||
|
+ break;
|
||
|
+ upper--;
|
||
|
+ }
|
||
|
+ upper++;
|
||
|
+
|
||
|
+ *shift = 32 - 8 - 1 - upper;
|
||
|
+
|
||
|
+ coefficients = vmalloc(sizeof (u32) * 3 * from + 1);
|
||
|
+ if (!coefficients)
|
||
|
+ return NULL;
|
||
|
+
|
||
|
+ while (1) {
|
||
|
+ u32 diff;
|
||
|
+ u32 sum = left;
|
||
|
+ col_cnt = 0;
|
||
|
+ row_cnt++;
|
||
|
+ while (sum < to) {
|
||
|
+ col_cnt++;
|
||
|
+ sum += from;
|
||
|
+ }
|
||
|
+ left = sum - to;
|
||
|
+ diff = from - left;
|
||
|
+ if (!left) {
|
||
|
+ coefficients[n] = col_cnt;
|
||
|
+ coefficients[0] = row_cnt;
|
||
|
+ return coefficients;
|
||
|
+ }
|
||
|
+ coefficients[n++] = col_cnt - 1;
|
||
|
+ coefficients[n++] = ((diff << *shift) + rnd) / from;
|
||
|
+ coefficients[n++] = ((left << *shift) + rnd) / from;
|
||
|
+ }
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+struct pixel
|
||
|
+{
|
||
|
+ u32 red;
|
||
|
+ u32 green;
|
||
|
+ u32 blue;
|
||
|
+};
|
||
|
+
|
||
|
+#define put_pixel(pix, buf, depth) \
|
||
|
+ switch (depth) { \
|
||
|
+ case 15: \
|
||
|
+ *(u16 *)(buf) = (u16)((pix).red << 10 | (pix).green << 5 | (pix).blue); \
|
||
|
+ (buf) += 2; \
|
||
|
+ break; \
|
||
|
+ case 16: \
|
||
|
+ *(u16 *)(buf) = (u16)((pix).red << 11 | (pix).green << 5 | (pix).blue); \
|
||
|
+ (buf) += 2; \
|
||
|
+ break; \
|
||
|
+ case 24: \
|
||
|
+ *(u16 *)(buf) = (u16)((pix).red << 8 | (pix).green); \
|
||
|
+ buf += 2; \
|
||
|
+ *((buf)++) = (pix).blue; \
|
||
|
+ break; \
|
||
|
+ case 32: \
|
||
|
+ *(u32 *)(buf) = (u32)((pix).red << 16 | (pix).green << 8 | (pix).blue); \
|
||
|
+ (buf) += 4; \
|
||
|
+ break; \
|
||
|
+}
|
||
|
+
|
||
|
+#define get_pixel(pix, buf, depth) \
|
||
|
+ switch (depth) { \
|
||
|
+case 15: \
|
||
|
+ (pix).red = ((*(u16 *)(buf)) >> 10) & 0x1f; \
|
||
|
+ (pix).green = ((*(u16 *)(buf)) >> 5) & 0x1f; \
|
||
|
+ (pix).blue = (*(u16 *)(buf)) & 0x1f; \
|
||
|
+ (buf) += 2; \
|
||
|
+ break; \
|
||
|
+case 16: \
|
||
|
+ (pix).red = ((*(u16 *)(buf)) >> 11) & 0x1f; \
|
||
|
+ (pix).green = ((*(u16 *)(buf)) >> 5) & 0x3f; \
|
||
|
+ (pix).blue = (*(u16 *)(buf)) & 0x1f; \
|
||
|
+ (buf) += 2; \
|
||
|
+ break; \
|
||
|
+case 24: \
|
||
|
+ (pix).blue = *(((buf))++); \
|
||
|
+ (pix).green = *(((buf))++); \
|
||
|
+ (pix).red = *(((buf))++); \
|
||
|
+ break; \
|
||
|
+case 32: \
|
||
|
+ (pix).blue = *(((buf))++); \
|
||
|
+ (pix).green = *(((buf))++); \
|
||
|
+ (pix).red = *(((buf))++); \
|
||
|
+ (buf)++; \
|
||
|
+ break; \
|
||
|
+}
|
||
|
+
|
||
|
+static inline void
|
||
|
+scale_x_down(int depth, int src_w, unsigned char **src_p, u32 *x_coeff, u32 x_shift, u32 y_coeff, struct pixel *row_buffer)
|
||
|
+{
|
||
|
+ u32 curr_x_coeff = 1;
|
||
|
+ struct pixel curr_pixel, tmp_pixel;
|
||
|
+ u32 x_array_size = x_coeff[0];
|
||
|
+ int x_column_num;
|
||
|
+ int i;
|
||
|
+ int l,m;
|
||
|
+ int k = 0;
|
||
|
+ u32 rnd = (1 << (x_shift - 1));
|
||
|
+
|
||
|
+ for (i = 0; i < src_w; ) {
|
||
|
+ curr_x_coeff = 1;
|
||
|
+ get_pixel(tmp_pixel, *src_p, depth);
|
||
|
+ i++;
|
||
|
+ for (l = 0; l < x_array_size; l++) {
|
||
|
+ x_column_num = x_coeff[curr_x_coeff++];
|
||
|
+ curr_pixel.red = curr_pixel.green = curr_pixel.blue = 0;
|
||
|
+ for (m = 0; m < x_column_num - 1; m++) {
|
||
|
+ curr_pixel.red += tmp_pixel.red * x_coeff[curr_x_coeff];
|
||
|
+ curr_pixel.green += tmp_pixel.green * x_coeff[curr_x_coeff];
|
||
|
+ curr_pixel.blue += tmp_pixel.blue * x_coeff[curr_x_coeff];
|
||
|
+ curr_x_coeff++;
|
||
|
+ get_pixel(tmp_pixel, *src_p, depth);
|
||
|
+ i++;
|
||
|
+ }
|
||
|
+ curr_pixel.red += tmp_pixel.red * x_coeff[curr_x_coeff];
|
||
|
+ curr_pixel.green += tmp_pixel.green * x_coeff[curr_x_coeff];
|
||
|
+ curr_pixel.blue += tmp_pixel.blue * x_coeff[curr_x_coeff];
|
||
|
+ curr_x_coeff++;
|
||
|
+ curr_pixel.red = (curr_pixel.red + rnd) >> x_shift;
|
||
|
+ curr_pixel.green = (curr_pixel.green + rnd) >> x_shift;
|
||
|
+ curr_pixel.blue = (curr_pixel.blue + rnd) >> x_shift;
|
||
|
+ row_buffer[k].red += curr_pixel.red * y_coeff;
|
||
|
+ row_buffer[k].green += curr_pixel.green * y_coeff;
|
||
|
+ row_buffer[k].blue += curr_pixel.blue * y_coeff;
|
||
|
+ k++;
|
||
|
+ }
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static inline void
|
||
|
+scale_x_up(int depth, int src_w, unsigned char **src_p, u32 *x_coeff, u32 x_shift, u32 y_coeff, struct pixel *row_buffer)
|
||
|
+{
|
||
|
+ u32 curr_x_coeff = 1;
|
||
|
+ struct pixel curr_pixel, tmp_pixel;
|
||
|
+ u32 x_array_size = x_coeff[0];
|
||
|
+ int x_column_num;
|
||
|
+ int i;
|
||
|
+ int l,m;
|
||
|
+ int k = 0;
|
||
|
+ u32 rnd = (1 << (x_shift - 1));
|
||
|
+
|
||
|
+ for (i = 0; i < src_w;) {
|
||
|
+ curr_x_coeff = 1;
|
||
|
+ get_pixel(tmp_pixel, *src_p, depth);
|
||
|
+ i++;
|
||
|
+ for (l = 0; l < x_array_size - 1; l++) {
|
||
|
+ x_column_num = x_coeff[curr_x_coeff++];
|
||
|
+ for (m = 0; m < x_column_num; m++) {
|
||
|
+ row_buffer[k].red += tmp_pixel.red * y_coeff;
|
||
|
+ row_buffer[k].green += tmp_pixel.green * y_coeff;
|
||
|
+ row_buffer[k].blue += tmp_pixel.blue * y_coeff;
|
||
|
+ k++;
|
||
|
+ }
|
||
|
+ curr_pixel.red = tmp_pixel.red * x_coeff[curr_x_coeff];
|
||
|
+ curr_pixel.green = tmp_pixel.green * x_coeff[curr_x_coeff];
|
||
|
+ curr_pixel.blue = tmp_pixel.blue * x_coeff[curr_x_coeff];
|
||
|
+ curr_x_coeff++;
|
||
|
+ get_pixel(tmp_pixel, *src_p, depth);
|
||
|
+ i++;
|
||
|
+ row_buffer[k].red += ((curr_pixel.red + tmp_pixel.red * x_coeff[curr_x_coeff] + rnd) >> x_shift) * y_coeff;
|
||
|
+ row_buffer[k].green += ((curr_pixel.green + tmp_pixel.green * x_coeff[curr_x_coeff] + rnd) >> x_shift) * y_coeff;
|
||
|
+ row_buffer[k].blue += ((curr_pixel.blue + tmp_pixel.blue * x_coeff[curr_x_coeff] + rnd) >> x_shift) * y_coeff;
|
||
|
+ k++;
|
||
|
+ curr_x_coeff++;
|
||
|
+ }
|
||
|
+ for (m = 0; m < x_coeff[curr_x_coeff]; m++) {
|
||
|
+ row_buffer[k].red += tmp_pixel.red * y_coeff;
|
||
|
+ row_buffer[k].green += tmp_pixel.green * y_coeff;
|
||
|
+ row_buffer[k].blue += tmp_pixel.blue * y_coeff;
|
||
|
+ k++;
|
||
|
+ }
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static int scale_y_down(unsigned char *src, unsigned char *dst, int depth, int src_w, int src_h, int dst_w, int dst_h)
|
||
|
+{
|
||
|
+ int octpp = (depth + 1) >> 3;
|
||
|
+ int src_x_bytes = octpp * ((src_w + SPLASH_ALIGN) & ~SPLASH_ALIGN);
|
||
|
+ int dst_x_bytes = octpp * ((dst_w + SPLASH_ALIGN) & ~SPLASH_ALIGN);
|
||
|
+ int j;
|
||
|
+ struct pixel *row_buffer;
|
||
|
+ u32 x_shift, y_shift;
|
||
|
+ u32 *x_coeff;
|
||
|
+ u32 *y_coeff;
|
||
|
+ u32 curr_y_coeff = 1;
|
||
|
+ unsigned char *src_p;
|
||
|
+ unsigned char *src_p_line = src;
|
||
|
+ char *dst_p_line;
|
||
|
+ int r,s;
|
||
|
+ int y_array_rows;
|
||
|
+ int y_column_num;
|
||
|
+ int k;
|
||
|
+ u32 rnd;
|
||
|
+ int xup;
|
||
|
+
|
||
|
+ row_buffer = (struct pixel *)vmalloc(sizeof(struct pixel) * (dst_w + 1));
|
||
|
+ x_coeff = do_coefficients(src_w, dst_w, &x_shift);
|
||
|
+ y_coeff = do_coefficients(src_h, dst_h, &y_shift);
|
||
|
+ if (!row_buffer || !x_coeff || !y_coeff) {
|
||
|
+ vfree(row_buffer);
|
||
|
+ vfree(x_coeff);
|
||
|
+ vfree(y_coeff);
|
||
|
+ return -ENOMEM;
|
||
|
+ }
|
||
|
+ y_array_rows = y_coeff[0];
|
||
|
+ rnd = (1 << (y_shift - 1));
|
||
|
+ xup = (src_w <= dst_w) ? 1 : 0;
|
||
|
+
|
||
|
+ dst_p_line = dst;
|
||
|
+
|
||
|
+ for (j = 0; j < src_h;) {
|
||
|
+ curr_y_coeff = 1;
|
||
|
+ for (r = 0; r < y_array_rows; r++) {
|
||
|
+ y_column_num = y_coeff[curr_y_coeff++];
|
||
|
+ for (k = 0; k < dst_w + 1; k++)
|
||
|
+ row_buffer[k].red = row_buffer[k].green = row_buffer[k].blue = 0;
|
||
|
+ src_p = src_p_line;
|
||
|
+ if (xup)
|
||
|
+ scale_x_up(depth, src_w, &src_p, x_coeff, x_shift, y_coeff[curr_y_coeff], row_buffer );
|
||
|
+ else
|
||
|
+ scale_x_down(depth, src_w, &src_p, x_coeff, x_shift, y_coeff[curr_y_coeff], row_buffer );
|
||
|
+ curr_y_coeff++;
|
||
|
+ for (s = 1; s < y_column_num; s++) {
|
||
|
+ src_p = src_p_line = src_p_line + src_x_bytes;
|
||
|
+ j++;
|
||
|
+ if (xup)
|
||
|
+ scale_x_up(depth, src_w, &src_p, x_coeff, x_shift, y_coeff[curr_y_coeff], row_buffer );
|
||
|
+ else
|
||
|
+ scale_x_down(depth, src_w, &src_p, x_coeff, x_shift, y_coeff[curr_y_coeff], row_buffer );
|
||
|
+ curr_y_coeff++;
|
||
|
+ }
|
||
|
+ for (k = 0; k < dst_w; k++) {
|
||
|
+ row_buffer[k].red = ( row_buffer[k].red + rnd) >> y_shift;
|
||
|
+ row_buffer[k].green = (row_buffer[k].green + rnd) >> y_shift;
|
||
|
+ row_buffer[k].blue = (row_buffer[k].blue + rnd) >> y_shift;
|
||
|
+ put_pixel (row_buffer[k], dst, depth);
|
||
|
+ }
|
||
|
+ dst = dst_p_line = dst_p_line + dst_x_bytes;
|
||
|
+ }
|
||
|
+ src_p_line = src_p_line + src_x_bytes;
|
||
|
+ j++;
|
||
|
+ }
|
||
|
+ vfree(row_buffer);
|
||
|
+ vfree(x_coeff);
|
||
|
+ vfree(y_coeff);
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static int scale_y_up(unsigned char *src, unsigned char *dst, int depth, int src_w, int src_h, int dst_w, int dst_h)
|
||
|
+{
|
||
|
+ int octpp = (depth + 1) >> 3;
|
||
|
+ int src_x_bytes = octpp * ((src_w + SPLASH_ALIGN) & ~SPLASH_ALIGN);
|
||
|
+ int dst_x_bytes = octpp * ((dst_w + SPLASH_ALIGN) & ~SPLASH_ALIGN);
|
||
|
+ int j;
|
||
|
+ u32 x_shift, y_shift;
|
||
|
+ u32 *x_coeff;
|
||
|
+ u32 *y_coeff;
|
||
|
+ struct pixel *row_buf_list[2];
|
||
|
+ struct pixel *row_buffer;
|
||
|
+ u32 curr_y_coeff = 1;
|
||
|
+ unsigned char *src_p;
|
||
|
+ unsigned char *src_p_line = src;
|
||
|
+ char *dst_p_line;
|
||
|
+ int r,s;
|
||
|
+ int y_array_rows;
|
||
|
+ int y_column_num;
|
||
|
+ int k;
|
||
|
+ u32 rnd;
|
||
|
+ int bi;
|
||
|
+ int xup;
|
||
|
+ int writes;
|
||
|
+
|
||
|
+ x_coeff = do_coefficients(src_w, dst_w, &x_shift);
|
||
|
+ y_coeff = do_coefficients(src_h, dst_h, &y_shift);
|
||
|
+ row_buf_list[0] = (struct pixel *)vmalloc(2 * sizeof(struct pixel) * (dst_w + 1));
|
||
|
+ if (!row_buf_list[0] || !x_coeff || !y_coeff) {
|
||
|
+ vfree(row_buf_list[0]);
|
||
|
+ vfree(x_coeff);
|
||
|
+ vfree(y_coeff);
|
||
|
+ return -ENOMEM;
|
||
|
+ }
|
||
|
+ row_buf_list[1] = row_buf_list[0] + (dst_w + 1);
|
||
|
+
|
||
|
+ y_array_rows = y_coeff[0];
|
||
|
+ rnd = (1 << (y_shift - 1));
|
||
|
+ bi = 1;
|
||
|
+ xup = (src_w <= dst_w) ? 1 : 0;
|
||
|
+ writes = 0;
|
||
|
+
|
||
|
+ dst_p_line = dst;
|
||
|
+ src_p = src_p_line;
|
||
|
+
|
||
|
+ row_buffer = row_buf_list[0];
|
||
|
+
|
||
|
+ for (j = 0; j < src_h;) {
|
||
|
+ memset(row_buf_list[0], 0, 2 * sizeof(struct pixel) * (dst_w + 1));
|
||
|
+ curr_y_coeff = 1;
|
||
|
+ if (xup)
|
||
|
+ scale_x_up(depth, src_w, &src_p, x_coeff, x_shift, 1, row_buffer );
|
||
|
+ else
|
||
|
+ scale_x_down(depth, src_w, &src_p, x_coeff, x_shift, 1, row_buffer );
|
||
|
+ src_p = src_p_line = src_p_line + src_x_bytes;
|
||
|
+ j++;
|
||
|
+ for (r = 0; r < y_array_rows - 1; r++) {
|
||
|
+ struct pixel *old_row_buffer = row_buffer;
|
||
|
+ u32 prev_y_coeff_val;
|
||
|
+
|
||
|
+ y_column_num = y_coeff[curr_y_coeff];
|
||
|
+ for (s = 0; s < y_column_num; s++) {
|
||
|
+ for (k = 0; k < dst_w; k++)
|
||
|
+ put_pixel(row_buffer[k], dst, depth);
|
||
|
+ dst = dst_p_line = dst_p_line + dst_x_bytes;
|
||
|
+ writes++;
|
||
|
+ }
|
||
|
+ curr_y_coeff++;
|
||
|
+ row_buffer = row_buf_list[(bi++) % 2];
|
||
|
+ prev_y_coeff_val = y_coeff[curr_y_coeff++];
|
||
|
+ if (xup)
|
||
|
+ scale_x_up(depth, src_w, &src_p, x_coeff, x_shift, 1, row_buffer );
|
||
|
+ else
|
||
|
+ scale_x_down(depth, src_w, &src_p, x_coeff, x_shift, 1, row_buffer );
|
||
|
+ src_p = src_p_line = src_p_line + src_x_bytes;
|
||
|
+ j++;
|
||
|
+ for (k = 0; k <dst_w; k++) {
|
||
|
+ struct pixel pix;
|
||
|
+ pix.red = (old_row_buffer[k].red * prev_y_coeff_val + row_buffer[k].red * y_coeff[curr_y_coeff] + rnd) >> y_shift;
|
||
|
+ pix.green = (old_row_buffer[k].green * prev_y_coeff_val + row_buffer[k].green * y_coeff[curr_y_coeff] + rnd) >> y_shift;
|
||
|
+ pix.blue = (old_row_buffer[k].blue * prev_y_coeff_val + row_buffer[k].blue * y_coeff[curr_y_coeff] + rnd) >> y_shift;
|
||
|
+ old_row_buffer[k].red = old_row_buffer[k].green = old_row_buffer[k].blue = 0;
|
||
|
+ put_pixel(pix, dst, depth);
|
||
|
+ }
|
||
|
+ dst = dst_p_line = dst_p_line + dst_x_bytes;
|
||
|
+ writes++;
|
||
|
+ curr_y_coeff++;
|
||
|
+ }
|
||
|
+ for (r = 0; r < y_coeff[curr_y_coeff]; r++) {
|
||
|
+ for (k = 0; k < dst_w; k++) {
|
||
|
+ put_pixel(row_buffer[k], dst, depth);
|
||
|
+ }
|
||
|
+ dst = dst_p_line = dst_p_line + dst_x_bytes;
|
||
|
+ writes++;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ vfree(row_buf_list[0]);
|
||
|
+ vfree(x_coeff);
|
||
|
+ vfree(y_coeff);
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static int jpeg_get(unsigned char *buf, unsigned char *pic,
|
||
|
+ int width, int height, int depth,
|
||
|
+ struct jpeg_decdata *decdata)
|
||
|
+{
|
||
|
+ int my_width, my_height;
|
||
|
+ int err;
|
||
|
+
|
||
|
+ jpeg_get_size(buf, &my_width, &my_height);
|
||
|
+
|
||
|
+ if (my_height != height || my_width != width) {
|
||
|
+ int my_size = ((my_width + 15) & ~15)
|
||
|
+ * ((my_height + 15) & ~15) * ((depth + 1) >> 3);
|
||
|
+ unsigned char *mem = vmalloc(my_size);
|
||
|
+ if (!mem)
|
||
|
+ return 17;
|
||
|
+ if ((err = jpeg_decode(buf, mem, ((my_width + 15) & ~15),
|
||
|
+ ((my_height + 15) & ~15), depth, decdata))) {
|
||
|
+ vfree(mem);
|
||
|
+ return err;
|
||
|
+ }
|
||
|
+ printk(KERN_INFO "bootsplash: scaling image from %dx%d to %dx%d\n", my_width, my_height, width, height);
|
||
|
+ if (my_height <= height)
|
||
|
+ err = scale_y_up(mem, pic, depth, my_width, my_height, ((width + 15) & ~15), ((height + 15) & ~15));
|
||
|
+ else
|
||
|
+ err = scale_y_down(mem, pic, depth, my_width, my_height, ((width + 15) & ~15), ((height + 15) & ~15));
|
||
|
+ vfree(mem);
|
||
|
+ if (err < 0)
|
||
|
+ return 17;
|
||
|
+ } else {
|
||
|
+ if ((err = jpeg_decode(buf, pic, ((width + 15) & ~15), ((height + 15) & ~15), depth, decdata)))
|
||
|
+ return err;
|
||
|
+ }
|
||
|
+ return 0;
|
||
|
+}
|
||
|
--- a/drivers/video/bootsplash/decode-jpg.c
|
||
|
+++ b/drivers/video/bootsplash/decode-jpg.c
|
||
|
@@ -888,9 +888,9 @@ PREC q[][64];
|
||
|
#define PIC_32(yin, xin, p, xout) \
|
||
|
( \
|
||
|
y = outy[(yin) * 8 + xin], \
|
||
|
- STORECLAMP(p[(xout) * 4 + 0], y + cr), \
|
||
|
+ STORECLAMP(p[(xout) * 4 + 0], y + cb), \
|
||
|
STORECLAMP(p[(xout) * 4 + 1], y - cg), \
|
||
|
- STORECLAMP(p[(xout) * 4 + 2], y + cb), \
|
||
|
+ STORECLAMP(p[(xout) * 4 + 2], y + cr), \
|
||
|
p[(xout) * 4 + 3] = 0 \
|
||
|
)
|
||
|
|
||
|
--- a/drivers/video/bootsplash/render.c
|
||
|
+++ b/drivers/video/bootsplash/render.c
|
||
|
@@ -45,7 +45,7 @@ void splash_putcs(struct vc_data *vc, st
|
||
|
transparent = sd->splash_color == bg_color;
|
||
|
xpos = xpos * vc->vc_font.width + sd->splash_text_xo;
|
||
|
ypos = ypos * vc->vc_font.height + sd->splash_text_yo;
|
||
|
- splashsrc.ub = (u8 *)(info->splash_pic + ypos * info->splash_pic_stride + xpos * octpp);
|
||
|
+ splashsrc.ub = (u8 *)(sd->splash_pic + ypos * sd->splash_pic_stride + xpos * octpp);
|
||
|
dst.ub = (u8 *)(info->screen_base + ypos * info->fix.line_length + xpos * octpp);
|
||
|
fgx = ((u32 *)info->pseudo_palette)[fg_color];
|
||
|
if (transparent && sd->splash_color == 15) {
|
||
|
@@ -109,10 +109,10 @@ void splash_putcs(struct vc_data *vc, st
|
||
|
}
|
||
|
}
|
||
|
dst.ub += info->fix.line_length - vc->vc_font.width * octpp;
|
||
|
- splashsrc.ub += info->splash_pic_stride - vc->vc_font.width * octpp;
|
||
|
+ splashsrc.ub += sd->splash_pic_stride - vc->vc_font.width * octpp;
|
||
|
}
|
||
|
dst.ub -= info->fix.line_length * vc->vc_font.height - vc->vc_font.width * octpp;
|
||
|
- splashsrc.ub -= info->splash_pic_stride * vc->vc_font.height - vc->vc_font.width * octpp;
|
||
|
+ splashsrc.ub -= sd->splash_pic_stride * vc->vc_font.height - vc->vc_font.width * octpp;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@@ -136,7 +136,7 @@ static void splash_renderc(struct fb_inf
|
||
|
sd = info->splash_data;
|
||
|
|
||
|
transparent = sd->splash_color == bg_color;
|
||
|
- splashsrc.ub = (u8*)(info->splash_pic + ypos * info->splash_pic_stride + xpos * octpp);
|
||
|
+ splashsrc.ub = (u8*)(sd->splash_pic + ypos * sd->splash_pic_stride + xpos * octpp);
|
||
|
dst.ub = (u8*)(info->screen_base + ypos * info->fix.line_length + xpos * octpp);
|
||
|
fgx = ((u32 *)info->pseudo_palette)[fg_color];
|
||
|
if (transparent && sd->splash_color == 15) {
|
||
|
@@ -197,7 +197,7 @@ static void splash_renderc(struct fb_inf
|
||
|
}
|
||
|
}
|
||
|
dst.ub += info->fix.line_length - width * octpp;
|
||
|
- splashsrc.ub += info->splash_pic_stride - width * octpp;
|
||
|
+ splashsrc.ub += sd->splash_pic_stride - width * octpp;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@@ -255,10 +255,11 @@ static void splashset(u8 *dst, int heigh
|
||
|
|
||
|
static void splashfill(struct fb_info *info, int sy, int sx, int height, int width) {
|
||
|
int octpp = (info->var.bits_per_pixel + 1) >> 3;
|
||
|
+ struct splash_data *sd = info->splash_data;
|
||
|
|
||
|
splashcopy((u8 *)(info->screen_base + sy * info->fix.line_length + sx * octpp),
|
||
|
- (u8 *)(info->splash_pic + sy * info->splash_pic_stride + sx * octpp),
|
||
|
- height, width, info->fix.line_length, info->splash_pic_stride,
|
||
|
+ (u8 *)(sd->splash_pic + sy * sd->splash_pic_stride + sx * octpp),
|
||
|
+ height, width, info->fix.line_length, sd->splash_pic_stride,
|
||
|
octpp);
|
||
|
}
|
||
|
|
||
|
@@ -442,6 +443,7 @@ void splash_bmove_redraw(struct vc_data
|
||
|
void splash_blank(struct vc_data *vc, struct fb_info *info, int blank)
|
||
|
{
|
||
|
SPLASH_DEBUG();
|
||
|
+
|
||
|
if (blank) {
|
||
|
splashset((u8 *)info->screen_base,
|
||
|
info->var.yres, info->var.xres,
|
||
|
--- a/drivers/video/console/fbcon.h
|
||
|
+++ b/drivers/video/console/fbcon.h
|
||
|
@@ -34,8 +34,10 @@ struct splash_data {
|
||
|
int splash_height; /* height of image */
|
||
|
int splash_text_xo; /* text area origin */
|
||
|
int splash_text_yo;
|
||
|
- int splash_text_wi; /* text area size */
|
||
|
+ int splash_text_wi; /* text area size used*/
|
||
|
int splash_text_he;
|
||
|
+ int splash_jpg_text_wi; /* text area size of jpeg*/
|
||
|
+ int splash_jpg_text_he;
|
||
|
int splash_showtext; /* silent/verbose mode */
|
||
|
int splash_boxcount;
|
||
|
int splash_percent;
|
||
|
@@ -45,12 +47,19 @@ struct splash_data {
|
||
|
unsigned char *splash_boxes;
|
||
|
unsigned char *splash_jpeg; /* jpeg */
|
||
|
unsigned char *splash_palette; /* palette for 8-bit */
|
||
|
+ int splash_boxes_xoff;
|
||
|
+ int splash_boxes_yoff;
|
||
|
|
||
|
int splash_dosilent; /* show silent jpeg */
|
||
|
unsigned char *splash_silentjpeg;
|
||
|
unsigned char *splash_sboxes;
|
||
|
int splash_sboxcount;
|
||
|
struct splash_data *next;
|
||
|
+ int splash_sboxes_xoff;
|
||
|
+ int splash_sboxes_yoff;
|
||
|
+ int splash_pic_stride;
|
||
|
+ unsigned char *splash_pic;
|
||
|
+ int splash_pic_size;
|
||
|
};
|
||
|
#endif
|
||
|
|
||
|
--- a/include/linux/fb.h
|
||
|
+++ b/include/linux/fb.h
|
||
|
@@ -861,9 +861,6 @@ struct fb_info {
|
||
|
void *par;
|
||
|
#ifdef CONFIG_BOOTSPLASH
|
||
|
struct splash_data *splash_data;
|
||
|
- unsigned char *splash_pic;
|
||
|
- int splash_pic_size;
|
||
|
- int splash_pic_stride;
|
||
|
char fb_cursordata[64];
|
||
|
#endif
|
||
|
/* we need the PCI or similiar aperture base/size not
|