[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[debian-knoppix] Suse style Framebuffer boot



Hi there, 
I mentioned a while ago about a LPP boot. 
LPP is the Linux Progress Patch, and introduces a framebuffer progress page 
with progress bar. I got it working, but there were some drawbacks - 
 1) required compiling the image into the kernel
 2) required adding CONSOLE=/dev/tty2 to the append line
 3) if they didn't have vesa fb then they saw nothing
 4) didn't work if it wasn't interactive, i.e if the startup required 
interaction, then you would not see it. 
conclusion :  lpp is suitable for harddrive installs only. 

Then I came along the suse kernel patch, with "splash" program

This is the framebuffer bootup that you see on suse machines. 
it overcomes _all_ the drawbacks of lpp :
	1) the image is stored seperatly ( in miniroot.gz )
	2) the console stays on tty1, as it is just written ontop of the image ( in a 
set area)
	3) if you don't have vesa fb compatible card, you just see normal knoppix 
bootup
	4) Made in .de ;)
one disadvantage - requires a statically compiled binary to be included in 
miniroot.gz

It creates a framebuffer image and draws the console text over top of the 
image, which is in jpeg format. I have implemented this in a remaster and it 
works well. 

I have used isolinux, so size wasn't an issue.
my image is 49KB, but could be smaller if more jpeg compression is used ( 
again not an issue with isolinux )
The statically compiled splash program is 384K. 

Recipe : ( makes 800x600 ;)
Ingredients
	- 800x600 Jpg - example attached ( made with gimp - if anyone wants the .xcf 
email me )
	- config file for the jpg - example attached
	- kernel patch - attached 
	- "splash" program - sources attached
all above programs and additinal documentation can be found at 
ftp://ftp.suse.com/pub/people/stepan/bootsplash

What I did Instructions: ( no these wont make sence to everyone just to people 
who have remastered or Klaus )

statically compiled the splash.c program ( with gcc --static option ) and put 
it in /static of miniroot.gz

made a directory "/splash" in miniroot.gz and put the .jpg and .cfg file there
compiled a kernel with the patch ( after patching, make sure that the 
"CONFIG_FBCON_SPLASHSCREEN" is Y - in fb section.) then compile. 

replace the vmlinuz and kernel modules both in miniroot.gz, and in 
/lib/modules/ etc with the compiled ones. ( you will prolly want to edit the 
kernel Makefile and chage the version )

change linuxrc ( in miniroot.gz)  to do the bootscreen. I have attached my  
linuxrc. basicly the change is adding

splash -s -u 0 /splash/bootsplash-800x600.cfg 2>&1 > /dev/null
 where -u is the TTY. 

now, for those wanting to see this in action, you can download bootdemo.iso 
from my site. Burn this image onto CD as you would knoppix. It's only 1.9M, 
but must be burned onto CD as an ISO. It will start loading knoppix, but fail 
at the "accessing KNOPPIX on cdrom", as I have left out the KNOPPIX file. 
download from http://www.knoppix.net/mirror/bootdemo.iso

As for syslinux vs isolinux
as kernel sized increase ( read 2.6 ) there is need for a larger boot image. 
By not limiting the boot sequence to 1.44 M you can achive a lot more : 

- nice fb boot screens
- memtest boot option
- localboot option
- multiple kernels ( e.g. non-SMP for dell machines that break when used with 
SMP kernel )

you can still include a 1.44M floppy image, without the above features for 
people that cannot boot off isolinux (who?), and provide instructions on how 
to do this ( easy with nero for example )

Hope this is of interest, and I hope this gets included with KNOPPIX, as the 
framebuffer boot is so sexy!!

Best Regards
Eaden McKee

Attachment: bootsplash-800x600.jpg
Description: JPEG image

# This is the configuration file for the bootsplash pictures for SuSE-Linux 8.1.
# This file is necessary to specify the coordinates of the text box on
# the splash screen.
#
# Comments are welcome by stepan@suse.de

# config file version
version=2

# should the picture be displayed?
state=1

# fgcolor is the text forground color.
# bgcolor is the text background (i.e. transparent) color.
fgcolor=FFFFFF
bgcolor=000000

# (tx, ty) are the (x, y) coordinates of the text window in pixels.
# tw/th is the width/height of the text window in pixels.
tx=35
ty=201
tw=663
th=370

# (ax, ay) are the (x, y) coordinates for playing boot/shutdown animations
#ax=112
#ay=30

