Date: Fri, 26 Sep 1997 11:48:25 +0200
From: Roman Hodek <rnhodek@faui22c.informatik.uni-erlangen.de>
To: linux-m68k@lists.linux-m68k.org
Subject: L68K: Generic logo drawing function
Sender: owner-linux-m68k@phil.uni-sb.de


The patch below implements a new logo drawing function in fbcon.c that
isn't specific to a particular framebuffer. Therefore, it also removes
the show_logo functions from amifb and retz3fb.

The new logo function should work with many kinds of video memory
organization:

 - truecolor/directcolor if the depth is a multiple of 8 (and <= 32)
   (still untested... would be interested if the color shifting stuff
   works in the Falcon's 16bit HiColor mode)
 - 8 bit packed pixels (untested, too, but rather straightforward) (is
   there any other reasonable packed-pixel mode with depth != 8??)
 - any planed mode with depth >= 2; this includes separated planes,
   Amiga line-interleaved planes, and Atari word-interleaved planes.
   With 4..7 planes, the reduced (16) color image is used, with 2..3
   planes the monochrome version.
 - monochrome

The function uses only infos from the fb driver, so it theoretically
also should work with all future framebuffers... :-)

Other changes:

 - The iplan2p* fbcon drivers incorrectly did set next_plane to 0, it
   should be 2.

 - kgdb: If gdb asks whether to kill the "program" and user answers
   'y', then reset the remote machine. I think this best matches the
   sense of "kill the kernel" :-), and you also get a fresh kernel run
   you can debug.

 - Clear the framepointer %a6 before calling start_kernel, so that
   gdb notices the top of stack here.

Roman

------------------------------------------------------------------------------
diff -u --recursive --exclude-from=diff-excludes --new-file linux-2.1.55.orig/arch/m68k/kernel/head.S linux-2.1.55/arch/m68k/kernel/head.S
--- linux-2.1.55.orig/arch/m68k/kernel/head.S	Wed Jun 25 14:17:13 1997
+++ linux-2.1.55/arch/m68k/kernel/head.S	Thu Sep 25 22:35:51 1997
@@ -899,6 +899,7 @@
 /* jump to the kernel start */
 	putr()
 
+	subl	%a6,%a6		/* clear a6 for gdb */
 	jbsr	SYMBOL_NAME(start_kernel)
 
 /*
diff -u --recursive --exclude-from=diff-excludes --new-file linux-2.1.55.orig/arch/m68k/kernel/kgdb.c linux-2.1.55/arch/m68k/kernel/kgdb.c
--- linux-2.1.55.orig/arch/m68k/kernel/kgdb.c	Fri May 16 14:43:49 1997
+++ linux-2.1.55/arch/m68k/kernel/kgdb.c	Thu Sep 25 22:57:24 1997
@@ -1057,17 +1057,16 @@
 			return;
 
 			/*
-			 * kill the program
+			 * kill the program means reset the machine
 			 */
 		  case 'k' :
-			break;		/* do nothing */
-
-			/*
-			 * Reset the whole machine
-			 */
 		  case 'r':
-			if (mach_reset)
+			if (mach_reset) {
+				/* reply OK before actual reset */
+				strcpy(output_buffer,"OK");
+				putpacket(output_buffer);
 				(*mach_reset)();
+			}
 			else
 				strcpy(output_buffer,"E01");
 			break;
diff -u --recursive --exclude-from=diff-excludes --new-file linux-2.1.55.orig/drivers/video/amifb.c linux-2.1.55/drivers/video/amifb.c
--- linux-2.1.55.orig/drivers/video/amifb.c	Mon Sep 15 17:39:09 1997
+++ linux-2.1.55/drivers/video/amifb.c	Tue Sep 23 14:39:23 1997
@@ -59,7 +59,6 @@
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
 #include <asm/setup.h>
-#include <asm/linux_logo.h>
 
 #define DEBUG
 
@@ -1706,72 +1705,6 @@
 }
 
 
