2873 lines
80 KiB
Plaintext
2873 lines
80 KiB
Plaintext
From: mls@suse.de
|
|
Subject: Bootsplash for current kernel
|
|
Patch-mainline: no
|
|
References: none
|
|
|
|
Better support for other VTs. Don't change percent or silent status
|
|
when installing a new jpeg. Provide splash_set_percent function.
|
|
|
|
Signed-off-by: mls@suse.de
|
|
|
|
---
|
|
drivers/tty/n_tty.c | 9
|
|
drivers/tty/vt/keyboard.c | 9
|
|
drivers/tty/vt/vt.c | 25
|
|
drivers/video/Kconfig | 4
|
|
drivers/video/Makefile | 1
|
|
drivers/video/bootsplash/Kconfig | 17
|
|
drivers/video/bootsplash/Makefile | 5
|
|
drivers/video/bootsplash/bootsplash.c | 1017 ++++++++++++++++++++++++++++++++++
|
|
drivers/video/bootsplash/bootsplash.h | 41 +
|
|
drivers/video/bootsplash/decode-jpg.c | 957 +++++++++++++++++++++++++++++++
|
|
drivers/video/bootsplash/decode-jpg.h | 35 +
|
|
drivers/video/bootsplash/render.c | 328 ++++++++++
|
|
drivers/video/console/bitblit.c | 39 +
|
|
drivers/video/console/fbcon.c | 53 +
|
|
drivers/video/console/fbcon.h | 28
|
|
drivers/video/vesafb.c | 8
|
|
include/linux/console_struct.h | 3
|
|
include/linux/fb.h | 8
|
|
kernel/panic.c | 13
|
|
19 files changed, 2598 insertions(+), 2 deletions(-)
|
|
|
|
--- a/drivers/tty/n_tty.c
|
|
+++ b/drivers/tty/n_tty.c
|
|
@@ -1790,6 +1790,15 @@ do_it_again:
|
|
tty->minimum_to_wake = (minimum - (b - buf));
|
|
|
|
if (!input_available_p(tty, 0)) {
|
|
+#ifdef CONFIG_BOOTSPLASH
|
|
+ if (file->f_dentry->d_inode->i_rdev == MKDEV(TTY_MAJOR,0) ||
|
|
+ file->f_dentry->d_inode->i_rdev == MKDEV(TTY_MAJOR,1) ||
|
|
+ file->f_dentry->d_inode->i_rdev == MKDEV(TTYAUX_MAJOR,0) ||
|
|
+ file->f_dentry->d_inode->i_rdev == MKDEV(TTYAUX_MAJOR,1)) {
|
|
+ extern int splash_verbose(void);
|
|
+ (void)splash_verbose();
|
|
+ }
|
|
+#endif
|
|
if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
|
|
retval = -EIO;
|
|
break;
|
|
--- a/drivers/tty/vt/keyboard.c
|
|
+++ b/drivers/tty/vt/keyboard.c
|
|
@@ -1202,6 +1202,15 @@ static void kbd_keycode(unsigned int key
|
|
pr_warning("can't emulate rawmode for keycode %d\n",
|
|
keycode);
|
|
|
|
+#ifdef CONFIG_BOOTSPLASH
|
|
+ /* This code has to be redone for some non-x86 platforms */
|
|
+ if (down == 1 && (keycode == 0x3c || keycode == 0x01)) { /* F2 and ESC on PC keyboard */
|
|
+ extern int splash_verbose(void);
|
|
+ if (splash_verbose())
|
|
+ return;
|
|
+ }
|
|
+#endif
|
|
+
|
|
#ifdef CONFIG_SPARC
|
|
if (keycode == KEY_A && sparc_l1_a_state) {
|
|
sparc_l1_a_state = false;
|
|
--- a/drivers/tty/vt/vt.c
|
|
+++ b/drivers/tty/vt/vt.c
|
|
@@ -4213,6 +4213,31 @@ void vcs_scr_updated(struct vc_data *vc)
|
|
notify_update(vc);
|
|
}
|
|
|
|
+#ifdef CONFIG_BOOTSPLASH
|
|
+void con_remap_def_color(struct vc_data *vc, int new_color)
|
|
+{
|
|
+ unsigned short *sbuf = vc->vc_screenbuf;
|
|
+ unsigned c, len = vc->vc_screenbuf_size >> 1;
|
|
+ int old_color;
|
|
+
|
|
+ if (sbuf) {
|
|
+ old_color = vc->vc_def_color << 8;
|
|
+ new_color <<= 8;
|
|
+ while(len--) {
|
|
+ c = *sbuf;
|
|
+ if (((c ^ old_color) & 0xf000) == 0)
|
|
+ *sbuf ^= (old_color ^ new_color) & 0xf000;
|
|
+ if (((c ^ old_color) & 0x0f00) == 0)
|
|
+ *sbuf ^= (old_color ^ new_color) & 0x0f00;
|
|
+ sbuf++;
|
|
+ }
|
|
+ new_color >>= 8;
|
|
+ }
|
|
+ vc->vc_def_color = vc->vc_color = new_color;
|
|
+ update_attr(vc);
|
|
+}
|
|
+#endif
|
|
+
|
|
/*
|
|
* Visible symbols for modules
|
|
*/
|
|
--- a/drivers/video/Kconfig
|
|
+++ b/drivers/video/Kconfig
|
|
@@ -2379,4 +2379,8 @@ if FB || SGI_NEWPORT_CONSOLE
|
|
source "drivers/video/logo/Kconfig"
|
|
endif
|
|
|
|
+if FB
|
|
+ source "drivers/video/bootsplash/Kconfig"
|
|
+endif
|
|
+
|
|
endmenu
|
|
--- a/drivers/video/Makefile
|
|
+++ b/drivers/video/Makefile
|
|
@@ -14,6 +14,7 @@ fb-objs := $(f
|
|
obj-$(CONFIG_VT) += console/
|
|
obj-$(CONFIG_LOGO) += logo/
|
|
obj-y += backlight/ display/
|
|
+obj-$(CONFIG_BOOTSPLASH) += bootsplash/
|
|
|
|
obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o
|
|
obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o
|
|
--- /dev/null
|
|
+++ b/drivers/video/bootsplash/Kconfig
|
|
@@ -0,0 +1,17 @@
|
|
+#
|
|
+# Bootsplash configuration
|
|
+#
|
|
+
|
|
+menu "Bootsplash configuration"
|
|
+
|
|
+config BOOTSPLASH
|
|
+ bool "Bootup splash screen"
|
|
+ depends on FRAMEBUFFER_CONSOLE && FB_VESA
|
|
+ default n
|
|
+ ---help---
|
|
+ This option enables the Linux bootsplash screen. For more
|
|
+ information on the bootsplash screen have a look at
|
|
+ http://www.bootsplash.org/.
|
|
+ If you are unsure, say N
|
|
+endmenu
|
|
+
|
|
--- /dev/null
|
|
+++ b/drivers/video/bootsplash/Makefile
|
|
@@ -0,0 +1,5 @@
|
|
+# Makefile for the Linux bootsplash
|
|
+
|
|
+obj-$(CONFIG_BOOTSPLASH) += bootsplash.o
|
|
+obj-$(CONFIG_BOOTSPLASH) += decode-jpg.o
|
|
+obj-$(CONFIG_BOOTSPLASH) += render.o
|
|
--- /dev/null
|
|
+++ b/drivers/video/bootsplash/bootsplash.c
|
|
@@ -0,0 +1,1017 @@
|
|
+/*
|
|
+ * linux/drivers/video/bootsplash/bootsplash.c -
|
|
+ * splash screen handling functions.
|
|
+ *
|
|
+ * (w) 2001-2004 by Volker Poplawski, <volker@poplawski.de>,
|
|
+ * Stefan Reinauer, <stepan@suse.de>,
|
|
+ * Steffen Winterfeldt, <snwint@suse.de>,
|
|
+ * Michael Schroeder <mls@suse.de>
|
|
+ *
|
|
+ * Ideas & SuSE screen work by Ken Wimer, <wimer@suse.de>
|
|
+ *
|
|
+ * For more information on this code check http://www.bootsplash.org/
|
|
+ */
|
|
+
|
|
+#include <linux/module.h>
|
|
+#include <linux/types.h>
|
|
+#include <linux/fb.h>
|
|
+#include <linux/vt_kern.h>
|
|
+#include <linux/vmalloc.h>
|
|
+#include <linux/unistd.h>
|
|
+#include <linux/syscalls.h>
|
|
+
|
|
+#include <asm/irq.h>
|
|
+#include <asm/system.h>
|
|
+
|
|
+#include "../console/fbcon.h"
|
|
+#include "bootsplash.h"
|
|
+#include "decode-jpg.h"
|
|
+
|
|
+extern struct fb_ops vesafb_ops;
|
|
+extern signed char con2fb_map[MAX_NR_CONSOLES];
|
|
+
|
|
+#define SPLASH_VERSION "3.1.6-2004/03/31"
|
|
+
|
|
+/* These errors have to match fbcon-jpegdec.h */
|
|
+static unsigned char *jpg_errors[] = {
|
|
+ "no SOI found",
|
|
+ "not 8 bit",
|
|
+ "height mismatch",
|
|
+ "width mismatch",
|
|
+ "bad width or height",
|
|
+ "too many COMPPs",
|
|
+ "illegal HV",
|
|
+ "quant table selector",
|
|
+ "picture is not YCBCR 221111",
|
|
+ "unknow CID in scan",
|
|
+ "dct not sequential",
|
|
+ "wrong marker",
|
|
+ "no EOI",
|
|
+ "bad tables",
|
|
+ "depth mismatch"
|
|
+};
|
|
+
|
|
+static struct jpeg_decdata *decdata = 0; /* private decoder data */
|
|
+
|
|
+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 __init splash_setup(char *options)
|
|
+{
|
|
+ if(!strncmp("silent", options, 6)) {
|
|
+ printk(KERN_INFO "bootsplash: silent mode.\n");
|
|
+ splash_usesilent = 1;
|
|
+ /* skip "silent," */
|
|
+ if (strlen(options) == 6)
|
|
+ return 0;
|
|
+ options += 7;
|
|
+ }
|
|
+ if(!strncmp("verbose", options, 7)) {
|
|
+ printk(KERN_INFO "bootsplash: verbose mode.\n");
|
|
+ splash_usesilent = 0;
|
|
+ return 0;
|
|
+ }
|
|
+ splash_default = simple_strtoul(options, NULL, 0);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+__setup("splash=", splash_setup);
|
|
+
|
|
+
|
|
+static int splash_hasinter(unsigned char *buf, int num)
|
|
+{
|
|
+ unsigned char *bufend = buf + num * 12;
|
|
+ while(buf < bufend) {
|
|
+ if (buf[1] > 127) /* inter? */
|
|
+ return 1;
|
|
+ buf += buf[3] > 127 ? 24 : 12; /* blend? */
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int boxextract(unsigned char *buf, unsigned short *dp, unsigned char *cols, int *blendp)
|
|
+{
|
|
+ dp[0] = buf[0] | buf[1] << 8;
|
|
+ dp[1] = buf[2] | buf[3] << 8;
|
|
+ dp[2] = buf[4] | buf[5] << 8;
|
|
+ dp[3] = buf[6] | buf[7] << 8;
|
|
+ *(unsigned int *)(cols + 0) =
|
|
+ *(unsigned int *)(cols + 4) =
|
|
+ *(unsigned int *)(cols + 8) =
|
|
+ *(unsigned int *)(cols + 12) = *(unsigned int *)(buf + 8);
|
|
+ if (dp[1] > 32767) {
|
|
+ dp[1] = ~dp[1];
|
|
+ *(unsigned int *)(cols + 4) = *(unsigned int *)(buf + 12);
|
|
+ *(unsigned int *)(cols + 8) = *(unsigned int *)(buf + 16);
|
|
+ *(unsigned int *)(cols + 12) = *(unsigned int *)(buf + 20);
|
|
+ *blendp = 1;
|
|
+ return 24;
|
|
+ }
|
|
+ return 12;
|
|
+}
|
|
+
|
|
+static void boxit(unsigned char *pic, int bytes, unsigned char *buf, int num, int percent, int overpaint)
|
|
+{
|
|
+ int x, y, i, p, doblend, r, g, b, a, add;
|
|
+ unsigned short data1[4];
|
|
+ unsigned char cols1[16];
|
|
+ unsigned short data2[4];
|
|
+ unsigned char cols2[16];
|
|
+ unsigned char *bufend;
|
|
+ unsigned short *picp;
|
|
+ unsigned int stipple[32], sti, stin, stinn, stixs, stixe, stiys, stiye;
|
|
+ int xs, xe, ys, ye, xo, yo;
|
|
+
|
|
+ if (num == 0)
|
|
+ return;
|
|
+ bufend = buf + num * 12;
|
|
+ stipple[0] = 0xffffffff;
|
|
+ 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];
|
|
+ }
|
|
+ stipple[stinn++] = (cols1[ 0] << 24) | (cols1[ 1] << 16) | (cols1[ 2] << 8) | cols1[ 3] ;
|
|
+ stipple[stinn++] = (cols1[ 4] << 24) | (cols1[ 5] << 16) | (cols1[ 6] << 8) | cols1[ 7] ;
|
|
+ stipple[stinn++] = (cols1[ 8] << 24) | (cols1[ 9] << 16) | (cols1[10] << 8) | cols1[11] ;
|
|
+ stipple[stinn++] = (cols1[12] << 24) | (cols1[13] << 16) | (cols1[14] << 8) | cols1[15] ;
|
|
+ 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) {
|
|
+ if (overpaint)
|
|
+ continue;
|
|
+ data1[2] = ~data1[2];
|
|
+ }
|
|
+ if (data1[3] > 32767) {
|
|
+ if (percent == 65536)
|
|
+ continue;
|
|
+ data1[3] = ~data1[3];
|
|
+ }
|
|
+ if (data1[0] > 32767) {
|
|
+ data1[0] = ~data1[0];
|
|
+ for (i = 0; i < 4; i++)
|
|
+ data1[i] = (data1[i] * (65536 - percent) + data2[i] * percent) >> 16;
|
|
+ for (i = 0; i < 16; i++)
|
|
+ cols1[i] = (cols1[i] * (65536 - percent) + cols2[i] * percent) >> 16;
|
|
+ }
|
|
+ *(unsigned int *)cols2 = *(unsigned int *)cols1;
|
|
+ a = cols2[3];
|
|
+ if (a == 0 && !doblend)
|
|
+ continue;
|
|
+
|
|
+ if (stixs >= 32768) {
|
|
+ xo = 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);
|
|
+ xo = xe + 1;
|
|
+ } else {
|
|
+ xo = xs = stixs;
|
|
+ xe = stixe ? stixe : data1[2];
|
|
+ }
|
|
+ if (stiys >= 32768) {
|
|
+ yo = 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);
|
|
+ yo = ye + 1;
|
|
+ } else {
|
|
+ yo = ys = stiys;
|
|
+ ye = stiye ? stiye : data1[3];
|
|
+ }
|
|
+ xo = 32 - (xo & 31);
|
|
+ yo = stin - (yo % stin);
|
|
+ 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];
|
|
+
|
|
+ for (y = ys; y <= ye; y++) {
|
|
+ sti = stipple[(y + yo) % stin];
|
|
+ x = (xs + xo) & 31;
|
|
+ if (x)
|
|
+ sti = (sti << x) | (sti >> (32 - x));
|
|
+ if (doblend) {
|
|
+ if ((p = data1[3] - data1[1]) != 0)
|
|
+ p = ((y - data1[1]) << 16) / p;
|
|
+ for (i = 0; i < 8; i++)
|
|
+ cols2[i + 8] = (cols1[i] * (65536 - p) + cols1[i + 8] * p) >> 16;
|
|
+ }
|
|
+ add = (xs & 1);
|
|
+ add ^= (add ^ y) & 1 ? 1 : 3; /* 2x2 ordered dithering */
|
|
+ picp = (unsigned short *)(pic + xs * 2 + y * bytes);
|
|
+ for (x = xs; x <= xe; x++) {
|
|
+ if (!(sti & 0x80000000)) {
|
|
+ sti <<= 1;
|
|
+ picp++;
|
|
+ add ^= 3;
|
|
+ continue;
|
|
+ }
|
|
+ sti = (sti << 1) | 1;
|
|
+ if (doblend) {
|
|
+ if ((p = data1[2] - data1[0]) != 0)
|
|
+ p = ((x - data1[0]) << 16) / p;
|
|
+ for (i = 0; i < 4; i++)
|
|
+ cols2[i] = (cols2[i + 8] * (65536 - p) + cols2[i + 12] * p) >> 16;
|
|
+ a = cols2[3];
|
|
+ }
|
|
+ r = cols2[0];
|
|
+ g = cols2[1];
|
|
+ b = cols2[2];
|
|
+ if (a != 255) {
|
|
+ i = *picp;
|
|
+ r = ((i >> 8 & 0xf8) * (255 - a) + r * a) / 255;
|
|
+ g = ((i >> 3 & 0xfc) * (255 - a) + g * a) / 255;
|
|
+ b = ((i << 3 & 0xf8) * (255 - a) + b * a) / 255;
|
|
+ }
|
|
+ #define CLAMP(x) ((x) >= 256 ? 255 : (x))
|
|
+ i = ((CLAMP(r + add*2+1) & 0xf8) << 8) |
|
|
+ ((CLAMP(g + add ) & 0xfc) << 3) |
|
|
+ ((CLAMP(b + add*2+1) ) >> 3);
|
|
+ *picp++ = i;
|
|
+ add ^= 3;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+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);
|
|
+ mem = vmalloc(size);
|
|
+ if (!mem) {
|
|
+ printk(KERN_INFO "bootsplash: no memory for decoded picture.\n");
|
|
+ return -1;
|
|
+ }
|
|
+ if (!decdata)
|
|
+ decdata = vmalloc(sizeof(*decdata));
|
|
+ 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);
|
|
+ return err ? -1 : 0;
|
|
+}
|
|
+
|
|
+static void splash_free(struct vc_data *vc, struct fb_info *info)
|
|
+{
|
|
+ if (!vc->vc_splash_data)
|
|
+ return;
|
|
+ if (info->silent_screen_base)
|
|
+ info->screen_base = info->silent_screen_base;
|
|
+ info->silent_screen_base = 0;
|
|
+ if (vc->vc_splash_data->splash_silentjpeg)
|
|
+ vfree(vc->vc_splash_data->splash_sboxes);
|
|
+ vfree(vc->vc_splash_data);
|
|
+ vc->vc_splash_data = 0;
|
|
+ info->splash_data = 0;
|
|
+}
|
|
+
|
|
+static int splash_mkpenguin(struct splash_data *data, int pxo, int pyo, int pwi, int phe, int pr, int pg, int pb)
|
|
+{
|
|
+ unsigned char *buf;
|
|
+ int i;
|
|
+
|
|
+ if (pwi ==0 || phe == 0)
|
|
+ return 0;
|
|
+ buf = (unsigned char *)data + sizeof(*data);
|
|
+ pwi += pxo - 1;
|
|
+ phe += pyo - 1;
|
|
+ *buf++ = pxo;
|
|
+ *buf++ = pxo >> 8;
|
|
+ *buf++ = pyo;
|
|
+ *buf++ = pyo >> 8;
|
|
+ *buf++ = pwi;
|
|
+ *buf++ = pwi >> 8;
|
|
+ *buf++ = phe;
|
|
+ *buf++ = phe >> 8;
|
|
+ *buf++ = pr;
|
|
+ *buf++ = pg;
|
|
+ *buf++ = pb;
|
|
+ *buf++ = 0;
|
|
+ for (i = 0; i < 12; i++, buf++)
|
|
+ *buf = buf[-12];
|
|
+ buf[-24] ^= 0xff;
|
|
+ buf[-23] ^= 0xff;
|
|
+ buf[-1] = 0xff;
|
|
+ return 2;
|
|
+}
|
|
+
|
|
+static const int splash_offsets[3][16] = {
|
|
+ /* len, unit, size, state, fgcol, col, xo, yo, wi, he
|
|
+ boxcnt, ssize, sboxcnt, percent, overok, palcnt */
|
|
+ /* V1 */
|
|
+ { 20, -1, 16, -1, -1, -1, 8, 10, 12, 14,
|
|
+ -1, -1, -1, -1, -1, -1 },
|
|
+ /* V2 */
|
|
+ { 35, 8, 12, 9, 10, 11, 16, 18, 20, 22,
|
|
+ -1, -1, -1, -1, -1, -1 },
|
|
+ /* V3 */
|
|
+ { 38, 8, 12, 9, 10, 11, 16, 18, 20, 22,
|
|
+ 24, 28, 32, 34, 36, 37 },
|
|
+};
|
|
+
|
|
+#define SPLASH_OFF_LEN offsets[0]
|
|
+#define SPLASH_OFF_UNIT offsets[1]
|
|
+#define SPLASH_OFF_SIZE offsets[2]
|
|
+#define SPLASH_OFF_STATE offsets[3]
|
|
+#define SPLASH_OFF_FGCOL offsets[4]
|
|
+#define SPLASH_OFF_COL offsets[5]
|
|
+#define SPLASH_OFF_XO offsets[6]
|
|
+#define SPLASH_OFF_YO offsets[7]
|
|
+#define SPLASH_OFF_WI offsets[8]
|
|
+#define SPLASH_OFF_HE offsets[9]
|
|
+#define SPLASH_OFF_BOXCNT offsets[10]
|
|
+#define SPLASH_OFF_SSIZE offsets[11]
|
|
+#define SPLASH_OFF_SBOXCNT offsets[12]
|
|
+#define SPLASH_OFF_PERCENT offsets[13]
|
|
+#define SPLASH_OFF_OVEROK offsets[14]
|
|
+#define SPLASH_OFF_PALCNT offsets[15]
|
|
+
|
|
+static inline int splash_getb(unsigned char *pos, int off)
|
|
+{
|
|
+ return off == -1 ? 0 : pos[off];
|
|
+}
|
|
+
|
|
+static inline int splash_gets(unsigned char *pos, int off)
|
|
+{
|
|
+ return off == -1 ? 0 : pos[off] | pos[off + 1] << 8;
|
|
+}
|
|
+
|
|
+static inline int splash_geti(unsigned char *pos, int off)
|
|
+{
|
|
+ return off == -1 ? 0 :
|
|
+ pos[off] | pos[off + 1] << 8 | pos[off + 2] << 16 | pos[off + 3] << 24;
|
|
+}
|
|
+
|
|
+static int splash_getraw(unsigned char *start, unsigned char *end, int *update)
|
|
+{
|
|
+ unsigned char *ndata;
|
|
+ int version;
|
|
+ int splash_size;
|
|
+ int unit;
|
|
+ int width, height;
|
|
+ int silentsize;
|
|
+ int boxcnt;
|
|
+ int sboxcnt;
|
|
+ int palcnt;
|
|
+ int i, len;
|
|
+ const int *offsets;
|
|
+ struct vc_data *vc;
|
|
+ struct fb_info *info;
|
|
+ struct splash_data *sd;
|
|
+ int oldpercent, oldsilent;
|
|
+
|
|
+ if (update)
|
|
+ *update = -1;
|
|
+
|
|
+ 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);
|
|
+
|
|
+ for (ndata = start; ndata < end; ndata++) {
|
|
+ if (ndata[0] != 'B' || ndata[1] != 'O' || ndata[2] != 'O' || ndata[3] != 'T')
|
|
+ continue;
|
|
+ if (ndata[4] != 'S' || ndata[5] != 'P' || ndata[6] != 'L' || ndata[7] < '1' || ndata[7] > '3')
|
|
+ continue;
|
|
+ version = ndata[7] - '0';
|
|
+ offsets = splash_offsets[version - 1];
|
|
+ len = SPLASH_OFF_LEN;
|
|
+ unit = splash_getb(ndata, SPLASH_OFF_UNIT);
|
|
+ if (unit >= MAX_NR_CONSOLES)
|
|
+ continue;
|
|
+ if (unit) {
|
|
+ vc_allocate(unit);
|
|
+ }
|
|
+ vc = vc_cons[unit].d;
|
|
+ info = registered_fb[(int)con2fb_map[unit]];
|
|
+ width = info->var.xres;
|
|
+ height = info->var.yres;
|
|
+ splash_size = splash_geti(ndata, SPLASH_OFF_SIZE);
|
|
+ if (splash_size == (int)0xffffffff && version > 1) {
|
|
+ if ((sd = vc->vc_splash_data) != 0) {
|
|
+ int up = 0;
|
|
+ i = splash_getb(ndata, SPLASH_OFF_STATE);
|
|
+ if (i != 255) {
|
|
+ sd->splash_state = i;
|
|
+ up = -1;
|
|
+ }
|
|
+ i = splash_getb(ndata, SPLASH_OFF_FGCOL);
|
|
+ if (i != 255) {
|
|
+ sd->splash_fg_color = i;
|
|
+ up = -1;
|
|
+ }
|
|
+ i = splash_getb(ndata, SPLASH_OFF_COL);
|
|
+ if (i != 255) {
|
|
+ sd->splash_color = i;
|
|
+ up = -1;
|
|
+ }
|
|
+ boxcnt = sboxcnt = 0;
|
|
+ if (ndata + len <= end) {
|
|
+ boxcnt = splash_gets(ndata, SPLASH_OFF_BOXCNT);
|
|
+ sboxcnt = splash_gets(ndata, SPLASH_OFF_SBOXCNT);
|
|
+ }
|
|
+ if (boxcnt) {
|
|
+ i = splash_gets(ndata, len);
|
|
+ if (boxcnt + i <= sd->splash_boxcount && ndata + len + 2 + boxcnt * 12 <= end) {
|
|
+
|
|
+ if (splash_geti(ndata, len + 2) != 0x7ffd7fff || !memcmp(ndata + len + 2, sd->splash_boxes + i * 12, 8)) {
|
|
+
|
|
+ memcpy(sd->splash_boxes + i * 12, ndata + len + 2, boxcnt * 12);
|
|
+ up |= 1;
|
|
+ }
|
|
+ }
|
|
+ len += boxcnt * 12 + 2;
|
|
+ }
|
|
+ if (sboxcnt) {
|
|
+ i = splash_gets(ndata, len);
|
|
+ if (sboxcnt + i <= sd->splash_sboxcount && ndata + len + 2 + sboxcnt * 12 <= end) {
|
|
+ if (splash_geti(ndata, len + 2) != 0x7ffd7fff || !memcmp(ndata + len + 2, sd->splash_sboxes + i * 12, 8)) {
|
|
+ memcpy(sd->splash_sboxes + i * 12, ndata + len + 2, sboxcnt * 12);
|
|
+ up |= 2;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ if (update)
|
|
+ *update = up;
|
|
+ }
|
|
+ return unit;
|
|
+ }
|
|
+ if (splash_size == 0) {
|
|
+ printk(KERN_INFO "bootsplash: ...found, freeing memory.\n");
|
|
+ if (vc->vc_splash_data)
|
|
+ splash_free(vc, info);
|
|
+ return unit;
|
|
+ }
|
|
+ boxcnt = splash_gets(ndata, SPLASH_OFF_BOXCNT);
|
|
+ palcnt = 3 * splash_getb(ndata, SPLASH_OFF_PALCNT);
|
|
+ if (ndata + len + splash_size > end) {
|
|
+ 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);
|
|
+ if (silentsize >= splash_size) {
|
|
+ printk(KERN_ERR "bootsplash: bigger than splashsize!\n");
|
|
+ return -1;
|
|
+ }
|
|
+ splash_size -= silentsize;
|
|
+ if (!splash_usesilent)
|
|
+ silentsize = 0;
|
|
+ else if (height * 2 * info->fix.line_length > info->fix.smem_len) {
|
|
+ printk(KERN_WARNING "bootsplash: does not fit into framebuffer.\n");
|
|
+ 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));
|
|
+ if (!sd)
|
|
+ break;
|
|
+ sd->splash_silentjpeg = 0;
|
|
+ sd->splash_sboxes = 0;
|
|
+ sd->splash_sboxcount = 0;
|
|
+ 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_silentjpeg += 12 * sboxcnt;
|
|
+ sd->splash_sboxcount = sboxcnt;
|
|
+ }
|
|
+ }
|
|
+ sd->splash_state = splash_getb(ndata, SPLASH_OFF_STATE);
|
|
+ sd->splash_fg_color = splash_getb(ndata, SPLASH_OFF_FGCOL);
|
|
+ sd->splash_color = splash_getb(ndata, SPLASH_OFF_COL);
|
|
+ sd->splash_overpaintok = splash_getb(ndata, SPLASH_OFF_OVEROK);
|
|
+ sd->splash_text_xo = splash_gets(ndata, SPLASH_OFF_XO);
|
|
+ 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_percent = oldpercent == -1 ? splash_gets(ndata, SPLASH_OFF_PERCENT) : oldpercent;
|
|
+ if (version == 1) {
|
|
+ sd->splash_text_xo *= 8;
|
|
+ sd->splash_text_wi *= 8;
|
|
+ sd->splash_text_yo *= 16;
|
|
+ sd->splash_text_he *= 16;
|
|
+ sd->splash_color = (splash_default >> 8) & 0x0f;
|
|
+ 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);
|
|
+ else if (version == 2)
|
|
+ boxcnt = splash_mkpenguin(sd, splash_gets(ndata, 24), splash_gets(ndata, 26), splash_gets(ndata, 28), splash_gets(ndata, 30), splash_getb(ndata, 32), splash_getb(ndata, 33), splash_getb(ndata, 34));
|
|
+
|
|
+ memcpy((char *)sd + sizeof(*sd) + (version < 3 ? boxcnt * 12 : 0), ndata + len, splash_size);
|
|
+ sd->splash_boxcount = boxcnt;
|
|
+ sd->splash_boxes = (unsigned char *)sd + sizeof(*sd);
|
|
+ sd->splash_palette = sd->splash_boxes + boxcnt * 12;
|
|
+ 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;
|
|
+ }
|
|
+ printk(KERN_ERR "bootsplash: ...no good signature found.\n");
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+int splash_verbose(void)
|
|
+{
|
|
+ struct vc_data *vc;
|
|
+ struct fb_info *info;
|
|
+
|
|
+ if (!splash_usesilent)
|
|
+ return 0;
|
|
+
|
|
+ vc = vc_cons[0].d;
|
|
+
|
|
+ if (!vc || !vc->vc_splash_data || !vc->vc_splash_data->splash_state)
|
|
+ return 0;
|
|
+ if (fg_console != vc->vc_num)
|
|
+ return 0;
|
|
+ if (!vc->vc_splash_data->splash_silentjpeg || !vc->vc_splash_data->splash_dosilent)
|
|
+ return 0;
|
|
+ vc->vc_splash_data->splash_dosilent = 0;
|
|
+ info = registered_fb[(int)con2fb_map[0]];
|
|
+ if (!info->silent_screen_base)
|
|
+ return 0;
|
|
+ splashcopy(info->silent_screen_base, info->screen_base, info->var.yres, info->var.xres, info->fix.line_length, info->fix.line_length);
|
|
+ info->screen_base = info->silent_screen_base;
|
|
+ info->silent_screen_base = 0;
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+static void splash_off(struct fb_info *info)
|
|
+{
|
|
+ if (info->silent_screen_base)
|
|
+ info->screen_base = info->silent_screen_base;
|
|
+ info->silent_screen_base = 0;
|
|
+ info->splash_data = 0;
|
|
+ if (info->splash_pic)
|
|
+ vfree(info->splash_pic);
|
|
+ info->splash_pic = 0;
|
|
+ info->splash_pic_size = 0;
|
|
+}
|
|
+
|
|
+int splash_prepare(struct vc_data *vc, struct fb_info *info)
|
|
+{
|
|
+ int err;
|
|
+ int width, height, depth, size, sbytes;
|
|
+
|
|
+ if (!vc->vc_splash_data || !vc->vc_splash_data->splash_state) {
|
|
+ if (decdata)
|
|
+ vfree(decdata);
|
|
+ decdata = 0;
|
|
+ splash_off(info);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ width = info->var.xres;
|
|
+ height = info->var.yres;
|
|
+ depth = info->var.bits_per_pixel;
|
|
+ if (depth != 16) { /* Other targets might need fixing */
|
|
+ splash_off(info);
|
|
+ return -2;
|
|
+ }
|
|
+
|
|
+ sbytes = ((width + 15) & ~15) * (depth >> 3);
|
|
+ size = sbytes * ((height + 15) & ~15);
|
|
+ if (size != info->splash_pic_size)
|
|
+ splash_off(info);
|
|
+ if (!info->splash_pic)
|
|
+ info->splash_pic = vmalloc(size);
|
|
+
|
|
+ if (!info->splash_pic) {
|
|
+ printk(KERN_INFO "bootsplash: not enough memory.\n");
|
|
+ splash_off(info);
|
|
+ return -3;
|
|
+ }
|
|
+
|
|
+ if (!decdata)
|
|
+ decdata = vmalloc(sizeof(*decdata));
|
|
+
|
|
+ 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))) {
|
|
+ printk(KERN_INFO "bootsplash: error while decompressing silent picture: %s (%d)\n", jpg_errors[err - 1], err);
|
|
+ if (info->silent_screen_base)
|
|
+ info->screen_base = info->silent_screen_base;
|
|
+ vc->vc_splash_data->splash_dosilent = 0;
|
|
+ } else {
|
|
+ if (vc->vc_splash_data->splash_sboxcount)
|
|
+ boxit(info->splash_pic, sbytes, vc->vc_splash_data->splash_sboxes,
|
|
+ vc->vc_splash_data->splash_sboxcount, vc->vc_splash_data->splash_percent, 0);
|
|
+
|
|
+ if (!info->silent_screen_base)
|
|
+ info->silent_screen_base = info->screen_base;
|
|
+ splashcopy(info->silent_screen_base, info->splash_pic, info->var.yres, info->var.xres, info->fix.line_length, sbytes);
|
|
+ info->screen_base = info->silent_screen_base + info->fix.line_length * info->var.yres;
|
|
+ }
|
|
+ } else if (info->silent_screen_base)
|
|
+ info->screen_base = info->silent_screen_base;
|
|
+
|
|
+ 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;
|
|
+ }
|
|
+ info->splash_pic_size = size;
|
|
+ info->splash_bytes = sbytes;
|
|
+ if (vc->vc_splash_data->splash_boxcount)
|
|
+ boxit(info->splash_pic, sbytes, vc->vc_splash_data->splash_boxes, vc->vc_splash_data->splash_boxcount, vc->vc_splash_data->splash_percent, 0);
|
|
+ if (vc->vc_splash_data->splash_state)
|
|
+ info->splash_data = vc->vc_splash_data;
|
|
+ else
|
|
+ splash_off(info);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+#ifdef CONFIG_PROC_FS
|
|
+
|
|
+#include <linux/proc_fs.h>
|
|
+
|
|
+static int splash_read_proc(char *buffer, char **start, off_t offset, int size,
|
|
+ int *eof, void *data);
|
|
+static int splash_write_proc(struct file *file, const char *buffer,
|
|
+ unsigned long count, void *data);
|
|
+static int splash_status(struct vc_data *vc);
|
|
+static int splash_recolor(struct vc_data *vc);
|
|
+static int splash_proc_register(void);
|
|
+
|
|
+static struct proc_dir_entry *proc_splash;
|
|
+
|
|
+static int splash_recolor(struct vc_data *vc)
|
|
+{
|
|
+ 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);
|
|
+ if (fg_console == vc->vc_num) {
|
|
+ update_region(vc,
|
|
+ vc->vc_origin + vc->vc_size_row * vc->vc_top,
|
|
+ vc->vc_size_row * (vc->vc_bottom - vc->vc_top) / 2);
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int splash_status(struct vc_data *vc)
|
|
+{
|
|
+ struct fb_info *info;
|
|
+ printk(KERN_INFO "bootsplash: status on console %d changed to %s\n", vc->vc_num, vc->vc_splash_data && vc->vc_splash_data->splash_state ? "on" : "off");
|
|
+
|
|
+ info = registered_fb[(int) con2fb_map[vc->vc_num]];
|
|
+ if (fg_console == vc->vc_num)
|
|
+ splash_prepare(vc, info);
|
|
+ if (vc->vc_splash_data && vc->vc_splash_data->splash_state) {
|
|
+ con_remap_def_color(vc, vc->vc_splash_data->splash_color << 4 | vc->vc_splash_data->splash_fg_color);
|
|
+ /* vc_resize also calls con_switch which resets yscroll */
|
|
+ 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);
|
|
+ if (fg_console == vc->vc_num) {
|
|
+ update_region(vc,
|
|
+ vc->vc_origin + vc->vc_size_row * vc->vc_top,
|
|
+ vc->vc_size_row * (vc->vc_bottom - vc->vc_top) / 2);
|
|
+ splash_clear_margins(vc->vc_splash_data, 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);
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int splash_read_proc(char *buffer, char **start, off_t offset, int size,
|
|
+ int *eof, void *data)
|
|
+{
|
|
+ int len = 0;
|
|
+ off_t begin = 0;
|
|
+ struct vc_data *vc = vc_cons[0].d;
|
|
+ struct fb_info *info = registered_fb[(int)con2fb_map[0]];
|
|
+ int color = vc->vc_splash_data ? vc->vc_splash_data->splash_color << 4 |
|
|
+ vc->vc_splash_data->splash_fg_color : splash_default >> 4;
|
|
+ int status = vc->vc_splash_data ? vc->vc_splash_data->splash_state & 1 : 0;
|
|
+ len += sprintf(buffer + len, "Splash screen v%s (0x%02x, %dx%d%s): %s\n",
|
|
+ SPLASH_VERSION, color, info->var.xres, info->var.yres,
|
|
+ (vc->vc_splash_data ? vc->vc_splash_data->splash_dosilent : 0)? ", silent" : "",
|
|
+ status ? "on" : "off");
|
|
+ if (offset >= begin + len)
|
|
+ return 0;
|
|
+
|
|
+ *start = buffer + (begin - offset);
|
|
+
|
|
+ return (size < begin + len - offset ? size : begin + len - offset);
|
|
+}
|
|
+
|
|
+void splash_set_percent(struct vc_data *vc, int pe)
|
|
+{
|
|
+ struct fb_info *info;
|
|
+ struct fbcon_ops *ops;
|
|
+ int oldpe;
|
|
+
|
|
+ if (pe < 0)
|
|
+ pe = 0;
|
|
+ if (pe > 65535)
|
|
+ pe = 65535;
|
|
+ pe += pe > 32767;;
|
|
+
|
|
+ if (!vc->vc_splash_data || vc->vc_splash_data->splash_percent == pe)
|
|
+ return;
|
|
+
|
|
+ oldpe = vc->vc_splash_data->splash_percent;
|
|
+ vc->vc_splash_data->splash_percent = pe;
|
|
+ if (fg_console != vc->vc_num || !vc->vc_splash_data->splash_state) {
|
|
+ return;
|
|
+ }
|
|
+ info = registered_fb[(int) con2fb_map[vc->vc_num]];
|
|
+ ops = info->fbcon_par;
|
|
+ if (ops->blank_state)
|
|
+ return;
|
|
+ if (!vc->vc_splash_data->splash_overpaintok || pe == 65536 || 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);
|
|
+ } else {
|
|
+ if (vc->vc_splash_data->splash_silentjpeg && vc->vc_splash_data->splash_dosilent && info->silent_screen_base)
|
|
+ boxit(info->silent_screen_base, info->fix.line_length, vc->vc_splash_data->splash_sboxes, vc->vc_splash_data->splash_sboxcount, vc->vc_splash_data->splash_percent, 1);
|
|
+ boxit(info->screen_base, info->fix.line_length, vc->vc_splash_data->splash_boxes, vc->vc_splash_data->splash_boxcount, vc->vc_splash_data->splash_percent, 1);
|
|
+ }
|
|
+}
|
|
+
|
|
+static int splash_write_proc(struct file *file, const char *buffer,
|
|
+ unsigned long count, void *data)
|
|
+{
|
|
+ int new, unit;
|
|
+ struct vc_data *vc;
|
|
+
|
|
+ if (!buffer || !splash_default)
|
|
+ return count;
|
|
+
|
|
+ console_lock();
|
|
+ unit = 0;
|
|
+ if (buffer[0] == '@' && buffer[1] >= '0' && buffer[1] <= '9') {
|
|
+ unit = buffer[1] - '0';
|
|
+ buffer += 2;
|
|
+ if (*buffer >= '0' && *buffer <= '9') {
|
|
+ unit = unit * 10 + *buffer - '0';
|
|
+ buffer++;
|
|
+ }
|
|
+ if (*buffer == ' ')
|
|
+ buffer++;
|
|
+ if (unit >= MAX_NR_CONSOLES || !vc_cons[unit].d) {
|
|
+ console_unlock();
|
|
+ return count;
|
|
+ }
|
|
+ }
|
|
+ vc = vc_cons[unit].d;
|
|
+ if (!strncmp(buffer, "redraw", 6)) {
|
|
+ splash_status(vc);
|
|
+ console_unlock();
|
|
+ return count;
|
|
+ }
|
|
+ if (!strncmp(buffer, "show", 4) || !strncmp(buffer, "hide", 4)) {
|
|
+ int pe;
|
|
+
|
|
+ if (buffer[4] == ' ' && buffer[5] == 'p')
|
|
+ pe = 0;
|
|
+ else if (buffer[4] == '\n')
|
|
+ pe = 65535;
|
|
+ else
|
|
+ pe = simple_strtoul(buffer + 5, NULL, 0);
|
|
+ if (pe < 0)
|
|
+ pe = 0;
|
|
+ if (pe > 65535)
|
|
+ pe = 65535;
|
|
+ if (*buffer == 'h')
|
|
+ pe = 65535 - pe;
|
|
+ splash_set_percent(vc, pe);
|
|
+ console_unlock();
|
|
+ return count;
|
|
+ }
|
|
+ if (!strncmp(buffer,"silent\n",7) || !strncmp(buffer,"verbose\n",8)) {
|
|
+ if (vc->vc_splash_data && vc->vc_splash_data->splash_silentjpeg) {
|
|
+ if (vc->vc_splash_data->splash_dosilent != (buffer[0] == 's')) {
|
|
+ vc->vc_splash_data->splash_dosilent = buffer[0] == 's';
|
|
+ splash_status(vc);
|
|
+ }
|
|
+ }
|
|
+ console_unlock();
|
|
+ return count;
|
|
+ }
|
|
+ if (!strncmp(buffer,"freesilent\n",11)) {
|
|
+ if (vc->vc_splash_data && vc->vc_splash_data->splash_silentjpeg) {
|
|
+ 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;
|
|
+ if (vc->vc_splash_data->splash_dosilent)
|
|
+ splash_status(vc);
|
|
+ vc->vc_splash_data->splash_dosilent = 0;
|
|
+ }
|
|
+ console_unlock();
|
|
+ return count;
|
|
+ }
|
|
+
|
|
+ if (!strncmp(buffer, "BOOTSPL", 7)) {
|
|
+ int up = -1;
|
|
+ unit = splash_getraw((unsigned char *)buffer, (unsigned char *)buffer + count, &up);
|
|
+ if (unit >= 0) {
|
|
+ vc = vc_cons[unit].d;
|
|
+ if (up == -1)
|
|
+ splash_status(vc);
|
|
+ else {
|
|
+ struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]];
|
|
+ struct fbcon_ops *ops = info->fbcon_par;
|
|
+ if (ops->blank_state)
|
|
+ up = 0;
|
|
+ if ((up & 2) != 0 && vc->vc_splash_data->splash_silentjpeg && vc->vc_splash_data->splash_dosilent && info->silent_screen_base)
|
|
+ boxit(info->silent_screen_base, info->fix.line_length, vc->vc_splash_data->splash_sboxes, vc->vc_splash_data->splash_sboxcount, vc->vc_splash_data->splash_percent, 1);
|
|
+ if ((up & 1) != 0)
|
|
+ boxit(info->screen_base, info->fix.line_length, vc->vc_splash_data->splash_boxes, vc->vc_splash_data->splash_boxcount, vc->vc_splash_data->splash_percent, 1);
|
|
+ }
|
|
+ }
|
|
+ console_unlock();
|
|
+ return count;
|
|
+ }
|
|
+ if (!vc->vc_splash_data) {
|
|
+ console_unlock();
|
|
+ return count;
|
|
+ }
|
|
+ if (buffer[0] == 't') {
|
|
+ vc->vc_splash_data->splash_state ^= 1;
|
|
+ splash_status(vc);
|
|
+ console_unlock();
|
|
+ return count;
|
|
+ }
|
|
+ new = simple_strtoul(buffer, NULL, 0);
|
|
+ if (new > 1) {
|
|
+ /* expert user */
|
|
+ vc->vc_splash_data->splash_color = new >> 8 & 0xff;
|
|
+ vc->vc_splash_data->splash_fg_color = new >> 4 & 0x0f;
|
|
+ }
|
|
+ if ((new & 1) == vc->vc_splash_data->splash_state)
|
|
+ splash_recolor(vc);
|
|
+ else {
|
|
+ vc->vc_splash_data->splash_state = new & 1;
|
|
+ splash_status(vc);
|
|
+ }
|
|
+ console_unlock();
|
|
+ return count;
|
|
+}
|
|
+
|
|
+static int splash_proc_register(void)
|
|
+{
|
|
+ if ((proc_splash = create_proc_entry("splash", 0, 0))) {
|
|
+ proc_splash->read_proc = splash_read_proc;
|
|
+ proc_splash->write_proc = splash_write_proc;
|
|
+ return 0;
|
|
+ }
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+# if 0
|
|
+static int splash_proc_unregister(void)
|
|
+{
|
|
+ if (proc_splash)
|
|
+ remove_proc_entry("splash", 0);
|
|
+ return 0;
|
|
+}
|
|
+# endif
|
|
+#endif /* CONFIG_PROC_FS */
|
|
+
|
|
+void splash_init(void)
|
|
+{
|
|
+ struct fb_info *info;
|
|
+ struct vc_data *vc;
|
|
+ int isramfs = 1;
|
|
+ int fd;
|
|
+ int len;
|
|
+ int max_len = 1024*1024*2;
|
|
+ char *mem;
|
|
+
|
|
+ if (splash_registered)
|
|
+ return;
|
|
+ vc = vc_cons[0].d;
|
|
+ info = registered_fb[0];
|
|
+ if (!vc || !info || info->var.bits_per_pixel != 16)
|
|
+ return;
|
|
+#ifdef CONFIG_PROC_FS
|
|
+ splash_proc_register();
|
|
+#endif
|
|
+ splash_registered = 1;
|
|
+ if (vc->vc_splash_data)
|
|
+ return;
|
|
+ if ((fd = sys_open("/bootsplash", O_RDONLY, 0)) < 0) {
|
|
+ isramfs = 0;
|
|
+ fd = sys_open("/initrd.image", O_RDONLY, 0);
|
|
+ }
|
|
+ if (fd < 0)
|
|
+ return;
|
|
+ if ((len = (int)sys_lseek(fd, (off_t)0, 2)) <= 0) {
|
|
+ sys_close(fd);
|
|
+ return;
|
|
+ }
|
|
+ /* Don't look for more than the last 2MB */
|
|
+ if (len > max_len) {
|
|
+ printk( KERN_INFO "bootsplash: scanning last %dMB of initrd for signature\n",
|
|
+ max_len>>20);
|
|
+ sys_lseek(fd, (off_t)(len - max_len), 0);
|
|
+ len = max_len;
|
|
+ } else {
|
|
+ sys_lseek(fd, (off_t)0, 0);
|
|
+ }
|
|
+
|
|
+ mem = vmalloc(len);
|
|
+ if (mem) {
|
|
+ console_lock();
|
|
+ if ((int)sys_read(fd, mem, len) == len && splash_getraw((unsigned char *)mem, (unsigned char *)mem + len, (int *)0) == 0 && vc->vc_splash_data)
|
|
+ vc->vc_splash_data->splash_state = splash_default & 1;
|
|
+ console_unlock();
|
|
+ vfree(mem);
|
|
+ }
|
|
+ sys_close(fd);
|
|
+ if (isramfs)
|
|
+ sys_unlink("/bootsplash");
|
|
+ return;
|
|
+}
|
|
+
|
|
--- /dev/null
|
|
+++ b/drivers/video/bootsplash/bootsplash.h
|
|
@@ -0,0 +1,41 @@
|
|
+/*
|
|
+ * linux/drivers/video/bootsplash/bootsplash.h - splash screen definition.
|
|
+ *
|
|
+ * (w) 2001-2003 by Volker Poplawski, <volker@poplawski.de>
|
|
+ * Stefan Reinauer, <stepan@suse.de>
|
|
+ *
|
|
+ *
|
|
+ * idea and SuSE screen work by Ken Wimer, <wimer@suse.de>
|
|
+ */
|
|
+
|
|
+#ifndef __BOOTSPLASH_H
|
|
+#define __BOOTSPLASH_H
|
|
+
|
|
+struct fb_info;
|
|
+
|
|
+/* splash.c */
|
|
+extern int splash_prepare(struct vc_data *, struct fb_info *);
|
|
+extern void splash_init(void);
|
|
+
|
|
+/* splash_render.c */
|
|
+extern void splash_putcs(struct splash_data *sd, struct vc_data *vc, struct fb_info *info,
|
|
+ const unsigned short *s, int count, int ypos, int xpos);
|
|
+extern void splash_putc(struct splash_data *sd, struct vc_data *vc, struct fb_info *info,
|
|
+ int c, int ypos, int xpos);
|
|
+extern void splashcopy(u8 *dst, u8 *src, int height, int width, int dstbytes, int srcbytes);
|
|
+extern void splash_clear(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, int sy,
|
|
+ int sx, int height, int width);
|
|
+extern void splash_bmove(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, int sy,
|
|
+ int sx, int dy, int dx, int height, int width);
|
|
+extern void splash_clear_margins(struct splash_data *sd, struct vc_data *vc, struct fb_info *info,
|
|
+ int bottom_only);
|
|
+extern int splash_cursor(struct splash_data *sd, struct fb_info *info, struct fb_cursor *cursor);
|
|
+extern void splash_bmove_redraw(struct splash_data *sd, struct vc_data *vc, struct fb_info *info,
|
|
+ int y, int sx, int dx, int width);
|
|
+extern void splash_blank(struct splash_data *sd, struct vc_data *vc, struct fb_info *info,
|
|
+ int blank);
|
|
+
|
|
+/* vt.c */
|
|
+extern void con_remap_def_color(struct vc_data *vc, int new_color);
|
|
+
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/drivers/video/bootsplash/decode-jpg.c
|
|
@@ -0,0 +1,957 @@
|
|
+/*
|
|
+ * linux/drivers/video/bootsplash/decode-jpg.c - a tiny jpeg decoder.
|
|
+ *
|
|
+ * (w) August 2001 by Michael Schroeder, <mls@suse.de>
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <linux/string.h>
|
|
+#include <asm/byteorder.h>
|
|
+
|
|
+#include "decode-jpg.h"
|
|
+
|
|
+#define ISHIFT 11
|
|
+
|
|
+#define IFIX(a) ((int)((a) * (1 << ISHIFT) + .5))
|
|
+#define IMULT(a, b) (((a) * (b)) >> ISHIFT)
|
|
+#define ITOINT(a) ((a) >> ISHIFT)
|
|
+
|
|
+#ifndef __P
|
|
+# define __P(x) x
|
|
+#endif
|
|
+
|
|
+/* special markers */
|
|
+#define M_BADHUFF -1
|
|
+#define M_EOF 0x80
|
|
+
|
|
+struct in {
|
|
+ unsigned char *p;
|
|
+ unsigned int bits;
|
|
+ int left;
|
|
+ int marker;
|
|
+
|
|
+ int (*func) __P((void *));
|
|
+ void *data;
|
|
+};
|
|
+
|
|
+/*********************************/
|
|
+struct dec_hufftbl;
|
|
+struct enc_hufftbl;
|
|
+
|
|
+union hufftblp {
|
|
+ struct dec_hufftbl *dhuff;
|
|
+ struct enc_hufftbl *ehuff;
|
|
+};
|
|
+
|
|
+struct scan {
|
|
+ int dc; /* old dc value */
|
|
+
|
|
+ union hufftblp hudc;
|
|
+ union hufftblp huac;
|
|
+ int next; /* when to switch to next scan */
|
|
+
|
|
+ int cid; /* component id */
|
|
+ int hv; /* horiz/vert, copied from comp */
|
|
+ int tq; /* quant tbl, copied from comp */
|
|
+};
|
|
+
|
|
+/*********************************/
|
|
+
|
|
+#define DECBITS 10 /* seems to be the optimum */
|
|
+
|
|
+struct dec_hufftbl {
|
|
+ int maxcode[17];
|
|
+ int valptr[16];
|
|
+ unsigned char vals[256];
|
|
+ unsigned int llvals[1 << DECBITS];
|
|
+};
|
|
+
|
|
+static void decode_mcus __P((struct in *, int *, int, struct scan *, int *));
|
|
+static int dec_readmarker __P((struct in *));
|
|
+static void dec_makehuff __P((struct dec_hufftbl *, int *, unsigned char *));
|
|
+
|
|
+static void setinput __P((struct in *, unsigned char *));
|
|
+/*********************************/
|
|
+
|
|
+#undef PREC
|
|
+#define PREC int
|
|
+
|
|
+static void idctqtab __P((unsigned char *, PREC *));
|
|
+static void idct __P((int *, int *, PREC *, PREC, int));
|
|
+static void scaleidctqtab __P((PREC *, PREC));
|
|
+
|
|
+/*********************************/
|
|
+
|
|
+static void initcol __P((PREC[][64]));
|
|
+
|
|
+static void col221111 __P((int *, unsigned char *, int));
|
|
+static void col221111_16 __P((int *, unsigned char *, int));
|
|
+
|
|
+/*********************************/
|
|
+
|
|
+#define M_SOI 0xd8
|
|
+#define M_APP0 0xe0
|
|
+#define M_DQT 0xdb
|
|
+#define M_SOF0 0xc0
|
|
+#define M_DHT 0xc4
|
|
+#define M_DRI 0xdd
|
|
+#define M_SOS 0xda
|
|
+#define M_RST0 0xd0
|
|
+#define M_EOI 0xd9
|
|
+#define M_COM 0xfe
|
|
+
|
|
+static unsigned char *datap;
|
|
+
|
|
+static int getbyte(void)
|
|
+{
|
|
+ return *datap++;
|
|
+}
|
|
+
|
|
+static int getword(void)
|
|
+{
|
|
+ int c1, c2;
|
|
+ c1 = *datap++;
|
|
+ c2 = *datap++;
|
|
+ return c1 << 8 | c2;
|
|
+}
|
|
+
|
|
+struct comp {
|
|
+ int cid;
|
|
+ int hv;
|
|
+ int tq;
|
|
+};
|
|
+
|
|
+#define MAXCOMP 4
|
|
+struct jpginfo {
|
|
+ int nc; /* number of components */
|
|
+ int ns; /* number of scans */
|
|
+ int dri; /* restart interval */
|
|
+ int nm; /* mcus til next marker */
|
|
+ int rm; /* next restart marker */
|
|
+};
|
|
+
|
|
+static struct jpginfo info;
|
|
+static struct comp comps[MAXCOMP];
|
|
+
|
|
+static struct scan dscans[MAXCOMP];
|
|
+
|
|
+static unsigned char quant[4][64];
|
|
+
|
|
+static struct dec_hufftbl dhuff[4];
|
|
+
|
|
+#define dec_huffdc (dhuff + 0)
|
|
+#define dec_huffac (dhuff + 2)
|
|
+
|
|
+static struct in in;
|
|
+
|
|
+static int readtables(int till)
|
|
+{
|
|
+ int m, l, i, j, lq, pq, tq;
|
|
+ int tc, th, tt;
|
|
+
|
|
+ for (;;) {
|
|
+ if (getbyte() != 0xff)
|
|
+ return -1;
|
|
+ if ((m = getbyte()) == till)
|
|
+ break;
|
|
+
|
|
+ switch (m) {
|
|
+ case 0xc2:
|
|
+ return 0;
|
|
+
|
|
+ case M_DQT:
|
|
+ lq = getword();
|
|
+ while (lq > 2) {
|
|
+ pq = getbyte();
|
|
+ tq = pq & 15;
|
|
+ if (tq > 3)
|
|
+ return -1;
|
|
+ pq >>= 4;
|
|
+ if (pq != 0)
|
|
+ return -1;
|
|
+ for (i = 0; i < 64; i++)
|
|
+ quant[tq][i] = getbyte();
|
|
+ lq -= 64 + 1;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case M_DHT:
|
|
+ l = getword();
|
|
+ while (l > 2) {
|
|
+ int hufflen[16], k;
|
|
+ unsigned char huffvals[256];
|
|
+
|
|
+ tc = getbyte();
|
|
+ th = tc & 15;
|
|
+ tc >>= 4;
|
|
+ tt = tc * 2 + th;
|
|
+ if (tc > 1 || th > 1)
|
|
+ return -1;
|
|
+ for (i = 0; i < 16; i++)
|
|
+ hufflen[i] = getbyte();
|
|
+ l -= 1 + 16;
|
|
+ k = 0;
|
|
+ for (i = 0; i < 16; i++) {
|
|
+ for (j = 0; j < hufflen[i]; j++)
|
|
+ huffvals[k++] = getbyte();
|
|
+ l -= hufflen[i];
|
|
+ }
|
|
+ dec_makehuff(dhuff + tt, hufflen,
|
|
+ huffvals);
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case M_DRI:
|
|
+ l = getword();
|
|
+ info.dri = getword();
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ l = getword();
|
|
+ while (l-- > 2)
|
|
+ getbyte();
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void dec_initscans(void)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ info.nm = info.dri + 1;
|
|
+ info.rm = M_RST0;
|
|
+ for (i = 0; i < info.ns; i++)
|
|
+ dscans[i].dc = 0;
|
|
+}
|
|
+
|
|
+static int dec_checkmarker(void)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ if (dec_readmarker(&in) != info.rm)
|
|
+ return -1;
|
|
+ info.nm = info.dri;
|
|
+ info.rm = (info.rm + 1) & ~0x08;
|
|
+ for (i = 0; i < info.ns; i++)
|
|
+ dscans[i].dc = 0;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int jpeg_check_size(unsigned char *buf, int width, int height)
|
|
+{
|
|
+ datap = buf;
|
|
+ getbyte();
|
|
+ getbyte();
|
|
+ readtables(M_SOF0);
|
|
+ getword();
|
|
+ getbyte();
|
|
+ if (height != getword() || width != getword())
|
|
+ return 0;
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+int jpeg_decode(buf, pic, width, height, depth, decdata)
|
|
+unsigned char *buf, *pic;
|
|
+int width, height, depth;
|
|
+struct jpeg_decdata *decdata;
|
|
+{
|
|
+ int i, j, m, tac, tdc;
|
|
+ int mcusx, mcusy, mx, my;
|
|
+ int max[6];
|
|
+
|
|
+ if (!decdata || !buf || !pic)
|
|
+ return -1;
|
|
+ datap = buf;
|
|
+ if (getbyte() != 0xff)
|
|
+ return ERR_NO_SOI;
|
|
+ if (getbyte() != M_SOI)
|
|
+ return ERR_NO_SOI;
|
|
+ if (readtables(M_SOF0))
|
|
+ return ERR_BAD_TABLES;
|
|
+ getword();
|
|
+ i = getbyte();
|
|
+ if (i != 8)
|
|
+ return ERR_NOT_8BIT;
|
|
+ if (((getword() + 15) & ~15) != height)
|
|
+ return ERR_HEIGHT_MISMATCH;
|
|
+ if (((getword() + 15) & ~15) != width)
|
|
+ return ERR_WIDTH_MISMATCH;
|
|
+ if ((height & 15) || (width & 15))
|
|
+ return ERR_BAD_WIDTH_OR_HEIGHT;
|
|
+ info.nc = getbyte();
|
|
+ if (info.nc > MAXCOMP)
|
|
+ return ERR_TOO_MANY_COMPPS;
|
|
+ for (i = 0; i < info.nc; i++) {
|
|
+ int h, v;
|
|
+ comps[i].cid = getbyte();
|
|
+ comps[i].hv = getbyte();
|
|
+ v = comps[i].hv & 15;
|
|
+ h = comps[i].hv >> 4;
|
|
+ comps[i].tq = getbyte();
|
|
+ if (h > 3 || v > 3)
|
|
+ return ERR_ILLEGAL_HV;
|
|
+ if (comps[i].tq > 3)
|
|
+ return ERR_QUANT_TABLE_SELECTOR;
|
|
+ }
|
|
+ if (readtables(M_SOS))
|
|
+ return ERR_BAD_TABLES;
|
|
+ getword();
|
|
+ info.ns = getbyte();
|
|
+ if (info.ns != 3)
|
|
+ return ERR_NOT_YCBCR_221111;
|
|
+ for (i = 0; i < 3; i++) {
|
|
+ dscans[i].cid = getbyte();
|
|
+ tdc = getbyte();
|
|
+ tac = tdc & 15;
|
|
+ tdc >>= 4;
|
|
+ if (tdc > 1 || tac > 1)
|
|
+ return ERR_QUANT_TABLE_SELECTOR;
|
|
+ for (j = 0; j < info.nc; j++)
|
|
+ if (comps[j].cid == dscans[i].cid)
|
|
+ break;
|
|
+ if (j == info.nc)
|
|
+ return ERR_UNKNOWN_CID_IN_SCAN;
|
|
+ dscans[i].hv = comps[j].hv;
|
|
+ dscans[i].tq = comps[j].tq;
|
|
+ dscans[i].hudc.dhuff = dec_huffdc + tdc;
|
|
+ dscans[i].huac.dhuff = dec_huffac + tac;
|
|
+ }
|
|
+
|
|
+ i = getbyte();
|
|
+ j = getbyte();
|
|
+ m = getbyte();
|
|
+
|
|
+ if (i != 0 || j != 63 || m != 0)
|
|
+ return ERR_NOT_SEQUENTIAL_DCT;
|
|
+
|
|
+ if (dscans[0].cid != 1 || dscans[1].cid != 2 || dscans[2].cid != 3)
|
|
+ return ERR_NOT_YCBCR_221111;
|
|
+
|
|
+ if (dscans[0].hv != 0x22 || dscans[1].hv != 0x11 || dscans[2].hv != 0x11)
|
|
+ return ERR_NOT_YCBCR_221111;
|
|
+
|
|
+ mcusx = width >> 4;
|
|
+ mcusy = height >> 4;
|
|
+
|
|
+
|
|
+ idctqtab(quant[dscans[0].tq], decdata->dquant[0]);
|
|
+ idctqtab(quant[dscans[1].tq], decdata->dquant[1]);
|
|
+ idctqtab(quant[dscans[2].tq], decdata->dquant[2]);
|
|
+ initcol(decdata->dquant);
|
|
+ setinput(&in, datap);
|
|
+
|
|
+#if 0
|
|
+ /* landing zone */
|
|
+ img[len] = 0;
|
|
+ img[len + 1] = 0xff;
|
|
+ img[len + 2] = M_EOF;
|
|
+#endif
|
|
+
|
|
+ dec_initscans();
|
|
+
|
|
+ dscans[0].next = 6 - 4;
|
|
+ dscans[1].next = 6 - 4 - 1;
|
|
+ dscans[2].next = 6 - 4 - 1 - 1; /* 411 encoding */
|
|
+ for (my = 0; my < mcusy; my++) {
|
|
+ for (mx = 0; mx < mcusx; mx++) {
|
|
+ if (info.dri && !--info.nm)
|
|
+ if (dec_checkmarker())
|
|
+ return ERR_WRONG_MARKER;
|
|
+
|
|
+ decode_mcus(&in, decdata->dcts, 6, dscans, max);
|
|
+ idct(decdata->dcts, decdata->out, decdata->dquant[0], IFIX(128.5), max[0]);
|
|
+ idct(decdata->dcts + 64, decdata->out + 64, decdata->dquant[0], IFIX(128.5), max[1]);
|
|
+ idct(decdata->dcts + 128, decdata->out + 128, decdata->dquant[0], IFIX(128.5), max[2]);
|
|
+ idct(decdata->dcts + 192, decdata->out + 192, decdata->dquant[0], IFIX(128.5), max[3]);
|
|
+ idct(decdata->dcts + 256, decdata->out + 256, decdata->dquant[1], IFIX(0.5), max[4]);
|
|
+ idct(decdata->dcts + 320, decdata->out + 320, decdata->dquant[2], IFIX(0.5), max[5]);
|
|
+
|
|
+ switch (depth) {
|
|
+ case 24:
|
|
+ col221111(decdata->out, pic + (my * 16 * mcusx + mx) * 16 * 3, mcusx * 16 * 3);
|
|
+ break;
|
|
+ case 16:
|
|
+ col221111_16(decdata->out, pic + (my * 16 * mcusx + mx) * (16 * 2), mcusx * (16 * 2));
|
|
+ break;
|
|
+ default:
|
|
+ return ERR_DEPTH_MISMATCH;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ m = dec_readmarker(&in);
|
|
+ if (m != M_EOI)
|
|
+ return ERR_NO_EOI;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/****************************************************************/
|
|
+/************** huffman decoder ***************/
|
|
+/****************************************************************/
|
|
+
|
|
+static int fillbits __P((struct in *, int, unsigned int));
|
|
+static int dec_rec2
|
|
+__P((struct in *, struct dec_hufftbl *, int *, int, int));
|
|
+
|
|
+static void setinput(in, p)
|
|
+struct in *in;
|
|
+unsigned char *p;
|
|
+{
|
|
+ in->p = p;
|
|
+ in->left = 0;
|
|
+ in->bits = 0;
|
|
+ in->marker = 0;
|
|
+}
|
|
+
|
|
+static int fillbits(in, le, bi)
|
|
+struct in *in;
|
|
+int le;
|
|
+unsigned int bi;
|
|
+{
|
|
+ int b, m;
|
|
+
|
|
+ if (in->marker) {
|
|
+ if (le <= 16)
|
|
+ in->bits = bi << 16, le += 16;
|
|
+ return le;
|
|
+ }
|
|
+ while (le <= 24) {
|
|
+ b = *in->p++;
|
|
+ if (b == 0xff && (m = *in->p++) != 0) {
|
|
+ if (m == M_EOF) {
|
|
+ if (in->func && (m = in->func(in->data)) == 0)
|
|
+ continue;
|
|
+ }
|
|
+ in->marker = m;
|
|
+ if (le <= 16)
|
|
+ bi = bi << 16, le += 16;
|
|
+ break;
|
|
+ }
|
|
+ bi = bi << 8 | b;
|
|
+ le += 8;
|
|
+ }
|
|
+ in->bits = bi; /* tmp... 2 return values needed */
|
|
+ return le;
|
|
+}
|
|
+
|
|
+static int dec_readmarker(in)
|
|
+struct in *in;
|
|
+{
|
|
+ int m;
|
|
+
|
|
+ in->left = fillbits(in, in->left, in->bits);
|
|
+ if ((m = in->marker) == 0)
|
|
+ return 0;
|
|
+ in->left = 0;
|
|
+ in->marker = 0;
|
|
+ return m;
|
|
+}
|
|
+
|
|
+#define LEBI_DCL int le, bi
|
|
+#define LEBI_GET(in) (le = in->left, bi = in->bits)
|
|
+#define LEBI_PUT(in) (in->left = le, in->bits = bi)
|
|
+
|
|
+#define GETBITS(in, n) ( \
|
|
+ (le < (n) ? le = fillbits(in, le, bi), bi = in->bits : 0), \
|
|
+ (le -= (n)), \
|
|
+ bi >> le & ((1 << (n)) - 1) \
|
|
+)
|
|
+
|
|
+#define UNGETBITS(in, n) ( \
|
|
+ le += (n) \
|
|
+)
|
|
+
|
|
+
|
|
+static int dec_rec2(in, hu, runp, c, i)
|
|
+struct in *in;
|
|
+struct dec_hufftbl *hu;
|
|
+int *runp;
|
|
+int c, i;
|
|
+{
|
|
+ LEBI_DCL;
|
|
+
|
|
+ LEBI_GET(in);
|
|
+ if (i) {
|
|
+ UNGETBITS(in, i & 127);
|
|
+ *runp = i >> 8 & 15;
|
|
+ i >>= 16;
|
|
+ } else {
|
|
+ for (i = DECBITS; (c = ((c << 1) | GETBITS(in, 1))) >= (hu->maxcode[i]); i++);
|
|
+ if (i >= 16) {
|
|
+ in->marker = M_BADHUFF;
|
|
+ return 0;
|
|
+ }
|
|
+ i = hu->vals[hu->valptr[i] + c - hu->maxcode[i - 1] * 2];
|
|
+ *runp = i >> 4;
|
|
+ i &= 15;
|
|
+ }
|
|
+ if (i == 0) { /* sigh, 0xf0 is 11 bit */
|
|
+ LEBI_PUT(in);
|
|
+ return 0;
|
|
+ }
|
|
+ /* receive part */
|
|
+ c = GETBITS(in, i);
|
|
+ if (c < (1 << (i - 1)))
|
|
+ c += (-1 << i) + 1;
|
|
+ LEBI_PUT(in);
|
|
+ return c;
|
|
+}
|
|
+
|
|
+#define DEC_REC(in, hu, r, i) ( \
|
|
+ r = GETBITS(in, DECBITS), \
|
|
+ i = hu->llvals[r], \
|
|
+ i & 128 ? \
|
|
+ ( \
|
|
+ UNGETBITS(in, i & 127), \
|
|
+ r = i >> 8 & 15, \
|
|
+ i >> 16 \
|
|
+ ) \
|
|
+ : \
|
|
+ ( \
|
|
+ LEBI_PUT(in), \
|
|
+ i = dec_rec2(in, hu, &r, r, i), \
|
|
+ LEBI_GET(in), \
|
|
+ i \
|
|
+ ) \
|
|
+)
|
|
+
|
|
+static void decode_mcus(in, dct, n, sc, maxp)
|
|
+struct in *in;
|
|
+int *dct;
|
|
+int n;
|
|
+struct scan *sc;
|
|
+int *maxp;
|
|
+{
|
|
+ struct dec_hufftbl *hu;
|
|
+ int i, r, t;
|
|
+ LEBI_DCL;
|
|
+
|
|
+ memset(dct, 0, n * 64 * sizeof(*dct));
|
|
+ LEBI_GET(in);
|
|
+ while (n-- > 0) {
|
|
+ hu = sc->hudc.dhuff;
|
|
+ *dct++ = (sc->dc += DEC_REC(in, hu, r, t));
|
|
+
|
|
+ hu = sc->huac.dhuff;
|
|
+ i = 63;
|
|
+ while (i > 0) {
|
|
+ t = DEC_REC(in, hu, r, t);
|
|
+ if (t == 0 && r == 0) {
|
|
+ dct += i;
|
|
+ break;
|
|
+ }
|
|
+ dct += r;
|
|
+ *dct++ = t;
|
|
+ i -= r + 1;
|
|
+ }
|
|
+ *maxp++ = 64 - i;
|
|
+ if (n == sc->next)
|
|
+ sc++;
|
|
+ }
|
|
+ LEBI_PUT(in);
|
|
+}
|
|
+
|
|
+static void dec_makehuff(hu, hufflen, huffvals)
|
|
+struct dec_hufftbl *hu;
|
|
+int *hufflen;
|
|
+unsigned char *huffvals;
|
|
+{
|
|
+ int code, k, i, j, d, x, c, v;
|
|
+ for (i = 0; i < (1 << DECBITS); i++)
|
|
+ hu->llvals[i] = 0;
|
|
+
|
|
+/*
|
|
+ * llvals layout:
|
|
+ *
|
|
+ * value v already known, run r, backup u bits:
|
|
+ * vvvvvvvvvvvvvvvv 0000 rrrr 1 uuuuuuu
|
|
+ * value unknown, size b bits, run r, backup u bits:
|
|
+ * 000000000000bbbb 0000 rrrr 0 uuuuuuu
|
|
+ * value and size unknown:
|
|
+ * 0000000000000000 0000 0000 0 0000000
|
|
+ */
|
|
+ code = 0;
|
|
+ k = 0;
|
|
+ for (i = 0; i < 16; i++, code <<= 1) { /* sizes */
|
|
+ hu->valptr[i] = k;
|
|
+ for (j = 0; j < hufflen[i]; j++) {
|
|
+ hu->vals[k] = *huffvals++;
|
|
+ if (i < DECBITS) {
|
|
+ c = code << (DECBITS - 1 - i);
|
|
+ v = hu->vals[k] & 0x0f; /* size */
|
|
+ for (d = 1 << (DECBITS - 1 - i); --d >= 0;) {
|
|
+ if (v + i < DECBITS) { /* both fit in table */
|
|
+ x = d >> (DECBITS - 1 - v -
|
|
+ i);
|
|
+ if (v && x < (1 << (v - 1)))
|
|
+ x += (-1 << v) + 1;
|
|
+ x = x << 16 | (hu-> vals[k] & 0xf0) << 4 |
|
|
+ (DECBITS - (i + 1 + v)) | 128;
|
|
+ } else
|
|
+ x = v << 16 | (hu-> vals[k] & 0xf0) << 4 |
|
|
+ (DECBITS - (i + 1));
|
|
+ hu->llvals[c | d] = x;
|
|
+ }
|
|
+ }
|
|
+ code++;
|
|
+ k++;
|
|
+ }
|
|
+ hu->maxcode[i] = code;
|
|
+ }
|
|
+ hu->maxcode[16] = 0x20000; /* always terminate decode */
|
|
+}
|
|
+
|
|
+/****************************************************************/
|
|
+/************** idct ***************/
|
|
+/****************************************************************/
|
|
+
|
|
+#define ONE ((PREC)IFIX(1.))
|
|
+#define S2 ((PREC)IFIX(0.382683432))
|
|
+#define C2 ((PREC)IFIX(0.923879532))
|
|
+#define C4 ((PREC)IFIX(0.707106781))
|
|
+
|
|
+#define S22 ((PREC)IFIX(2 * 0.382683432))
|
|
+#define C22 ((PREC)IFIX(2 * 0.923879532))
|
|
+#define IC4 ((PREC)IFIX(1 / 0.707106781))
|
|
+
|
|
+#define C3IC1 ((PREC)IFIX(0.847759065)) /* c3/c1 */
|
|
+#define C5IC1 ((PREC)IFIX(0.566454497)) /* c5/c1 */
|
|
+#define C7IC1 ((PREC)IFIX(0.198912367)) /* c7/c1 */
|
|
+
|
|
+#define XPP(a,b) (t = a + b, b = a - b, a = t)
|
|
+#define XMP(a,b) (t = a - b, b = a + b, a = t)
|
|
+#define XPM(a,b) (t = a + b, b = b - a, a = t)
|
|
+
|
|
+#define ROT(a,b,s,c) ( t = IMULT(a + b, s), \
|
|
+ a = IMULT(a, c - s) + t, \
|
|
+ b = IMULT(b, c + s) - t)
|
|
+
|
|
+#define IDCT \
|
|
+( \
|
|
+ XPP(t0, t1), \
|
|
+ XMP(t2, t3), \
|
|
+ t2 = IMULT(t2, IC4) - t3, \
|
|
+ XPP(t0, t3), \
|
|
+ XPP(t1, t2), \
|
|
+ XMP(t4, t7), \
|
|
+ XPP(t5, t6), \
|
|
+ XMP(t5, t7), \
|
|
+ t5 = IMULT(t5, IC4), \
|
|
+ ROT(t4, t6, S22, C22),\
|
|
+ t6 -= t7, \
|
|
+ t5 -= t6, \
|
|
+ t4 -= t5, \
|
|
+ XPP(t0, t7), \
|
|
+ XPP(t1, t6), \
|
|
+ XPP(t2, t5), \
|
|
+ XPP(t3, t4) \
|
|
+)
|
|
+
|
|
+static unsigned char zig2[64] = {
|
|
+ 0, 2, 3, 9, 10, 20, 21, 35,
|
|
+ 14, 16, 25, 31, 39, 46, 50, 57,
|
|
+ 5, 7, 12, 18, 23, 33, 37, 48,
|
|
+ 27, 29, 41, 44, 52, 55, 59, 62,
|
|
+ 15, 26, 30, 40, 45, 51, 56, 58,
|
|
+ 1, 4, 8, 11, 19, 22, 34, 36,
|
|
+ 28, 42, 43, 53, 54, 60, 61, 63,
|
|
+ 6, 13, 17, 24, 32, 38, 47, 49
|
|
+};
|
|
+
|
|
+void idct(in, out, quant, off, max)
|
|
+int *in;
|
|
+int *out;
|
|
+PREC *quant;
|
|
+PREC off;
|
|
+int max;
|
|
+{
|
|
+ PREC t0, t1, t2, t3, t4, t5, t6, t7, t;
|
|
+ PREC tmp[64], *tmpp;
|
|
+ int i, j;
|
|
+ unsigned char *zig2p;
|
|
+
|
|
+ t0 = off;
|
|
+ if (max == 1) {
|
|
+ t0 += in[0] * quant[0];
|
|
+ for (i = 0; i < 64; i++)
|
|
+ out[i] = ITOINT(t0);
|
|
+ return;
|
|
+ }
|
|
+ zig2p = zig2;
|
|
+ tmpp = tmp;
|
|
+ for (i = 0; i < 8; i++) {
|
|
+ j = *zig2p++;
|
|
+ t0 += in[j] * quant[j];
|
|
+ j = *zig2p++;
|
|
+ t5 = in[j] * quant[j];
|
|
+ j = *zig2p++;
|
|
+ t2 = in[j] * quant[j];
|
|
+ j = *zig2p++;
|
|
+ t7 = in[j] * quant[j];
|
|
+ j = *zig2p++;
|
|
+ t1 = in[j] * quant[j];
|
|
+ j = *zig2p++;
|
|
+ t4 = in[j] * quant[j];
|
|
+ j = *zig2p++;
|
|
+ t3 = in[j] * quant[j];
|
|
+ j = *zig2p++;
|
|
+ t6 = in[j] * quant[j];
|
|
+ IDCT;
|
|
+ tmpp[0 * 8] = t0;
|
|
+ tmpp[1 * 8] = t1;
|
|
+ tmpp[2 * 8] = t2;
|
|
+ tmpp[3 * 8] = t3;
|
|
+ tmpp[4 * 8] = t4;
|
|
+ tmpp[5 * 8] = t5;
|
|
+ tmpp[6 * 8] = t6;
|
|
+ tmpp[7 * 8] = t7;
|
|
+ tmpp++;
|
|
+ t0 = 0;
|
|
+ }
|
|
+ for (i = 0; i < 8; i++) {
|
|
+ t0 = tmp[8 * i + 0];
|
|
+ t1 = tmp[8 * i + 1];
|
|
+ t2 = tmp[8 * i + 2];
|
|
+ t3 = tmp[8 * i + 3];
|
|
+ t4 = tmp[8 * i + 4];
|
|
+ t5 = tmp[8 * i + 5];
|
|
+ t6 = tmp[8 * i + 6];
|
|
+ t7 = tmp[8 * i + 7];
|
|
+ IDCT;
|
|
+ out[8 * i + 0] = ITOINT(t0);
|
|
+ out[8 * i + 1] = ITOINT(t1);
|
|
+ out[8 * i + 2] = ITOINT(t2);
|
|
+ out[8 * i + 3] = ITOINT(t3);
|
|
+ out[8 * i + 4] = ITOINT(t4);
|
|
+ out[8 * i + 5] = ITOINT(t5);
|
|
+ out[8 * i + 6] = ITOINT(t6);
|
|
+ out[8 * i + 7] = ITOINT(t7);
|
|
+ }
|
|
+}
|
|
+
|
|
+static unsigned char zig[64] = {
|
|
+ 0, 1, 5, 6, 14, 15, 27, 28,
|
|
+ 2, 4, 7, 13, 16, 26, 29, 42,
|
|
+ 3, 8, 12, 17, 25, 30, 41, 43,
|
|
+ 9, 11, 18, 24, 31, 40, 44, 53,
|
|
+ 10, 19, 23, 32, 39, 45, 52, 54,
|
|
+ 20, 22, 33, 38, 46, 51, 55, 60,
|
|
+ 21, 34, 37, 47, 50, 56, 59, 61,
|
|
+ 35, 36, 48, 49, 57, 58, 62, 63
|
|
+};
|
|
+
|
|
+static PREC aaidct[8] = {
|
|
+ IFIX(0.3535533906), IFIX(0.4903926402),
|
|
+ IFIX(0.4619397663), IFIX(0.4157348062),
|
|
+ IFIX(0.3535533906), IFIX(0.2777851165),
|
|
+ IFIX(0.1913417162), IFIX(0.0975451610)
|
|
+};
|
|
+
|
|
+
|
|
+static void idctqtab(qin, qout)
|
|
+unsigned char *qin;
|
|
+PREC *qout;
|
|
+{
|
|
+ int i, j;
|
|
+
|
|
+ for (i = 0; i < 8; i++)
|
|
+ for (j = 0; j < 8; j++)
|
|
+ qout[zig[i * 8 + j]] = qin[zig[i * 8 + j]] *
|
|
+ IMULT(aaidct[i], aaidct[j]);
|
|
+}
|
|
+
|
|
+static void scaleidctqtab(q, sc)
|
|
+PREC *q;
|
|
+PREC sc;
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < 64; i++)
|
|
+ q[i] = IMULT(q[i], sc);
|
|
+}
|
|
+
|
|
+/****************************************************************/
|
|
+/************** color decoder ***************/
|
|
+/****************************************************************/
|
|
+
|
|
+#define ROUND
|
|
+
|
|
+/*
|
|
+ * YCbCr Color transformation:
|
|
+ *
|
|
+ * y:0..255 Cb:-128..127 Cr:-128..127
|
|
+ *
|
|
+ * R = Y + 1.40200 * Cr
|
|
+ * G = Y - 0.34414 * Cb - 0.71414 * Cr
|
|
+ * B = Y + 1.77200 * Cb
|
|
+ *
|
|
+ * =>
|
|
+ * Cr *= 1.40200;
|
|
+ * Cb *= 1.77200;
|
|
+ * Cg = 0.19421 * Cb + .50937 * Cr;
|
|
+ * R = Y + Cr;
|
|
+ * G = Y - Cg;
|
|
+ * B = Y + Cb;
|
|
+ *
|
|
+ * =>
|
|
+ * Cg = (50 * Cb + 130 * Cr + 128) >> 8;
|
|
+ */
|
|
+
|
|
+static void initcol(q)
|
|
+PREC q[][64];
|
|
+{
|
|
+ scaleidctqtab(q[1], IFIX(1.77200));
|
|
+ scaleidctqtab(q[2], IFIX(1.40200));
|
|
+}
|
|
+
|
|
+/* This is optimized for the stupid sun SUNWspro compiler. */
|
|
+#define STORECLAMP(a,x) \
|
|
+( \
|
|
+ (a) = (x), \
|
|
+ (unsigned int)(x) >= 256 ? \
|
|
+ ((a) = (x) < 0 ? 0 : 255) \
|
|
+ : \
|
|
+ 0 \
|
|
+)
|
|
+
|
|
+#define CLAMP(x) ((unsigned int)(x) >= 256 ? ((x) < 0 ? 0 : 255) : (x))
|
|
+
|
|
+#ifdef ROUND
|
|
+
|
|
+#define CBCRCG(yin, xin) \
|
|
+( \
|
|
+ cb = outc[0 +yin*8+xin], \
|
|
+ cr = outc[64+yin*8+xin], \
|
|
+ cg = (50 * cb + 130 * cr + 128) >> 8 \
|
|
+)
|
|
+
|
|
+#else
|
|
+
|
|
+#define CBCRCG(yin, xin) \
|
|
+( \
|
|
+ cb = outc[0 +yin*8+xin], \
|
|
+ cr = outc[64+yin*8+xin], \
|
|
+ cg = (3 * cb + 8 * cr) >> 4 \
|
|
+)
|
|
+
|
|
+#endif
|
|
+
|
|
+#define PIC(yin, xin, p, xout) \
|
|
+( \
|
|
+ y = outy[(yin) * 8 + xin], \
|
|
+ STORECLAMP(p[(xout) * 3 + 0], y + cr), \
|
|
+ STORECLAMP(p[(xout) * 3 + 1], y - cg), \
|
|
+ STORECLAMP(p[(xout) * 3 + 2], y + cb) \
|
|
+)
|
|
+
|
|
+#ifdef __LITTLE_ENDIAN
|
|
+#define PIC_16(yin, xin, p, xout, add) \
|
|
+( \
|
|
+ y = outy[(yin) * 8 + xin], \
|
|
+ y = ((CLAMP(y + cr + add*2+1) & 0xf8) << 8) | \
|
|
+ ((CLAMP(y - cg + add ) & 0xfc) << 3) | \
|
|
+ ((CLAMP(y + cb + add*2+1) ) >> 3), \
|
|
+ p[(xout) * 2 + 0] = y & 0xff, \
|
|
+ p[(xout) * 2 + 1] = y >> 8 \
|
|
+)
|
|
+#else
|
|
+#ifdef CONFIG_PPC
|
|
+#define PIC_16(yin, xin, p, xout, add) \
|
|
+( \
|
|
+ y = outy[(yin) * 8 + xin], \
|
|
+ y = ((CLAMP(y + cr + add*2+1) & 0xf8) << 7) | \
|
|
+ ((CLAMP(y - cg + add*2+1) & 0xf8) << 2) | \
|
|
+ ((CLAMP(y + cb + add*2+1) ) >> 3), \
|
|
+ p[(xout) * 2 + 0] = y >> 8, \
|
|
+ p[(xout) * 2 + 1] = y & 0xff \
|
|
+)
|
|
+#else
|
|
+#define PIC_16(yin, xin, p, xout, add) \
|
|
+( \
|
|
+ y = outy[(yin) * 8 + xin], \
|
|
+ y = ((CLAMP(y + cr + add*2+1) & 0xf8) << 8) | \
|
|
+ ((CLAMP(y - cg + add ) & 0xfc) << 3) | \
|
|
+ ((CLAMP(y + cb + add*2+1) ) >> 3), \
|
|
+ p[(xout) * 2 + 0] = y >> 8, \
|
|
+ p[(xout) * 2 + 1] = y & 0xff \
|
|
+)
|
|
+#endif
|
|
+#endif
|
|
+
|
|
+#define PIC221111(xin) \
|
|
+( \
|
|
+ CBCRCG(0, xin), \
|
|
+ PIC(xin / 4 * 8 + 0, (xin & 3) * 2 + 0, pic0, xin * 2 + 0), \
|
|
+ PIC(xin / 4 * 8 + 0, (xin & 3) * 2 + 1, pic0, xin * 2 + 1), \
|
|
+ PIC(xin / 4 * 8 + 1, (xin & 3) * 2 + 0, pic1, xin * 2 + 0), \
|
|
+ PIC(xin / 4 * 8 + 1, (xin & 3) * 2 + 1, pic1, xin * 2 + 1) \
|
|
+)
|
|
+
|
|
+#define PIC221111_16(xin) \
|
|
+( \
|
|
+ CBCRCG(0, xin), \
|
|
+ PIC_16(xin / 4 * 8 + 0, (xin & 3) * 2 + 0, pic0, xin * 2 + 0, 3), \
|
|
+ PIC_16(xin / 4 * 8 + 0, (xin & 3) * 2 + 1, pic0, xin * 2 + 1, 0), \
|
|
+ PIC_16(xin / 4 * 8 + 1, (xin & 3) * 2 + 0, pic1, xin * 2 + 0, 1), \
|
|
+ PIC_16(xin / 4 * 8 + 1, (xin & 3) * 2 + 1, pic1, xin * 2 + 1, 2) \
|
|
+)
|
|
+
|
|
+static void col221111(out, pic, width)
|
|
+int *out;
|
|
+unsigned char *pic;
|
|
+int width;
|
|
+{
|
|
+ int i, j, k;
|
|
+ unsigned char *pic0, *pic1;
|
|
+ int *outy, *outc;
|
|
+ int cr, cg, cb, y;
|
|
+
|
|
+ pic0 = pic;
|
|
+ pic1 = pic + width;
|
|
+ outy = out;
|
|
+ outc = out + 64 * 4;
|
|
+ for (i = 2; i > 0; i--) {
|
|
+ for (j = 4; j > 0; j--) {
|
|
+ for (k = 0; k < 8; k++) {
|
|
+ PIC221111(k);
|
|
+ }
|
|
+ outc += 8;
|
|
+ outy += 16;
|
|
+ pic0 += 2 * width;
|
|
+ pic1 += 2 * width;
|
|
+ }
|
|
+ outy += 64 * 2 - 16 * 4;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void col221111_16(out, pic, width)
|
|
+int *out;
|
|
+unsigned char *pic;
|
|
+int width;
|
|
+{
|
|
+ int i, j, k;
|
|
+ unsigned char *pic0, *pic1;
|
|
+ int *outy, *outc;
|
|
+ int cr, cg, cb, y;
|
|
+
|
|
+ pic0 = pic;
|
|
+ pic1 = pic + width;
|
|
+ outy = out;
|
|
+ outc = out + 64 * 4;
|
|
+ for (i = 2; i > 0; i--) {
|
|
+ for (j = 4; j > 0; j--) {
|
|
+ for (k = 0; k < 8; k++) {
|
|
+ PIC221111_16(k);
|
|
+ }
|
|
+ outc += 8;
|
|
+ outy += 16;
|
|
+ pic0 += 2 * width;
|
|
+ pic1 += 2 * width;
|
|
+ }
|
|
+ outy += 64 * 2 - 16 * 4;
|
|
+ }
|
|
+}
|
|
--- /dev/null
|
|
+++ b/drivers/video/bootsplash/decode-jpg.h
|
|
@@ -0,0 +1,35 @@
|
|
+/*
|
|
+ * linux/drivers/video/bootsplash/decode-jpg.h - a tiny jpeg decoder.
|
|
+ *
|
|
+ * (w) August 2001 by Michael Schroeder, <mls@suse.de>
|
|
+ */
|
|
+
|
|
+#ifndef __DECODE_JPG_H
|
|
+#define __DECODE_JPG_H
|
|
+
|
|
+#define ERR_NO_SOI 1
|
|
+#define ERR_NOT_8BIT 2
|
|
+#define ERR_HEIGHT_MISMATCH 3
|
|
+#define ERR_WIDTH_MISMATCH 4
|
|
+#define ERR_BAD_WIDTH_OR_HEIGHT 5
|
|
+#define ERR_TOO_MANY_COMPPS 6
|
|
+#define ERR_ILLEGAL_HV 7
|
|
+#define ERR_QUANT_TABLE_SELECTOR 8
|
|
+#define ERR_NOT_YCBCR_221111 9
|
|
+#define ERR_UNKNOWN_CID_IN_SCAN 10
|
|
+#define ERR_NOT_SEQUENTIAL_DCT 11
|
|
+#define ERR_WRONG_MARKER 12
|
|
+#define ERR_NO_EOI 13
|
|
+#define ERR_BAD_TABLES 14
|
|
+#define ERR_DEPTH_MISMATCH 15
|
|
+
|
|
+struct jpeg_decdata {
|
|
+ int dcts[6 * 64 + 16];
|
|
+ int out[64 * 6];
|
|
+ int dquant[3][64];
|
|
+};
|
|
+
|
|
+extern int jpeg_decode(unsigned char *, unsigned char *, int, int, int, struct jpeg_decdata *);
|
|
+extern int jpeg_check_size(unsigned char *, int, int);
|
|
+
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/drivers/video/bootsplash/render.c
|
|
@@ -0,0 +1,328 @@
|
|
+/*
|
|
+ * linux/drivers/video/bootsplash/render.c - splash screen render functions.
|
|
+ */
|
|
+
|
|
+#include <linux/module.h>
|
|
+#include <linux/types.h>
|
|
+#include <linux/fb.h>
|
|
+#include <linux/vt_kern.h>
|
|
+#include <linux/selection.h>
|
|
+#include <asm/irq.h>
|
|
+#include <asm/system.h>
|
|
+
|
|
+#include "../console/fbcon.h"
|
|
+#include "bootsplash.h"
|
|
+
|
|
+void splash_putcs(struct splash_data *sd, struct vc_data *vc, struct fb_info *info,
|
|
+ const unsigned short *s, int count, int ypos, int xpos)
|
|
+{
|
|
+ unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
|
|
+ int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
|
|
+ int fgshift = (vc->vc_hi_font_mask) ? 9 : 8;
|
|
+ u8 *src;
|
|
+ u8 *dst, *splashsrc;
|
|
+ unsigned int d, x, y;
|
|
+ u32 dd, fgx, bgx;
|
|
+ u16 c = scr_readw(s);
|
|
+
|
|
+ int fg_color, bg_color, transparent;
|
|
+ if (console_blanked)
|
|
+ return;
|
|
+ fg_color = attr_fgcol(fgshift, c);
|
|
+ bg_color = attr_bgcol(bgshift, c);
|
|
+ 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 = (u8 *)(info->splash_pic + ypos * info->splash_bytes + xpos * 2);
|
|
+ dst = (u8 *)(info->screen_base + ypos * info->fix.line_length + xpos * 2);
|
|
+
|
|
+ fgx = ((u32 *)info->pseudo_palette)[fg_color];
|
|
+ if (transparent && sd->splash_color == 15) {
|
|
+ if (fgx == 0xffea)
|
|
+ fgx = 0xfe4a;
|
|
+ else if (fgx == 0x57ea)
|
|
+ fgx = 0x0540;
|
|
+ else if (fgx == 0xffff)
|
|
+ fgx = 0x52aa;
|
|
+ }
|
|
+ bgx = ((u32 *)info->pseudo_palette)[bg_color];
|
|
+ d = 0;
|
|
+
|
|
+ while (count--) {
|
|
+ c = scr_readw(s++);
|
|
+ src = vc->vc_font.data + (c & charmask) * vc->vc_font.height * ((vc->vc_font.width + 7) >> 3);
|
|
+
|
|
+ for (y = 0; y < vc->vc_font.height; y++) {
|
|
+ for (x = 0; x < vc->vc_font.width; x += 2) {
|
|
+ if ((x & 7) == 0)
|
|
+ d = *src++;
|
|
+ if (d & 0x80)
|
|
+ dd = fgx;
|
|
+ else
|
|
+ dd = transparent ? *(u16 *)splashsrc : bgx;
|
|
+ splashsrc += 2;
|
|
+ if (d & 0x40)
|
|
+ dd |= fgx << 16;
|
|
+ else
|
|
+ dd |= (transparent ? *(u16 *)splashsrc : bgx) << 16;
|
|
+ splashsrc += 2;
|
|
+ d <<= 2;
|
|
+ fb_writel(dd, dst);
|
|
+ dst += 4;
|
|
+ }
|
|
+ dst += info->fix.line_length - vc->vc_font.width * 2;
|
|
+ splashsrc += info->splash_bytes - vc->vc_font.width * 2;
|
|
+ }
|
|
+ dst -= info->fix.line_length * vc->vc_font.height - vc->vc_font.width * 2;
|
|
+ splashsrc -= info->splash_bytes * vc->vc_font.height - vc->vc_font.width * 2;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void splash_renderc(struct splash_data *sd, struct fb_info *info, int fg_color, int bg_color, u8 *src, int ypos, int xpos, int height, int width)
|
|
+{
|
|
+ int transparent = sd->splash_color == bg_color;
|
|
+ u32 dd, fgx, bgx;
|
|
+ u8 *dst, *splashsrc;
|
|
+ unsigned int d, x, y;
|
|
+
|
|
+ if (console_blanked)
|
|
+ return;
|
|
+ splashsrc = (u8 *)(info->splash_pic + ypos * info->splash_bytes + xpos * 2);
|
|
+ dst = (u8 *)(info->screen_base + ypos * info->fix.line_length + xpos * 2);
|
|
+ fgx = ((u32 *)info->pseudo_palette)[fg_color];
|
|
+ if (transparent && sd->splash_color == 15) {
|
|
+ if (fgx == 0xffea)
|
|
+ fgx = 0xfe4a;
|
|
+ else if (fgx == 0x57ea)
|
|
+ fgx = 0x0540;
|
|
+ else if (fgx == 0xffff)
|
|
+ fgx = 0x52aa;
|
|
+ }
|
|
+ bgx = ((u32 *)info->pseudo_palette)[bg_color];
|
|
+ d = 0;
|
|
+ for (y = 0; y < height; y++) {
|
|
+ for (x = 0; x < width; x += 2) {
|
|
+ if ((x & 7) == 0)
|
|
+ d = *src++;
|
|
+ if (d & 0x80)
|
|
+ dd = fgx;
|
|
+ else
|
|
+ dd = transparent ? *(u16 *)splashsrc : bgx;
|
|
+ splashsrc += 2;
|
|
+ if (d & 0x40)
|
|
+ dd |= fgx << 16;
|
|
+ else
|
|
+ dd |= (transparent ? *(u16 *)splashsrc : bgx) << 16;
|
|
+ splashsrc += 2;
|
|
+ d <<= 2;
|
|
+ fb_writel(dd, dst);
|
|
+ dst += 4;
|
|
+ }
|
|
+ dst += info->fix.line_length - width * 2;
|
|
+ splashsrc += info->splash_bytes - width * 2;
|
|
+ }
|
|
+}
|
|
+
|
|
+void splash_putc(struct splash_data *sd, struct vc_data *vc, struct fb_info *info,
|
|
+ int c, int ypos, int xpos)
|
|
+{
|
|
+ unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
|
|
+ int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
|
|
+ int fgshift = (vc->vc_hi_font_mask) ? 9 : 8;
|
|
+ u8 *src = vc->vc_font.data + (c & charmask) * vc->vc_font.height * ((vc->vc_font.width + 7) >> 3);
|
|
+ xpos = xpos * vc->vc_font.width + sd->splash_text_xo;
|
|
+ ypos = ypos * vc->vc_font.height + sd->splash_text_yo;
|
|
+ splash_renderc(sd, info, attr_fgcol(fgshift, c), attr_bgcol(bgshift, c), src, ypos, xpos, vc->vc_font.height, vc->vc_font.width);
|
|
+}
|
|
+
|
|
+void splashcopy(u8 *dst, u8 *src, int height, int width, int dstbytes, int srcbytes)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ while (height-- > 0) {
|
|
+ u32 *p = (u32 *)dst;
|
|
+ u32 *q = (u32 *)src;
|
|
+ for (i=0; i < width/4; i++) {
|
|
+ fb_writel(*q++,p++);
|
|
+ fb_writel(*q++,p++);
|
|
+ }
|
|
+ if (width & 2)
|
|
+ fb_writel(*q++,p++);
|
|
+ if (width & 1)
|
|
+ fb_writew(*(u16*)q,(u16*)p);
|
|
+ dst += dstbytes;
|
|
+ src += srcbytes;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void splashset(u8 *dst, int height, int width, int dstbytes, u32 bgx) {
|
|
+ int i;
|
|
+
|
|
+ bgx |= bgx << 16;
|
|
+ while (height-- > 0) {
|
|
+ u32 *p = (u32 *)dst;
|
|
+ for (i=0; i < width/4; i++) {
|
|
+ fb_writel(bgx,p++);
|
|
+ fb_writel(bgx,p++);
|
|
+ }
|
|
+ if (width & 2)
|
|
+ fb_writel(bgx,p++);
|
|
+ if (width & 1)
|
|
+ fb_writew(bgx,(u16*)p);
|
|
+ dst += dstbytes;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void splashfill(struct fb_info *info, int sy, int sx, int height, int width) {
|
|
+ splashcopy((u8 *)(info->screen_base + sy * info->fix.line_length + sx * 2), (u8 *)(info->splash_pic + sy * info->splash_bytes + sx * 2), height, width, info->fix.line_length, info->splash_bytes);
|
|
+}
|
|
+
|
|
+void splash_clear(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, int sy,
|
|
+ int sx, int height, int width)
|
|
+{
|
|
+ int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
|
|
+ int bg_color = attr_bgcol_ec(bgshift, vc, info);
|
|
+ int transparent = sd->splash_color == bg_color;
|
|
+ u32 bgx;
|
|
+ u8 *dst;
|
|
+
|
|
+ if (console_blanked)
|
|
+ return;
|
|
+ sy = sy * vc->vc_font.height + sd->splash_text_yo;
|
|
+ sx = sx * vc->vc_font.width + sd->splash_text_xo;
|
|
+ height *= vc->vc_font.height;
|
|
+ width *= vc->vc_font.width;
|
|
+ if (transparent) {
|
|
+ splashfill(info, sy, sx, height, width);
|
|
+ return;
|
|
+ }
|
|
+ dst = (u8 *)(info->screen_base + sy * info->fix.line_length + sx * 2);
|
|
+ bgx = ((u32 *)info->pseudo_palette)[bg_color];
|
|
+ splashset(dst, height, width, info->fix.line_length, bgx);
|
|
+}
|
|
+
|
|
+void splash_bmove(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, int sy,
|
|
+ int sx, int dy, int dx, int height, int width)
|
|
+{
|
|
+ struct fb_copyarea area;
|
|
+
|
|
+ if (console_blanked)
|
|
+ return;
|
|
+ area.sx = sx * vc->vc_font.width;
|
|
+ area.sy = sy * vc->vc_font.height;
|
|
+ area.dx = dx * vc->vc_font.width;
|
|
+ area.dy = dy * vc->vc_font.height;
|
|
+ area.sx += sd->splash_text_xo;
|
|
+ area.sy += sd->splash_text_yo;
|
|
+ area.dx += sd->splash_text_xo;
|
|
+ area.dy += sd->splash_text_yo;
|
|
+ area.height = height * vc->vc_font.height;
|
|
+ area.width = width * vc->vc_font.width;
|
|
+
|
|
+ info->fbops->fb_copyarea(info, &area);
|
|
+}
|
|
+
|
|
+void splash_clear_margins(struct splash_data *sd, struct vc_data *vc, struct fb_info *info,
|
|
+ int bottom_only)
|
|
+{
|
|
+ unsigned int tw = vc->vc_cols*vc->vc_font.width;
|
|
+ unsigned int th = vc->vc_rows*vc->vc_font.height;
|
|
+
|
|
+ if (console_blanked)
|
|
+ return;
|
|
+ if (!bottom_only) {
|
|
+ /* top margin */
|
|
+ splashfill(info, 0, 0, sd->splash_text_yo, info->var.xres);
|
|
+ /* left margin */
|
|
+ splashfill(info, sd->splash_text_yo, 0, th, sd->splash_text_xo);
|
|
+ /* right margin */
|
|
+ splashfill(info, sd->splash_text_yo, sd->splash_text_xo + tw, th, info->var.xres - sd->splash_text_xo - tw);
|
|
+
|
|
+ }
|
|
+ splashfill(info, sd->splash_text_yo + th, 0, info->var.yres - sd->splash_text_yo - th, info->var.xres);
|
|
+}
|
|
+
|
|
+int splash_cursor(struct splash_data *sd, struct fb_info *info, struct fb_cursor *cursor)
|
|
+{
|
|
+ int i;
|
|
+ unsigned int dsize, s_pitch;
|
|
+
|
|
+ if (info->state != FBINFO_STATE_RUNNING)
|
|
+ return 0;
|
|
+
|
|
+ s_pitch = (cursor->image.width + 7) >> 3;
|
|
+ dsize = s_pitch * cursor->image.height;
|
|
+ if (cursor->enable) {
|
|
+ switch (cursor->rop) {
|
|
+ case ROP_XOR:
|
|
+ for (i = 0; i < dsize; i++)
|
|
+ info->fb_cursordata[i] = cursor->image.data[i] ^ cursor->mask[i];
|
|
+ break;
|
|
+ case ROP_COPY:
|
|
+ default:
|
|
+ for (i = 0; i < dsize; i++)
|
|
+ info->fb_cursordata[i] = cursor->image.data[i] & cursor->mask[i];
|
|
+ break;
|
|
+ }
|
|
+ } else if (info->fb_cursordata != cursor->image.data)
|
|
+ memcpy(info->fb_cursordata, cursor->image.data, dsize);
|
|
+ cursor->image.data = info->fb_cursordata;
|
|
+ splash_renderc(sd, info, cursor->image.fg_color, cursor->image.bg_color, (u8 *)info->fb_cursordata, cursor->image.dy + sd->splash_text_yo, cursor->image.dx + sd->splash_text_xo, cursor->image.height, cursor->image.width);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void splash_bmove_redraw(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, int y, int sx, int dx, int width)
|
|
+{
|
|
+ unsigned short *d = (unsigned short *) (vc->vc_origin + vc->vc_size_row * y + dx * 2);
|
|
+ unsigned short *s = d + (dx - sx);
|
|
+ unsigned short *start = d;
|
|
+ unsigned short *ls = d;
|
|
+ unsigned short *le = d + width;
|
|
+ unsigned short c;
|
|
+ int x = dx;
|
|
+ unsigned short attr = 1;
|
|
+
|
|
+ if (console_blanked)
|
|
+ return;
|
|
+ do {
|
|
+ c = scr_readw(d);
|
|
+ if (attr != (c & 0xff00)) {
|
|
+ attr = c & 0xff00;
|
|
+ if (d > start) {
|
|
+ splash_putcs(sd, vc, info, start, d - start, y, x);
|
|
+ x += d - start;
|
|
+ start = d;
|
|
+ }
|
|
+ }
|
|
+ if (s >= ls && s < le && c == scr_readw(s)) {
|
|
+ if (d > start) {
|
|
+ splash_putcs(sd, vc, info, start, d - start, y, x);
|
|
+ x += d - start + 1;
|
|
+ start = d + 1;
|
|
+ } else {
|
|
+ x++;
|
|
+ start++;
|
|
+ }
|
|
+ }
|
|
+ s++;
|
|
+ d++;
|
|
+ } while (d < le);
|
|
+ if (d > start)
|
|
+ splash_putcs(sd, vc, info, start, d - start, y, x);
|
|
+}
|
|
+
|
|
+void splash_blank(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, int blank)
|
|
+{
|
|
+ if (blank) {
|
|
+ if (info->silent_screen_base)
|
|
+ splashset((u8 *)info->silent_screen_base, info->var.yres, info->var.xres, info->fix.line_length, 0);
|
|
+ splashset((u8 *)info->screen_base, info->var.yres, info->var.xres, info->fix.line_length, 0);
|
|
+ } else {
|
|
+ if (info->silent_screen_base)
|
|
+ splash_prepare(vc, info);
|
|
+ splash_clear_margins(vc->vc_splash_data, vc, info, 0);
|
|
+ /* no longer needed, done in fbcon_blank */
|
|
+ /* update_screen(vc->vc_num); */
|
|
+ }
|
|
+}
|
|
+
|
|
--- a/drivers/video/console/bitblit.c
|
|
+++ b/drivers/video/console/bitblit.c
|
|
@@ -18,6 +18,9 @@
|
|
#include <linux/console.h>
|
|
#include <asm/types.h>
|
|
#include "fbcon.h"
|
|
+#ifdef CONFIG_BOOTSPLASH
|
|
+#include "../bootsplash/bootsplash.h"
|
|
+#endif
|
|
|
|
/*
|
|
* Accelerated handlers.
|
|
@@ -48,6 +51,13 @@ static void bit_bmove(struct vc_data *vc
|
|
{
|
|
struct fb_copyarea area;
|
|
|
|
+#ifdef CONFIG_BOOTSPLASH
|
|
+ if (info->splash_data) {
|
|
+ splash_bmove(info->splash_data, vc, info,
|
|
+ sy, sx, dy, dx, height, width);
|
|
+ return;
|
|
+ }
|
|
+#endif
|
|
area.sx = sx * vc->vc_font.width;
|
|
area.sy = sy * vc->vc_font.height;
|
|
area.dx = dx * vc->vc_font.width;
|
|
@@ -64,6 +74,13 @@ static void bit_clear(struct vc_data *vc
|
|
int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
|
|
struct fb_fillrect region;
|
|
|
|
+#ifdef CONFIG_BOOTSPLASH
|
|
+ if (info->splash_data) {
|
|
+ splash_clear(info->splash_data, vc, info,
|
|
+ sy, sx, height, width);
|
|
+ return;
|
|
+ }
|
|
+#endif
|
|
region.color = attr_bgcol_ec(bgshift, vc, info);
|
|
region.dx = sx * vc->vc_font.width;
|
|
region.dy = sy * vc->vc_font.height;
|
|
@@ -161,6 +178,13 @@ static void bit_putcs(struct vc_data *vc
|
|
image.height = vc->vc_font.height;
|
|
image.depth = 1;
|
|
|
|
+#ifdef CONFIG_BOOTSPLASH
|
|
+ if (info->splash_data) {
|
|
+ splash_putcs(info->splash_data, vc, info, s, count, yy, xx);
|
|
+ return;
|
|
+ }
|
|
+#endif
|
|
+
|
|
if (attribute) {
|
|
buf = kmalloc(cellsize, GFP_KERNEL);
|
|
if (!buf)
|
|
@@ -214,6 +238,13 @@ static void bit_clear_margins(struct vc_
|
|
unsigned int bs = info->var.yres - bh;
|
|
struct fb_fillrect region;
|
|
|
|
+#ifdef CONFIG_BOOTSPLASH
|
|
+ if (info->splash_data) {
|
|
+ splash_clear_margins(info->splash_data, vc, info, bottom_only);
|
|
+ return;
|
|
+ }
|
|
+#endif
|
|
+
|
|
region.color = attr_bgcol_ec(bgshift, vc, info);
|
|
region.rop = ROP_COPY;
|
|
|
|
@@ -380,6 +411,14 @@ static void bit_cursor(struct vc_data *v
|
|
cursor.image.depth = 1;
|
|
cursor.rop = ROP_XOR;
|
|
|
|
+#ifdef CONFIG_BOOTSPLASH
|
|
+ if (info->splash_data) {
|
|
+ splash_cursor(info->splash_data, info, &cursor);
|
|
+ ops->cursor_reset = 0;
|
|
+ return;
|
|
+ }
|
|
+#endif
|
|
+
|
|
if (info->fbops->fb_cursor)
|
|
err = info->fbops->fb_cursor(info, &cursor);
|
|
|
|
--- a/drivers/video/console/fbcon.c
|
|
+++ b/drivers/video/console/fbcon.c
|
|
@@ -80,6 +80,9 @@
|
|
#include <asm/system.h>
|
|
|
|
#include "fbcon.h"
|
|
+#ifdef CONFIG_BOOTSPLASH
|
|
+#include "../bootsplash/bootsplash.h"
|
|
+#endif
|
|
|
|
#ifdef FBCONDEBUG
|
|
# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args)
|
|
@@ -95,7 +98,11 @@ enum {
|
|
|
|
static struct display fb_display[MAX_NR_CONSOLES];
|
|
|
|
+#ifdef CONFIG_BOOTSPLASH
|
|
+signed char con2fb_map[MAX_NR_CONSOLES];
|
|
+#else
|
|
static signed char con2fb_map[MAX_NR_CONSOLES];
|
|
+#endif
|
|
static signed char con2fb_map_boot[MAX_NR_CONSOLES];
|
|
|
|
static int logo_lines;
|
|
@@ -538,6 +545,10 @@ static int fbcon_takeover(int show_logo)
|
|
for (i = first_fb_vc; i <= last_fb_vc; i++)
|
|
con2fb_map[i] = info_idx;
|
|
|
|
+#ifdef CONFIG_BOOTSPLASH
|
|
+ splash_init();
|
|
+#endif
|
|
+
|
|
err = take_over_console(&fb_con, first_fb_vc, last_fb_vc,
|
|
fbcon_is_default);
|
|
|
|
@@ -1101,6 +1112,16 @@ static void fbcon_init(struct vc_data *v
|
|
new_cols /= vc->vc_font.width;
|
|
new_rows /= vc->vc_font.height;
|
|
|
|
+#ifdef CONFIG_BOOTSPLASH
|
|
+ if (vc->vc_splash_data && vc->vc_splash_data->splash_state) {
|
|
+ new_cols = vc->vc_splash_data->splash_text_wi / vc->vc_font.width;
|
|
+ new_rows = vc->vc_splash_data->splash_text_he / vc->vc_font.height;
|
|
+ logo = 0;
|
|
+ con_remap_def_color(vc, vc->vc_splash_data->splash_color << 4 | vc->vc_splash_data->splash_fg_color);
|
|
+ }
|
|
+#endif
|
|
+
|
|
+
|
|
/*
|
|
* We must always set the mode. The mode of the previous console
|
|
* driver could be in the same resolution but we are using different
|
|
@@ -1802,6 +1823,10 @@ static int fbcon_scroll(struct vc_data *
|
|
fbcon_softback_note(vc, t, count);
|
|
if (logo_shown >= 0)
|
|
goto redraw_up;
|
|
+#ifdef CONFIG_BOOTSPLASH
|
|
+ if (info->splash_data)
|
|
+ goto redraw_up;
|
|
+#endif
|
|
switch (p->scrollmode) {
|
|
case SCROLL_MOVE:
|
|
fbcon_redraw_blit(vc, info, p, t, b - t - count,
|
|
@@ -1893,6 +1918,10 @@ static int fbcon_scroll(struct vc_data *
|
|
count = vc->vc_rows;
|
|
if (logo_shown >= 0)
|
|
goto redraw_down;
|
|
+#ifdef CONFIG_BOOTSPLASH
|
|
+ if (info->splash_data)
|
|
+ goto redraw_down;
|
|
+#endif
|
|
switch (p->scrollmode) {
|
|
case SCROLL_MOVE:
|
|
fbcon_redraw_blit(vc, info, p, b - 1, b - t - count,
|
|
@@ -2041,6 +2070,14 @@ static void fbcon_bmove_rec(struct vc_da
|
|
}
|
|
return;
|
|
}
|
|
+
|
|
+#ifdef CONFIG_BOOTSPLASH
|
|
+ if (info->splash_data && sy == dy && height == 1) {
|
|
+ /* must use slower redraw bmove to keep background pic intact */
|
|
+ splash_bmove_redraw(info->splash_data, vc, info, sy, sx, dx, width);
|
|
+ return;
|
|
+ }
|
|
+#endif
|
|
ops->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx,
|
|
height, width);
|
|
}
|
|
@@ -2149,6 +2186,10 @@ static int fbcon_switch(struct vc_data *
|
|
info = registered_fb[con2fb_map[vc->vc_num]];
|
|
ops = info->fbcon_par;
|
|
|
|
+#ifdef CONFIG_BOOTSPLASH
|
|
+ splash_prepare(vc, info);
|
|
+#endif
|
|
+
|
|
if (softback_top) {
|
|
if (softback_lines)
|
|
fbcon_set_origin(vc);
|
|
@@ -2282,6 +2323,12 @@ static void fbcon_generic_blank(struct v
|
|
{
|
|
struct fb_event event;
|
|
|
|
+#ifdef CONFIG_BOOTSPLASH
|
|
+ if (info->splash_data) {
|
|
+ splash_blank(info->splash_data, vc, info, blank);
|
|
+ return;
|
|
+ }
|
|
+#endif
|
|
if (blank) {
|
|
unsigned short charmask = vc->vc_hi_font_mask ?
|
|
0x1ff : 0xff;
|
|
@@ -2507,6 +2554,12 @@ static int fbcon_do_set_font(struct vc_d
|
|
|
|
cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
|
|
rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
|
|
+#ifdef CONFIG_BOOTSPLASH
|
|
+ if (info->splash_data) {
|
|
+ cols = info->splash_data->splash_text_wi;
|
|
+ rows = info->splash_data->splash_text_he;
|
|
+ }
|
|
+#endif
|
|
cols /= w;
|
|
rows /= h;
|
|
vc_resize(vc, cols, rows);
|
|
--- a/drivers/video/console/fbcon.h
|
|
+++ b/drivers/video/console/fbcon.h
|
|
@@ -25,6 +25,34 @@
|
|
* low-level frame buffer device
|
|
*/
|
|
|
|
+#ifdef CONFIG_BOOTSPLASH
|
|
+struct splash_data {
|
|
+ int splash_state; /* show splash? */
|
|
+ int splash_color; /* transparent color */
|
|
+ int splash_fg_color; /* foreground color */
|
|
+ int splash_width; /* width of image */
|
|
+ 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_he;
|
|
+ int splash_showtext; /* silent/verbose mode */
|
|
+ int splash_boxcount;
|
|
+ int splash_percent;
|
|
+ int splash_overpaintok; /* is it ok to overpaint boxes */
|
|
+ int splash_palcnt;
|
|
+ char *oldscreen_base; /* pointer to top of virtual screen */
|
|
+ unsigned char *splash_boxes;
|
|
+ unsigned char *splash_jpeg; /* jpeg */
|
|
+ unsigned char *splash_palette; /* palette for 8-bit */
|
|
+
|
|
+ int splash_dosilent; /* show silent jpeg */
|
|
+ unsigned char *splash_silentjpeg;
|
|
+ unsigned char *splash_sboxes;
|
|
+ int splash_sboxcount;
|
|
+};
|
|
+#endif
|
|
+
|
|
struct display {
|
|
/* Filled in by the low-level console driver */
|
|
const u_char *fontdata;
|
|
--- a/drivers/video/vesafb.c
|
|
+++ b/drivers/video/vesafb.c
|
|
@@ -181,7 +181,10 @@ static void vesafb_destroy(struct fb_inf
|
|
framebuffer_release(info);
|
|
}
|
|
|
|
-static struct fb_ops vesafb_ops = {
|
|
+#ifndef CONFIG_BOOTSPLASH
|
|
+static
|
|
+#endif
|
|
+struct fb_ops vesafb_ops = {
|
|
.owner = THIS_MODULE,
|
|
.fb_destroy = vesafb_destroy,
|
|
.fb_setcolreg = vesafb_setcolreg,
|
|
@@ -266,6 +269,9 @@ static int __init vesafb_probe(struct pl
|
|
* option to simply use size_total as that
|
|
* wastes plenty of kernel address space. */
|
|
size_remap = size_vmode * 2;
|
|
+#ifdef CONFIG_BOOTSPLASH
|
|
+ size_remap *= 2; /* some more for the images */
|
|
+#endif
|
|
if (vram_remap)
|
|
size_remap = vram_remap * 1024 * 1024;
|
|
if (size_remap < size_vmode)
|
|
--- a/include/linux/console_struct.h
|
|
+++ b/include/linux/console_struct.h
|
|
@@ -106,6 +106,9 @@ struct vc_data {
|
|
struct vc_data **vc_display_fg; /* [!] Ptr to var holding fg console for this display */
|
|
unsigned long vc_uni_pagedir;
|
|
unsigned long *vc_uni_pagedir_loc; /* [!] Location of uni_pagedir variable for this console */
|
|
+#ifdef CONFIG_BOOTSPLASH
|
|
+ struct splash_data *vc_splash_data;
|
|
+#endif
|
|
bool vc_panic_force_write; /* when oops/panic this VC can accept forced output/blanking */
|
|
/* additional information is in vt_kern.h */
|
|
};
|
|
--- a/include/linux/fb.h
|
|
+++ b/include/linux/fb.h
|
|
@@ -875,6 +875,14 @@ struct fb_info {
|
|
void *fbcon_par; /* fbcon use-only private area */
|
|
/* From here on everything is device dependent */
|
|
void *par;
|
|
+#ifdef CONFIG_BOOTSPLASH
|
|
+ struct splash_data *splash_data;
|
|
+ unsigned char *splash_pic;
|
|
+ int splash_pic_size;
|
|
+ int splash_bytes;
|
|
+ char *silent_screen_base; /* real screen base */
|
|
+ char fb_cursordata[64];
|
|
+#endif
|
|
/* we need the PCI or similiar aperture base/size not
|
|
smem_start/size as smem_start may just be an object
|
|
allocated inside the aperture so may not actually overlap */
|
|
--- a/kernel/panic.c
|
|
+++ b/kernel/panic.c
|
|
@@ -110,7 +110,12 @@ NORET_TYPE void panic(const char * fmt,
|
|
* We can't use the "normal" timers since we just panicked.
|
|
*/
|
|
printk(KERN_EMERG "Rebooting in %d seconds..", panic_timeout);
|
|
-
|
|
+#ifdef CONFIG_BOOTSPLASH
|
|
+ {
|
|
+ extern int splash_verbose(void);
|
|
+ (void)splash_verbose();
|
|
+ }
|
|
+#endif
|
|
for (i = 0; i < panic_timeout * 1000; i += PANIC_TIMER_STEP) {
|
|
touch_nmi_watchdog();
|
|
if (i >= i_next) {
|
|
@@ -143,6 +148,12 @@ NORET_TYPE void panic(const char * fmt,
|
|
}
|
|
#endif
|
|
local_irq_enable();
|
|
+#ifdef CONFIG_BOOTSPLASH
|
|
+ {
|
|
+ extern int splash_verbose(void);
|
|
+ (void)splash_verbose();
|
|
+ }
|
|
+#endif
|
|
for (i = 0; ; i += PANIC_TIMER_STEP) {
|
|
touch_softlockup_watchdog();
|
|
if (i >= i_next) {
|