[PATCH v2.4.x] Yet Another Boot Logo

From: Jason McMullan (jmcmullan@linuxcare.com)
Date: Tue Oct 03 2000 - 20:49:50 EST


        This kernel patch will allow you to have a full-screen
boot logo in any FBcon supported video mode, except for
VGA text mode. After applying the patch, you simply need to
answer `Y' to `Custom boot logo' under the Framebuffer Support
options. Then, place your custom boot_logo.ppm into
linux/Documentation/boot_logo.ppm

        When you recompile your kernel, the boot_logo.ppm
file will be reconstructed into a 214 color, 16 color, and
2 color B&W include file in linux/drivers/video/boot_logo.h

        When you boot into the logo-enabled kernel, the
logo will be automatically centered on your framebuffer,
and you will have 2 lines of kernel/init status at the bottom
of your screen. Like the std. ``penguin'' logo, your custom
logo will be repeated horizontally for however many processors
your have on your system, or however many logos will fit - whichever
is smaller.

        To remove the logo from the screen, simply switch away
from, them back to, the original boot-up VT.

        16 bit color seems buggy color-wise (pallette issue?) at this time.

        Comments, suggestions, patches, etc. are welcome.

diff --new-file -u -r linux-2.4.x/Documentation/Configure.help linux-2.4.x-logo/Documentation/Configure.help
--- linux-2.4.x/Documentation/Configure.help Wed Aug 30 12:57:37 2000
+++ linux-2.4.x-logo/Documentation/Configure.help Sat Sep 23 20:12:50 2000
@@ -3052,6 +3052,21 @@
   running kernel whenever you want), say M here and read
   Documentation/modules.txt. The module will be called vga16fb.o.
 