-#ifndef MODULE
-__initfunc(static int amifb_show_logo(void))
-{
-    struct amiga_fb_par *par = &currentpar;
-    int x1, x2, y, i, m, colorshift;
-    u_char *fb = (u_char *)videomemory, *p, s, t;
-
-    if (IS_AGA)
-	colorshift = 0;
-    else if (par->clk_shift == TAG_SHRES)
-	colorshift = 6;
-    else
-	colorshift = 4;
-    if (par->bpp == 8) {
-	/* 256 colors */
-	for (i = 0; i < LINUX_LOGO_COLORS; i++)
-	    ami_setcolreg(32+i, linux_logo_red[i]>>colorshift,
-	    		  linux_logo_green[i]>>colorshift,
-	    		  linux_logo_blue[i]>>colorshift, 0);
-	for (y = 0; y < 80; y++)
-	    for (x1 = 0; x1 < 10; x1++) {
-		p = fb+y*par->next_line+x1;
-		for (m = 1; m < 256; m <<= 1, p += par->next_plane) {
-		    t = 0;
-		    for (s = 0x80, x2 = 0; s; s >>= 1, x2++)
-			if (linux_logo[(y*10+x1)*8+x2] & m)
-			    t |= s;
-		    *p = t;
-		}
-	    }
-    } else if (par->bpp >= 4) {
-	/* 16 colors */
-	for (i = 0; i < 16; i++)
-	    ami_setcolreg(par->bpp == 4 ? i : 16+i,
-	    		  linux_logo16_red[i]>>colorshift,
-	    		  linux_logo16_green[i]>>colorshift,
-	    		  linux_logo16_blue[i]>>colorshift, 0);
-	for (y = 0; y < 80; y++) {
-	    for (x1 = 0; x1 < 10; x1++) {
-		p = fb+y*par->next_line+x1;
-		for (m = 1; m < 16; m <<= 1, p += par->next_plane) {
-		    t = 0;
-		    for (s = 0x80, x2 = 0; s; s >>= 1, x2++) {
-			if ((linux_logo16[(y*10+x1)*4+x2]>>4) & m)
-			    t |= s;
-			s >>= 1;
-			if (linux_logo16[(y*10+x1)*4+x2] & m)
-			    t |= s;
-		    }
-		    *p = t;
-		}
-	    }
-	    for (i = 4; i < par->bpp; i++)
-		memset(&fb[y*par->next_line+i*par->next_plane],
-		       i == 4 ? 0xff : 0x00, 10);
-	}
-    } else {
-	/* monochrome */
-	for (y = 0; y < 80; y++)
-	    memcpy(&fb[y*par->next_line], &linux_logo_bw[y*10], 10);
-    }
-    return(80/fb_display[0].fontheight+1);
-}
-#endif /* MODULE */
-
-
 	/*
 	 * Initialisation
 	 */
@@ -1953,11 +1886,6 @@
 
 	/* TODO: This driver cannot be unloaded yet */
 	MOD_INC_USE_COUNT;
-
-#ifndef MODULE
-	if (!console_show_logo)
-	    console_show_logo = amifb_show_logo;
-#endif
 
 	return mem_start;
 }
diff -u --recursive --exclude-from=diff-excludes --new-file linux-2.1.55.orig/drivers/video/fbcon-iplan2p2.c linux-2.1.55/drivers/video/fbcon-iplan2p2.c
--- linux-2.1.55.orig/drivers/video/fbcon-iplan2p2.c	Fri Sep 12 20:41:59 1997
+++ linux-2.1.55/drivers/video/fbcon-iplan2p2.c	Tue Sep 23 15:12:43 1997
@@ -188,7 +188,7 @@
 	return -EINVAL;
 
     p->next_line = p->var.xres_virtual>>2;
-    p->next_plane = 0;
+    p->next_plane = 2;
     MOD_INC_USE_COUNT;
     return 0;
 }
diff -u --recursive --exclude-from=diff-excludes --new-file linux-2.1.55.orig/drivers/video/fbcon-iplan2p4.c linux-2.1.55/drivers/video/fbcon-iplan2p4.c
--- linux-2.1.55.orig/drivers/video/fbcon-iplan2p4.c	Fri Sep 12 20:41:59 1997
+++ linux-2.1.55/drivers/video/fbcon-iplan2p4.c	Tue Sep 23 15:13:08 1997
@@ -207,7 +207,7 @@
 	return -EINVAL;
 
     p->next_line = p->var.xres_virtual>>1;