# name of the picture file (full path recommended)
jpeg=/splash/bootsplash-800x600.jpg
/* Splash control program.
 * 
 * (c) 2001, 2002 by Stefan Reinauer <stepan@suse.de>
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version
 * 2 of the License, or (at your option) any later version.
 *
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <libgen.h>
#include <getopt.h>

#define PROCSPLASH "/proc/splash"
#define SPLASHDSC  "/usr/share/splash/splash.dsc"
#define BUFSIZE 4096

#ifndef FBMNGDEBUG
#define DEBUG(x...)
#else
#define DEBUG(x...) printf(x)
#endif

int unit = 0;
int version = 1;
int state = -1;
int fgcolor = -1;
int bgcolor = -1;
int tx = -1;
int ty = -1;
int tw = -1;
int th = -1;
int px = 0;
int py = 0;
int pw = 0;
int ph = 0;
int pr = 0;
int pg = 0;
int pb = 0;

struct parstab {
    char *name;
    int *val;
} parstab[] = {
    {"unit", &unit},
    {"version", &version},
    {"state", &state},
    {"fgcolor", &fgcolor},
    {"bgcolor", &bgcolor},
    {"tx", &tx},
    {"ty", &ty},
    {"tw", &tw},
    {"th", &th},
    {"px", &px},
    {"py", &py},
    {"pw", &pw},
    {"ph", &ph},
    {"pr", &pr},
    {"pg", &pg},
    {"pb", &pb},
    {"jpeg", (int *)0},
    {(char *)0, (int *)0},
};

void setsplash(char *cfgfile, int filterflag)
{
	struct stat stb;
	char buf[256];
	char *jpgfile = 0;
	char *p;
	int l, size, fd;
	FILE *fp = 0;
	struct parstab *pt;
	unsigned char *pic;

	if (cfgfile) {
		if ((fp = fopen(cfgfile, "r")) == 0) {
			perror(cfgfile);
			exit(1);
		}
		while (fgets(buf, sizeof(buf), fp)) {
			l = strlen(buf);
			if (l == 0)
				continue;
			if (l == sizeof(buf) - 1) {
			    fprintf(stderr, "line too long\n");
			    exit(1);
			}
			buf[--l] = 0;
			while(l && (buf[l - 1] == ' ' || (buf[l - 1] == '\t')))
				buf[--l] = 0;
			for (p = buf; *p == ' ' || *p == '\t'; p++)
				;
			if (*p == 0 || *p == '#')
				continue;
			for (pt = parstab; pt->name; pt++) {
				l = strlen(pt->name);
				if (!strncmp(p, pt->name, l) && (p[l] == ' ' || p[l] == '\t' || p[l] == '='))
					break;
			}
			if (!pt->name) {
			    fprintf(stderr, "syntax error: %s\n", p);
			    exit(1);
			}
			while (p[l] == ' ' || p[l] == '\t')
				l++;
			if (p[l++] != '=') {
			    fprintf(stderr, "syntax error: %s\n", p);
			    exit(1);
			}
			while (p[l] == ' ' || p[l] == '\t')
				l++;
			if (pt->val)
				*pt->val = atoi(p + l);
			else
				jpgfile = strdup(p + l);
		}
		fclose(fp);
		if (!jpgfile) {
			l = strlen(cfgfile);
			if (l > 4 && !strcmp(cfgfile + l - 4, ".cfg")) {
				jpgfile = strdup(cfgfile);
				strcpy(jpgfile + l - 4, ".jpg");
			}
		}
		if (jpgfile && (*jpgfile == 0 || tx < 0 || ty < 0 || tw <= 0 || th <= 0)) {
			free(jpgfile);
			jpgfile = 0;
		}
	}
	if (jpgfile) {
		if ((fp = fopen(jpgfile, "r")) == 0) {
			perror(jpgfile);
			exit(1);
		}
		if (fstat(fileno(fp), &stb) == -1) {
			perror("fstat");
			exit(1);
		}
		l = stb.st_size;
		pic = calloc(35 + l, 1);
		if (pic == 0) {
			fprintf(stderr, "Out of memory.\n");
			exit(1);
		}
		if (fread(pic + 35, l , 1, fp) != 1) {
			perror("fread");
			exit(1);
		}
		fclose(fp);
	} else {
		l = 0;
		pic = calloc(35, 1);
		if (pic == 0) {
			fprintf(stderr, "Out of memory.\n");
			exit(1);
		}
	}
	size = l;
	if (version != 1 && version != 2) {
		fprintf(stderr, "Illegal version: %d\n", version);
		exit(1);
	}
	if (version == 1 && unit != 0) {
		/* convert to version 2 */
		tx *= 8;
		ty *= 16;
		tw *= 8;
		th *= 16;
		px = tx + 10;
		py = ty + 10;
		pw = tw - 20;
		ph = th - 20;
		pr = pg = pb = 240;
		state = 1;
		fgcolor = 0;
		bgcolor = 15;
		version = 2;
	}
	if (version == 1) {
		/* write version 1 file */
		strcpy(pic, "BOOTSPL1");
		pic[8] = tx;
		pic[9] = tx >> 8;
		pic[10] = ty;
		pic[11] = ty >> 8;
		pic[12] = tw;
		pic[13] = tw >> 8;
		pic[14] = th;
		pic[15] = th >> 8;
		pic[16] = size;
		pic[17] = size >> 8;
		pic[18] = size >> 16;
		pic[19] = size >> 24;
		if (l > 0)
			memmove(pic + 20, pic + 35, l);
		l += 20;
	} else {
		/* write version 2 file */
		strcpy(pic, "BOOTSPL2");
		pic[8] = unit;
		pic[9] = state;
		pic[10] = fgcolor;
		pic[11] = bgcolor;
		if (cfgfile && size == 0 && (state != -1 || fgcolor != -1 || bgcolor != -1))
			size = -1;
		pic[12] = size;
		pic[13] = size >> 8;
		pic[14] = size >> 16;
		pic[15] = size >> 24;
		pic[16] = tx;
		pic[17] = tx >> 8;
		pic[18] = ty;
		pic[19] = ty >> 8;
		pic[20] = tw;
		pic[21] = tw >> 8;
		pic[22] = th;
		pic[23] = th >> 8;
		pic[24] = px;
		pic[25] = px >> 8;
		pic[26] = py;
		pic[27] = py >> 8;
		pic[28] = pw;
		pic[29] = pw >> 8;
		pic[30] = ph;
		pic[31] = ph >> 8;
		pic[32] = pr;
		pic[33] = pg;
		pic[34] = pb;
		l += 35;
	}

	if (filterflag)
		fd = 1;
	else if ((fd = open(PROCSPLASH, O_WRONLY)) == -1) {
		perror(PROCSPLASH);
		exit(1);
	}
	if (write(fd, pic, l) != l) {
		perror("write");
		exit(1);
	}
	if (!filterflag)
		close(fd);
	free(pic);
}

void spawncommand(unsigned char *command)
{
	DEBUG("splash: Spawning command %s.\n", command);
	system(command);
}

