diff -Naur linux-2.6.8-rc1-orig/Documentation/fb/00-INDEX linux-2.6.8-rc1-bp/Documentation/fb/00-INDEX --- linux-2.6.8-rc1-orig/Documentation/fb/00-INDEX 2004-06-16 07:19:36.000000000 +0200 +++ linux-2.6.8-rc1-bp/Documentation/fb/00-INDEX 2004-07-19 11:50:55.000000000 +0200 @@ -19,6 +19,8 @@ - info on the Matrox frame buffer driver pvr2fb.txt - info on the PowerVR 2 frame buffer driver +splash.txt + - info on the Framebuffer Splash tgafb.txt - info on the TGA (DECChip 21030) frame buffer driver vesafb.txt diff -Naur linux-2.6.8-rc1-orig/Documentation/fb/splash.txt linux-2.6.8-rc1-bp/Documentation/fb/splash.txt --- linux-2.6.8-rc1-orig/Documentation/fb/splash.txt 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.8-rc1-bp/Documentation/fb/splash.txt 2004-07-19 12:02:36.008967440 +0200 @@ -0,0 +1,261 @@ +What is it? +----------- + +The framebuffer splash is a kernel feature that allows displaying a background +picture on selected consoles and switching the first console to the so-called +silent mode, while booting/rebooting/shutting down the system. + +What do I need to get it to work? +--------------------------------- + +To get fb splash up-and-running you will have to: + 1) get a copy of splashutils from (FIXME URL) + 2) get some splash themes (FIXME URL) + 3) build the kernel helper program + 4) build your kernel with the FB_SPLASH option enabled. + +To get fb splash operational right after fbcon initialization is finished, you +will have to include a theme and the kernel helper into your initramfs image. +Please refer to splashutils documentation for instructions on how to do that. + +Operation modes +--------------- + +The framebuffer splash can work in two modes: verbose and silent. The first +one means "console with a background image". The latter one is a concept +first introduced in bootsplash. When silent mode is active, the console is +switched to a graphic mode and no text is displayed. It's up to the userspace +programs to display something (a progress bar for example) on the screen. + +Kernel command line parameters +------------------------------ + +Framebuffer splash can be configured from the kernel command line by passing +options in the following way: "splash=option1,option2". + +The following options are recognized: + +off - do not enable fbsplash after fbcon initialization, this is + default behaviour +verbose - switch fbsplash to verbose mode after fbcon is initialized +silent - switch fbsplash to silent mode after fbcon is initialized + +theme: - use theme 'name' on the first console, default theme name + is 'default' (who'd have guessed?) + +Example - you want to get verbose splash with the theme 'tux' right after +fbcon is up: + splash=verbose,theme:tux + +The userspace helper +-------------------- + +The userspace splash helper (by default: /sbin/splash_helper) is called by the +kernel whenever an important event occurs and the kernel needs some kind of +job to be carried out. Important events include console switches and graphic +mode switches (the kernel requests background images and config for the current +console). The splash helper must be accessible at all times. If it's not, fb +splash will be switched off automatically. + +***************************************************************************** + +The information below is mostly technical stuff. If you don't plan to develop +something fbsplash-related, there's probably no need to read it. + +The splash protocol +------------------- + +The splash protocol defines a communication interface between the kernel and +the userspace splash helper. + +The kernel side is responsible for: + + o rendering console text, using an image as a background (instead of a + standard solid color fbcon uses), + o accepting commands from the user via the /proc/splash file, + o calling the userspace helper to set things up as soon as the fb subsystem is + initialized. + +The userspace helper is responsible for everything else, including parsing +configuration files, decompressing the image files whenever the kernel needs +it, and communicating with the kernel if necessary. + +The splash protocol specifies how communication is done in both ways: +kernel->userspace and userspace->helper. + +Kernel -> Userspace +------------------- + +The kernel communicates with the userspace helper by calling it and specifying +the task that to be done in a series of arguments. + +The arguments follow the pattern: + + +All commands defined in splash protocol v1 have the following parameters: + virtual console + framebuffer number + splash mode - 'v' indicates verbose, 's' indicates silent + theme + +Splash protocol v1 specifies the following commands: + +getpic +------ + The kernel issues this command to request image data. It's up to the userspace + helper to find a background image appropriate for the specified theme and the + current resolution. The userspace helper should respond by issuing the + 'setpic' command to the kernel. + +init +---- + The kernel issues this command if either 'verbose' or 'silent' has been + specified in splash= on the kernel command line. Upon receiving this command, + the userspace helper should find a proper configuration file for the + specified theme and the current resolution, and issue the 'config' command + followed by the 'setpic' command. + + When the userspace helper is called in an early phase of the boot process + (right after the initialization of fbcon), the kernel ensures that /sys and + /proc are mounted. The helper program should create the appropriate framebuffer + device and tty0 file (if they don't already exist) to get current display + settings. + +Userspace -> Kernel +------------------- + +Userspace can communicate with the kernel side via /proc/splash. This file is +used by both the userspace helper (called only by the kernel) and userspace +configuration tools (run by the users). + +All commands should be written separately to /proc/splash, one command per a +single write. The first written byte specifies the version of the splash +protocol. The outline of a single write /proc/splash looks like: + + b splash protocol version + t command + d parameters + +In the above simple scheme and in the command description below the following +convention will be used: + + b byte + w word, 16-bit, 2 bytes + l long, 32-bit, 4 bytes + s string (a variable number of characters, zero-ended) + t string (a variable number of characters, not zero-ended) + d data (a variable number of bytes) + +Splash protocol v1 defines the following commands: + +sethelper +--------- +arguments: + s path to the new splash helper + +description: + Sets the path to the userspace splash helper. The path defaults to: + `/sbin/splash_helper` + +setpic +------ +arguments: + b virtual console + w image width + w image height + b image depth, bits per pixel + b palette colors [only if depth == 8] + d palette data [only if depth == 8] + d image data (size = width * height * depth/8) + +description: + Loads picture data for the given console into kernel space. This command can + be used by the kernel when switching consoles or by an userspace + configuration tool, which should issue it before enabling splash on the + console. If the console for which the image is loaded is not the foreground + console, all image data will be discarded. + + If image depth is equal to 8 bits per pixel, palette data has to be included + before the image data. Palette data should be specified in the following + format: + + - * 2 bytes: + red color data for colors, 2 bytes per color (u16) + - * 2 bytes: + green color data for colors, 2 bytes per color (u16) + - * 2 bytes: + blue color data for colors, 2 bytes per color (u16) + + Total length of the palette data should therefore be equal to: + * 2 * 3 bytes. + +config +------ +arguments: + b virtual console + b background color - the color that is to be treated as transparent + w text field upper left corner x coordinate + w text field upper left corner y coordinate + w text field width + w text field height + s splash theme + +description: + Sets the config parameters for the specified virtual console. These are + stored in vc_splash structure which is a part of vc_data struct. Each virtual + console remembers its theme. It is the task of the userspace helper to find a + background image appropriate for the current resolution and theme. + +verbose +------- +arguments: + none + +description: + Sets the global splash mode to 'verbose'. + +silent +------ +arguments: + none + +description: + Sets the global splash mode to 'silent'. + + NOTE: This command is only used to change a variable in the kernel space. + It's up to the userspace programs to switch the console to KD_GRAPHICS and + display the silent splash picture. + +on +-- +arguments: + b virtual console + +description: + Enables splash on the specified virtual console. + + NOTE: Before enabling splash a configuration utility should issue the 'config' + splash command and the 'setpic' command (the latter one only is current vc == + foreground vc). + +off +--- +arguments: + b virtual console + +description: + Disables splash on the specified virtual console. + +***************************************************************************** + +Credit +------ + +Original idea & implementation by: + Volker Poplawski , Stefan Reinauer , + Steffen Winterfeldt , Michael Schroeder , + Ken Wimer . + +Splash protocol redesign, current implementation, docs by: + Michal Januszewski + diff -Naur linux-2.6.8-rc1-orig/drivers/char/keyboard.c linux-2.6.8-rc1-bp/drivers/char/keyboard.c --- linux-2.6.8-rc1-orig/drivers/char/keyboard.c 2004-07-16 23:14:34.000000000 +0200 +++ linux-2.6.8-rc1-bp/drivers/char/keyboard.c 2004-07-18 21:05:02.000000000 +0200 @@ -41,6 +41,10 @@ #include #include +#ifdef CONFIG_FB_SPLASH +#include "../video/fbsplash.h" +#endif + static void kbd_disconnect(struct input_handle *handle); extern void ctrl_alt_del(void); @@ -1058,6 +1062,13 @@ if (keycode < BTN_MISC) printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode); +#ifdef CONFIG_FB_SPLASH + /* switch splash to verbose mode if ESC or F2 is pressed */ + if (down == 1 && (keycode == KEY_ESC || keycode == KEY_F2)) { + if (fbsplash_verbose()) + return; + } +#endif #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ if (keycode == KEY_SYSRQ && (sysrq_down || (down == 1 && sysrq_alt))) { sysrq_down = down; diff -Naur linux-2.6.8-rc1-orig/drivers/char/n_tty.c linux-2.6.8-rc1-bp/drivers/char/n_tty.c --- linux-2.6.8-rc1-orig/drivers/char/n_tty.c 2004-07-16 23:14:34.000000000 +0200 +++ linux-2.6.8-rc1-bp/drivers/char/n_tty.c 2004-07-18 21:04:51.000000000 +0200 @@ -49,6 +49,10 @@ #include #include +#ifdef CONFIG_FB_SPLASH +#include "../video/fbsplash.h" +#endif + /* number of characters left in xmit buffer before select has we have room */ #define WAKEUP_CHARS 256 @@ -994,6 +998,17 @@ return -EIO; } +#ifdef CONFIG_FB_SPLASH + /* automatically switch splash to verbose mode if someone tries to + read from tty0 */ + if (file->f_dentry->d_inode->i_rdev == MKDEV(TTY_MAJOR,0) || + file->f_dentry->d_inode->i_rdev == MKDEV(TTY_MAJOR,1) || + file->f_dentry->d_inode->i_rdev == MKDEV(TTYAUX_MAJOR,0) || + file->f_dentry->d_inode->i_rdev == MKDEV(TTYAUX_MAJOR,1)) { + fbsplash_verbose(); + } +#endif + /* Job control check -- must be done at start and after every sleep (POSIX.1 7.1.1.4). */ /* NOTE: not yet done after every sleep pending a thorough diff -Naur linux-2.6.8-rc1-orig/drivers/video/cfbsplash.c linux-2.6.8-rc1-bp/drivers/video/cfbsplash.c --- linux-2.6.8-rc1-orig/drivers/video/cfbsplash.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.8-rc1-bp/drivers/video/cfbsplash.c 2004-07-19 11:53:47.000000000 +0200 @@ -0,0 +1,474 @@ +/* + * linux/drivers/video/cfbsplash.c -- Framebuffer splash render functions + * + * Copyright (C) 2004 Michal Januszewski + * + * Code based upon "Bootsplash" (C) 2001-2003 + * Volker Poplawski , + * Stefan Reinauer , + * Steffen Winterfeldt , + * Michael Schroeder , + * Ken Wimer . + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ +#include +#include +#include +#include +#include +#include +#include + +#include "console/fbcon.h" +#include "fbsplash.h" + +#define parse_pixel(shift,bpp,type) \ + do { \ + if (d & (0x80 >> (shift))) \ + dd2[(shift)] = fgx; \ + else \ + dd2[(shift)] = transparent ? *(type *)splash_src : bgx; \ + splash_src += (bpp); \ + } while (0) \ + +void fbsplash_renderc(struct fb_info *info, int ypos, int xpos, int height, + int width, u8* src, u32 fgx, u32 bgx, u8 transparent) +{ + unsigned int x, y; + u32 dd; + int bytespp = (info->var.bits_per_pixel >> 3); + unsigned int d = ypos * info->fix.line_length + xpos * bytespp; + u16 dd2[4]; + + u8* splash_src = (u8 *)(info->splash.data + d); + u8* dst = (u8 *)(info->screen_base + d); + + if ((ypos + height) > info->var.yres || (xpos + width) > info->var.xres) + return; + + for (y = 0; y < height; y++) { + switch (info->var.bits_per_pixel) { + + case 32: + for (x = 0; x < width; x++) { + + if ((x & 7) == 0) + d = *src++; + if (d & 0x80) + dd = fgx; + else + dd = transparent ? + *(u32 *)splash_src : bgx; + + d <<= 1; + splash_src += 4; + fb_writel(dd, dst); + dst += 4; + } + break; + case 24: + for (x = 0; x < width; x++) { + + if ((x & 7) == 0) + d = *src++; + if (d & 0x80) + dd = fgx; + else + dd = transparent ? + (*(u32 *)splash_src & 0xffffff) : bgx; + + d <<= 1; + splash_src += 3; +#ifdef __LITTLE_ENDIAN + fb_writew(dd & 0xffff, dst); + dst += 2; + fb_writeb((dd >> 16), dst); +#else + fb_writew(dd >> 8, dst); + dst += 2; + fb_writeb(dd & 0xff, dst); +#endif + dst++; + } + break; + case 16: + for (x = 0; x < width; x += 2) { + if ((x & 7) == 0) + d = *src++; + + parse_pixel(0, 2, u16); + parse_pixel(1, 2, u16); +#ifdef __LITTLE_ENDIAN + dd = dd2[0] | (dd2[1] << 16); +#else + dd = dd2[1] | (dd2[1] << 16); +#endif + d <<= 2; + fb_writel(dd, dst); + dst += 4; + } + break; + + case 8: + for (x = 0; x < width; x += 4) { + if ((x & 7) == 0) + d = *src++; + + parse_pixel(0, 1, u8); + parse_pixel(1, 1, u8); + parse_pixel(2, 1, u8); + parse_pixel(3, 1, u8); + +#ifdef __LITTLE_ENDIAN + dd = dd2[0] | (dd2[1] << 8) | (dd2[2] << 16) | (dd2[3] << 24); +#else + dd = dd2[3] | (dd2[2] << 8) | (dd2[1] << 16) | (dd2[0] << 24); +#endif + d <<= 4; + fb_writel(dd, dst); + dst += 4; + } + } + + d = info->fix.line_length - width * bytespp; + dst += d; + splash_src += d; + } +} + +#define cc2cx(a) \ + ((info->fix.visual == FB_VISUAL_TRUECOLOR || \ + info->fix.visual == FB_VISUAL_DIRECTCOLOR) ? \ + ((u32*)info->pseudo_palette)[a] : a) + +void fbsplash_putcs(struct vc_data *vc, struct fb_info *info, + const unsigned short *s, int count, int yy, int xx) +{ + unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; + int fgshift = (vc->vc_hi_font_mask) ? 9 : 8; + int fg_color, bg_color, transparent; + + u8 *src; + u32 bgx, fgx; + + u16 c = scr_readw(s); + + fg_color = attr_fgcol(fgshift, c); + bg_color = attr_bgcol(bgshift, c); + transparent = vc->vc_splash.bg_color == bg_color; + + xx = xx * vc->vc_font.width + vc->vc_splash.tx; + yy = yy * vc->vc_font.height + vc->vc_splash.ty; + + fgx = cc2cx(fg_color); + bgx = cc2cx(bg_color); + + while (count--) { + c = scr_readw(s++); + src = vc->vc_font.data + (c & charmask) * vc->vc_font.height * + ((vc->vc_font.width + 7) >> 3); + + fbsplash_renderc(info, yy, xx, vc->vc_font.height, + vc->vc_font.width, src, fgx, bgx, transparent); + xx += vc->vc_font.width; + } +} + +void fbsplash_putc(struct vc_data *vc, struct fb_info *info, int c, + int ypos, int xpos) +{ + unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; + int fgshift = (vc->vc_hi_font_mask) ? 9 : 8; + u32 bg_color = attr_bgcol(bgshift, c); + u32 fg_color = attr_fgcol(fgshift, c); + u8 *src = vc->vc_font.data + (c & charmask) * vc->vc_font.height * + ((vc->vc_font.width + 7) >> 3); + xpos = xpos * vc->vc_font.width + vc->vc_splash.tx; + ypos = ypos * vc->vc_font.height + vc->vc_splash.ty; + + fbsplash_renderc(info, ypos, xpos, vc->vc_font.height, vc->vc_font.width, + src, cc2cx(fg_color), cc2cx(bg_color), + vc->vc_splash.bg_color == bg_color); +} + +void fbsplash_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + int i; + unsigned int dsize, s_pitch; + char *t = (char *)info->cursor.image.data; + struct vc_data* vc; + + vc = vc_cons[info->currcon].d; + + if (cursor->set & FB_CUR_SETSIZE) { + info->cursor.image.height = cursor->image.height; + info->cursor.image.width = cursor->image.width; + } + if (cursor->set & FB_CUR_SETPOS) { + info->cursor.image.dx = cursor->image.dx; + info->cursor.image.dy = cursor->image.dy; + } + if (cursor->set & FB_CUR_SETHOT) + info->cursor.hot = cursor->hot; + if (cursor->set & FB_CUR_SETCMAP) { + if (cursor->image.depth == 1) { + info->cursor.image.bg_color = cursor->image.bg_color; + info->cursor.image.fg_color = cursor->image.fg_color; + } else { + if (cursor->image.cmap.len) + fb_copy_cmap(&cursor->image.cmap, + &info->cursor.image.cmap, 0); + } + info->cursor.image.depth = cursor->image.depth; + } + s_pitch = (info->cursor.image.width + 7) >> 3; + dsize = s_pitch * info->cursor.image.height; + if (info->cursor.enable) { + switch (info->cursor.rop) { + case ROP_XOR: + for (i = 0; i < dsize; i++) + t[i] = cursor->image.data[i] ^ info->cursor.mask[i]; + break; + case ROP_COPY: + default: + for (i = 0; i < dsize; i++) + t[i] = cursor->image.data[i] & info->cursor.mask[i]; + break; + } + } else if (t != cursor->image.data) + memcpy(t, cursor->image.data, dsize); + + fbsplash_renderc(info, + info->cursor.image.dy + vc->vc_splash.ty, + info->cursor.image.dx + vc->vc_splash.tx, + info->cursor.image.height, + info->cursor.image.width, + (u8*)info->cursor.image.data, + cc2cx(info->cursor.image.fg_color), + cc2cx(info->cursor.image.bg_color), + info->cursor.image.bg_color == vc->vc_splash.bg_color); +} + +static void splashset(u8 *dst, int height, int width, int dstbytes, + u32 bgx, int bpp) +{ + int i; + + if (bpp == 8) + bgx |= bgx << 8; + if (bpp == 16 || bpp == 8) + bgx |= bgx << 16; + + while (height-- > 0) { + u8 *p = dst; + + switch (bpp) { + + case 32: + for (i=0; i < width; i++) { + fb_writel(bgx, p); p += 4; + } + break; + case 24: + for (i=0; i < width; i++) { +#ifdef __LITTLE_ENDIAN + fb_writew((bgx & 0xffff),(u16*)p); p += 2; + fb_writeb((bgx >> 16),p++); +#else + fb_writew((bgx >> 8),(u16*)p); p += 2; + fb_writeb((bgx & 0xff),p++); +#endif + } + case 16: + for (i=0; i < width/4; i++) { + fb_writel(bgx,p); p += 4; + fb_writel(bgx,p); p += 4; + } + if (width & 2) { + fb_writel(bgx,p); p += 4; + } + if (width & 1) + fb_writew(bgx,(u16*)p); + break; + case 8: + for (i=0; i < width/4; i++) { + fb_writel(bgx,p); p += 4; + } + + if (width & 2) { + fb_writew(bgx,p); p += 2; + } + if (width & 1) + fb_writeb(bgx,(u8*)p); + break; + + } + dst += dstbytes; + } +} + +void fbsplash_copy(u8 *dst, u8 *src, int height, int width, int linebytes, + int bpp) +{ + int i; + + while (height-- > 0) { + u32 *p = (u32 *)dst; + u32 *q = (u32 *)src; + + switch (bpp) { + + case 32: + for (i=0; i < width; i++) + fb_writel(*q++, p++); + break; + case 24: + for (i=0; i < (width*3/4); i++) + fb_writel(*q++, p++); + if ((width*3) % 4) { + if (width & 2) { + fb_writeb(*(u8*)q, (u8*)p); + } else if (width & 1) { + fb_writew(*(u16*)q, (u16*)p); + fb_writeb(*(u8*)((u16*)q+1),(u8*)((u16*)p+2)); + } + } + break; + case 16: + 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); + break; + case 8: + for (i=0; i < width/4; i++) + fb_writel(*q++, p++); + + if (width & 2) { + fb_writew(*(u16*)q, (u16*)p); + q = (u32*) ((u16*)q + 1); + p = (u32*) ((u16*)p + 1); + } + if (width & 1) + fb_writeb(*(u8*)q, (u8*)p); + break; + } + + dst += linebytes; + src += linebytes; + } +} + +static void splashfill(struct fb_info *info, int sy, int sx, int height, + int width) +{ + int d = sy * info->fix.line_length + sx * (info->var.bits_per_pixel >> 3); + + fbsplash_copy((u8 *)(info->screen_base + d), (u8 *)(info->splash.data + d), + height, width, info->fix.line_length, info->var.bits_per_pixel); +} + + + +void fbsplash_clear(struct vc_data *vc, struct fb_info *info, int sy, int sx, + int height, int width) +{ + int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; + int bg_color = attr_bgcol_ec(bgshift, vc); + int transparent = vc->vc_splash.bg_color == bg_color; + u8 *dst; + + sy = sy * vc->vc_font.height + vc->vc_splash.ty; + sx = sx * vc->vc_font.width + vc->vc_splash.tx; + height *= vc->vc_font.height; + width *= vc->vc_font.width; + + if (transparent) { + splashfill(info, sy, sx, height, width); + } else { + dst = (u8 *)(info->screen_base + sy * info->fix.line_length + + sx * (info->var.bits_per_pixel >> 3)); + splashset(dst, height, width, info->fix.line_length, cc2cx(bg_color), + info->var.bits_per_pixel); + } +} + +void fbsplash_clear_margins(struct vc_data *vc, struct fb_info *info, + int bottom_only) +{ + unsigned int tw = vc->vc_cols*vc->vc_font.width; + unsigned int th = vc->vc_rows*vc->vc_font.height; + + if (!bottom_only) { + /* top margin */ + splashfill(info, 0, 0, vc->vc_splash.ty, info->var.xres); + /* left margin */ + splashfill(info, vc->vc_splash.ty, 0, th, vc->vc_splash.tx); + /* right margin */ + splashfill(info, vc->vc_splash.ty, vc->vc_splash.tx + tw, th, + info->var.xres - vc->vc_splash.tx - tw); + } + splashfill(info, vc->vc_splash.ty + th, 0, + info->var.yres - vc->vc_splash.ty - th, info->var.xres); +} + + +void fbsplash_bmove_redraw(struct vc_data *vc, struct fb_info *info, int y, + int sx, int dx, int width) +{ + u16 *d = (u16 *) (vc->vc_origin + vc->vc_size_row * y + dx * 2); + u16 *s = d + (dx - sx); + u16 *start = d; + u16 *ls = d; + u16 *le = d + width; + u16 c; + int x = dx; + u16 attr = 1; + + do { + c = scr_readw(d); + if (attr != (c & 0xff00)) { + attr = c & 0xff00; + if (d > start) { + fbsplash_putcs(vc, info, start, d - start, y, x); + x += d - start; + start = d; + } + } + if (s >= ls && s < le && c == scr_readw(s)) { + if (d > start) { + fbsplash_putcs(vc, info, start, d - start, y, x); + x += d - start + 1; + start = d + 1; + } else { + x++; + start++; + } + } + s++; + d++; + } while (d < le); + if (d > start) + fbsplash_putcs(vc, info, start, d - start, y, x); +} + +void fbsplash_blank(struct vc_data *vc, struct fb_info *info, int blank) +{ + if (blank) { + splashset((u8 *)info->screen_base, info->var.yres, info->var.xres, + info->fix.line_length, 0, info->var.bits_per_pixel); + } else { + update_screen(vc->vc_num); + fbsplash_clear_margins(vc, info, 0); + } +} + diff -Naur linux-2.6.8-rc1-orig/drivers/video/console/fbcon.c linux-2.6.8-rc1-bp/drivers/video/console/fbcon.c --- linux-2.6.8-rc1-orig/drivers/video/console/fbcon.c 2004-07-16 23:14:44.000000000 +0200 +++ linux-2.6.8-rc1-bp/drivers/video/console/fbcon.c 2004-07-19 11:57:43.000000000 +0200 @@ -93,6 +93,7 @@ #endif #include "fbcon.h" +#include "../fbsplash.h" #ifdef FBCONDEBUG # define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) @@ -211,9 +212,14 @@ info->cursor.rop == ROP_COPY || !vc || !CON_IS_VISIBLE(vc) || registered_fb[(int) con2fb_map[vc->vc_num]] != info) return; + acquire_console_sem(); info->cursor.enable ^= 1; - info->fbops->fb_cursor(info, &info->cursor); + if (fbsplash_active(info, vc_cons[info->currcon].d)) { + fbsplash_cursor(info, &info->cursor); + } else { + info->fbops->fb_cursor(info, &info->cursor); + } release_console_sem(); } @@ -415,6 +421,14 @@ area.sy = sy * vc->vc_font.height; area.dx = dx * vc->vc_font.width; area.dy = dy * vc->vc_font.height; + + if (fbsplash_active(info, vc)) { + area.sx += vc->vc_splash.tx; + area.sy += vc->vc_splash.ty; + area.dx += vc->vc_splash.tx; + area.dy += vc->vc_splash.ty; + } + area.height = height * vc->vc_font.height; area.width = width * vc->vc_font.width; @@ -427,6 +441,11 @@ int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; struct fb_fillrect region; + if (fbsplash_active(info, vc)) { + fbsplash_clear(vc, info, sy, sx, height, width); + return; + } + region.color = attr_bgcol_ec(bgshift, vc); region.dx = sx * vc->vc_font.width; region.dy = sy * vc->vc_font.height; @@ -459,6 +478,11 @@ struct fb_image image; u8 *src, *dst; + if (fbsplash_active(info, vc)) { + fbsplash_putcs(vc, info, s, count, yy, xx); + return; + } + image.fg_color = attr_fgcol((vc->vc_hi_font_mask) ? 9 : 8, scr_readw(s)); image.bg_color = attr_bgcol((vc->vc_hi_font_mask) ? 13 : 12, @@ -527,6 +551,11 @@ unsigned int bs = info->var.yres - bh; struct fb_fillrect region; + if (fbsplash_active(info, vc)) { + fbsplash_clear_margins(vc, info, bottom_only); + return; + } + region.color = attr_bgcol_ec(bgshift, vc); region.rop = ROP_COPY; @@ -623,6 +652,12 @@ cols = info->var.xres / vc->vc_font.width; rows = info->var.yres / vc->vc_font.height; + + if (fbsplash_active(info, vc)) { + cols = vc->vc_splash.twidth / vc->vc_font.width; + rows = vc->vc_splash.theight / vc->vc_font.height; + } + vc_resize(vc->vc_num, cols, rows); DPRINTK("mode: %s\n", info->fix.id); @@ -719,7 +754,7 @@ if (info_idx == -1 || info == NULL) return; if (vc->vc_num != display_fg || (info->flags & FBINFO_MODULE) || - (info->fix.type == FB_TYPE_TEXT)) + (info->fix.type == FB_TYPE_TEXT) || fbsplash_active(info, vc)) logo = 0; info->var.xoffset = info->var.yoffset = p->yscroll = 0; /* reset wrap/pan */ @@ -949,6 +984,11 @@ if (vt_cons[vc->vc_num]->vc_mode != KD_TEXT) return; + if (fbsplash_active(info, vc)) { + fbsplash_putc(vc, info, c, ypos, xpos); + return; + } + image.dx = xpos * vc->vc_font.width; image.dy = real_y(p, ypos) * vc->vc_font.height; image.width = vc->vc_font.width; @@ -1026,7 +1066,11 @@ if (info->cursor.rop == ROP_XOR) { info->cursor.enable = 0; info->cursor.rop = ROP_COPY; - info->fbops->fb_cursor(info, &cursor); + if (fbsplash_active(info, vc)) { + fbsplash_cursor(info, &cursor); + } else { + info->fbops->fb_cursor(info, &cursor); + } } break; case CM_MOVE: @@ -1102,7 +1146,11 @@ mask[i++] = 0xff; } info->cursor.rop = ROP_XOR; - info->fbops->fb_cursor(info, &cursor); + if (fbsplash_active(info, vc)) { + fbsplash_cursor(info, &cursor); + } else { + info->fbops->fb_cursor(info, &cursor); + } vbl_cursor_cnt = CURSOR_DRAW_DELAY; break; } @@ -1539,7 +1587,7 @@ count = vc->vc_rows; if (softback_top) fbcon_softback_note(vc, t, count); - if (logo_shown >= 0) + if (logo_shown >= 0 || fbsplash_active(info, vc)) goto redraw_up; switch (p->scrollmode) { case SCROLL_MOVE: @@ -1626,6 +1674,8 @@ case SM_DOWN: if (count > vc->vc_rows) /* Maximum realistic size */ count = vc->vc_rows; + if (fbsplash_active(info, vc)) + goto redraw_down; switch (p->scrollmode) { case SCROLL_MOVE: accel_bmove(vc, info, t, 0, t + count, 0, @@ -1768,6 +1818,13 @@ } return; } + + if (fbsplash_active(info, vc) && sy == dy && height == 1) { + /* must use slower redraw bmove to keep background pic intact */ + fbsplash_bmove_redraw(vc, info, sy, sx, dx, width); + return; + } + accel_bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx, height, width); } @@ -1822,7 +1879,7 @@ var.yres = height * fh; x_diff = info->var.xres - var.xres; y_diff = info->var.yres - var.yres; - if (x_diff < 0 || x_diff > fw || (y_diff < 0 || y_diff > fh)) { + if ((x_diff < 0 || x_diff > fw || (y_diff < 0 || y_diff > fh)) && !vc->vc_splash.state) { char mode[40]; DPRINTK("attempting resize %ix%i\n", var.xres, var.yres); @@ -1850,6 +1907,15 @@ struct display *p = &fb_display[vc->vc_num]; int i; + if (fbsplash_active_vc(vc)) { + struct vc_data *vc_curr = vc_cons[info->currcon].d; + + if (!vc_curr->vc_splash.theme || strcmp(vc->vc_splash.theme, vc_curr->vc_splash.theme)) { + if (fbsplash_call_helper("getpic", vc->vc_num)) + vc->vc_splash.state = 0; + } + } + if (softback_top) { int l = fbcon_softback_size / vc->vc_size_row; if (softback_lines) @@ -1967,6 +2033,12 @@ fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW); if (!info->fbops->fb_blank) { + + if (fbsplash_active(info, vc)) { + fbsplash_blank(vc, info, blank); + return 0; + } + if (blank) { unsigned short oldc; u_int height; @@ -2143,9 +2215,16 @@ } if (resize) { + u32 xres = info->var.xres, yres = info->var.yres; /* reset wrap/pan */ info->var.xoffset = info->var.yoffset = p->yscroll = 0; - vc_resize(vc->vc_num, info->var.xres / w, info->var.yres / h); + + if (fbsplash_active(info, vc)) { + xres = vc->vc_splash.twidth; + yres = vc->vc_splash.theight; + } + + vc_resize(vc->vc_num, xres / w, yres / h); if (CON_IS_VISIBLE(vc) && softback_buf) { int l = fbcon_softback_size / vc->vc_size_row; if (l > 5) @@ -2340,7 +2419,63 @@ else palette_cmap.len = 16; palette_cmap.start = 0; - return fb_set_cmap(&palette_cmap, 1, info); + + if (fbsplash_active(info, vc) && info->fix.visual == FB_VISUAL_DIRECTCOLOR) { + + u16 *red, *green, *blue; + u32 col; + int minlen = min(min(info->var.red.length, info->var.green.length), + info->var.blue.length); + int h; + + struct fb_cmap cmap = { + .start = 0, + .len = (1 << minlen), + .red = NULL, + .green = NULL, + .blue = NULL, + .transp = NULL + }; + + red = kmalloc(256 * sizeof(u16) * 3, GFP_KERNEL); + + if (!red) + goto out; + + green = red + 256; + blue = green + 265; + cmap.red = red; + cmap.green = green; + cmap.blue = blue; + + for (i = 0; i < cmap.len; i++) { + red[i] = green[i] = blue[i] = (0xffff * i)/(cmap.len-1); + } + + h = fb_set_cmap(&cmap,1,info); + + for (j = i = 0; i < 16; i++) { + k = table[i]; + + col = ((vc->vc_palette[j++] >> (8-minlen)) + << info->var.red.offset); + col |= ((vc->vc_palette[j++] >> (8-minlen)) + << info->var.green.offset); + col |= ((vc->vc_palette[j++] >> (8-minlen)) + << info->var.blue.offset); + + ((u32 *)info->pseudo_palette)[k] = col; + } + + kfree(red); + + return h; + + } else if (fbsplash_active(info, vc) && info->var.bits_per_pixel == 8 && + info->splash_cmap.red != NULL) + fb_set_cmap(&info->splash_cmap, 1, info); + +out: return fb_set_cmap(&palette_cmap, 1, info); } static u16 *fbcon_screen_pos(struct vc_data *vc, int offset) @@ -2520,7 +2655,10 @@ { /* Clear cursor, restore saved data */ info->cursor.enable = 0; - info->fbops->fb_cursor(info, &info->cursor); + if (fbsplash_active(info, vc_cons[info->currcon].d)) + fbsplash_cursor(info, &info->cursor); + else + info->fbops->fb_cursor(info, &info->cursor); } static void fbcon_resumed(struct fb_info *info) @@ -2552,7 +2690,13 @@ if (CON_IS_VISIBLE(vc)) { cols = info->var.xres / vc->vc_font.width; rows = info->var.yres / vc->vc_font.height; - vc_resize(vc->vc_num, cols, rows); + + if (!fbsplash_active(info, vc)) { + vc_resize(vc->vc_num, cols, rows); + } else { + if (fbsplash_call_helper("modechange", vc->vc_num)) + vc_resize(vc->vc_num, cols, rows); + } updatescrollmode(p, info, vc); scrollback_max = 0; scrollback_current = 0; @@ -2659,6 +2803,9 @@ fbcon_event_notifier_registered = 1; } release_console_sem(); + + fbsplash_init(); + return 0; } diff -Naur linux-2.6.8-rc1-orig/drivers/video/fbsplash.c linux-2.6.8-rc1-bp/drivers/video/fbsplash.c --- linux-2.6.8-rc1-orig/drivers/video/fbsplash.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.8-rc1-bp/drivers/video/fbsplash.c 2004-07-19 11:53:55.000000000 +0200 @@ -0,0 +1,471 @@ +/* + * linux/drivers/video/fbsplash.c -- Framebuffer splash routines + * + * Copyright (C) 2004 Michal Januszewski + * + * Code based upon "Bootsplash" (C) 2001-2003 + * Volker Poplawski , + * Stefan Reinauer , + * Steffen Winterfeldt , + * Michael Schroeder , + * Ken Wimer . + * + * Splash render routines are located in /linux/drivers/video/cfbsplash.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "console/fbcon.h" +#include "fbsplash.h" + +#define SPLASH_VERSION "0.9" + +#ifdef DEBUG +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +#else +#define DPRINTK(fmt, args...) +#endif + +static void splash_work_verbose(void *data); +static int splash_enable(unsigned int cons); +static int splash_disable(unsigned int cons); + +DECLARE_WORK(splash_wq_verbose, splash_work_verbose, NULL); + +static int splash_mode = 0; /* 0 = off, 1 = verbose, 2 = silent */ +static char *splash_helper; /* usermode helper program, + defaults to '/sbin/splash_helper' */ +static char splash_theme[64] __initdata = "default"; +static struct proc_dir_entry *proc_splash; + +int fbsplash_call_helper(char* cmd, unsigned short vc) +{ + char *envp[] = { + "HOME=/", + "PATH=/sbin:/bin", + NULL + }; + + char tfb[5]; + char tcons[5]; + unsigned char fb = (int) con2fb_map[vc]; + + char *argv[] = { + splash_helper, + "1", + cmd, + tcons, + tfb, + (splash_mode == 2) ? "s" : "v", + vc_cons[vc].d->vc_splash.theme, + NULL + }; + + snprintf(tfb,5,"%d",fb); + snprintf(tcons,5,"%d",vc); + + return call_usermodehelper(splash_helper, argv, envp, 1); +} + +int fbsplash_verbose(void) +{ + if (splash_mode != 2) + return 0; + + splash_mode = 1; + + /* we have to do the switch from a workqueue helper, because chances are this + * function is called from interrupt context, and we can't get hold of the + * console sem this way */ + schedule_work(&splash_wq_verbose); + + return 1; +} + +/* Switches the first console to verbose mode */ +static void splash_work_verbose(void *data) +{ + struct fb_info *info; + struct vc_data *vc; + + vc = vc_cons[0].d; + info = registered_fb[(int) con2fb_map[vc->vc_num]]; + + printk(KERN_INFO "splash: switching to verbose mode\n"); + + vt_cons[0]->vc_mode = KD_TEXT; + + acquire_console_sem(); + do_unblank_screen(0); + release_console_sem(); + + if (info->splash.data) { + splash_enable(0); + } else { + splash_disable(0); + } +} + +static int splash_disable(unsigned int cons) +{ + struct vc_data* vc; + struct fb_info* info; + + vc = vc_cons[cons].d; + info = registered_fb[(int) con2fb_map[vc->vc_num]]; + + if (!vc->vc_splash.state) + return -1; + + vc->vc_splash.state = 0; + + acquire_console_sem(); + vc_resize(vc->vc_num, info->var.xres / vc->vc_font.width, + info->var.yres / vc->vc_font.height); + + if (fg_console == vc->vc_num) { + redraw_screen(fg_console, 0); + update_region(fg_console, vc->vc_origin + + vc->vc_size_row * vc->vc_top, + vc->vc_size_row * (vc->vc_bottom - vc->vc_top) / 2); + } + release_console_sem(); + + printk(KERN_INFO "splash: switched splash state to 'off' on console %d\n", + vc->vc_num); + + return 0; +} + +static int splash_enable(unsigned int cons) +{ + struct vc_data* vc; + struct fb_info* info; + + vc = vc_cons[cons].d; + info = registered_fb[(int) con2fb_map[vc->vc_num]]; + + if (vc->vc_splash.twidth == 0 || vc->vc_splash.theight == 0 || !info->splash.data) + return -1; + + if (vc->vc_splash.state) + return -1; + + vc->vc_splash.state = 1; + + acquire_console_sem(); + vc_resize(vc->vc_num, vc->vc_splash.twidth / vc->vc_font.width, + vc->vc_splash.theight / vc->vc_font.height); + + if (fg_console == vc->vc_num) { + redraw_screen(fg_console, 0); + update_region(fg_console, vc->vc_origin + + vc->vc_size_row * vc->vc_top, + vc->vc_size_row * (vc->vc_bottom - vc->vc_top) / 2); + fbsplash_clear_margins(vc, info, 0); + } + release_console_sem(); + + printk(KERN_INFO "splash: switched splash state to 'on' on console %d\n", + vc->vc_num); + + return 0; +} + +static void splash_start(void) +{ + u8 splash_mounts = 0; + + if (sys_mount("proc", "/proc", "proc", 0, NULL) >= 0) + splash_mounts |= 0x1; + + if (sys_mount("sysfs", "/sys", "sysfs", 0, NULL) >= 0) + splash_mounts |= 0x2; + + fbsplash_call_helper("init", 0); + + if (splash_mounts & 0x2) + sys_umount("/sys", 0); + + if (splash_mounts & 0x1) + sys_umount("/proc",0); +} + +static int __init splash_setup(char *options) +{ + char *this_opt; + struct fb_info *info; + struct vc_data* vc; + + vc = vc_cons[0].d; + info = registered_fb[(int) con2fb_map[vc_cons[0].d->vc_num]]; + + while ((this_opt = strsep(&options, ",")) != NULL) { + + if (!strcmp(this_opt, "silent")) { + splash_mode = 2; + } else if (!strcmp(this_opt, "verbose")) { + splash_mode = 1; + printk(KERN_INFO "splash: verbose\n"); + } else if (!strcmp(this_opt, "off")) { + splash_mode = 0; + } else if (!strncmp(this_opt, "theme:", 6)) { + strncpy(splash_theme, this_opt+6, 64); + printk(KERN_INFO "splash: theme %s\n", splash_theme); + } else { + printk(KERN_WARNING "splash: unrecognized option %s\n", this_opt); + } + } + return 0; +} + +__setup("splash=", splash_setup); + +static int splash_read_proc(char *buffer, char **start, off_t offset, int size, + int *eof, void *data) +{ + int len = 0; + off_t begin = 0; + len += sprintf(buffer + len, "Splash v%s, mode: %s\n", SPLASH_VERSION, + ((splash_mode == 2) ? "silent" : (splash_mode == 1) ? + "verbose" : "off")); + + if (offset >= begin + len) + return 0; + + *start = buffer + (begin - offset); + + return (size < begin + len - offset ? size : begin + len - offset); +} + +#define BUF_SIZE 64 +#define PTC_XRES 1 +#define PTC_YRES 3 +#define PTC_BPP 5 +#define PTC_VC 0 +#define PTC_HDR (PTC_BPP + 1) +#define PTC_PAL 6 + +/* Handles the 'setpic' command */ +static int splash_setpic(const char __user *buffer, u8 *kbuf, int count) +{ + struct fb_image img; + struct vc_data* vc; + struct fb_info* info; + + int bytespp; + int paloff = 0; + + vc = vc_cons[kbuf[PTC_VC]].d; + info = registered_fb[(int) con2fb_map[vc->vc_num]]; + + if (vc->vc_num != fg_console) + return -1; + + memset(&img, 0, sizeof(struct fb_image)); + img.width = *(u16*)(kbuf+PTC_XRES); + img.height = *(u16*)(kbuf+PTC_YRES); + img.depth = kbuf[PTC_BPP]; + bytespp = img.depth >> 3; + + if (img.depth == 8) + paloff = kbuf[PTC_PAL] * 3 * 2 + 1; + + if (count - PTC_HDR - paloff < img.width * img.height * bytespp) { + printk(KERN_WARNING "splash: truncated image data - " + "not setting splash image\n"); + return -1; + } + + if (img.depth == 8) { + if (info->splash_cmap.red) + vfree((void*)info->splash_cmap.red); + + info->splash_cmap.red = vmalloc(kbuf[PTC_PAL] * 3 * 2); + info->splash_cmap.green = info->splash_cmap.red + kbuf[PTC_PAL]; + info->splash_cmap.blue = info->splash_cmap.green + kbuf[PTC_PAL]; + info->splash_cmap.transp = NULL; + info->splash_cmap.start = 16; + info->splash_cmap.len = kbuf[PTC_PAL]; + + copy_from_user(info->splash_cmap.red, + (void*)(buffer + PTC_PAL + 1), paloff-1); + } + + img.data = vmalloc(img.width * img.height * bytespp); + if (!img.data) { + printk(KERN_ERR + "splash: not enough memory to set image (%dx%d-%d)\n", + img.width, img.height, bytespp); + return -1; + } + + copy_from_user((void*)img.data, (void*)(buffer + PTC_HDR + paloff), + img.width * img.height * bytespp); + + if (info->splash.data) { + vfree((void*)info->splash.data); + info->splash.data = NULL; + } + + info->splash = img; + DPRINTK("set new image\n"); + + return 0; +} + +static int splash_write_proc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + struct vc_data* vc; + struct fb_info* info; + + u8 tbuf[BUF_SIZE]; + u8 *buf = tbuf; + + int buf_size = (count < BUF_SIZE) ? count : BUF_SIZE; + + if (!buffer) + return count; + + copy_from_user(tbuf, buffer, buf_size); + + /* we currently support only splash protocol v1 */ + if (tbuf[0] != 1) { + printk(KERN_WARNING + "splash: unsupported version of the bootsplash protocol (%d)\n", + buffer[0]); + return count; + } + + buf++; + buffer++; + + if (!strncmp(buf, "setpic", 6)) { + + buf += 6; + buffer += 6; + + splash_setpic(buffer, buf, count - 7); + + } else if (!strncmp(buf, "config", 6)) { + + buf += 6; + vc = vc_cons[(int)buf[0]].d; + info = registered_fb[(int) con2fb_map[vc->vc_num]]; + + if (vc->vc_splash.state) + splash_disable(vc->vc_num); + + vc->vc_splash.bg_color = *(u8*)(buf+1); + vc->vc_splash.tx = *(u16*)(buf+2); + vc->vc_splash.ty = *(u16*)(buf+4); + vc->vc_splash.twidth = *(u16*)(buf+6); + vc->vc_splash.theight = *(u16*)(buf+8); + + if (vc->vc_splash.theme) + kfree(vc->vc_splash.theme); + + tbuf[buf_size] = 0; + vc->vc_splash.theme = kmalloc(strlen(buf+10)+1,GFP_KERNEL); + strcpy(vc->vc_splash.theme, buf+10); + + printk(KERN_INFO "splash: console %d using theme '%s'\n", + vc->vc_num, vc->vc_splash.theme); + + } else if (!strncmp(buf, "sethelper", 9)) { + + char *t, *tmp; + buf += 9; + + if (count <= 10) + return count; + + tmp = kmalloc(count - 10, GFP_KERNEL); + copy_from_user(tmp, buffer + 9, count - 10); + tmp[count - 10] = 0; + + t = splash_helper; + splash_helper = tmp; + kfree(t); + + } else if (!strncmp(buf, "verbose", 7)) { + splash_mode = 1; + splash_work_verbose(NULL); + } else if (!strncmp(buf, "silent", 6)) { + splash_mode = 2; + } else if (!strncmp(buf, "off", 3)) { + buf += 3; + vc = vc_cons[buf[0]].d; + splash_disable(buf[0]); + } else if (!strncmp(buf, "on", 2)) { + buf += 2; + vc = vc_cons[buf[0]].d; + splash_enable(buf[0]); + } + + return count; +} + +static int splash_proc_register(void) +{ + if ((proc_splash = create_proc_entry("splash", 0, 0))) { + proc_splash->read_proc = splash_read_proc; + proc_splash->write_proc = splash_write_proc; + return 0; + } + return 1; +} + +int fbsplash_init(void) +{ + struct fb_info *info; + struct vc_data *vc; + int i; + + vc = vc_cons[0].d; + info = registered_fb[0]; + + splash_helper = kmalloc(20, GFP_KERNEL); + strcpy(splash_helper, "/sbin/splash_helper"); + splash_proc_register(); + + for (i = 0; i < num_registered_fb; i++) { + registered_fb[i]->splash.data = NULL; + registered_fb[i]->splash_cmap.red = NULL; + } + + for (i = 0; i < MAX_NR_CONSOLES; i++) { + vc_cons[i].d->vc_splash.state = vc_cons[i].d->vc_splash.twidth = + vc_cons[i].d->vc_splash.theight = 0; + } + + vc->vc_splash.theme = kmalloc((strlen(splash_theme)+1) * sizeof(char), GFP_KERNEL); + strcpy(vc->vc_splash.theme, splash_theme); + + if (splash_mode) + splash_start(); + + return 0; +} + diff -Naur linux-2.6.8-rc1-orig/drivers/video/fbsplash.h linux-2.6.8-rc1-bp/drivers/video/fbsplash.h --- linux-2.6.8-rc1-orig/drivers/video/fbsplash.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.8-rc1-bp/drivers/video/fbsplash.h 2004-07-18 21:06:14.000000000 +0200 @@ -0,0 +1,57 @@ +/* + * linux/drivers/video/fbsplash.h -- Framebuffer splash headers + * + * Copyright (C) 2004 Michal Januszewski + * + */ + +#ifndef __FB_SPLASH_H +#define __FB_SPLASH_H + +struct fb_cursor; +struct fb_info; +struct vc_data; + +/* fbsplash.c */ +int fbsplash_init(void); +int fbsplash_verbose(void); +int fbsplash_call_helper(char* cmd, unsigned short cons); + +/* cfbsplash.c */ +void fbsplash_putcs(struct vc_data *vc, struct fb_info *info, const unsigned short *s, int count, int yy, int xx); +void fbsplash_putc(struct vc_data *vc, struct fb_info *info, int c, int ypos, int xpos); +void fbsplash_cursor(struct fb_info *info, struct fb_cursor *cursor); +void fbsplash_clear(struct vc_data *vc, struct fb_info *info, int sy, int sx, int height, int width); +void fbsplash_clear_margins(struct vc_data *vc, struct fb_info *info, int bottom_only); +void fbsplash_blank(struct vc_data *vc, struct fb_info *info, int blank); +void fbsplash_bmove_redraw(struct vc_data *vc, struct fb_info *info, int y, int sx, int dx, int width); +void fbsplash_copy(u8 *dst, u8 *src, int height, int width, int linebytes, int bpp); + +/* vt.c */ +void acquire_console_sem(void); +void release_console_sem(void); +void do_unblank_screen(int entering_gfx); + +#ifndef CONFIG_FB_SPLASH +static inline void fbsplash_putcs(struct vc_data *vc, struct fb_info *info, const unsigned short *s, int count, int yy, int xx) {} +static inline void fbsplash_putc(struct vc_data *vc, struct fb_info *info, int c, int ypos, int xpos) {} +static inline void fbsplash_cursor(struct fb_info *info, struct fb_cursor *cursor) {} +static inline void fbsplash_clear(struct vc_data *vc, struct fb_info *info, int sy, int sx, int height, int width) {} +static inline void fbsplash_clear_margins(struct vc_data *vc, struct fb_info *info, int bottom_only) {} +static inline void fbsplash_blank(struct vc_data *vc, struct fb_info *info, int blank) {} +static inline void fbsplash_bmove_redraw(struct vc_data *vc, struct fb_info *info, int y, int sx, int dx, int width) {} +static inline int fbsplash_call_helper(char* cmd, unsigned short cons) { return 0; } +static inline int fbsplash_init(void) { return 0; } +static inline int fbsplash_verbose(void) { return 0; } +#endif + +/* struct vc_data *y */ +#define fbsplash_active_vc(y) (y->vc_splash.state && y->vc_splash.theme) + +/* struct fb_info *x, struct vc_data *y */ +#define fbsplash_active(x,y) (x->splash.data && fbsplash_active_vc(y) && \ + x->splash.width == x->var.xres && \ + x->splash.height == x->var.yres && \ + x->splash.depth == x->var.bits_per_pixel) + +#endif diff -Naur linux-2.6.8-rc1-orig/drivers/video/Kconfig linux-2.6.8-rc1-bp/drivers/video/Kconfig --- linux-2.6.8-rc1-orig/drivers/video/Kconfig 2004-07-17 03:11:43.000000000 +0200 +++ linux-2.6.8-rc1-bp/drivers/video/Kconfig 2004-07-18 19:18:02.000000000 +0200 @@ -1002,5 +1002,15 @@ source "drivers/video/logo/Kconfig" endif -endmenu +config FB_SPLASH + bool "Support for boot-up splash screen & graphical backgrounds on consoles" + depends on FRAMEBUFFER_CONSOLE=y + default n + ---help--- + This option enables support for the Linux boot-up splash screen and + graphical backgrounds on consoles. Note that you will need userspace + splashutils in order to take advantage of these features. Refer to + Documentation/fb/splash.txt for more information. + If you unsure, say N. +endmenu diff -Naur linux-2.6.8-rc1-orig/drivers/video/Makefile linux-2.6.8-rc1-bp/drivers/video/Makefile --- linux-2.6.8-rc1-orig/drivers/video/Makefile 2004-07-17 03:11:43.000000000 +0200 +++ linux-2.6.8-rc1-bp/drivers/video/Makefile 2004-07-19 12:06:44.000000000 +0200 @@ -6,6 +6,7 @@ obj-$(CONFIG_VT) += console/ obj-$(CONFIG_LOGO) += logo/ +obj-$(CONFIG_FB_SPLASH) += fbsplash.o cfbsplash.o obj-$(CONFIG_FB) += fbmem.o fbmon.o fbcmap.o fbsysfs.o modedb.o softcursor.o # Only include macmodes.o if we have FB support and are PPC diff -Naur linux-2.6.8-rc1-orig/include/linux/console_struct.h linux-2.6.8-rc1-bp/include/linux/console_struct.h --- linux-2.6.8-rc1-orig/include/linux/console_struct.h 2004-06-16 07:18:38.000000000 +0200 +++ linux-2.6.8-rc1-bp/include/linux/console_struct.h 2004-07-19 11:56:44.000000000 +0200 @@ -11,6 +11,15 @@ #define NPAR 16 +/* A structure used by the framebuffer splash code (drivers/video/fbsplash.c) */ +struct vc_splash { + u8 bg_color; /* The color that is to be treated as transparent */ + u8 state; /* Current splash state: 0 = off, 1 = on */ + u16 tx, ty; /* Top left corner coordinates of the text field */ + u16 twidth, theight; /* Width and height of the text field */ + char* theme; +}; + struct vc_data { unsigned short vc_num; /* Console number */ unsigned int vc_cols; /* [#] Console size */ @@ -87,6 +96,8 @@ struct vc_data **vc_display_fg; /* [!] Ptr to var holding fg console for this display */ unsigned long vc_uni_pagedir; unsigned long *vc_uni_pagedir_loc; /* [!] Location of uni_pagedir variable for this console */ + + struct vc_splash vc_splash; /* additional information is in vt_kern.h */ }; diff -Naur linux-2.6.8-rc1-orig/include/linux/fb.h linux-2.6.8-rc1-bp/include/linux/fb.h --- linux-2.6.8-rc1-orig/include/linux/fb.h 2004-07-16 23:14:48.000000000 +0200 +++ linux-2.6.8-rc1-bp/include/linux/fb.h 2004-07-17 00:19:07.000000000 +0200 @@ -555,6 +555,9 @@ #define FBINFO_STATE_SUSPENDED 1 u32 state; /* Hardware state i.e suspend */ + struct fb_image splash; + struct fb_cmap splash_cmap; + /* From here on everything is device dependent */ void *par; }; diff -Naur linux-2.6.8-rc1-orig/kernel/panic.c linux-2.6.8-rc1-bp/kernel/panic.c --- linux-2.6.8-rc1-orig/kernel/panic.c 2004-06-16 07:20:04.000000000 +0200 +++ linux-2.6.8-rc1-bp/kernel/panic.c 2004-07-19 12:04:48.000000000 +0200 @@ -82,6 +82,12 @@ * We can't use the "normal" timers since we just panicked.. */ printk(KERN_EMERG "Rebooting in %d seconds..",panic_timeout); +#ifdef CONFIG_FB_SPLASH + { + extern int fbsplash_verbose(void); + fbsplash_verbose(); + } +#endif for (i = 0; i < panic_timeout; i++) { touch_nmi_watchdog(); mdelay(1000); @@ -105,6 +111,12 @@ disabled_wait(caller); #endif local_irq_enable(); +#ifdef CONFIG_FB_SPLASH + { + extern int fbsplash_verbose(void); + fbsplash_verbose(); + } +#endif for (;;) ; }