-    p->next_plane = 0;
+    p->next_plane = 2;
     MOD_INC_USE_COUNT;
     return 0;
 }
diff -u --recursive --exclude-from=diff-excludes --new-file linux-2.1.55.orig/drivers/video/fbcon-iplan2p8.c linux-2.1.55/drivers/video/fbcon-iplan2p8.c
--- linux-2.1.55.orig/drivers/video/fbcon-iplan2p8.c	Fri Sep 12 20:42:00 1997
+++ linux-2.1.55/drivers/video/fbcon-iplan2p8.c	Tue Sep 23 15:13:44 1997
@@ -256,7 +256,7 @@
 	return -EINVAL;
 
     p->next_line = p->var.xres_virtual;
-    p->next_plane = 0;
+    p->next_plane = 2;
     MOD_INC_USE_COUNT;
     return 0;
 }
diff -u --recursive --exclude-from=diff-excludes --new-file linux-2.1.55.orig/drivers/video/fbcon.c linux-2.1.55/drivers/video/fbcon.c
--- linux-2.1.55.orig/drivers/video/fbcon.c	Sun Sep 21 10:25:35 1997
+++ linux-2.1.55/drivers/video/fbcon.c	Fri Sep 26 10:32:05 1997
@@ -88,6 +88,7 @@
 #ifdef CONFIG_ATARI
 #include <asm/atariints.h>
 #endif
+#include <asm/linux_logo.h>
 
 #include "fbcon.h"
 
@@ -154,7 +155,6 @@
 static int fbcon_get_font(struct vc_data *conp, int *w, int *h, char *data);
 static int fbcon_set_font(struct vc_data *conp, int w, int h, char *data);
 static int fbcon_set_palette(struct vc_data *conp, unsigned char *table);
-
 int fbcon_register_driver(struct display_switch *dispsw, int is_accel);
 int fbcon_unregister_driver(struct display_switch *dispsw);
 
@@ -182,6 +182,7 @@
 static void request_driver(struct display *disp, int is_accel);
 #endif
 static struct display_switch *fbcon_get_driver(struct display *disp);