int main(int argc, char *argv[])
{
	int procsplash, splashdsc, c;
	int setflag = 0;
	int errflag = 0;
	int filterflag = 0;
	unsigned char *readbuffer;
	unsigned char *versiontext, *statustext;
	unsigned char *match,*command, *cmp;
	unsigned char *tokenize;
	
	while ((c = getopt(argc, argv, "fsu:")) != EOF) {
		switch (c) {
		case 's':
			setflag = 1;
			break;
		case 'f':
			filterflag = 1;
			break;
		case 'u':
			unit = atoi(optarg);
			break;
		case '?':
			errflag = 1;
			break;
		}
	}

	if (errflag || (argc != optind + 1 && (argc != optind || !setflag))) {
		printf("Usage: %s logstring\n",argv[0]);
		printf("       %s -s [-u unit] [cfgfile]\n",argv[0]);
		return 0;
	}
	
	readbuffer = malloc(BUFSIZE);
	
	if (!readbuffer) {
		DEBUG("splash: Not enough memory.\n");
		return -ENOMEM;
	}
	
	if (!setflag || !filterflag) {
		procsplash = open(PROCSPLASH, O_RDONLY);
		if (procsplash < 0) {
			if (setflag) {
				perror(PROCSPLASH);
				exit(1);
			}
			DEBUG("splash: File %s not available.\n",PROCSPLASH);
			return 0;
		}

		if (read(procsplash, readbuffer, BUFSIZE)<0) {
			if (setflag)
				perror("read");
			DEBUG("splash: Read error in file %s.\n",PROCSPLASH);
			return -EBUSY;
		}
		close(procsplash);
	}
	if (setflag) {
		if (!filterflag && !strncmp(readbuffer, "Splash screen v0", 16)) {
			fprintf(stderr, "Your kernel does not support new-style splash pictures.\n");
			exit(1);
		}
		setsplash(argc > optind ? argv[optind] : 0, filterflag);
		exit(0);
	}
	
	versiontext=strtok(readbuffer,":");
	statustext=strtok(NULL,":");
	if (!statustext || strncmp(" on\n",statustext, 4)) {
		DEBUG("splash: Boot splash is off.\n");
		return 0;
	}

	memset(readbuffer,0,BUFSIZE);
	
	splashdsc=open(SPLASHDSC,O_RDONLY);
	if (splashdsc<0) {
		DEBUG("splash: File %s not available.\n", SPLASHDSC);
		return -ENOENT;
	}

	if (read(splashdsc, readbuffer, BUFSIZE)<0) {
		DEBUG("splash: Read error in file %s.\n",SPLASHDSC);
		return -EBUSY;
	}

	DEBUG("splash: Looking for match with \"%s\"\n",basename(argv[1]));
	
	tokenize=readbuffer;
	do {
		match=strtok(tokenize,":");
		tokenize=NULL;

		command=strtok(NULL,"\n");
		DEBUG("splash: Match=\"%s\"\n",match);
		if (match && (cmp=strstr(basename(argv[1]),match))
		    && !strncmp(match,cmp,strlen(match)) ) {

			DEBUG("splash: Match found: \"%s\".\n",match);
			spawncommand(command);
			return 0;
		}
		
	} while (match && command);
	
	return 0;
}
--- 2.4.19-vanilla/include/video/fbcon.h	2001-09-14 01:25:07.000000000 +0200
+++ 2.4.19-vanilla/include/video/fbcon.h	2002-11-03 22:27:20.000000000 +0100
@@ -43,4 +43,27 @@
 }; 
 
+#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_penguin_xo;		/* penguin area origin */
+	int	splash_penguin_yo;
+	int	splash_penguin_wi;		/* penguin area size */
+	int	splash_penguin_he;
+	int	splash_penguin_r;		/* penguin bg color */
+	int	splash_penguin_g;
+	int	splash_penguin_b;
+	int	splash_no_penguin;		/* don't display him */
+	char	splash_jpeg[1];			/* jpeg */
+};
+#endif
+
 extern struct display_switch fbcon_dummy;
 
@@ -96,4 +119,9 @@
     unsigned char fgshift, bgshift;
     unsigned short charmask;        /* 0xff or 0x1ff */
+
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+    struct splash_data *splash_data;
+#endif
+
 };
 
--- 2.4.19-vanilla/drivers/video/fbcon.c	2002-08-03 02:39:45.000000000 +0200
+++ 2.4.19-vanilla/drivers/video/fbcon.c	2002-11-03 22:24:38.000000000 +0100
@@ -35,4 +35,7 @@
  *	- Brad Douglas <brad@neruo.com>
  *
+ *  Alterations marked G.S. contributed by Gerard Sharp (gsharp@ihug.co.nz)
+ *  Essentially a line of text above the Boot Logo stating kernel version. :)
+ *
  *  The low level operations for the various display memory organizations are
  *  now in separate source files.
@@ -59,4 +62,5 @@
 #undef FBCONDEBUG
 
+#include <linux/version.h>
 #include <linux/config.h>
 #include <linux/module.h>
@@ -105,4 +109,17 @@
 #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;
+  #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)
@@ -479,4 +496,7 @@
 }
 
+#if defined(CONFIG_FBCON_SPLASHSCREEN) 
+static int splash_registered=0;
+#endif
 
 static void fbcon_init(struct vc_data *conp, int init)
@@ -503,4 +523,24 @@
     fb_display[unit].cmap.blue = 0;
     fb_display[unit].cmap.transp = 0;
+
+#ifdef CONFIG_FBCON_SPLASHSCREEN 
+    if (!splash_registered && fb_display[unit].dispsw->setup == fbcon_cfb16.setup) {
+	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].dispsw->setup != fbcon_cfb16.setup) {
+	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 */
@@ -519,4 +559,13 @@
     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
+
 }
 
@@ -659,5 +708,13 @@
     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 */
@@ -665,5 +722,6 @@
 	int step;
     
-    	logo_lines = (LOGO_H + fontheight(p) - 1) / fontheight(p);
+	/* G.S. Make logo 1 (text) line taller - for version text */
+	logo_lines = (LOGO_H + (fontheight(p)*2) - 1) / fontheight(p);
     	q = (unsigned short *)(conp->vc_origin + conp->vc_size_row * old_rows);
     	step = logo_lines * old_cols;
@@ -736,4 +794,9 @@
     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)
@@ -1324,4 +1387,7 @@
 	        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:
@@ -1384,4 +1450,7 @@
 	    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:
@@ -1500,4 +1569,11 @@
 	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);
 }
@@ -1510,4 +1586,8 @@
     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;
@@ -1554,4 +1634,13 @@
 	p->dispsw->clear_margins(conp, p, 0);
     if (logo_shown == -2) {
+	/* G.S.: Display a line above the Boot Logo to state what
+	* version of the kernel we are booting.
+	*/
+	char welcometext[] = "Linux " UTS_RELEASE;
+	unsigned short welcomestring[ sizeof(welcometext) ];
+	int i;
+	for(i = 0; i < sizeof(welcometext); i++)
+	    scr_writew(0x0700 | welcometext[i], &welcomestring[i]);
+	fbcon_putcs( conp, welcomestring, sizeof(welcometext), 0, 0 );
 	logo_shown = fg_console;
 	fbcon_show_logo(); /* This is protected above by initmem_freed */
@@ -1600,4 +1689,7 @@
 		} else
 			p->dispsw->clear(conp, p, real_y(p, 0), 0, height, conp->vc_cols);
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+                p->dispsw->clear_margins(conp, p, -1);
+#endif
 		conp->vc_video_erase_char = oldc;
 	    }
@@ -1767,11 +1859,19 @@
     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;
@@ -2151,4 +2251,6 @@
 	return 0;
 	
