Sophie

Sophie

distrib > PLD > ac > amd64 > by-pkgid > 950ec4453099b5125884e99014f11757 > files > 23

kernel24-2.4.34-1.src.rpm

diff -urN linux-2.4.24.org/drivers/char/console.c linux-2.4.24/drivers/char/console.c
--- linux-2.4.24.org/drivers/char/console.c	2004-01-19 21:00:14.495123806 +0100
+++ linux-2.4.24/drivers/char/console.c	2004-01-19 21:03:48.017721428 +0100
@@ -3025,6 +3025,31 @@
 	return 0;
 }
 
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+void con_remap_def_color(int currcons, int new_color)
+{
+	unsigned short *sbuf = screenbuf;
+	unsigned c, len = screenbuf_size >> 1;
+	int old_color;
+
+	if (sbuf) {
+		old_color = 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;
+	}
+	def_color = color = new_color;
+	update_attr(currcons);
+}
+#endif
+
 /*
  *	Visible symbols for modules
  */
diff -urN linux-2.4.24.org/drivers/char/keyboard.c linux-2.4.24/drivers/char/keyboard.c
--- linux-2.4.24.org/drivers/char/keyboard.c	2004-01-19 21:00:14.168191795 +0100
+++ linux-2.4.24/drivers/char/keyboard.c	2004-01-19 21:03:48.066711241 +0100
@@ -263,6 +263,15 @@
 	} else
 		rep = test_and_set_bit(keycode, key_down);
 
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+	/* This code has to be redone for some non-x86 platforms */
+	if (keycode == 0x3c || keycode == 0x01) {	/* F2 and ESC on a PC keyboard */
+		extern int splash_verbose(void);
+		if (splash_verbose())
+		    goto out;
+	}
+#endif
+
 #ifdef CONFIG_MAGIC_SYSRQ		/* Handle the SysRq Hack */
 	if (keycode == SYSRQ_KEY) {
 		sysrq_pressed = !up_flag;
--- linux-2.4.29/drivers/char/n_tty.c.orig	2005-01-20 16:15:28.000000000 +0100
+++ linux-2.4.29/drivers/char/n_tty.c	2005-01-20 16:18:59.000000000 +0100
@@ -47,6 +47,7 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/poll.h>
+#include <linux/config.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -1186,6 +1187,16 @@
 		return -EIO;
 	}
 
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+	if (file->f_dentry->d_inode->i_rdev == CONSOLE_DEV ||
+	    file->f_dentry->d_inode->i_rdev == SYSCONS_DEV ||
+	    file->f_dentry->d_inode->i_rdev == MKDEV(TTYAUX_MAJOR,0) ||
+	    file->f_dentry->d_inode->i_rdev == MKDEV(TTY_MAJOR,1)) {
+		extern int splash_verbose(void);
+		(void)splash_verbose();
+	}
+#endif
+
 	c = job_control(tty, file);
 	if(c < 0)
 		return c;
diff -urN linux-2.4.24.org/drivers/video/Config.in linux-2.4.24/drivers/video/Config.in
--- linux-2.4.24.org/drivers/video/Config.in	2004-01-19 21:01:12.428076192 +0100
+++ linux-2.4.24/drivers/video/Config.in	2004-01-19 21:05:33.568745824 +0100
@@ -243,13 +243,20 @@
       tristate '  Virtual Frame Buffer support (ONLY FOR TESTING!) (EXPERIMENTAL)' CONFIG_FB_VIRTUAL
    fi
 
+   dep_bool '  Use splash screen instead of boot logo' CONFIG_FBCON_SPLASHSCREEN $CONFIG_BLK_DEV_INITRD
+   if [ "$CONFIG_FBCON_SPLASHSCREEN" = "y" ]; then
+      define_bool CONFIG_FBCON_CFB16 y
+   fi
+
    bool '  Advanced low level driver options' CONFIG_FBCON_ADVANCED
    if [ "$CONFIG_FBCON_ADVANCED" = "y" ]; then
       tristate '    Monochrome support' CONFIG_FBCON_MFB
       tristate '    2 bpp packed pixels support' CONFIG_FBCON_CFB2
       tristate '    4 bpp packed pixels support' CONFIG_FBCON_CFB4
       tristate '    8 bpp packed pixels support' CONFIG_FBCON_CFB8
-      tristate '    16 bpp packed pixels support' CONFIG_FBCON_CFB16
+      if [ "$CONFIG_FBCON_SPLASHSCREEN" != "y" ]; then
+         tristate '    16 bpp packed pixels support' CONFIG_FBCON_CFB16
+      fi
       tristate '    24 bpp packed pixels support' CONFIG_FBCON_CFB24
       tristate '    32 bpp packed pixels support' CONFIG_FBCON_CFB32
       tristate '    Amiga bitplanes support' CONFIG_FBCON_AFB
@@ -361,7 +368,9 @@
 	   "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" -o \
 	   "$CONFIG_FB_NEOMAGIC" = "y" -o "$CONFIG_FB_INTEL" = "y" -o \
 	   "$CONFIG_FB_I810" = "y" ]; then
-	 define_tristate CONFIG_FBCON_CFB16 y
+	 if [ "$CONFIG_FBCON_CFB16" != "m" ]; then
+		 define_tristate CONFIG_FBCON_CFB16 y
+	 fi
       else
 	 if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
 	      "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VESA" = "m" -o \
@@ -380,7 +389,9 @@
 	      "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" -o \
 	      "$CONFIG_FB_NEOMAGIC" = "m" -o "$CONFIG_FB_INTEL" = "m" -o \
 	      "$CONFIG_FB_I810" = "m" ]; then
-	    define_tristate CONFIG_FBCON_CFB16 m
+	    if [ "$CONFIG_FBCON_CFB16" != "y" ]; then
+		    define_tristate CONFIG_FBCON_CFB16 m
+	    fi
 	 fi
       fi
       if [ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
diff -urN linux-2.4.24.org/drivers/video/fbcon.c linux-2.4.24/drivers/video/fbcon.c
--- linux-2.4.24.org/drivers/video/fbcon.c	2004-01-19 21:01:12.383085548 +0100
+++ linux-2.4.24/drivers/video/fbcon.c	2004-01-19 21:03:48.196684214 +0100
@@ -76,6 +76,7 @@
 #include <linux/smp.h>
 #include <linux/init.h>
 #include <linux/pm.h>
+#include <linux/vmalloc.h>
 
 #include <asm/irq.h>
 #include <asm/system.h>
@@ -104,6 +105,23 @@
 #include <video/fbcon-mac.h>	/* for 6x11 font on mac */
 #include <video/font.h>
 
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+#include <video/fbcon-cfb16.h>	/* for fbcon_cfb16 */
+#include "fbcon-splash.h"
+
+extern void con_remap_def_color(int currcons, int new_color);
+
+extern int splash_default;
+extern int splash_shown;
+
+extern struct display_switch fbcon_splash16;
+
+#ifdef CONFIG_PROC_FS
+int splash_proc_register(void);
+int splash_proc_unregister(void);
+#endif
+#endif
+
 #ifdef FBCONDEBUG
 #  define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
 #else
@@ -477,7 +495,9 @@
     return display_desc;
 }
 
-
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+static int splash_registered=0;
+#endif
 static void fbcon_init(struct vc_data *conp, int init)
 {
     int unit = conp->vc_num;
@@ -501,6 +521,26 @@
     fb_display[unit].cmap.green = 0;
     fb_display[unit].cmap.blue = 0;
     fb_display[unit].cmap.transp = 0;
+
+#ifdef CONFIG_FBCON_SPLASHSCREEN 
+    if (!splash_registered && fb_display[unit].var.bits_per_pixel == 16 ) {
+	if (unit == 0 && !fb_display[unit].splash_data) {
+	    extern unsigned long initrd_start, initrd_end;
+
+	    if (initrd_start && !splash_getraw((unsigned char *)initrd_start, (unsigned char *)initrd_end) && fb_display[unit].splash_data)
+		fb_display[unit].splash_data->splash_state = splash_default & 1;
+	}
+	splash_registered = 1;
+#ifdef CONFIG_PROC_FS
+	splash_proc_register();
+#endif
+    }
+    if (fb_display[unit].splash_data && fb_display[unit].var.bits_per_pixel != 16 ) {
+	vfree(fb_display[unit].splash_data);
+	fb_display[unit].splash_data = 0;
+    }
+#endif
+
     fbcon_setup(unit, init, !init);
     /* Must be done after fbcon_setup to prevent excess updates */
     conp->vc_display_fg = &info->display_fg;
@@ -517,6 +557,15 @@
     fbcon_free_font(p);
     p->dispsw = &fbcon_dummy;
     p->conp = 0;
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+    if (splash_registered) {
+#ifdef CONFIG_PROC_FS
+        splash_proc_unregister();
+#endif
+	splash_registered = 0;
+    }
+#endif
+
 }
 
 