+static int fbcon_show_logo(void);
 
 
 /*
@@ -294,6 +295,9 @@
     if (irqres)
 	panic("fbcon_startup: Couldn't add vblank interrupt");
 
+    if (!console_show_logo)
+	console_show_logo = fbcon_show_logo;
+
     return kmem_start;
 }
 
@@ -987,6 +991,199 @@
 	palette_cmap.len = 16;
     return(p->fb_info->setcmap(&palette_cmap, unit));
 }
+
+
+
+#define LOGO_H		80
+#define LOGO_W		80
+#define LOGO_LINE	(LOGO_W/8)
+
+__initfunc(static int fbcon_show_logo( void ))
+{
+    struct display *p = &fb_display[fg_console]; /* draw to vt in foreground */
+    int depth = p->var.bits_per_pixel;
+    int line = p->next_line;
+    unsigned char *fb = p->screen_base;
+    unsigned char *logo;
+    unsigned char *dst, *src;
+    int i, j, n, x1, y1;
+    int logo_depth, done = 0;
+	
+    /* Set colors if visual is PSEUDOCOLOR and we have enough colors */
+    if (p->visual == FB_VISUAL_PSEUDOCOLOR && depth >= 4) {
+	int first_col = depth >= 8 ? 32 : depth > 4 ? 16 : 0;
+	int num_cols = depth >= 8 ? LINUX_LOGO_COLORS : 16;
+	unsigned char *red, *green, *blue;
+	int old_cmap_len;
+	
+	if (depth >= 8) {
+	    red   = linux_logo_red;
+	    green = linux_logo_green;
+	    blue  = linux_logo_blue;
+	}
+	else {
+	    red   = linux_logo16_red;
+	    green = linux_logo16_green;
+	    blue  = linux_logo16_blue;
+	}
+
+	/* dirty trick to avoid setcmap calling kmalloc which isn't
+	 * initialized yet... */
+	old_cmap_len = fb_display[fg_console].cmap.len;
+	fb_display[fg_console].cmap.len = 1 << depth;
+	
+	for( i = 0; i < num_cols; i += n ) {
+	    n = num_cols - i;
+	    if (n > 16)
+		/* palette_cmap provides space for only 16 colors at once */
+		n = 16;
+	    palette_cmap.start = first_col + i;
+	    palette_cmap.len   = n;
+	    for( j = 0; j < n; ++j ) {
+		palette_cmap.red[j]   = (red[i+j] << 8) | red[i+j];
+		palette_cmap.green[j] = (green[i+j] << 8) | green[i+j];
+		palette_cmap.blue[j]  = (blue[i+j] << 8) | blue[i+j];
+	    }
+	    p->fb_info->setcmap( &palette_cmap, fg_console );
+	}
+	fb_display[fg_console].cmap.len = old_cmap_len;
+    }
+
+    if (depth >= 8) {
+	logo = linux_logo;
+	logo_depth = 8;
+    }
+    else if (depth >= 4) {
+	logo = linux_logo16;
+	logo_depth = 4;
+    }
+    else {
+	logo = linux_logo_bw;
+	logo_depth = 1;
+    }
+
+#if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CYBER) || \
+    defined(CONFIG_FBCON_RETINAZ3)
+    if ((depth % 8 == 0) && (p->visual == FB_VISUAL_TRUECOLOR ||
+			     p->visual == FB_VISUAL_DIRECTCOLOR)) {
+	/* Modes without color mapping, needs special data transformation... */
+	unsigned long val;		/* max. depth 32! */
+	int bdepth = depth/8;
+	unsigned char mask[9] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff };
+	unsigned char redmask, greenmask, bluemask;
+	int redshift, greenshift, blueshift;
+		
+	/* Bug: Doesn't obey msb_right ... (who needs that?) */
+	redmask   = mask[p->var.red.length   < 8 ? p->var.red.length   : 8];
+	greenmask = mask[p->var.green.length < 8 ? p->var.green.length : 8];
+	bluemask  = mask[p->var.blue.length  < 8 ? p->var.blue.length  : 8];
+	redshift   = p->var.red.offset   - (8-p->var.red.length);
+	greenshift = p->var.green.offset - (8-p->var.green.length);
+	blueshift  = p->var.blue.offset  - (8-p->var.blue.length);
+
+	src = logo;
+	for( y1 = 0; y1 < LOGO_H; y1++ ) {
+	    dst = fb + y1*line;
+	    for( x1 = 0; x1 < LOGO_W; x1++, src++ ) {
+		val = ((linux_logo_red[*src]   & redmask)   << redshift) |
+		      ((linux_logo_green[*src] & greenmask) << greenshift) |
+		      ((linux_logo_blue[*src]  & bluemask)  << blueshift);
+		for( i = 0; i < bdepth; ++i )
+		    *dst++ = val >> (i*8);
+	    }
+	}
+		
+	done = 1;
+    }
+#endif
+#if defined(CONFIG_FBCON_CFB8) || defined(CONFIG_FBCON_CYBER) || \
+    defined(CONFIG_FBCON_RETINAZ3)
+    if (depth == 8 && p->type == FB_TYPE_PACKED_PIXELS) {
+	/* depth 8 or more, packed, with color registers */
+		
+	src = logo;
+	for( y1 = 0; y1 < LOGO_H; y1++ ) {
+	    dst = fb + y1*line;
+	    for( x1 = 0; x1 < LOGO_W; x1++ ) {
+		*dst++ = *src++;
+	    }
+	}
+
+	done = 1;
+    }
+#endif
+#if defined(CONFIG_FBCON_AFB) || defined(CONFIG_FBCON_ILBM) || \
+    defined(CONFIG_FBCON_IPLAN2P2) || defined(CONFIG_FBCON_IPLAN2P4) || \
+    defined(CONFIG_FBCON_IPLAN2P8)
+    if (depth >= 2 && (p->type == FB_TYPE_PLANES ||
+		       p->type == FB_TYPE_INTERLEAVED_PLANES)) {
+	/* planes (normal or interleaved), with color registers */
+	int bit;
+	unsigned char val, mask;
+	int plane = p->next_plane;
+
+	/* for support of Atari interleaved planes */
+#define MAP_X(x)	(plane > line ? x : (x & ~1)*depth + (x & 1))
+	/* extract a bit from the source image */
+#define	BIT(p,pix,bit)	(p[pix*logo_depth/8] & \
+			 (1 << ((8-((pix*logo_depth)&7)-logo_depth) + bit)))
+		
+	src = logo;
+	for( y1 = 0; y1 < LOGO_H; y1++ ) {
+	    for( x1 = 0; x1 < LOGO_LINE; x1++, src += logo_depth ) {
+		dst = fb + y1*line + MAP_X(x1);
+		for( bit = 0; bit < logo_depth; bit++ ) {
+		    val = 0;
+		    for( mask = 0x80, i = 0; i < 8; mask >>= 1, i++ ) {
+			if (BIT( src, i, bit ))
+			    val |= mask;
+		    }
+		    *dst = val;
+		    dst += plane;
+		}
+	    }
+	}
+	
+	/* fill remaining planes
+	 * special case for logo_depth == 4: we used color registers 16..31,
+	 * so fill plane 4 with 1 bits instead of 0 */
+	if (depth > logo_depth) {
+	    for( y1 = 0; y1 < LOGO_H; y1++ ) {
+		for( x1 = 0; x1 < LOGO_LINE; x1++ ) {
+		    dst = fb + y1*line + MAP_X(x1) + logo_depth*plane;
+		    for( i = logo_depth; i < depth; i++, dst += plane )
+			*dst = (i == logo_depth && logo_depth == 4)
+			       ? 0xff : 0x00;
+		}
+	    }
+	}
+	
+	done = 1;
+    }
+#endif
+#if defined(CONFIG_FBCON_MFB) || defined(CONFIG_FBCON_AFB) || \
+    defined(CONFIG_FBCON_ILBM)
+    if (depth == 1) {
+	/* monochrome */
+	unsigned char inverse = p->inverse ? 0x00 : 0xff;
+
+	/* can't use simply memcpy because need to apply inverse */
+	for( y1 = 0; y1 < LOGO_H; y1++ ) {
+	    src = logo + y1*LOGO_LINE;
+	    dst = fb + y1*line;
+	    for( x1 = 0; x1 < LOGO_LINE; ++x1 )
+		*dst++ = *src++ ^ inverse;
+	}
+
+	done = 1;
+    }
+#endif
+    /* Modes not yet supported: packed pixels with depth != 8 (does such a
+     * thing exist in reality?) */
+
+    return( done ? LOGO_H/p->fontheight + 1 : 0 );
+}
+
 
 
 /*
diff -u --recursive --exclude-from=diff-excludes --new-file linux-2.1.55.orig/drivers/video/retz3fb.c linux-2.1.55/drivers/video/retz3fb.c
--- linux-2.1.55.orig/drivers/video/retz3fb.c	Mon Sep 15 17:39:10 1997
+++ linux-2.1.55/drivers/video/retz3fb.c	Tue Sep 23 14:39:47 1997
@@ -37,7 +37,6 @@
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/pgtable.h>
-#include <asm/linux_logo.h>
 
 #include "retz3fb.h"
 
@@ -1479,36 +1478,6 @@
 }
 
 
-#ifndef MODULE
-__initfunc(static int retz3_show_logo(void))
-{
-	struct retz3_fb_par *par = &current_par;
-	short i;
-	unsigned int next_line;
-	unsigned char *p = (unsigned char *)z3_fbmem;
-
-	next_line = (par->xres_vir * par->bpp / 8);
-
-	if (par->bpp == 8) {
-		for (i = 0; i < LINUX_LOGO_COLORS; i++) {
-			retz3_setcolreg(32 + i,
-					linux_logo_red[i],
-					linux_logo_green[i],
-					linux_logo_blue[i],
-					0);
-		}
-#if 0
-		(*fbinfo [0].loadcmap)(&fbinfo [0], 0, linux_logo_colors + 32);
-#endif
-		for (i = 0; i < 80; i++, p += next_line){
-			memcpy (p, linux_logo + 80 * i, 80);
-		}
-	}
-
-	return(80/fb_display[0].fontheight + 1);
-}
-#endif
-
 /*
  *    Initialization
  */
@@ -1581,10 +1550,6 @@
 	/* TODO: This driver cannot be unloaded yet */
 	MOD_INC_USE_COUNT;
 
-#ifndef MODULE
-	if (!console_show_logo)
-		console_show_logo = retz3_show_logo;
-#endif
 	return mem_start;
 }
 