+Customizable Boot Logo for graphics modes
+CONFIG_FBCON_LOGO_BOOT
+ This allows you to change the boot logo from the default
+ `penguin' bootup. If you enable this option, make sure that
+ the PNM utilities and development headers/libraries are installed.
+ (aka libgr and libgr-devel).
+
+ Place your custom logo as a PPM file in the Documentation directory:
+
+ /usr/src/linux/Documentation/boot_logo.ppm
+
+ When you recompile your kernel and fbcon is enabled in a graphics
+ mode (ie anything but VGA text), your logo will be centered and
+ there will be 2 lines for boot messages.
+
 Select other compiled-in fonts
 CONFIG_FBCON_FONTS
   Say Y here if you would like to use fonts other than the default
diff --new-file -u -r linux-2.4.x/drivers/video/Config.in linux-2.4.x-logo/drivers/video/Config.in
--- linux-2.4.x/drivers/video/Config.in Mon Aug 14 09:04:25 2000
+++ linux-2.4.x-logo/drivers/video/Config.in Sat Sep 23 19:44:52 2000
@@ -159,6 +159,7 @@
       tristate ' Virtual Frame Buffer support (ONLY FOR TESTING!)' CONFIG_FB_VIRTUAL
    fi
 
+ bool ' Custom boot splash screen (graphics mode only)?' CONFIG_FBCON_LOGO_BOOT
    bool ' Advanced low level driver options' CONFIG_FBCON_ADVANCED
    if [ "$CONFIG_FBCON_ADVANCED" = "y" ]; then
       tristate ' Monochrome support' CONFIG_FBCON_MFB
diff --new-file -u -r linux-2.4.x/drivers/video/Makefile linux-2.4.x-logo/drivers/video/Makefile
--- linux-2.4.x/drivers/video/Makefile Mon Aug 14 09:04:25 2000
+++ linux-2.4.x-logo/drivers/video/Makefile Sat Sep 23 20:14:48 2000
@@ -160,7 +160,7 @@
 include $(TOPDIR)/Rules.make
 
 clean:
- rm -f core *.o *.a *.s
+ rm -f core *.o *.a *.s boot_logo.h
 
 ../conmakehash: ../conmakehash.c
         $(HOSTCC) $(HOSTCFLAGS) -o ../conmakehash ../conmakehash.c
@@ -171,3 +171,14 @@
             -e 's/dfont\(_uni.*\]\)/promfont\1 __initdata/' > promcon_tbl.c
 
 promcon_tbl.o: promcon_tbl.c $(TOPDIR)/include/linux/types.h
+
+ifeq ($(CONFIG_FBCON_LOGO_BOOT),y)
+fbcon.o: boot_logo.h
+
+boot_logo.h: $(TOPDIR)/Documentation/boot_logo.ppm
+ $(MAKE) -C $(TOPDIR)/scripts ppmtolinuxlogo
+ ppmquant 214 $(TOPDIR)/Documentation/boot_logo.ppm | $(TOPDIR)/scripts/ppmtolinuxlogo >boot_logo.h
+ ppmquant 16 $(TOPDIR)/Documentation/boot_logo.ppm | $(TOPDIR)/scripts/ppmtolinuxlogo -16 >>boot_logo.h
+ ppmquant 2 $(TOPDIR)/Documentation/boot_logo.ppm | $(TOPDIR)/scripts/ppmtolinuxlogo -bw >>boot_logo.h
+endif
+
diff --new-file -u -r linux-2.4.x/drivers/video/fbcon.c linux-2.4.x-logo/drivers/video/fbcon.c
--- linux-2.4.x/drivers/video/fbcon.c Mon Jul 24 21:24:26 2000
+++ linux-2.4.x-logo/drivers/video/fbcon.c Sat Sep 23 20:03:04 2000
@@ -94,9 +94,12 @@
 #ifdef CONFIG_FBCON_VGA_PLANES
 #include <asm/io.h>
 #endif
+#ifndef CONFIG_FBCON_LOGO_BOOT
 #define INCLUDE_LINUX_LOGO_DATA
+#endif
 #include <asm/linux_logo.h>
 
+
 #include <video/fbcon.h>
 #include <video/fbcon-mac.h> /* for 6x11 font on mac */
 #include <video/font.h>
@@ -107,8 +110,14 @@
 # define DPRINTK(fmt, args...)
 #endif
 
-#define LOGO_H 80
-#define LOGO_W 80
+#ifndef CONFIG_FBCON_LOGO_BOOT
+#define LOGO_W 80
+#define LOGO_H 80
+#else
+#define INCLUDE_LINUX_LOGO16
+#define INCLUDE_LINUX_LOGOBW
+#include "boot_logo.h"
+#endif
 #define LOGO_LINE (LOGO_W/8)
 
 struct display fb_display[MAX_NR_CONSOLES];
@@ -608,8 +617,12 @@
             /* Need to make room for the logo */
         int cnt;
         int step;
-
+
+#ifdef CONFIG_FBCON_LOGO_BOOT
+ logo_lines = nr_rows - 2;
+#else
             logo_lines = (LOGO_H + fontheight(p) - 1) / fontheight(p);
+#endif
             q = (unsigned short *)(conp->vc_origin + conp->vc_size_row * old_rows);
             step = logo_lines * old_cols;
             for (r = q - logo_lines * old_cols; r < q; r++)
@@ -638,10 +651,15 @@
                     conp->vc_pos += logo_lines * conp->vc_size_row;
                 }
             }
+ if (conp->vc_y < logo_lines) {
+ conp->vc_y=logo_lines;
+ conp->vc_pos=logo_lines*conp->vc_size_row;
+ }
             scr_memsetw((unsigned short *)conp->vc_origin,
                     conp->vc_video_erase_char,
                     conp->vc_size_row * logo_lines);
     }
+
     
     /*
      * ++guenther: console.c:vc_allocate() relies on initializing
@@ -2054,6 +2072,7 @@
     unsigned char *dst, *src;
     int i, j, n, x1, y1, x;
     int logo_depth, done = 0;
+ int num_logos,x_offset,y_offset;
 
     /* Return if the frame buffer is not mapped */
     if (!fb)
@@ -2114,8 +2133,17 @@
     if (p->fb_info->fbops->fb_rasterimg)
             p->fb_info->fbops->fb_rasterimg(p->fb_info, 1);
 
- for (x = 0; x < smp_num_cpus * (LOGO_W + 8) &&
- x < p->var.xres - (LOGO_W + 8); x += (LOGO_W + 8)) {
+ num_logos=(p->var.xres/(LOGO_W+8));
+ num_logos=(num_logos < smp_num_cpus) ? num_logos : smp_num_cpus;
+#ifdef CONFIG_FBCON_LOGO_BOOT
+ y_offset=(p->var.yres-LOGO_H)/2;
+ x_offset=(p->var.xres-(LOGO_W+8)*num_logos)/2;
+#else
+ y_offset=0;
+ x_offset=0;
+#endif
+
+ for (x = x_offset; num_logos > 0; x += (LOGO_W + 8), num_logos--) {
              
 #if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB24) || \
     defined(CONFIG_FBCON_CFB32) || defined(CONFIG_FB_SBUS)
@@ -2134,7 +2162,7 @@
                 src = logo;
                 bdepth = depth/8;
                 for( y1 = 0; y1 < LOGO_H; y1++ ) {
- dst = fb + y1*line + x*bdepth;
+ dst = fb + (y1+y_offset)*line + x*bdepth;
                     for( x1 = 0; x1 < LOGO_W; x1++, src++ ) {
                         val = (*src << redshift) |
                               (*src << greenshift) |
@@ -2160,7 +2188,7 @@
                 src = linux_logo16;
                 bdepth = (depth+7)/8;
                 for( y1 = 0; y1 < LOGO_H; y1++ ) {
- dst = fb + y1*line + x*bdepth;
+ dst = fb + (y1+y_offset)*line + x*bdepth;
                     for( x1 = 0; x1 < LOGO_W/2; x1++, src++ ) {
                         pix = (*src >> 4) | 0x10; /* upper nibble */
                         val = (pix << redshift) |
@@ -2208,7 +2236,7 @@
 
             src = logo;
             for( y1 = 0; y1 < LOGO_H; y1++ ) {
- dst = fb + y1*line + x*bdepth;
+ dst = fb + (y1+y_offset)*line + x*bdepth;
                 for( x1 = 0; x1 < LOGO_W; x1++, src++ ) {
                     val = safe_shift((linux_logo_red[*src-32] & redmask), redshift) |
                           safe_shift((linux_logo_green[*src-32] & greenmask), greenshift) |
@@ -2234,7 +2262,7 @@
         if (depth == 4 && p->type == FB_TYPE_PACKED_PIXELS) {
                 src = logo;
                 for( y1 = 0; y1 < LOGO_H; y1++) {
- dst = fb + y1*line + x/2;
+ dst = fb + (y1+y_offset)*line + x/2;
                         for( x1 = 0; x1 < LOGO_W/2; x1++) {
                                 u8 q = *src++;
                                 q = (q << 4) | (q >> 4);
@@ -2250,7 +2278,7 @@
                 
             src = logo;
             for( y1 = 0; y1 < LOGO_H; y1++ ) {
- dst = fb + y1*line + x;
+ dst = fb + (y1+y_offset)*line + x;
                 for( x1 = 0; x1 < LOGO_W; x1++ )
                     fb_writeb (*src++, dst++);
             }
@@ -2283,7 +2311,7 @@
             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(x/8+x1);
+ dst = fb + (y1+y_offset)*line + MAP_X(x/8+x1);
                     for( bit = 0; bit < logo_depth; bit++ ) {
                         val = 0;
                         for( mask = 0x80, i = 0; i < 8; mask >>= 1, i++ ) {
@@ -2302,7 +2330,7 @@
             if (depth > logo_depth) {
                 for( y1 = 0; y1 < LOGO_H; y1++ ) {
                     for( x1 = 0; x1 < LOGO_LINE; x1++ ) {
- dst = fb + y1*line + MAP_X(x/8+x1) + logo_depth*plane;
+ dst = fb + (y1+y_offset)*line + MAP_X(x/8+x1) + logo_depth*plane;
                         for( i = logo_depth; i < depth; i++, dst += plane )
                             *dst = (i == logo_depth && logo_depth == 4)
                                    ? 0xff : 0x00;
@@ -2329,9 +2357,9 @@
             for( y1 = 0; y1 < LOGO_H; y1++ ) {
                 src = logo + y1*LOGO_LINE;
                 if (is_hga)
- dst = fb + (y1%4)*8192 + (y1>>2)*line + x/8;
+ dst = fb + ((y1+y_offset)%4)*8192 + ((y1+y_offset)>>2)*line + x/8;
                 else
- dst = fb + y1*line + x/8;
+ dst = fb + (y1+y_offset)*line + x/8;
                 for( x1 = 0; x1 < LOGO_LINE; ++x1 )
                     fb_writeb(fb_readb(src++) ^ inverse, dst++);
             }
@@ -2347,7 +2375,7 @@
                 src = logo;
                 for (y1 = 0; y1 < LOGO_H; y1++) {
                         for (x1 = 0; x1 < LOGO_W / 2; x1++) {
- dst = fb + y1*line + x1/4 + x/8;
+ dst = fb + (y1+y_offset)*line + x1/4 + x/8;
 
                                 outb_p(0,0x3ce);
                                 outb_p(*src >> 4,0x3cf);
diff --new-file -u -r linux-2.4.x/scripts/Makefile linux-2.4.x-logo/scripts/Makefile
--- linux-2.4.x/scripts/Makefile Thu Mar 16 14:27:17 2000
+++ linux-2.4.x-logo/scripts/Makefile Sat Sep 23 20:13:23 2000
@@ -39,7 +39,10 @@
 docproc: docproc.o
         ${HOSTCC} -o docproc docproc.o
 
+ppmtolinuxlogo: ppmtolinuxlogo.o
+ ${HOSTCC} -o ppmtolinuxlogo ppmtolinuxlogo.o -lpnm -lppm -lpgm -lpbm
+
 clean:
- rm -f *~ kconfig.tk *.o tkparse mkdep split-include docproc
+ rm -f *~ kconfig.tk *.o tkparse mkdep split-include docproc ppmtolinuxlogo
 
 include $(TOPDIR)/Rules.make
diff --new-file -u -r linux-2.4.x/scripts/ppmtolinuxlogo.c linux-2.4.x-logo/scripts/ppmtolinuxlogo.c
--- linux-2.4.x/scripts/ppmtolinuxlogo.c Wed Dec 31 19:00:00 1969
+++ linux-2.4.x-logo/scripts/ppmtolinuxlogo.c Sat Sep 23 19:58:20 2000
@@ -0,0 +1,205 @@
+#include <stdio.h>
+
+#include <pnm.h>
+
+#define MAX_COLORS 214
+#define MAX_COLORS_16 16
+#define MAX_COLORS_BW 2
+
+int color_lookup(xel color,xel *colormap,int *used,int maxcolor)
+{
+ int i;
+
+ for (i=0;i<*used;i++) {
+ if (PPM_EQUAL(colormap[i],color))
+ return i;
+ }
+
+ if (i >= maxcolor) {
+ fprintf(stderr,"Too many colors: %d\n",maxcolor);
+ exit(1);
+ }
+
+ (*used)++;
+ colormap[i]=color;
+ return i;
+}
+
+void print_data(int *data,int len,const char *prefix,const char *name)
+{
+ int i;
+
+ printf("unsigned char linux_logo%s%s[] __initdata = {",prefix,name);
+
+ for (i=0;i<len;i++) {
+ if ( (i%8) == 0) printf("\n ");
+ printf(" 0x%.2X,",data[i]);
+ }
+
+ printf("\n};\n\n");
+}
+
+void linux_encode_bw(xel **ppm,int rows,int cols,int colormax,const char *prefix)
+{
+ int *m;
+ int row,col,i,used=0,bytes;
+ xel black;
+
+ PPM_PUTR(black,0);
+ PPM_PUTG(black,0);
+ PPM_PUTB(black,0);
+
+ bytes=(cols+7)>>3;
+ m=malloc(sizeof(int)*rows*bytes);
+ for (row=i=0;row<rows;row++) {
+ for (col=0;col<cols;col++) {
+ if ((col&7)==0) {
+ m[++i] = 0;
+ } else {
+ m[i] <<= 1;
+ }
+ if (!PPM_EQUAL(ppm[row][col],black))
+ m[i] |= 1;
+ }
+ /* End of row... */
+ for (;(col&7) != 0;col++) {
+ m[i] <<= 1;
+ }
+ }
+
+ printf("#ifdef INCLUDE_LINUX_LOGOBW\n\n");
+
+ print_data(m,rows*bytes,prefix,"");
+
+ printf("\n#endif /* INCLUDE_LINUX_LOGOBW */\n\n");
+
+ free(m);
+}
+
+void linux_encode_16(xel **ppm,int rows,int cols,int colormax,const char *prefix)
+{
+ int *r,*g,*b,*m;
+ xel colormap[MAX_COLORS];
+ int row,col,i,used=0;
+
+ m=malloc(sizeof(int)*rows*((cols+1)>>1));
+ for (row=i=0;row<rows;row++) {
+ for (col=0;col<cols;col++) {
+ if ((col&1)==0) {
+ m[++i]=0;
+ } else {
+ m[i] <<= 4;
+ }
+ m[i] |= color_lookup(ppm[row][col],colormap,&used,colormax);
+ }
+ }
+
+ r=malloc(sizeof(int)*used);
+ g=malloc(sizeof(int)*used);
+ b=malloc(sizeof(int)*used);
+
+ for (i=0;i<used;i++) {
+ r[i]=PPM_GETR(colormap[i]);
+ g[i]=PPM_GETG(colormap[i]);
+ b[i]=PPM_GETB(colormap[i]);
+ }
+
+ printf("#ifdef INCLUDE_LINUX_LOGO%s\n\n",prefix);
+
+ print_data(r,used,prefix,"_red");
+ print_data(g,used,prefix,"_green");
+ print_data(b,used,prefix,"_blue");
+ print_data(m,rows*((cols+1)>>1),prefix,"");
+
+ printf("\n#endif /* INCLUDE_LINUX_LOGO%s */\n\n",prefix);
+
+ free(r);
+ free(g);
+ free(b);
+ free(m);
+}
+
+void linux_encode(xel **ppm,int rows,int cols,int colormax,const char *prefix)
+{
+ int *r,*g,*b,*m;
+ xel colormap[MAX_COLORS];
+ int row,col,i,used=0;
+
+ m=malloc(sizeof(int)*rows*cols);
+ for (row=i=0;row<rows;row++) {
+ for (col=0;col<cols;col++,i++) {
+ m[i]=color_lookup(ppm[row][col],colormap,&used,colormax)+32;
+ }
+ }
+
+ r=malloc(sizeof(int)*used);
+ g=malloc(sizeof(int)*used);
+ b=malloc(sizeof(int)*used);
+
+ for (i=0;i<used;i++) {
+ r[i]=PPM_GETR(colormap[i]);
+ g[i]=PPM_GETG(colormap[i]);
+ b[i]=PPM_GETB(colormap[i]);
+ }
+
+ printf("#define LOGO_W %d\n",cols);
+ printf("#define LOGO_H %d\n\n",rows);
+
+ print_data(r,used,prefix,"_red");
+ print_data(g,used,prefix,"_green");
+ print_data(b,used,prefix,"_blue");
+ print_data(m,rows*cols,prefix,"");
+
+ free(r);
+ free(g);
+ free(b);
+ free(m);
+}
+
+int main(int argc,char **argv)
+{
+ xelval maxval;
+ xel **ppm;
+ FILE *inf;
+ int rows,cols,format,colors,colormax;
+ xel colormap[MAX_COLORS];
+ const char *prefix;
+ void (*encode)(xel **ppm,int rows,int cols,int colormax,const char *prefix);
+
+ if (argc>1 && strcmp(argv[1],"-16")==0) {
+ argc--;
+ memcpy(argv+1,argv+2,(argc-1)*sizeof(argv[0]));
+ prefix="16";
+ colormax=MAX_COLORS_16;
+ encode=linux_encode_16;
+ } else if (argc>1 && strcmp(argv[1],"-bw")==0) {
+ argc--;
+ memcpy(argv+1,argv+2,(argc-1)*sizeof(argv[0]));
+ prefix="_bw";
+ colormax=MAX_COLORS_BW;
+ encode=linux_encode_bw;
+ } else {
+ prefix="";
+ colormax=MAX_COLORS;
+ encode=linux_encode;
+ }
+
+ if (argc==1) {
+ inf=stdin;
+ } else {
+ inf=fopen(argv[1],"r");
+ if (inf==NULL)
+ exit(1);
+ }
+
+ ppm=pnm_readpnm(inf,&cols,&rows,&maxval,&format);
+ if (format != RPPM_FORMAT &&
+ format != PPM_FORMAT) {
+ fprintf(stderr,"%s: Not a ppm file!\n",argv[1]);
+ exit(1);
+ }
+
+ encode(ppm,rows,cols,colormax,prefix);
+
+ return 0;
+}

-- 
Jason McMullan, Senior Linux Consultant, Linuxcare, Inc.
412.422.8077 tel, 412.656.3519 cell, 415.701.0792 fax
jmcmullan@linuxcare.com, http://www.linuxcare.com/
Linuxcare. Support for the revolution.
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Sat Oct 07 2000 - 21:00:13 EST