@@ -657,7 +706,14 @@
     
     nr_cols = p->var.xres/fontwidth(p);
     nr_rows = p->var.yres/fontheight(p);
-    
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+    if (p->splash_data && p->splash_data->splash_state) {
+	nr_cols = p->splash_data->splash_text_wi / fontwidth(p);
+	nr_rows = p->splash_data->splash_text_he / fontheight(p);
+	logo = 0;
+    }
+#endif
+ 
     if (logo) {
     	/* Need to make room for the logo */
 	int cnt;
@@ -734,6 +790,11 @@
     p->fgcol = p->var.bits_per_pixel > 2 ? 7 : (1<<p->var.bits_per_pixel)-1;
     p->bgcol = 0;
 
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+    if(p->splash_data && p->splash_data->splash_state)
+	con_remap_def_color(con, p->splash_data->splash_color << 4 | p->splash_data->splash_fg_color);
+#endif	
+
     if (!init) {
 	if (conp->vc_cols != nr_cols || conp->vc_rows != nr_rows)
 	    vc_resize_con(nr_rows, nr_cols, con);
@@ -1323,6 +1384,9 @@
 	    if (softback_top)
 	        fbcon_softback_note(conp, t, count);
 	    if (logo_shown >= 0) goto redraw_up;
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+	    if (splash_shown) goto redraw_up;
+#endif
 	    switch (p->scrollmode & __SCROLL_YMASK) {
 	    case __SCROLL_YMOVE:
 		p->dispsw->bmove(p, t+count, 0, t, 0, b-t-count,
@@ -1383,6 +1447,9 @@
 	case SM_DOWN:
 	    if (count > conp->vc_rows)	/* Maximum realistic size */
 		count = conp->vc_rows;
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+	    if (splash_shown) goto redraw_down;
+#endif
 	    switch (p->scrollmode & __SCROLL_YMASK) {
 	    case __SCROLL_YMOVE:
 		p->dispsw->bmove(p, t, 0, t+count, 0, b-t-count,
@@ -1499,6 +1566,13 @@
 	}
 	return;
     }
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+    if (splash_shown && sy == dy) {
+	/* must use slower redraw bmove to keep background pic intact */
+	fbcon_redraw_bmove(p, real_y(p, sy), sx, real_y(p, dy), dx, height, width);
+	return;
+    }
+#endif
     p->dispsw->bmove(p, real_y(p, sy), sx, real_y(p, dy), dx, height, width);
 }
 
@@ -1509,6 +1583,10 @@
     struct display *p = &fb_display[unit];
     struct fb_info *info = p->fb_info;
 
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+    splash_prepare(p);
+#endif
+
     if (softback_top) {
     	int l = fbcon_softback_size / conp->vc_size_row;
 	if (softback_lines)
@@ -1568,14 +1646,41 @@
 {
     struct display *p = &fb_display[conp->vc_num];
     struct fb_info *info = p->fb_info;
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+    struct display_switch *olddispsw=NULL;
+    char    *oldscreen_base=NULL;
+#endif
+   
 
     if (blank < 0)	/* Entering graphics mode */
 	return 0;
 
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+
+    if (p->splash_data && p->splash_data->oldscreen_base) {
+	oldscreen_base = p->screen_base;
+        p->screen_base = p->splash_data->oldscreen_base;
+    }
+    if (p->splash_data && p->splash_data->olddispsw) {
+        olddispsw = p->dispsw;
+        p->dispsw = p->splash_data->olddispsw;
+    }
+#endif
+
     fbcon_cursor(p->conp, blank ? CM_ERASE : CM_DRAW);
 
     if (!p->can_soft_blank) {
 	if (blank) {
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+	    if (p->splash_data && p->splash_data->oldscreen_base) {
+		oldscreen_base = p->screen_base;
+	        p->screen_base = p->splash_data->oldscreen_base;
+	    }
+	    if (p->splash_data && p->splash_data->olddispsw) {
+	        olddispsw = p->dispsw;
+	        p->dispsw = p->splash_data->olddispsw;
+	    }
+#endif
 	    if (p->visual == FB_VISUAL_MONO01) {
 		if (p->screen_base)
 		    fb_memset255(p->screen_base,
@@ -1583,25 +1688,39 @@
 				 p->var.bits_per_pixel>>3);
 	    } else {
 	    	unsigned short oldc;
-	    	u_int height;
+	    	u_int height, width;
 	    	u_int y_break;
 
 	    	oldc = conp->vc_video_erase_char;
 	    	conp->vc_video_erase_char &= p->charmask;
 	    	height = conp->vc_rows;
+		width  = conp->vc_cols;
 		y_break = p->vrows-p->yscroll;
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+		if (splash_shown) {
+			width=p->var.xres/fontwidth(p);
+			height=p->var.yres/fontheight(p);
+		}
+#endif
 		if (height > y_break) {
-			p->dispsw->clear(conp, p, real_y(p, 0), 0, y_break, conp->vc_cols);
-			p->dispsw->clear(conp, p, real_y(p, y_break), 0, height-y_break, conp->vc_cols);
+			p->dispsw->clear(conp, p, real_y(p, 0), 0, y_break, width);
+			p->dispsw->clear(conp, p, real_y(p, y_break), 0, height-y_break, width);
 		} else
-			p->dispsw->clear(conp, p, real_y(p, 0), 0, height, conp->vc_cols);
+			p->dispsw->clear(conp, p, real_y(p, 0), 0, height, width);
 		conp->vc_video_erase_char = oldc;
 	    }
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+	    if(oldscreen_base)
+		p->screen_base=oldscreen_base;
+	    if(olddispsw)
+		p->dispsw=olddispsw;
+#endif
 	    return 0;
 	} else {
 	    /* Tell console.c that it has to restore the screen itself */
 	    return 1;
 	}
+
     }
     (*info->blank)(blank, info);
     return 0;
@@ -1762,13 +1881,21 @@
 
     if (resize) {
     	struct vc_data *conp = p->conp;
+	__u32 xres = p->var.xres, yres = p->var.yres;
+
 	/* reset wrap/pan */
 	p->var.xoffset = p->var.yoffset = p->yscroll = 0;
 	p->vrows = p->var.yres_virtual/h;
-	if ((p->var.yres % h) && (p->var.yres_virtual % h < p->var.yres % h))
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+	if (p->splash_data && p->splash_data->splash_state) {
+	    xres = p->splash_data->splash_text_wi;
+	    yres = p->splash_data->splash_text_he;
+        }
+#endif
+	if ((yres % h) && (p->var.yres_virtual % h < p->var.yres % h))
 	    p->vrows--;
 	updatescrollmode(p);
-	vc_resize_con( p->var.yres/h, p->var.xres/w, unit );
+	vc_resize_con( yres/h, xres/w, unit );
         if (CON_IS_VISIBLE(conp) && softback_buf) {
 	    int l = fbcon_softback_size / conp->vc_size_row;
 	    if (l > 5)
@@ -2189,6 +2316,9 @@
     if (p->fb_info->fbops->fb_rasterimg)
     	p->fb_info->fbops->fb_rasterimg(p->fb_info, 1);
 
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+    if (!splash_shown) {
+#endif
     for (x = 0; x < smp_num_cpus * (LOGO_W + 8) &&
     	 x < p->var.xres - (LOGO_W + 8); x += (LOGO_W + 8)) {
     	 
@@ -2450,7 +2580,10 @@
 	}
 #endif			
     }
-    
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+    }
+#endif    
+
     if (p->fb_info->fbops->fb_rasterimg)
     	p->fb_info->fbops->fb_rasterimg(p->fb_info, 0);
 
diff -urN linux-2.4.24.org/drivers/video/fbcon-jpegdec.c linux-2.4.24/drivers/video/fbcon-jpegdec.c
--- linux-2.4.24.org/drivers/video/fbcon-jpegdec.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.24/drivers/video/fbcon-jpegdec.c	2004-01-19 21:03:48.203682758 +0100
@@ -0,0 +1,960 @@
+/* 
+ *    linux/drivers/video/fbcon-jpegdec.c - a tiny jpeg decoder.
+ *      
+ *      (w) August 2001 by Michael Schroeder, <mls@suse.de>
+ *                  
+ */
+
+#include <linux/config.h>
+#include <linux/string.h>
+#include <asm/byteorder.h>
+
+struct display;
+#include "fbcon-splash.h"
+#include "fbcon-jpegdec.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)
+		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;
+	}
+}
diff -urN linux-2.4.24.org/drivers/video/fbcon-jpegdec.h linux-2.4.24/drivers/video/fbcon-jpegdec.h
--- linux-2.4.24.org/drivers/video/fbcon-jpegdec.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.24/drivers/video/fbcon-jpegdec.h	2004-01-19 21:03:48.205682343 +0100
@@ -0,0 +1,24 @@
+#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);
diff -urN linux-2.4.24.org/drivers/video/fbcon-splash16.c linux-2.4.24/drivers/video/fbcon-splash16.c
--- linux-2.4.24.org/drivers/video/fbcon-splash16.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.24/drivers/video/fbcon-splash16.c	2004-01-19 21:03:48.209681511 +0100
@@ -0,0 +1,488 @@
+/*
+ *  linux/drivers/video/fbcon-splash16.c -- Low level frame buffer operations for 16 bpp
+ *                                          framebuffer operation. Modified to present
+ *					    boot splash screen. 2002/11/7 stepan@suse.de
+ * 
+ * Based on linux/drivers/video/fbcon-cfb16.c, which is
+ *
+ *	Created 5 Apr 1997 by Geert Uytterhoeven
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <asm/io.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb16.h>
+
+#include "fbcon-splash.h"
+
+    /*
+     *  16 bpp packed pixels
+     */
+
+static u32 tab_cfb16[] = {
+#if defined(__BIG_ENDIAN)
+    0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
+#elif defined(__LITTLE_ENDIAN)
+    0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff
+#else
+#error FIXME: No endianness??
+#endif
+};
+
+void fbcon_splash16_bmove(struct display *p, int sy, int sx, int dy, int dx,
+		       int height, int width)
+{
+    int bytes = p->next_line, linesize = bytes * fontheight(p), rows;
+    u8 *src, *dst;
+
+    if (sx == 0 && dx == 0 && width * fontwidth(p) * 2 == bytes) {
+	fb_memmove(p->screen_base + dy * linesize,
+		  p->screen_base + sy * linesize,
+		  height * linesize);
+	return;
+    }
+    if (fontwidthlog(p)) {
+	sx <<= fontwidthlog(p)+1;
+	dx <<= fontwidthlog(p)+1;
+	width <<= fontwidthlog(p)+1;
+    } else {
+	sx *= fontwidth(p)*2;
+	dx *= fontwidth(p)*2;
+	width *= fontwidth(p)*2;
+    }
+    sx += splash_data.splash_text_xo*2 + splash_data.splash_text_yo * bytes;
+    dx += splash_data.splash_text_xo*2 + splash_data.splash_text_yo * bytes;
+    if (dy < sy || (dy == sy && dx < sx)) {
+	src = p->screen_base + sy * linesize + sx;
+	dst = p->screen_base + dy * linesize + dx;
+	for (rows = height * fontheight(p); rows--;) {
+	    fb_memmove(dst, src, width);
+	    src += bytes;
+	    dst += bytes;
+	}
+    } else {
+	src = p->screen_base + (sy+height) * linesize + sx - bytes;
+	dst = p->screen_base + (dy+height) * linesize + dx - bytes;
+	for (rows = height * fontheight(p); rows--;) {
+	    fb_memmove(dst, src, width);
+	    src -= bytes;
+	    dst -= bytes;
+	}
+    }
+}
+
+static inline void rectfill(u8 *dest, int width, int height, u32 data,
+			    int linesize)
+{
+    int i;
+
+    data |= data<<16;
+
+    while (height-- > 0) {
+	u32 *p = (u32 *)dest;
+	for (i = 0; i < width/4; i++) {
+	    fb_writel(data, p++);
+	    fb_writel(data, p++);
+	}
+	if (width & 2)
+	    fb_writel(data, p++);
+	if (width & 1)
+	    fb_writew(data, (u16*)p);
+	dest += linesize;
+    }
+}
+
+void splashfill(u8 *dest, u8 *src, int width, int height,
+                       int dest_linesize, int src_linesize)
+{
+
+    int i;
+
+    while (height-- > 0) {
+	u32 *p = (u32 *)dest;
+	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);
+	dest += dest_linesize;
+	src  += src_linesize;
+    }
+}
+
+void fbcon_splash16_clear(struct vc_data *conp, struct display *p, int sy, int sx,
+		       int height, int width)
+{
+    u8 *dest;
+    int bytes = p->next_line, lines = height * fontheight(p);
+    u32 bgx;
+    int offset, transparent=0;
+
+    dest = p->screen_base + sy * fontheight(p) * bytes + sx * fontwidth(p) * 2;
+
+    bgx = ((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
+
+    width *= fontwidth(p)/4;
+
+    dest   += splash_data.splash_text_yo * bytes  +
+		  splash_data.splash_text_xo * 2;
+
+    transparent = (splash_data.splash_color == attr_bgcol_ec(p, conp));
+    
+    if (transparent) {
+	offset = (sy * fontheight(p) + splash_data.splash_text_yo) * splash_bytes +
+		 (sx * fontwidth(p) + splash_data.splash_text_xo) *  2;
+	
+	if ((width * 8 == bytes && splash_bytes == bytes))
+	    splashfill(dest,linux_splash + offset, lines * width * 4, 
+			    1, bytes, splash_bytes);
+	else
+	    splashfill(dest,linux_splash + offset, width*4, lines,
+			    bytes, splash_bytes);
+    } else {
+	 if (width * 8 == bytes)
+	    rectfill(dest, lines * width * 4, 1, bgx, bytes);
+	 else
+	    rectfill(dest, width * 4, lines, bgx, bytes);
+    }
+}
+
+
+/*
+ *  Helper function to read the background from the splashscreen
+ */
+# define SPLASH_BGX(off)			\
+	if (transparent) {			\
+	    bgx = *(u32*)(splashbgx + (off));	\
+	    eorx = fgx ^ bgx;			\
+	}
+
+
+void fbcon_splash16_putc(struct vc_data *conp, struct display *p, int c, int yy,
+		      int xx)
+{
+    u8 *dest, *cdat, bits;
+    int bytes = p->next_line, rows;
+    u32 eorx, fgx, bgx;
+    int transparent = 0;
+    u8 *splashbgx = 0;
+ 
+    dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 2;
+
+    fgx = ((u16 *)p->dispsw_data)[attr_fgcol(p, c)];
+    bgx = ((u16 *)p->dispsw_data)[attr_bgcol(p, c)];
+
+    transparent = (splash_data.splash_color == attr_bgcol(p, c));
+    
+    dest += splash_data.splash_text_xo * 2 + splash_data.splash_text_yo * bytes;
+    splashbgx = linux_splash +
+	    (yy * fontheight(p) + splash_data.splash_text_yo) * splash_bytes + 
+	    (xx * fontwidth(p) + splash_data.splash_text_xo) * 2;
+
+    if (transparent && splash_data.splash_color == 0xf) {
+	if (fgx == 0xffea)
+	    fgx = 0xfe4a;
+	else if (fgx == 0x57ea)
+	    fgx = 0x0540;
+	else if (fgx == 0xffff)
+	    fgx = 0x52aa;
+    }
+
+    fgx |= (fgx << 16);
+    bgx |= (bgx << 16);
+    eorx = fgx ^ bgx;
+
+    switch (fontwidth(p)) {
+    case 4:
+    case 8:
+	cdat = p->fontdata + (c & p->charmask) * fontheight(p);
+	for (rows = fontheight(p); rows--; dest += bytes) {
+	    bits = *cdat++;
+	    SPLASH_BGX(0);
+	    fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest);
+	    SPLASH_BGX(4);
+	    fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest+4);
+	    if (fontwidth(p) == 8) {
+		SPLASH_BGX(8);
+		fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest+8);
+		SPLASH_BGX(12);
+		fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest+12);
+	    }
+
+	    splashbgx += splash_bytes;
+
+	}
+	break;
+    case 12:
+    case 16:
+	cdat = p->fontdata + ((c & p->charmask) * fontheight(p) << 1);
+	for (rows = fontheight(p); rows--; dest += bytes) {
+	    bits = *cdat++;
+	    SPLASH_BGX(0);
+	    fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest);
+	    SPLASH_BGX(4);
+	    fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest+4);
+	    SPLASH_BGX(8);
+	    fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest+8);
+	    SPLASH_BGX(12);
+	    fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest+12);
+	    bits = *cdat++;
+	    SPLASH_BGX(16);
+	    fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest+16);
+	    SPLASH_BGX(20);
+	    fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest+20);
+	    if (fontwidth(p) == 16) {
+		SPLASH_BGX(24);
+		fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest+24);
+		SPLASH_BGX(28);
+		fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest+28);
+	    }
+	}
+	break;
+    }
+}
+
+void fbcon_splash16_putcs(struct vc_data *conp, struct display *p,
+		       const unsigned short *s, int count, int yy, int xx)
+{
+    u8 *cdat, *dest, *dest0;
+    u16 c;
+    int rows, bytes = p->next_line;
+    u32 eorx, fgx, bgx;
+    int transparent = 0;
+    u8 *splashbgx0 = 0, *splashbgx;
+
+    dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 2;
+    c = scr_readw(s);
+    fgx = ((u16 *)p->dispsw_data)[attr_fgcol(p, c)];
+    bgx = ((u16 *)p->dispsw_data)[attr_bgcol(p, c)];
+
+    transparent = (splash_data.splash_color == attr_bgcol(p, c));
+    
+    dest0 += splash_data.splash_text_xo * 2 + splash_data.splash_text_yo * bytes;
+    splashbgx0 = linux_splash +
+	      (yy * fontheight(p) + splash_data.splash_text_yo) * splash_bytes +
+	      (xx * fontwidth(p) + splash_data.splash_text_xo) * 2;
+
+    if (transparent && splash_data.splash_color == 0xf) {
+	if (fgx == 0xffea)
+	    fgx = 0xfe4a;
+	else if (fgx == 0x57ea)
+	    fgx = 0x0540;
+	else if (fgx == 0xffff)
+	    fgx = 0x52aa;
+    }
+
+    fgx |= (fgx << 16);
+    bgx |= (bgx << 16);
+    eorx = fgx ^ bgx;
+
+    switch (fontwidth(p)) {
+    case 4:
+    case 8:
+	while (count--) {
+	    c = scr_readw(s++) & p->charmask;
+	    cdat = p->fontdata + c * fontheight(p);
+
+	    splashbgx = splashbgx0;
+
+	    for (rows = fontheight(p), dest = dest0; rows--; dest += bytes) {
+		u8 bits = *cdat++;
+		SPLASH_BGX(0);
+	        fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest);
+		SPLASH_BGX(4);
+	        fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest+4);
+		if (fontwidth(p) == 8) {
+		    SPLASH_BGX(8);
+		    fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest+8);
+		    SPLASH_BGX(12);
+		    fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest+12);
+		}
+		splashbgx += splash_bytes;
+	    }
+
+	    dest0 += fontwidth(p)*2;
+	    splashbgx0 += fontwidth(p) * 2;
+	}
+
+	break;
+    case 12:
+    case 16:
+	while (count--) {
+	    c = scr_readw(s++) & p->charmask;
+	    cdat = p->fontdata + (c * fontheight(p) << 1);
+
+	    splashbgx = splashbgx0;
+
+	    for (rows = fontheight(p), dest = dest0; rows--; dest += bytes) {
+		u8 bits = *cdat++;
+		SPLASH_BGX(0);
+	        fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest);
+		SPLASH_BGX(4);
+	        fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest+4);
+		SPLASH_BGX(8);
+	        fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest+8);
+		SPLASH_BGX(12);
+	        fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest+12);
+		bits = *cdat++;
+		SPLASH_BGX(16);
+	        fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest+16);
+		SPLASH_BGX(20);
+	        fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest+20);
+		if (fontwidth(p) == 16) {
+		    SPLASH_BGX(24);
+		    fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest+24);
+		    SPLASH_BGX(28);
+		    fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest+28);
+		}
+		splashbgx += splash_bytes;
+	    }
+
+	    dest0 += fontwidth(p)*2;
+	    splashbgx0 += fontwidth(p) * 2;
+	}
+
+	break;
+    }
+}
+
+void fbcon_splash16_revc(struct display *p, int xx, int yy)
+{
+    u8 *dest;
+    int bytes = p->next_line, rows;
+
+    dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p)*2;
+    dest += splash_data.splash_text_yo * bytes + splash_data.splash_text_xo * 2;
+
+    for (rows = fontheight(p); rows--; dest += bytes) {
+	switch (fontwidth(p)) {
+	case 16:
+	    fb_writel(fb_readl(dest+24) ^ 0xffffffff, dest+24);
+	    fb_writel(fb_readl(dest+28) ^ 0xffffffff, dest+28);
+	    /* FALL THROUGH */
+	case 12:
+	    fb_writel(fb_readl(dest+16) ^ 0xffffffff, dest+16);
+	    fb_writel(fb_readl(dest+20) ^ 0xffffffff, dest+20);
+	    /* FALL THROUGH */
+	case 8:
+	    fb_writel(fb_readl(dest+8) ^ 0xffffffff, dest+8);
+	    fb_writel(fb_readl(dest+12) ^ 0xffffffff, dest+12);
+	    /* FALL THROUGH */
+	case 4:
+	    fb_writel(fb_readl(dest+0) ^ 0xffffffff, dest+0);
+	    fb_writel(fb_readl(dest+4) ^ 0xffffffff, dest+4);
+	}
+    }
+}
+
+void fbcon_splash16_clear_margins(struct vc_data *conp, struct display *p,
+			       int bottom_only)
+{
+    int bytes = p->next_line;
+    u32 bgx;
+
+    unsigned int right_start = conp->vc_cols*fontwidth(p);
+    unsigned int bottom_start = conp->vc_rows*fontheight(p);
+    unsigned int right_width, bottom_width;
+
+    int left_margin_width = splash_data.splash_text_xo;
+    int text_width = conp->vc_cols * fontwidth(p);
+    int right_margin_width = p->var.xres - text_width - left_margin_width;
+    int top_margin_height = splash_data.splash_text_yo;
+    int text_height = conp->vc_rows * fontheight(p);
+    int bottom_margin_height = p->var.yres - text_height - top_margin_height;
+ 
+    bgx = ((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
+
+    if (bottom_only == -1) {
+	printk(KERN_DEBUG "Called with bottom-only\n");
+	splashfill(p->screen_base, linux_splash, p->var.xres, p->var.yres, bytes, splash_bytes); 
+	return;
+    }
+
+    if (!bottom_only && (right_width = p->var.xres-right_start)) {
+  	/* left margin */
+	splashfill(p->screen_base + top_margin_height * bytes,
+		   linux_splash + top_margin_height * 
+		   splash_bytes, left_margin_width,
+		   text_height, bytes, splash_bytes);
+
+	/* right margin */
+	splashfill(p->screen_base + left_margin_width*2 + text_width*2 +
+		    top_margin_height * bytes, linux_splash +
+		    left_margin_width*2 + text_width*2 + top_margin_height *
+		    splash_bytes, right_margin_width, text_height,
+		    bytes, splash_bytes);
+    }
+
+    if ((bottom_width = p->var.yres-bottom_start))
+	/* bottom margin */
+	splashfill(p->screen_base + (top_margin_height + text_height) *
+		    bytes, linux_splash + (top_margin_height +
+		    text_height) * splash_bytes, p->var.xres, 
+		    bottom_margin_height, bytes, splash_bytes);
+
+    /* top margin */
+    splashfill(p->screen_base, linux_splash,
+	    p->var.xres, top_margin_height,
+	    bytes, splash_bytes);
+
+    /* leave function if work is done */
+    return;
+}
+
+
+    /*
+     *  `switch' for the low level operations
+     */
+
+struct display_switch fbcon_splash16 = {
+    bmove:		fbcon_splash16_bmove,
+    clear:		fbcon_splash16_clear,
+    putc:		fbcon_splash16_putc,
+    putcs:		fbcon_splash16_putcs,
+    revc:		fbcon_splash16_revc,
+    clear_margins:	fbcon_splash16_clear_margins,
+    fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+
+
+#ifdef MODULE
+MODULE_LICENSE("GPL");
+
+int init_module(void)
+{
+    return 0;
+}
+
+void cleanup_module(void)
+{}
+#endif /* MODULE */
+
+
+    /*
+     *  Visible symbols for modules
+     */
+
+EXPORT_SYMBOL(fbcon_splash16);
+EXPORT_SYMBOL(fbcon_splash16_bmove);
+EXPORT_SYMBOL(fbcon_splash16_clear);
+EXPORT_SYMBOL(fbcon_splash16_putc);
+EXPORT_SYMBOL(fbcon_splash16_putcs);
+EXPORT_SYMBOL(fbcon_splash16_revc);
+EXPORT_SYMBOL(fbcon_splash16_clear_margins);
diff -urN linux-2.4.24.org/drivers/video/fbcon-splash.c linux-2.4.24/drivers/video/fbcon-splash.c
--- linux-2.4.24.org/drivers/video/fbcon-splash.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.24/drivers/video/fbcon-splash.c	2004-01-19 21:03:48.216680056 +0100
@@ -0,0 +1,848 @@
+/* 
+ *    linux/drivers/video/fbcon-splash.c - splash screen handling functions.
+ *	
+ *	(w) 2001-2003 by Volker Poplawski, <volker@suse.de>
+ * 		    Stefan Reinauer, <stepan@suse.de>
+ * 		    Steffen Winterfeldt, <snwint@suse.de>
+ * 		    
+ * 	       Ideas & SuSE screen work by Ken Wimer, <wimer@suse.de>
+ */
+
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/fb.h>
+#include <linux/vt_kern.h>
+#include <linux/vmalloc.h>
+
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include <video/fbcon.h>
+#include <video/font.h>
+#include <video/fbcon-cfb16.h>  /* for fbcon_cfb16 */
+
+#include "fbcon-splash.h"
+#include "fbcon-jpegdec.h"
+
+#define SPLASH_VERSION "3.0.7-2003/03/10"
+
+#ifdef CONFIG_BLK_DEV_INITRD
+unsigned char signature[] = "BOOTSPL1SPL2SPL3";
+#endif
+
+/* from drivers/char/console.c */
+extern void con_remap_def_color(int currcons, int new_color);
+
+/* from drivers/video/fbcon-splash16.c */
+extern void splashfill(u8 *dest, u8 *src, int width, int height, 
+			int dest_linesize, int src_linesize);
+
+/* internal control states and data pointers */
+struct splash_data splash_data;
+
+unsigned char *linux_splash;	/* decoded picture */
+int linux_splash_size = 0;
+
+static struct jpeg_decdata *decdata = 0; /* private decoder data */
+
+int splash_bytes;		/* bytes per line in linux_splash */
+int splash_shown = 0;		/* is the splash onscreen? */
+int splash_usesilent = 0;	/* shall we display the silentjpeg */
+int splash_default = 0xf01;
+
+static int splash_status(struct display *p);
+static int splash_recolor(struct display *p);
+static int splash_check_jpeg(unsigned char *jpeg, int width, int height, int depth);
+
+extern struct display_switch fbcon_splash16;
+
+int __init splash_init(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_init);
+
+
+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;
+
+    if (num == 0)
+	return;
+    bufend = buf + num * 12;
+    while(buf < bufend) {
+	doblend = 0;
+	buf += boxextract(buf, data1, cols1, &doblend);
+	if (data1[0] > 32767)
+	    buf += boxextract(buf, data2, cols2, &doblend);
+	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;
+	for (y = data1[1]; y <= data1[3]; y++) {
+	    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 = (data1[0] & 1);
+	    add ^= (add ^ y) & 1 ? 1 : 3;		/* 2x2 ordered dithering */
+	    picp = (unsigned short *)(pic + data1[0] * 2 + y * bytes);
+	    for (x = data1[0]; x <= data1[2]; x++) {
+		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 "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 "error %d while decompressing picture.\n",err);
+    vfree(mem);
+    return err ? -1 : 0;
+}
+
+static void splash_free(struct display * p)
+{
+    if (!p->splash_data)
+	return;
+    if (p->splash_data->oldscreen_base)
+	    p->screen_base = p->splash_data->oldscreen_base;
+    if (p->splash_data->olddispsw)
+	    p->dispsw = p->splash_data->olddispsw;
+    if (p->splash_data->splash_silentjpeg)
+	    vfree(p->splash_data->splash_sboxes);
+    vfree(p->splash_data);
+    p->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;
+}
+
+int splash_getraw(unsigned char *start, unsigned char *end)
+{
+	unsigned char *ndata;
+	int found = 0;
+	int splash_size = 0;
+	void *splash_start = 0;
+        int unit = 0;
+        int width = 0, height = 0;
+	int silentsize;
+	int boxcount = 0;
+	int sboxcount = 0;
+	int palcnt = 0;
+	struct display *p;
+
+	printk(KERN_INFO "Looking for splash picture...");
+
+	p = &fb_display[0];
+        silentsize = 0;
+
+	for (ndata = start; ndata < end; ndata++) {
+		if (*((unsigned int *)ndata) != *((unsigned int *)signature))
+			continue;
+		if (*((unsigned int *)(ndata+4))==*((unsigned int *)(signature+4))) {
+			printk(".");
+			unit = 0;
+			p = &fb_display[0];
+			width = p->var.xres;
+			height = p->var.yres;
+
+			splash_size = ndata[16] + (ndata[17] << 8) + (ndata[18] << 16) + (ndata[19] << 24);
+			if (ndata + 20 + splash_size > end) {
+				printk(" found, but truncated!\n");
+				return -1;
+			}
+			if (!jpeg_check_size(ndata + 20, width, height)) { 
+				ndata += 20 - 1 + splash_size;
+				continue;
+			}
+			if (splash_check_jpeg(ndata + 20, width, height, p->var.bits_per_pixel))
+				return -1;
+			if (p->splash_data)
+				splash_free(p);
+			p->splash_data = vmalloc(sizeof(*p->splash_data) + splash_size + 24);
+			if (!p->splash_data)
+				break;
+
+			p->splash_data->oldscreen_base = 0;
+			p->splash_data->olddispsw = 0;
+			p->splash_data->splash_silentjpeg = 0;
+
+			p->splash_data->splash_text_xo = ndata[ 8] + (ndata[ 9] << 8);
+			p->splash_data->splash_text_yo = ndata[10] + (ndata[11] << 8);
+			p->splash_data->splash_text_wi = ndata[12] + (ndata[13] << 8);
+			p->splash_data->splash_text_he = ndata[14] + (ndata[15] << 8);
+			/* use 8x16 font... */
+			p->splash_data->splash_text_xo *= 8;
+			p->splash_data->splash_text_wi *= 8;
+			p->splash_data->splash_text_yo *= 16;
+			p->splash_data->splash_text_he *= 16;
+			p->splash_data->splash_color = (splash_default >> 8) & 0x0f;
+			p->splash_data->splash_fg_color = (splash_default >> 4) & 0x0f;
+			p->splash_data->splash_state = splash_default & 1;
+			p->splash_data->splash_percent = 0;
+			p->splash_data->splash_overpaintok = 0;
+			boxcount = splash_mkpenguin(p->splash_data, p->splash_data->splash_text_xo + 10, p->splash_data->splash_text_yo + 10, p->splash_data->splash_text_wi - 20, p->splash_data->splash_text_he - 20, 0xf0, 0xf0, 0xf0);
+			splash_start = ndata + 20;
+			found = 1;
+			break;
+		}
+		if (*((unsigned int *)(ndata + 4)) == *((unsigned int *)(signature+8))) {
+			printk(".");
+			unit = ndata[8];
+			if (unit >= MAX_NR_CONSOLES)
+			    continue;
+			if (unit)
+			    vc_allocate(unit);
+			p = &fb_display[unit];
+			width = fb_display[unit].var.xres;
+			height = fb_display[unit].var.yres;
+			splash_size = ndata[12] + (ndata[13] << 8) + (ndata[14] << 16) + (ndata[15] << 24);
+			if (splash_size == -1) {
+			    printk(" found, updating values.\n");
+			    if (p->splash_data) {
+				if (ndata[9] != 255)
+				    p->splash_data->splash_state = ndata[9];
+				if (ndata[10] != 255)
+				    p->splash_data->splash_fg_color = ndata[10];
+				if (ndata[11] != 255)
+				    p->splash_data->splash_color = ndata[11];
+			    }
+			    return unit;
+			}
+			if (splash_size == 0) {
+				printk(" found, freeing memory.\n");
+				if (p->splash_data)
+					splash_free(p);
+				return unit;
+			}
+			if (ndata + 35 + splash_size > end) {
+				printk(" found, but truncated!\n");
+				return -1;
+			}
+			if (!jpeg_check_size(ndata + 35, width, height)) {
+				ndata += 35 - 1 + splash_size;
+				continue;
+			}
+			if (splash_check_jpeg(ndata + 35, width, height, p->var.bits_per_pixel))
+				return -1;
+			if (p->splash_data)
+				splash_free(p);
+			p->splash_data = vmalloc(sizeof(*p->splash_data) + splash_size + 24);
+			if (!p->splash_data)
+				break;
+
+			p->splash_data->oldscreen_base = 0;
+			p->splash_data->olddispsw = 0;
+			p->splash_data->splash_silentjpeg = 0;
+
+			p->splash_data->splash_state = ndata[9];
+			p->splash_data->splash_fg_color = ndata[10];
+			p->splash_data->splash_color = ndata[11];
+			p->splash_data->splash_text_xo = ndata[16] + (ndata[17] << 8);
+			p->splash_data->splash_text_yo = ndata[18] + (ndata[19] << 8);
+			p->splash_data->splash_text_wi = ndata[20] + (ndata[21] << 8);
+			p->splash_data->splash_text_he = ndata[22] + (ndata[23] << 8);
+			p->splash_data->splash_percent = 0;
+			p->splash_data->splash_overpaintok = 0;
+			boxcount = splash_mkpenguin(p->splash_data, ndata[24] + (ndata[25] << 8), ndata[26] + (ndata[27] << 8), ndata[28] + (ndata[29] << 8), ndata[30] + (ndata[31] << 8), ndata[32], ndata[33], ndata[34]);
+			splash_start = ndata + 35;
+			found = 2;
+			break;
+		}
+		if (*((unsigned int *)(ndata + 4)) == *((unsigned int *)(signature+12))) {
+			printk(".");
+			unit = ndata[8];
+			if (unit >= MAX_NR_CONSOLES)
+			    continue;
+			if (unit)
+			    vc_allocate(unit);
+			p = &fb_display[unit];
+			width = p->var.xres;
+			height = p->var.yres;
+			splash_size = ndata[12] + (ndata[13] << 8) + (ndata[14] << 16) + (ndata[15] << 24);
+			if (splash_size == -1) {
+			    printk(" found, updating values.\n");
+			    if (p->splash_data) {
+				if (ndata[9] != 255)
+				    p->splash_data->splash_state = ndata[9];
+				if (ndata[10] != 255)
+				    p->splash_data->splash_fg_color = ndata[10];
+				if (ndata[11] != 255)
+				    p->splash_data->splash_color = ndata[11];
+			    }
+			    return unit;
+			}
+			if (splash_size == 0) {
+				printk(" found, freeing memory.\n");
+				if (p->splash_data)
+					splash_free(p);
+				return unit;
+			}
+			boxcount = ndata[24] + (ndata[25] << 8);
+			palcnt = ndata[37] * 3;
+			if (ndata + 38 + splash_size > end) {
+				printk(" found, but truncated!\n");
+				return -1;
+			}
+			if (!jpeg_check_size(ndata + 38 + boxcount * 12 + palcnt, width, height)) {
+				ndata += 38 - 1 + splash_size;
+				continue;
+			}
+			if (splash_check_jpeg(ndata + 38 + boxcount * 12 + palcnt, width, height, p->var.bits_per_pixel))
+				return -1;
+			silentsize = ndata[28] + (ndata[29] << 8) + (ndata[30] << 16) + (ndata[31] << 24);
+			if (silentsize)
+			    printk(" silenjpeg size %d bytes,", silentsize);
+			if (silentsize >= splash_size) {
+				printk(" bigger than splashsize!\n");
+				return -1;
+			}
+			splash_size -= silentsize;
+			if (!splash_usesilent || !p->fb_info->fbops->fb_get_fix ) {
+				silentsize = 0;
+			} else {
+				struct fb_fix_screeninfo fix;
+				p->fb_info->fbops->fb_get_fix(&fix, unit, 0);
+				if (height * 2 * p->next_line > fix.smem_len) {
+					printk(" does not fit into framebuffer.\n");
+					silentsize = 0;
+				}
+			}
+
+			sboxcount = ndata[32] + (ndata[33] << 8);
+			if (silentsize) {
+				char *simage=ndata + 38 + splash_size + 12 * sboxcount;
+				if (!jpeg_check_size(simage, width, height) ||
+				    splash_check_jpeg(simage, width, height, p->var.bits_per_pixel)) {
+					printk(" error in silent jpeg.\n");
+					silentsize = 0;
+				}
+			}
+			if (p->splash_data)
+				splash_free(p);
+			p->splash_data = vmalloc(sizeof(*p->splash_data) + splash_size);
+			if (!p->splash_data)
+				break;
+			p->splash_data->oldscreen_base = 0;
+			p->splash_data->olddispsw = 0;
+			p->splash_data->splash_silentjpeg = 0;
+			if (silentsize) {
+				p->splash_data->splash_silentjpeg = vmalloc(silentsize);
+				if (p->splash_data->splash_silentjpeg) {
+					memcpy(p->splash_data->splash_silentjpeg, ndata + 38 + splash_size, silentsize);
+					p->splash_data->splash_sboxes = p->splash_data->splash_silentjpeg;
+					p->splash_data->splash_silentjpeg += 12 * sboxcount;
+					p->splash_data->splash_sboxcount = sboxcount;
+				}
+			}
+			p->splash_data->splash_state = ndata[9];
+			p->splash_data->splash_fg_color = ndata[10];
+			p->splash_data->splash_color = ndata[11];
+			p->splash_data->splash_overpaintok = ndata[36];
+			p->splash_data->splash_text_xo = ndata[16] + (ndata[17] << 8);
+			p->splash_data->splash_text_yo = ndata[18] + (ndata[19] << 8);
+			p->splash_data->splash_text_wi = ndata[20] + (ndata[21] << 8);
+			p->splash_data->splash_text_he = ndata[22] + (ndata[23] << 8);
+			p->splash_data->splash_percent = ndata[34] + (ndata[35] << 8);
+			p->splash_data->splash_percent += p->splash_data->splash_percent > 32767;
+			splash_start = ndata + 38;
+			found = 3;
+			break;
+		}
+	}
+	
+	if (!found) {
+		printk(" no good signature found.\n");
+		return -1;
+	}
+	if (p->splash_data->splash_text_xo + p->splash_data->splash_text_wi > width || p->splash_data->splash_text_yo + p->splash_data->splash_text_he > height) {
+		splash_free(p);
+		p->splash_data = 0;
+		printk(" found, but has oversized text area!\n");
+		return -1;
+	}
+	if (p->dispsw->setup != fbcon_cfb16.setup) {
+		splash_free(p);
+		p->splash_data = 0;
+		printk(" found, but framebuffer can't handle it!\n");
+		return -1;
+	}
+	printk(" found (%dx%d, %d bytes, v%d).\n", width, height, splash_size, found);
+
+	if (found==1) {
+		printk(KERN_WARNING "bootsplash: Using deprecated v1 header. Updating your splash utility recommended.\n");
+		printk(KERN_INFO    "bootsplash: Find the latest version at ftp.suse.com/pub/people/stepan/bootsplash/\n");
+	}
+
+	/* copy data so that initrd memory can be freed. */
+	memcpy((char *)p->splash_data + sizeof(*p->splash_data) + (found < 3 ? boxcount * 12 : 0), splash_start, splash_size);
+	p->splash_data->splash_boxcount = boxcount;
+	p->splash_data->splash_boxes = (unsigned char *)p->splash_data + sizeof(*p->splash_data);
+	p->splash_data->splash_jpeg = (unsigned char *)p->splash_data + sizeof(*p->splash_data) + boxcount * 12 + palcnt;
+	p->splash_data->splash_palette = (unsigned char *)p->splash_data + sizeof(*p->splash_data) + boxcount * 12;
+	p->splash_data->splash_palcnt = palcnt / 3;
+	p->splash_data->splash_dosilent = p->splash_data->splash_silentjpeg != 0;
+	return unit;
+}
+
+int splash_verbose(void) 
+{
+    struct display *p;
+
+    p = &fb_display[0];
+    if (!p || !p->splash_data || !p->splash_data->splash_state || !p->conp)
+	return 0;
+    if (fg_console != p->conp->vc_num)
+	return 0;
+    if (!p->splash_data->splash_silentjpeg || !p->splash_data->splash_dosilent)
+	return 0;
+    if (!p->splash_data->oldscreen_base)
+	return 0;
+
+    p->splash_data->splash_dosilent = 0;
+
+    splashfill(p->splash_data->oldscreen_base, p->screen_base, p->var.xres, p->var.yres, p->next_line, p->next_line);
+    p->screen_base = p->splash_data->oldscreen_base;
+
+    return 1;
+}
+
+static void splash_off(struct display *p)
+{
+    if (p->splash_data && p->splash_data->oldscreen_base)
+	p->screen_base = p->splash_data->oldscreen_base;
+    if (p->splash_data && p->splash_data->olddispsw)
+	p->dispsw = p->splash_data->olddispsw;
+    splash_shown = 0;
+}
+
+int splash_prepare(struct display *p)
+{
+	int err;
+        int width, height, depth, size, sbytes;
+
+	if (!p->splash_data || !p->splash_data->splash_state) {
+		if (linux_splash)
+			vfree(linux_splash);
+		if (decdata)
+			vfree(decdata);
+		linux_splash = 0;
+		decdata = 0;
+		linux_splash_size = 0;
+		splash_off(p);
+		return -1;
+	}
+
+        width = p->var.xres;
+        height = p->var.yres;
+        depth = p->var.bits_per_pixel;
+	if (depth != 16) {	/* Other targets might need fixing */
+		splash_off(p);
+		return -2;
+	}
+
+	sbytes = ((width + 15) & ~15) * (depth >> 3);
+	size = sbytes * ((height + 15) & ~15);
+	if (size != linux_splash_size) {
+		if (linux_splash)
+			vfree(linux_splash);
+		linux_splash_size = 0;
+		linux_splash = 0;
+		splash_off(p);
+	}
+	if (!linux_splash)
+		linux_splash = vmalloc(size);
+
+	if (!linux_splash) {
+		linux_splash_size = 0;
+		printk(KERN_INFO "Not enough memory for splash screen.\n");
+		splash_off(p);
+		return -3;
+	}
+
+	if (!decdata)
+	    decdata = vmalloc(sizeof(*decdata));
+
+	if (!p->splash_data->oldscreen_base)
+		p->splash_data->oldscreen_base = p->screen_base;
+
+	if (p->splash_data->splash_silentjpeg && p->splash_data->splash_dosilent) {
+		printk(KERN_INFO "Got silent jpeg.\n");
+		/* fill area after framebuffer with other jpeg */
+		if ((err = jpeg_decode(p->splash_data->splash_silentjpeg, linux_splash, 
+			 ((width + 15) & ~15), ((height + 15) & ~15), depth, decdata))) {
+			printk(KERN_INFO "Error %d while decompressing silent jpeg.\n", err);
+			p->screen_base = p->splash_data->oldscreen_base;
+			p->splash_data->splash_dosilent = 0;
+		} else {
+			if (p->splash_data->splash_sboxcount)
+				boxit(linux_splash, sbytes, p->splash_data->splash_sboxes, 
+					p->splash_data->splash_sboxcount, p->splash_data->splash_percent, 0);
+
+			splashfill(p->screen_base, linux_splash, p->var.xres, p->var.yres, p->next_line, sbytes);
+			p->screen_base = p->splash_data->oldscreen_base + p->next_line * p->var.yres;
+		}
+	} else
+		p->screen_base = p->splash_data->oldscreen_base;
+
+	if ((err = jpeg_decode(p->splash_data->splash_jpeg, linux_splash, 
+		 ((width + 15) & ~15), ((height + 15) & ~15), depth, decdata))) {
+		printk(KERN_INFO "Error %d while decompressing splash screen.\n", err);
+		vfree(linux_splash);
+		linux_splash = 0;
+		linux_splash_size = 0;
+		splash_off(p);
+		return -4;
+	}
+	linux_splash_size = size;
+	splash_bytes = sbytes;
+	if (p->splash_data->splash_boxcount)
+		boxit(linux_splash, sbytes, p->splash_data->splash_boxes, p->splash_data->splash_boxcount, p->splash_data->splash_percent, 0);
+	splash_data = *p->splash_data;
+	splash_shown = p->splash_data->splash_state;
+	if (splash_shown) {
+	    if (p->dispsw != &fbcon_splash16)
+		p->splash_data->olddispsw = p->dispsw;
+	    p->dispsw = &fbcon_splash16;
+	} else
+		splash_off(p);
+	return 0;
+}
+
+
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+
+struct proc_dir_entry *proc_splash;
+int splash_read_proc(char *buffer, char **start, off_t offset, int size,
+			int *eof, void *data);
+int splash_write_proc(struct file *file, const char *buffer,
+			unsigned long count, void *data);
+
+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 display *p = &fb_display[0];
+
+	int color = p->splash_data ? p->splash_data->splash_color << 4 |
+			p->splash_data->splash_fg_color : splash_default >> 4;
+	int status = p->splash_data ? p->splash_data->splash_state & 1 : 0;
+	len += sprintf(buffer + len, "Splash screen v%s (0x%02x, %dx%d%s): %s\n",
+		        SPLASH_VERSION, color, p->var.xres, p->var.yres,
+			(p->splash_data ?  p->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);
+}
+
+static int splash_recolor(struct display *p)
+{
+	if (!p->splash_data)
+	    return -1;
+	if (!p->splash_data->splash_state)
+	    return 0;
+	con_remap_def_color(p->conp->vc_num, p->splash_data->splash_color << 4 | p->splash_data->splash_fg_color);
+	if (fg_console == p->conp->vc_num) {
+	        splash_data = *p->splash_data;
+		update_region(fg_console,
+			      p->conp->vc_origin +
+			      p->conp->vc_size_row *
+			      p->conp->vc_top,
+			      p->conp->vc_size_row *
+			      (p->conp->vc_bottom -
+			       p->conp->vc_top) / 2);
+	}
+	return 0;
+}
+
+static int splash_status(struct display *p)
+{
+	printk(KERN_INFO "Splash status on console %d changed to %s\n", p->conp->vc_num, p->splash_data && p->splash_data->splash_state ? "on" : "off");
+
+	if (fg_console == p->conp->vc_num)
+		splash_prepare(p);
+	if (p->splash_data && p->splash_data->splash_state) {
+		con_remap_def_color(p->conp->vc_num, p->splash_data->splash_color << 4 | p->splash_data->splash_fg_color);
+		/* resize_con also calls con_switch which resets yscroll */
+		vc_resize_con(p->splash_data->splash_text_he / fontheight(p),
+                              p->splash_data->splash_text_wi / fontwidth(p),
+                              p->conp->vc_num);
+		if (fg_console == p->conp->vc_num) {
+			update_region(fg_console,
+				      p->conp->vc_origin +
+				      p->conp->vc_size_row *
+				      p->conp->vc_top,
+				      p->conp->vc_size_row *
+				      (p->conp->vc_bottom -
+				       p->conp->vc_top) / 2);
+			    fbcon_splash16.clear_margins(p->conp, p, 0);
+		}
+	} else {
+	  	/* Switch bootsplash off */
+		con_remap_def_color(p->conp->vc_num, 0x07);
+		vc_resize_con(p->var.yres / fontheight(p),
+			      p->var.xres / fontwidth(p),
+			      p->conp->vc_num);
+	}
+	return 0;
+}
+
+int splash_write_proc(struct file *file, const char *buffer,
+		      unsigned long count, void *data)
+{
+        int new, unit;
+	struct display *p;
+	
+	if (!buffer || !splash_default)
+		return count;
+
+	if (!strncmp(buffer, "show", 4) || !strncmp(buffer, "hide", 4)) {
+		int pe;
+
+		p = &fb_display[0];
+		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;
+		pe += pe > 32767;
+		if (p->splash_data && p->splash_data->splash_percent != pe) {
+			p->splash_data->splash_percent = pe;
+			if (fg_console != p->conp->vc_num || !p->splash_data->splash_state)
+			    return count;
+			if (!p->splash_data->splash_overpaintok || p->splash_data->splash_percent == 65536) {
+				if (splash_hasinter(p->splash_data->splash_boxes, p->splash_data->splash_boxcount))
+					splash_status(p);
+				else
+					splash_prepare(p);
+			} else {
+				if (p->splash_data->splash_silentjpeg && p->splash_data->splash_dosilent && p->splash_data->oldscreen_base)
+					boxit(p->splash_data->oldscreen_base, p->next_line, p->splash_data->splash_sboxes, p->splash_data->splash_sboxcount, p->splash_data->splash_percent, 1);
+				boxit(p->screen_base, p->next_line, p->splash_data->splash_boxes, p->splash_data->splash_boxcount, p->splash_data->splash_percent, 1);
+			}
+		}
+		return count;
+	}
+	if (!strncmp(buffer,"silent\n",7) || !strncmp(buffer,"verbose\n",8)) {
+		p = &fb_display[0];
+		if (p->splash_data && p->splash_data->splash_silentjpeg) {
+		    if (p->splash_data->splash_dosilent != (buffer[0] == 's')) {
+			p->splash_data->splash_dosilent = buffer[0] == 's';
+			splash_status(p);
+		    }
+		}
+		return count;
+	}
+	if (!strncmp(buffer,"freesilent\n",11)) {
+		p = &fb_display[0];
+		if (p->splash_data && p->splash_data->splash_silentjpeg) {
+		    printk(KERN_INFO "bootsplash: freeing silent jpeg\n");
+		    p->splash_data->splash_silentjpeg = 0;
+		    vfree(p->splash_data->splash_sboxes);
+		    p->splash_data->splash_sboxes = 0;
+		    p->splash_data->splash_sboxcount = 0;
+		    if (p->splash_data->splash_dosilent)
+			splash_status(p);
+		    p->splash_data->splash_dosilent = 0;
+		}
+		return count;
+	}
+
+	if (!strncmp(buffer, signature, 7)) {
+	    unit = splash_getraw((unsigned char *)buffer, (unsigned char *)buffer + count);
+	    if (unit >= 0) {
+		p = &fb_display[unit];
+		splash_status(p);
+	    }
+	    return count;
+	}
+	p = &fb_display[0];
+	if (!p->splash_data)
+		return count;
+	if (buffer[0] == 't') {
+	        p->splash_data->splash_state ^= 1;
+		splash_status(p);
+		return count;
+	}
+	new = simple_strtoul(buffer, NULL, 0);
+	if (new > 1) {
+		/* expert user */
+		p->splash_data->splash_color    = new >> 8 & 0xff;
+		p->splash_data->splash_fg_color = new >> 4 & 0x0f;
+	}
+	if ((new & 1) == p->splash_data->splash_state)
+		splash_recolor(p);
+	else {
+	        p->splash_data->splash_state = new & 1;
+		splash_status(p);
+	}
+	return count;
+}
+
+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;
+}
+
+int splash_proc_unregister(void)
+{
+	if (proc_splash)
+		remove_proc_entry("splash", 0);
+	return 0;
+}
+#endif
diff -urN linux-2.4.24.org/drivers/video/fbcon-splash.h linux-2.4.24/drivers/video/fbcon-splash.h
--- linux-2.4.24.org/drivers/video/fbcon-splash.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.24/drivers/video/fbcon-splash.h	2004-01-19 21:03:48.218679640 +0100
@@ -0,0 +1,18 @@
+/* 
+ *    linux/drivers/video/splash.h - splash screen definition.
+ *	
+ *	(w) 2001-2003 by Volker Poplawski, <volker@suse.de>
+ * 		    Stefan Reinauer, <stepan@suse.de>
+ * 		    
+ * 		    
+ * 	idea and SuSE screen work by Ken Wimer, <wimer@suse.de>
+ */
+
+extern int splash_getraw(unsigned char *, unsigned char *);
+extern int splash_prepare(struct display *);
+
+extern int splash_shown;		/* is splash shown? */
+extern struct splash_data splash_data;	/* image data, copied over
+					   from display */
+extern unsigned char *linux_splash;	/* decoded pic data */
+extern int splash_bytes;		/* bytes per line */
diff -urN linux-2.4.24.org/drivers/video/Makefile linux-2.4.24/drivers/video/Makefile
--- linux-2.4.24.org/drivers/video/Makefile	2004-01-19 21:01:12.732012987 +0100
+++ linux-2.4.24/drivers/video/Makefile	2004-01-19 21:05:58.628528100 +0100
@@ -14,7 +14,7 @@
 		  fbcon-vga.o fbcon-iplan2p2.o fbcon-iplan2p4.o \
 		  fbcon-iplan2p8.o fbcon-vga-planes.o fbcon-cfb16.o \
 		  fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o \
-		  fbcon-cfb8.o fbcon-mac.o fbcon-mfb.o \
+		  fbcon-cfb8.o fbcon-splash16.o fbcon-mac.o fbcon-mfb.o \
 		  cyber2000fb.o sa1100fb.o fbcon-hga.o fbgen.o macmodes.o
 
 # Each configuration option enables a list of files.
@@ -159,6 +159,10 @@
 obj-$(CONFIG_FBCON_HGA)           += fbcon-hga.o
 obj-$(CONFIG_FBCON_STI)           += fbcon-sti.o
 
+obj-$(CONFIG_FBCON_SPLASHSCREEN)  += fbcon-splash.o
+obj-$(CONFIG_FBCON_SPLASHSCREEN)  += fbcon-splash16.o
+obj-$(CONFIG_FBCON_SPLASHSCREEN)  += fbcon-jpegdec.o
+
 include $(TOPDIR)/Rules.make
 
 clean:
diff -urN linux-2.4.24.org/include/video/fbcon.h linux-2.4.24/include/video/fbcon.h
--- linux-2.4.24.org/include/video/fbcon.h	2004-01-19 20:59:23.213788389 +0100
+++ linux-2.4.24/include/video/fbcon.h	2004-01-19 21:03:48.295663632 +0100
@@ -42,6 +42,35 @@
     unsigned int fontwidthmask;      /* 1 at (1 << (width - 1)) if width is supported */
 }; 
 
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+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;
+	struct display_switch *olddispsw;	/* old dispsw, normally &fbcon_cfb16*/
+	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
+
 extern struct display_switch fbcon_dummy;
 
    /*
@@ -95,6 +124,10 @@
     short yscroll;                  /* Hardware scrolling */
     unsigned char fgshift, bgshift;
     unsigned short charmask;        /* 0xff or 0x1ff */
+
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+    struct splash_data *splash_data;
+#endif
 };
 
 /* drivers/video/fbcon.c */
diff -urN linux-2.4.24.org/kernel/panic.c linux-2.4.24/kernel/panic.c
--- linux-2.4.24.org/kernel/panic.c	2004-01-19 20:58:34.218977671 +0100
+++ linux-2.4.24/kernel/panic.c	2004-01-19 21:03:48.336655108 +0100
@@ -83,6 +83,13 @@
 		 * We can't use the "normal" timers since we just panicked..
 	 	 */
 		printk(KERN_EMERG "Rebooting in %d seconds..",panic_timeout);
+
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+		{
+			extern int splash_verbose(void);
+			(void)splash_verbose();
+		}
+#endif
 		mdelay(panic_timeout*1000);
 		/*
 		 *	Should we run the reboot notifier. For the moment Im
@@ -103,6 +110,12 @@
         disabled_wait(caller);
 #endif
 	sti();
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+	{
+		extern int splash_verbose(void);
+		(void)splash_verbose();
+	}
+#endif
 	for(;;) {
 #if defined(CONFIG_X86) && defined(CONFIG_VT) 
 		extern void panic_blink(void);