+    /* G.S. : Move Penguin(s) down one line; for version line */
+    fb += fontheight(p) * line;
     /*
      * Set colors if visual is PSEUDOCOLOR and we have enough colors, or for
@@ -2194,4 +2296,8 @@
     	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)) {
@@ -2455,4 +2561,8 @@
 #endif			
     }
+
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+    }
+#endif    
     
     if (p->fb_info->fbops->fb_rasterimg)
--- 2.4.19-vanilla/drivers/video/fbcon-cfb16.c	2001-10-15 22:47:13.000000000 +0200
+++ 2.4.19-vanilla/drivers/video/fbcon-cfb16.c	2002-11-03 21:39:18.000000000 +0100
@@ -11,4 +11,5 @@
 
 #include <linux/module.h>
+#include <linux/config.h>
 #include <linux/tty.h>
 #include <linux/console.h>
@@ -20,4 +21,7 @@
 #include <video/fbcon-cfb16.h>
 
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+#include "fbcon-splash.h"
+#endif
 
     /*
@@ -62,4 +66,10 @@
 	width *= fontwidth(p)*2;
     }
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+    if (splash_shown) {
+	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;
+    }
+#endif
     if (dy < sy || (dy == sy && dx < sx)) {
 	src = p->screen_base + sy * linesize + sx;
@@ -102,4 +112,29 @@
 }
 
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+static 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;
+    }
+}
+#endif
+
 void fbcon_cfb16_clear(struct vc_data *conp, struct display *p, int sy, int sx,
 		       int height, int width)
@@ -108,4 +143,7 @@
     int bytes = p->next_line, lines = height * fontheight(p);
     u32 bgx;
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+    int offset, transparent=0;
+#endif
 
     dest = p->screen_base + sy * fontheight(p) * bytes + sx * fontwidth(p) * 2;
@@ -114,4 +152,26 @@
 
     width *= fontwidth(p)/4;
+
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+    if (splash_shown) {
+	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);
+		return;
+	}
+    }
+#endif
     if (width * 8 == bytes)
 	rectfill(dest, lines * width * 4, 1, bgx, bytes);
@@ -120,4 +180,19 @@
 }
 
+
+/*
+ *  Helper function to read the background from the splashscreen
+ */
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+# define SPLASH_BGX(off)			\
+	if (transparent) {			\
+	    bgx = *(u32*)(splashbgx + (off));	\
+	    eorx = fgx ^ bgx;			\
+	}
+#else
+# define SPLASH_BGX(off)
+#endif
+
+
 void fbcon_cfb16_putc(struct vc_data *conp, struct display *p, int c, int yy,
 		      int xx)
@@ -127,8 +202,34 @@
     u32 eorx, fgx, bgx;
 
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+    int transparent = 0;
+    u8 *splashbgx = 0;
+#endif
+
     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)];
+
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+    if (splash_shown) {
+	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;
+	}
+    }
+#endif
+
     fgx |= (fgx << 16);
     bgx |= (bgx << 16);
@@ -141,10 +242,17 @@
 	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);
 	    }
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+	    splashbgx += splash_bytes;
+#endif
 	}
 	break;
@@ -154,13 +262,21 @@
 	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);
 	    }
@@ -177,4 +293,8 @@
     int rows, bytes = p->next_line;
     u32 eorx, fgx, bgx;
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+    int transparent = 0;
+    u8 *splashbgx0 = 0, *splashbgx;
+#endif
 
     dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 2;
@@ -182,4 +302,24 @@
     fgx = ((u16 *)p->dispsw_data)[attr_fgcol(p, c)];
     bgx = ((u16 *)p->dispsw_data)[attr_bgcol(p, c)];
+
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+    if (splash_shown) {
+	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;
+	}
+    }
+#endif
     fgx |= (fgx << 16);
     bgx |= (bgx << 16);
@@ -192,14 +332,27 @@
 	    c = scr_readw(s++) & p->charmask;
 	    cdat = p->fontdata + c * fontheight(p);
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+	    splashbgx = splashbgx0;
+#endif
 	    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);
 		}
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+		splashbgx += splash_bytes;
+#endif
 	    }
 	    dest0 += fontwidth(p)*2;;
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+	    splashbgx0 += fontwidth(p) * 2;
+#endif
 	}
 	break;
@@ -209,19 +362,36 @@
 	    c = scr_readw(s++) & p->charmask;
 	    cdat = p->fontdata + (c * fontheight(p) << 1);
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+	    splashbgx = splashbgx0;
+#endif
 	    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);
 		}
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+		splashbgx += splash_bytes;
+#endif
 	    }
 	    dest0 += fontwidth(p)*2;
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+	    splashbgx0 += fontwidth(p) * 2;
+#endif
 	}
 	break;
@@ -235,4 +405,9 @@
 
     dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p)*2;
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+    if (splash_shown) {
+	dest += splash_data.splash_text_yo * bytes + splash_data.splash_text_xo * 2;
+    }
+#endif
     for (rows = fontheight(p); rows--; dest += bytes) {
 	switch (fontwidth(p)) {
@@ -266,6 +441,55 @@
     unsigned int right_width, bottom_width;
 
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+    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;
+#endif
+ 
     bgx = ((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
 
+#ifdef CONFIG_FBCON_SPLASHSCREEN
+    if (bottom_only == -1) {
+	rectfill(p->screen_base, p->var.xres, p->var.yres, bgx, bytes);
+	return;
+    }
+
+    if (splash_shown) {
+	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;
+    }
+#endif
+
     if (!bottom_only && (right_width = p->var.xres-right_start))
 	rectfill(p->screen_base+right_start*2, right_width,
--- 2.4.19-vanilla/drivers/video/Makefile	2002-08-03 02:39:45.000000000 +0200
+++ 2.4.19-vanilla/drivers/video/Makefile	2002-11-03 20:55:41.000000000 +0100
@@ -140,4 +140,7 @@
 obj-$(CONFIG_FBCON_STI)           += fbcon-sti.o
 
+obj-$(CONFIG_FBCON_SPLASHSCREEN)  += fbcon-splash.o
+obj-$(CONFIG_FBCON_SPLASHSCREEN)  += fbcon-jpegdec.o
+
 include $(TOPDIR)/Rules.make
 
--- 2.4.19-vanilla/drivers/video/fbcon-jpegdec.c	Thu Sep 12 13:46:32 2002
+++ 2.4.19-vanilla/drivers/video/fbcon-jpegdec.c	Thu Sep 12 14:38:32 2002
@@ -0,0 +1,935 @@
+/* 
+ *    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>
+
+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)		\
+)
+
+#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                    \
+)
+
+#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;
+	}
+}
--- 2.4.19-vanilla/drivers/video/fbcon-jpegdec.h	Thu Sep 12 13:46:33 2002
+++ 2.4.19-vanilla/drivers/video/fbcon-jpegdec.h	Thu Sep 12 14:16:35 2002
@@ -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);
--- 2.4.19-vanilla/drivers/video/fbcon-splash.c	Thu Sep 12 13:46:33 2002
+++ 2.4.19-vanilla/drivers/video/fbcon-splash.c	Thu Sep 12 14:35:27 2002
@@ -0,0 +1,481 @@
+/* 
+ *    linux/drivers/video/fbcon-splash.c - splash screen handling functions.
+ *	
+ *	(w) 2001 by Volker Poplawski, <volker@suse.de>
+ * 		    Stefan Reinauer, <stepan@suse.de>
+ * 		    Steffen Winterfeldt, <snwint@suse.de>
+ * 		    
+ * 	       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 "2.0.3"
+
+#ifdef CONFIG_BLK_DEV_INITRD
+unsigned char signature[] = "BOOTSPL1SPL2";
+#endif
+
+/* from drivers/char/console.c */
+extern void con_remap_def_color(int currcons, int new_color);
+
+/* 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_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);
+
+int __init splash_init(char *options)
+{
+	splash_default = simple_strtoul(options, NULL, 0);
+	return 0;
+}
+
+__setup("splash=", splash_init);
+
+
+void penguin_off(struct display *p, int update)
+{
+	unsigned int i, j, x, y, width, height;
+	unsigned short bg;
+
+	if (fg_console != p->conp->vc_num)
+	    return;
+	if (!linux_splash)
+	    return;
+        if (!p->splash_data || p->splash_data->splash_penguin_wi <= 0 || p->splash_data->splash_penguin_he <= 0)
+	    return;
+	if (p->var.bits_per_pixel != 16)
+	    return;
+	bg = (p->splash_data->splash_penguin_r & 0xf8) << 8 |
+	     (p->splash_data->splash_penguin_g & 0xfc) << 3 |
+	     (p->splash_data->splash_penguin_b & 0xf8) >> 3;
+	x = p->splash_data->splash_penguin_xo;
+	y = p->splash_data->splash_penguin_yo;
+	width = p->splash_data->splash_penguin_wi;
+	height = p->splash_data->splash_penguin_he;
+	for (i = y; i < y + height; i++)
+	    for (j = x; j < x + width; j++)
+		*(unsigned short *)(linux_splash + j * 2 + i * splash_bytes) = bg;
+
+	if (update) {
+	    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 );
+	    if (p->dispsw->clear_margins)
+		p->dispsw->clear_margins(p->conp, p, 0);
+	}
+}
+
+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;
+}
+
+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;
+	struct display *p;
+
+	printk(KERN_INFO "Looking for splash picture...");
+
+	p = &fb_display[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)
+				vfree(p->splash_data);
+			p->splash_data = vmalloc(sizeof(*p->splash_data) + splash_size);
+			if (!p->splash_data)
+				break;
+			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_penguin_xo = p->splash_data->splash_text_xo + 10;
+			p->splash_data->splash_penguin_yo = p->splash_data->splash_text_yo + 10;
+			p->splash_data->splash_penguin_wi = p->splash_data->splash_text_wi - 20;
+			p->splash_data->splash_penguin_he = p->splash_data->splash_text_he - 20;
+			p->splash_data->splash_penguin_r = 0xf0;
+			p->splash_data->splash_penguin_g = 0xf0;
+			p->splash_data->splash_penguin_b = 0xf0;
+			p->splash_data->splash_no_penguin = 0;
+			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)
+					vfree(p->splash_data);
+				p->splash_data = 0;
+				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)
+				vfree(p->splash_data);
+			p->splash_data = vmalloc(sizeof(*p->splash_data) + splash_size);
+			if (!p->splash_data)
+				break;
+			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_penguin_xo = ndata[24] + (ndata[25] << 8);
+			p->splash_data->splash_penguin_yo = ndata[26] + (ndata[27] << 8);
+			p->splash_data->splash_penguin_wi = ndata[28] + (ndata[29] << 8);
+			p->splash_data->splash_penguin_he = ndata[30] + (ndata[31] << 8);
+			p->splash_data->splash_penguin_r = ndata[32];
+			p->splash_data->splash_penguin_g = ndata[33];
+			p->splash_data->splash_penguin_b = ndata[34];
+			p->splash_data->splash_no_penguin = 0;
+			splash_start = ndata + 35;
+			found = 1;
+			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) {
+		vfree(p->splash_data);
+		p->splash_data = 0;
+		printk(" found, but has oversized text area!\n");
+		return -1;
+	}
+        if (p->dispsw->setup != fbcon_cfb16.setup) {
+		vfree(p->splash_data);
+		p->splash_data = 0;
+		printk(" found, but framebuffer can't handle it!\n");
+		return -1;
+	}
+	printk (" found (%dx%d, %d bytes).\n", width, height, splash_size);
+	/* copy data so that initrd memory can be freed. */
+	memcpy(p->splash_data->splash_jpeg, splash_start, splash_size);
+	return unit;
+}
+
+int splash_prepare(p)
+struct display *p;
+{
+	int err;
+        int width, height, depth, size;
+
+	if (!p->splash_data || !p->splash_data->splash_state) {
+		if (linux_splash)
+			vfree(linux_splash);
+		linux_splash = 0;
+		linux_splash_size = 0;
+		splash_shown = 0;
+		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_shown = 0;
+		return -2;
+	}
+
+	size = ((width + 15) & ~15) * ((height + 15) & ~15) * (depth>>3);
+	if (size != linux_splash_size) {
+		if (linux_splash)
+			vfree(linux_splash);
+		linux_splash_size = 0;
+		linux_splash = 0;
+		splash_shown = 0;
+	}
+	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_shown = 0;
+		return -3;
+	}
+
+	if (!decdata)
+	    decdata = vmalloc(sizeof(*decdata));
+
+	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_shown = 0;
+		return -4;
+	}
+	linux_splash_size = size;
+	splash_bytes = ((width + 15) & ~15) * (depth >> 3);
+	splash_data = *p->splash_data;
+	splash_shown = p->splash_data->splash_state;
+	if (p->splash_data->splash_no_penguin)
+	    penguin_off(p, 0);
+	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\n",
+		    SPLASH_VERSION, color, p->var.xres, p->var.yres, 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);
+			if (p->dispsw->clear_margins)
+			    p->dispsw->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 (!strcmp(buffer,"hide penguin\n") || !strcmp(buffer,"show penguin\n")) {
+		p = &fb_display[0];
+		if (p->splash_data) {
+		    if (*buffer == 'h') {
+			printk(KERN_INFO "Switching off penguin.\n");
+			p->splash_data->splash_no_penguin = 1;
+			penguin_off(p, 1);
+		    } else {
+			printk(KERN_INFO "Switching on penguin.\n");
+			p->splash_data->splash_no_penguin = 0;
+			splash_status(p);
+		    }
+		}
+		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
--- 2.4.19-vanilla/drivers/video/fbcon-splash.h	Thu Sep 12 13:46:33 2002
+++ 2.4.19-vanilla/drivers/video/fbcon-splash.h	Thu Sep 12 13:51:25 2002
@@ -0,0 +1,18 @@
+/* 
+ *    linux/drivers/video/splash.h - splash screen definition.
+ *	
+ *	(w) 2001 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 */

--- 2.4.19-vanilla/drivers/video/Config.in	2002-08-03 02:39:45.000000000 +0200
+++ 2.4.19-vanilla/drivers/video/Config.in	2002-11-03 20:42:36.000000000 +0100
@@ -205,13 +205,19 @@
       tristate '  Virtual Frame Buffer support (ONLY FOR TESTING!)' 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
@@ -314,7 +320,9 @@
 	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" -o \
 	   "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" -o \
 	   "$CONFIG_FB_NEOMAGIC" = "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 \
@@ -331,7 +339,9 @@
 	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
 	      "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" -o \
 	      "$CONFIG_FB_NEOMAGIC" = "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 \

--- 2.4.19-vanilla/drivers/char/console.c	2002-08-03 02:39:43.000000000 +0200
+++ 2.4.19-vanilla/drivers/char/console.c	2002-11-03 20:52:07.000000000 +0100
@@ -3004,4 +3004,29 @@
 	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
 
 /*
#!/static/sh
#
# KNOPPIX General Startup Script
# (C) Klaus Knopper <knoppix@knopper.net>
#
#
# This script needs some of the builtin ash commands (if, test, ...)
# mount/umount, insmod/rmmod are also a builtin in ash-knoppix.
#

# hardcoded configurable options
# Default maximum size of dynamic ramdisk in kilobytes
RAMSIZE=1000000
# End of options

# Don't allow interrupt signals
trap "" 1 2 3 15

# "Safe" SCSI modules in the right order for autoprobe
# Warning: The sym53c8xx.o and g_NCR* cause a kernel Oops if no such adapter
# is present.
#
# NB: It looks like that ncr53c8xx.o is more stable than 53c7,8xx.o for
# a ncr53c810 controller (at least on my installation box it's more
# immune to SCSI timeouts)
# Removed 53c7,8xx -> crashes if no device attached.
# Removed AM53C974 -> crashes tmscsim if adapter found
# Added initio.o on request (untested)
SCSI_MODULES="aic7xxx.o aic7xxx_old.o BusLogic.o \
ncr53c8xx.o NCR53c406a.o \
initio.o \
advansys.o aha1740.o aha1542.o aha152x.o \
atp870u.o dtc.o eata.o fdomain.o gdth.o \
megaraid.o pas16.o pci2220i.o pci2000.o psi240i.o \
qlogicfas.o qlogicfc.o qlogicisp.o \
seagate.o t128.o tmscsim.o u14-34f.o ultrastor.o wd7000.o \
a100u2w.o 3w-xxxx.o"

# Misc functions

mountit(){
# Usage: mountit src dst "options"
# Uses builtin mount of ash.knoppix
# Builin filesystems
BUILTIN_FS="iso9660 ext2 vfat"
for fs in $BUILTIN_FS; do
test -b $1 && mount -t $fs $3 $1 $2 >/dev/null 2>&1 && return 0
done
return 1
}

FOUND_SCSI=""
FOUND_KNOPPIX=""
INTERACTIVE=""

# Clean input/output
exec >/dev/console </dev/console 2>&1

# Reset fb color mode
RESET="]R"
# ANSI COLORS
# Erase to end of line
CRE="
"
# Clear and reset Screen
CLEAR="c"
# Normal color
NORMAL=""
# RED: Failure or error message
RED=""
# GREEN: Success message
GREEN=""
# YELLOW: Descriptions
YELLOW=""
# BLUE: System mesages
BLUE=""
# MAGENTA: Found devices or drivers
MAGENTA=""
# CYAN: Questions
CYAN=""
# BOLD WHITE: Hint
WHITE=""

# Clear screen with colormode reset
# echo "$CLEAR$RESET"
# echo "$CLEAR"

# We only need the builtin commands and /static at this point
PATH=/static
export PATH

umask 022

# Mount /proc and /dev/pts
mount -t proc none /proc
mount -t devpts none /dev/pts

# Bootsplash by Eadz at eadz.co.nz
splash -s -u 0 /splash/bootsplash-800x600.cfg 2>&1 > /dev/null
splash -s -u 1 /splash/bootsplash-800x600.cfg 2>&1 > /dev/null 
splash -s -u 2 /splash/bootsplash-800x600.cfg 2>&1 > /dev/null
splash -s -u 3 /splash/bootsplash-800x600.cfg 2>&1 > /dev/null
splash -s -u 4 /splash/bootsplash-800x600.cfg 2>&1 > /dev/null 

# Just go to the top of the screen
echo -n ""
echo ""
# Be verbose
#echo "${WHITE}Welcome to the ${CYAN}K${MAGENTA}N${YELLOW}O${WHITE}P${RED}P${GREEN}I${BLUE}X${WHITE} ${GREEN}KDE EDITION${NORMAL} live Linux-on-CD!${NORMAL}"
echo "Welcome to ..."
echo "${YELLOW}"
echo "______ ______   ___________________________________  __"
echo "___  //_/__  | / /_  __ \__  __ \__  __ \___  _/_  |/ /"
echo "__  ,<  __   |/ /_  / / /_  /_/ /_  /_/ /__  / __    / "
echo "_  /| | _  /|  / / /_/ /_  ____/_  ____/__/ /  _    |  "
echo "/_/ |_| /_/ |_/  \____/ /_/     /_/     /___/  /_/|_|  "
echo "${WHITE}"
echo "    __  __   __        __              "
echo "|_/|  \|_     _)  /|  |_  _|.|_. _  _  "
echo "| \|__/|__   __).  |  |__(_|||_|(_)| ) "
echo "${NORMAL}"
# Read boot command line with builtin cat command (shell read function fails in Kernel 2.4.19-rc1)
CMDLINE="$(cat /proc/cmdline)"

# Check if we are in interactive startup mode
case "$CMDLINE" in *BOOT_IMAGE=expert\ *) INTERACTIVE="yes"; :>/interactive; ;; esac
# Does the user want to skip scsi detection?
NOSCSI=""
case "$CMDLINE" in *noscsi*) NOSCSI="yes"; ;; esac

# Disable kernel messages while probing modules in autodetect mode
echo "0" > /proc/sys/kernel/printk

# Mount module disk
mountmodules(){
TYPE="$1"; shift
echo -n "${CRE}${CYAN}Please insert ${TYPE} modules disk and hit Return. ${NORMAL}"
read a
echo -n "${CRE}${BLUE}Mounting ${TYPE} modules disk... ${NORMAL}"
# We always mount over /modules/scsi (because it's there ;-)
if mountit /dev/fd0 /modules/scsi "-o ro"; then
echo "${GREEN}OK.${NORMAL}"
return 0
fi
echo "${RED}NOT FOUND.${NORMAL}"
return 1
}

# Unmount module disk
umountmodules(){
TYPE="$1"; shift
echo -n "${CRE}${BLUE}Unmounting ${TYPE} modules disk... ${NORMAL}"
umount /modules/scsi 2>/dev/null
echo "${GREEN}DONE.${NORMAL}"
}

# Ask user for modules
askmodules(){
TYPE="$1"; shift
echo "${BLUE}${TYPE} modules available:${WHITE}"
c=""; for m in "$@"; do
if test -f "/modules/scsi/$m"; then
test -z "$c"  && { echo -n "	$m"; c="1"; } || { echo "		$m"; c=""; }
fi
done
[ -n "$c" ] && echo ""
echo "${CYAN}Load ${TYPE} Modules?${NORMAL}"
echo "${CYAN}[Enter full filename(s) (space-separated), Return for autoprobe, ${WHITE}n${CYAN} for none] ${NORMAL}"
echo -n "${CYAN}insmod module(s)> ${NORMAL}"
read MODULES
case "$MODULES" in n|N) MODULES=""; ;; y|"")  MODULES="$*"; ;; esac
}

# Try to load the given modules (full path or current directory)
loadmodules(){
TYPE="$1"; shift
test -n "$INTERACTIVE" && echo "6" > /proc/sys/kernel/printk
for i in "$@"; do
echo -n "${CRE}${BLUE}Probing ${TYPE}... ${MAGENTA}$i${NORMAL}"
if test -f /modules/scsi/$i && insmod -f /modules/scsi/$i >/dev/null 2>&1
then
echo "${CRE} ${GREEN}Found ${TYPE} device(s) handled by ${MAGENTA}$i${GREEN}.${NORMAL}"
case "$TYPE" in scsi|SCSI) FOUND_SCSI="yes"; ;; esac
fi
done
test -n "$INTERACTIVE" && echo "0" > /proc/sys/kernel/printk
echo -n "${CRE}"
}

# Check for SCSI, use modules on bootfloppy first
if test -n "$INTERACTIVE"; then
# Let the user select interactively
askmodules SCSI $(cd /modules/scsi; echo *.o)
else
# these are the autoprobe-safe modules
MODULES="$SCSI_MODULES"
fi
test -z "$NOSCSI" && test -n "$MODULES" && loadmodules SCSI $MODULES
# End of SCSI check

# Check for misc modules in expert mode
if test -n "$INTERACTIVE"; then
another=""; answer=""
while test "$answer" != "n" -a "$answer" != "N"; do
echo -n "${CYAN}Do you want to load additional modules from$another floppy disk? [${WHITE}Y${CYAN}/n] ${NORMAL}"
another=" another"
read answer
case "$answer" in n*|N*) break; ;; esac
if mountmodules new; then
askmodules new $(cd /modules/scsi; echo *.o)
test -n "$MODULES" && loadmodules new $MODULES
umountmodules current
fi
done
fi
# All interactively requested modules should be loaded now.

# Check for ide-scsi supported CD-Roms et al.
test -f /proc/scsi/scsi && FOUND_SCSI="yes"

# Disable kernel messages again
echo "0" > /proc/sys/kernel/printk

# Now that the right SCSI driver is (hopefully) loaded, try to find CDROM
DEVICES="/dev/hd?"
test -n "$FOUND_SCSI" && DEVICES="/dev/scd? /dev/scd?? $DEVICES"
# New: Also try parallel port CD-Roms [for Mike].
DEVICES="$DEVICES /dev/pcd?"
# New: also check HD partitions for a KNOPPIX/KNOPPIX image
test -n "$FOUND_SCSI" && DEVICES="$DEVICES /dev/sd?[1-9] /dev/sd?[1-9][0-9]"
DEVICES="$DEVICES /dev/hd?[1-9] /dev/hd?[1-9][0-9]"
for i in $DEVICES
do
echo -n "${CRE}${BLUE}Looking for CDROM in: ${MAGENTA}$i${NORMAL}   "
if mountit $i /cdrom "-o ro" >/dev/null 2>&1
then
if test -d /cdrom/KNOPPIX
then
echo -n "${CRE} ${GREEN}Accessing KNOPPIX CDROM at ${MAGENTA}$i${GREEN}...${NORMAL}"
FOUND_KNOPPIX="$i"
break
fi
umount /cdrom
fi
done

# Harddisk-installed script part version has been removed
# (KNOPPIX can be booted directly from HD now).

if test -n "$FOUND_KNOPPIX" -a -f /cdrom/KNOPPIX/KNOPPIX; then
# DEBUG
# echo "6" > /proc/sys/kernel/printk
insmod -f /modules/cloop.o file=/cdrom/KNOPPIX/KNOPPIX
mountit /dev/cloop /KNOPPIX "-o ro" || FOUND_KNOPPIX=""
fi

# Final test if everything succeeded.
if test -n "$FOUND_KNOPPIX"
then
# copy library cache
cat /KNOPPIX/etc/ld.so.cache > /etc/ld.so.cache
echo ""

# Enable kernel messages
echo "6" > /proc/sys/kernel/printk

# Set paths
echo -n "${CRE}${BLUE}Setting paths...${NORMAL}"
PATH="/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:."
export PATH

# Debian weirdness
/bin/cp -a /KNOPPIX/etc/alternatives /etc/ 2>/dev/null

# From here, we should have all essential commands available.
hash -r

# Clean up /
rm -rf /modules /static

# New in Kernel 2.4.x: tempfs with variable ramdisk size.
# We check for available memory anyways and limit the ramdisks
# to a reasonable size.
FOUNDMEM="$(awk '/MemTotal/{print $2}' /proc/meminfo)"
TOTALMEM="$(awk 'BEGIN{m=0};/MemFree|Cached/{m+=$2};END{print m}' /proc/meminfo)"
 
# Be verbose
echo "${CRE}${BLUE}Total memory found: ${YELLOW}${FOUNDMEM}${BLUE} kB${NORMAL}"

# Now we need to use a little intuition for finding a ramdisk size
# that keeps us from running out of space, but still doesn't crash the
# machine due to lack of Ram

# Minimum size of additional ram partitions
MINSIZE=2000
# At least this much memory minus 30% should remain when home and var are full.
MINLEFT=16000
# Maximum ramdisk size
MAXSIZE="$(expr $TOTALMEM - $MINLEFT)"
# Default ramdisk size for ramdisk
RAMSIZE="$(expr $TOTALMEM / 5)"

# Check for sufficient memory to mount extra ramdisk for /home + /var
if test -n "$TOTALMEM" -a "$TOTALMEM" -gt "$MINLEFT"; then
test -z "$RAMSIZE" && RAMSIZE=1000000
mkdir -p /ramdisk
# tmpfs/varsize version, can use swap
RAMSIZE=$(expr $RAMSIZE \* 4)
echo -n "${CRE}${BLUE}Creating ${YELLOW}/ramdisk${BLUE} (dynamic size=${RAMSIZE}k) on ${MAGENTA}/dev/shm${BLUE}...${NORMAL}"
# We need /bin/mount here for the -o size= option
/bin/mount -t tmpfs -o "size=${RAMSIZE}k" /dev/shm /ramdisk && mkdir -p /ramdisk/home /ramdisk/var && ln -s /ramdisk/home /ramdisk/var /
echo "${BLUE}Done.${NORMAL}"
else
mkdir -p /home /var
fi

echo -n "${CRE}${BLUE}Creating directories and symlinks on ramdisk...${NORMAL}"
# Create common WRITABLE (empty) dirs
mkdir -p /var/run /var/backups /var/cache/apache /var/local /var/lock/news \
         /var/nis /var/preserve /var/state/misc /var/tmp /var/lib \
	 /var/spool/cups/tmp \
         /mnt/cdrom /mnt/floppy /mnt/hd /mnt/test \
         /home/knoppix /home/root /etc/sysconfig /etc/X11 /etc/cups
chown knoppix.knoppix /home/knoppix
# Create empty utmp and wtmp
:> /var/run/utmp
:> /var/run/wtmp
# CUPS wants writable files. :-/
cp -a /KNOPPIX/etc/cups/*.conf /etc/cups/ 2>/dev/null
# All files in here should be size zero after Knoppix.clean was run
cp -a /KNOPPIX/var/local /KNOPPIX/var/games /KNOPPIX/var/log \
      /KNOPPIX/var/spool /var/ 2>/dev/null
cp -a /KNOPPIX/var/lib/games /KNOPPIX/var/lib/wine \
      /KNOPPIX/var/lib/nfs /KNOPPIX/var/lib/xkb /KNOPPIX/var/lib/isdn \
      /KNOPPIX/var/lib/kdm /KNOPPIX/var/lib/pcmcia \
      /var/lib/ 2>/dev/null
# Problematic directories in /var/lib (lots and lots of inodes)
ln -s /KNOPPIX/var/lib/dpkg /KNOPPIX/var/lib/apt /KNOPPIX/var/lib/doc-base \
      /KNOPPIX/var/lib/gnome /KNOPPIX/var/lib/kde \
      /KNOPPIX/var/lib/scrollkeeper /KNOPPIX/var/lib/texmf \
      /var/lib/ 2>/dev/null
# Debian-apt
ln -s /KNOPPIX/var/cache/apt /var/cache/ 2>/dev/null
ln -s /KNOPPIX/etc/skel /KNOPPIX/etc/nessus /etc/dhcpc/resolv.conf \
      /etc/ 2>/dev/null
ln -s /KNOPPIX/dev/* /dev/ 2>/dev/null
# Index files can be HUGE, so better replace cache/man tree by links later
# cp -a /KNOPPIX/var/cache/man /var/cache/ 2>/dev/null
# Create links from CDROM for UNWRITABLE (remaining) files
cp -aus /KNOPPIX/var/* /var/ 2>/dev/null
cp -aus /KNOPPIX/etc/* /etc/ 2>/dev/null
# Make SURE that these are files, not links!
rm -rf /etc/passwd /etc/shadow /etc/group \
       /etc/ppp /etc/isdn /etc/ssh /etc/ioctl.save \
       /etc/inittab /etc/network /etc/sudoers \
       /etc/init /etc/localtime /etc/dhcpc /etc/pnm2ppa.conf 2>/dev/null
cp -a /KNOPPIX/etc/passwd /KNOPPIX/etc/shadow /KNOPPIX/etc/group \
      /KNOPPIX/etc/ppp /KNOPPIX/etc/isdn /KNOPPIX/etc/ssh \
      /KNOPPIX/etc/inittab /KNOPPIX/etc/network /KNOPPIX/etc/sudoers \
      /KNOPPIX/sbin/init /KNOPPIX/etc/dhcpc /etc/ 2>/dev/null
# Extremely important, init crashes on shutdown if this is only a link
:> /etc/ioctl.save
:> /etc/pnm2ppa.conf
# Diet libc bug workaround
cp -f /KNOPPIX/etc/localtime /etc/localtime
echo "${BLUE}Done.${NORMAL}"

# Now tell kernel where the real modprobe lives
echo "/sbin/modprobe" > /proc/sys/kernel/modprobe

# Change root device from /dev/fd0 to /dev/ram0
echo "0x100" > /proc/sys/kernel/real-root-dev

# Give control to the init process.
echo "${CRE}${BLUE}Starting init process.${NORMAL}"
rm -f /linuxrc
exit 0

else
echo "${CRE}${RED}Can't find KNOPPIX filesystem, sorry.${NORMAL}"
echo "${RED}Dropping you to a (very limited) shell.${NORMAL}"
echo "${RED}Press reset button to quit.${NORMAL}"
echo ""
echo "Additional builtin commands avaliable:"
echo "	cat        mount     umount"
echo "	insmod     rmmod     lsmod"
echo ""
PS1="knoppix# "
export PS1
echo "6" > /proc/sys/kernel/printk
# Allow signals
trap 1 2 3 15
exec /static/ash
fi

Reply to: