diff -Naur --exclude='*.rej' --exclude='*.orig' linux-2.6.9-rc2-mm4/Documentation/fb/00-INDEX linux-2.6.9-rc2-mm4-fbsplash/Documentation/fb/00-INDEX --- linux-2.6.9-rc2-mm4/Documentation/fb/00-INDEX 2004-08-14 08:37:15.000000000 +0300 +++ linux-2.6.9-rc2-mm4-fbsplash/Documentation/fb/00-INDEX 2004-09-29 11:22:19.979787880 +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 --exclude='*.rej' --exclude='*.orig' linux-2.6.9-rc2-mm4/Documentation/fb/splash.txt linux-2.6.9-rc2-mm4-fbsplash/Documentation/fb/splash.txt --- linux-2.6.9-rc2-mm4/Documentation/fb/splash.txt 1970-01-01 02:00:00.000000000 +0200 +++ linux-2.6.9-rc2-mm4-fbsplash/Documentation/fb/splash.txt 2004-09-29 11:22:20.111767816 +0200 @@ -0,0 +1,230 @@ +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, +fbsplash will be switched off automatically. + +It's possible to set path to the splash helper by writing it to +/proc/sys/kernel/fbsplash. + +***************************************************************************** + +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 ioctls on the fbsplash device, + 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 + FBIOSPLASH_SETPIC ioctl. + +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 FBIOSPLASH_SETCFG. + FBIOSPLASH_SETPIC and FBIOSPLASH_SETSTATE commands. + + When the userspace helper is called in an early phase of the boot process + (right after the initialization of fbcon), no filesystems will be mounted. + The helper program should mount sysfs and then create the appropriate + framebuffer, fbsplash and tty0 devices (if they don't already exist) to get + current display settings and to be able to communicate with the kernel side. + + Note that the console sem is not held when the kernel calls splash_helper + with the 'init' command. The splash helper should perform all ioctls with + origin set to FB_SPLASH_IO_ORIG_USER. + +modechange +---------- + The kernel issues this command on a mode change. The helper's response should + be similar to the response to the 'init' command. Note that this time the + console sem is held and all ioctls must be performed with origin set to + FB_SPLASH_IO_ORIG_KERNEL. + + +Userspace -> Kernel +------------------- + +Userspace programs can communicate with the kernel side via ioctls on the +on the fbsplash device. These ioctls are to be used by both the userspace helper +(called only by the kernel) and userspace configuration tools (run by the users). +The splash helper should set the origin field to FB_SPLASH_IO_ORIG_KERNEL when +doing the appropriate ioctls. All userspace configuration tools should use +FB_SPLASH_IO_ORIG_USER. Failure to set the appropriate value in the origin +field when performing ioctls from the kernel helper may result in a deadlock. + +The framebuffer splash provides the following ioctls (all defined in linux/fb.h): + +FBIOSPLASH_SETMODE +description: sets the global fbsplash mode +argument: unsigned int; values: FB_SPLASH_MODE_VERBOSE, FB_SPLASH_MODE_SILENT + +FBIOSPLASH_GETMODE +description: gets the global fbsplash mode +argument: unsigned int*; values as in FBIOSPLASH_SETMODE + +FBIOSPLASH_SETPIC +description: loads a background picture for a virtual console +argument: struct fb_splash_iowrapper*; data: struct fb_image* +notes: +If called for consoles other than the current foreground one, the picture data +will be ignored. + +If the current virtual console is running in a 8-bpp mode, the cmap substruct +of fb_image has to be filled appropriately: start should be set to 16 (first 16 +colors are reserved for fbcon), len to a value <= 240 and red, green and blue +should point to valid cmap data. The transp field is ingored. The fields dx, dy +bg_color, fg_color in fb_image are ignored as well. + +FBIOSPLASH_SETCFG +description: sets the fbsplash config for a virtual console +argument: struct fb_splash_iowrapper*; data: struct vc_splash*; + the structure has to be filled with valid data. + +FBIOSPLASH_GETCFG +description: gets the fbsplash config for a virtual console +argument: struct fb_splash_iowrapper*; data: struct vc_splash* + +FBIOSPLASH_SETSTATE +description: sets the fbsplash state for a virtual console +argument: struct fb_splash_iowrapper*; data: unsigned int* + values: 0 = disabled, 1 = enabled. + +FBIOSPLASH_GETSTATE +description: gets the fbsplash state for a virtual console +argument: struct fb_splash_iowrapper*; data: unsigned int* + values: as in FBIOSPLASH_SETSTATE + +Info on used structures: + +Definition of struct vc_splash can be found in linux/console_splash.h, it's +heavily commented, so no special descriptions are necessary. Note that +the 'theme' field should point to a string no longer than FB_SPLASH_THEME_LEN. +When FBIOSPLASH_GETCFG call is performed, the theme field should point to a +char buffer of length FB_SPLASH_THEME_LEN. + +Definition of struct fb_splash_iowrapper can be found in linux/fb.h. +The fields in this struct have the following meaning: + +vc: +Virtual console number. + +origin: +Specifies if the ioctl is performed as a response to a kernel request. The +splash helper should set this field to FB_SPLASH_IO_ORIG_KERNEL, userspace +programs should set it to FB_SPLASH_IO_ORIG_USER. This field is necessary to +avoid console semaphore deadlocks. + +data: +Pointer to a data structure appropriate for the performed ioctl. Type of +the data struct is specified in the ioctls description, for example 'data: +struct vc_splash*' means that the 'data' field should be a pointer to a +vc_splash struct. + +***************************************************************************** + +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 --exclude='*.rej' --exclude='*.orig' linux-2.6.9-rc2-mm4/drivers/Makefile linux-2.6.9-rc2-mm4-fbsplash/drivers/Makefile --- linux-2.6.9-rc2-mm4/drivers/Makefile 2004-09-29 11:11:54.000000000 +0200 +++ linux-2.6.9-rc2-mm4-fbsplash/drivers/Makefile 2004-09-29 11:23:33.140665736 +0200 @@ -7,6 +7,7 @@ obj-$(CONFIG_PCI) += pci/ obj-$(CONFIG_PARISC) += parisc/ +obj-y += char/ obj-y += video/ obj-$(CONFIG_ACPI_BOOT) += acpi/ # PnP must come after ACPI since it will eventually need to check if acpi @@ -15,7 +16,6 @@ # char/ comes before serial/ etc so that the VT console is the boot-time # default. -obj-y += char/ # i810fb depends on char/agp/ obj-$(CONFIG_FB_I810) += video/i810/ diff -Naur --exclude='*.rej' --exclude='*.orig' linux-2.6.9-rc2-mm4/drivers/char/keyboard.c linux-2.6.9-rc2-mm4-fbsplash/drivers/char/keyboard.c --- linux-2.6.9-rc2-mm4/drivers/char/keyboard.c 2004-09-29 11:11:50.000000000 +0200 +++ linux-2.6.9-rc2-mm4-fbsplash/drivers/char/keyboard.c 2004-09-29 11:22:20.000000000 +0200 @@ -41,6 +41,8 @@ #include #include +#include "../video/fbsplash.h" + static void kbd_disconnect(struct input_handle *handle); extern void ctrl_alt_del(void); @@ -1074,6 +1076,12 @@ if (keycode < BTN_MISC) printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode); + /* switch splash to verbose mode if ESC or F2 is pressed */ + if (down == 1 && (keycode == KEY_ESC || keycode == KEY_F2)) { + if (fbsplash_verbose()) + return; + } + #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ if (keycode == KEY_SYSRQ && (sysrq_down || (down == 1 && sysrq_alt))) { sysrq_down = down; diff -Naur --exclude='*.rej' --exclude='*.orig' linux-2.6.9-rc2-mm4/drivers/char/n_tty.c linux-2.6.9-rc2-mm4-fbsplash/drivers/char/n_tty.c --- linux-2.6.9-rc2-mm4/drivers/char/n_tty.c 2004-08-14 08:36:11.000000000 +0300 +++ linux-2.6.9-rc2-mm4-fbsplash/drivers/char/n_tty.c 2004-09-29 11:22:20.000000000 +0200 @@ -49,6 +49,8 @@ #include #include +#include "../video/fbsplash.h" + /* number of characters left in xmit buffer before select has we have room */ #define WAKEUP_CHARS 256 @@ -989,6 +991,15 @@ return -EIO; } + /* 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(); + } + /* 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 --exclude='*.rej' --exclude='*.orig' linux-2.6.9-rc2-mm4/drivers/video/Kconfig linux-2.6.9-rc2-mm4-fbsplash/drivers/video/Kconfig --- linux-2.6.9-rc2-mm4/drivers/video/Kconfig 2004-09-29 11:12:21.000000000 +0200 +++ linux-2.6.9-rc2-mm4-fbsplash/drivers/video/Kconfig 2004-09-29 11:22:20.000000000 +0200 @@ -49,24 +49,6 @@ your driver does not take advantage of this feature, choosing Y will just increase the kernel size by about 5K. -config FB_TILEBLITTING - bool "Enable Tile Blitting Support" - depends on FB - default n - ---help--- - This enables tile blitting. Tile blitting is a drawing technique - where the screen is divided into rectangular sections (tiles), whereas - the standard blitting divides the screen into pixels. Because the - default drawing element is a tile, drawing functions will be passed - parameters in terms of number of tiles instead of number of pixels. - For example, to draw a single character, instead of using bitmaps, - an index to an array of bitmaps will be used. To clear or move a - rectangular section of a screen, the rectangle willbe described in - terms of number of tiles in the x- and y-axis. - - This is particularly important to one driver, the matroxfb. If - unsure, say N. - config FB_CIRRUS tristate "Cirrus Logic support" depends on FB && (ZORRO || PCI) @@ -1029,5 +1011,15 @@ source "drivers/video/logo/Kconfig" endif -endmenu +config FB_SPLASH + bool "Support for the framebuffer splash" + 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 unsure, say N. +endmenu diff -Naur --exclude='*.rej' --exclude='*.orig' linux-2.6.9-rc2-mm4/drivers/video/Makefile linux-2.6.9-rc2-mm4-fbsplash/drivers/video/Makefile --- linux-2.6.9-rc2-mm4/drivers/video/Makefile 2004-09-29 11:12:21.000000000 +0200 +++ linux-2.6.9-rc2-mm4-fbsplash/drivers/video/Makefile 2004-09-29 11:22:20.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 --exclude='*.rej' --exclude='*.orig' linux-2.6.9-rc2-mm4/drivers/video/cfbsplash.c linux-2.6.9-rc2-mm4-fbsplash/drivers/video/cfbsplash.c --- linux-2.6.9-rc2-mm4/drivers/video/cfbsplash.c 1970-01-01 02:00:00.000000000 +0200 +++ linux-2.6.9-rc2-mm4-fbsplash/drivers/video/cfbsplash.c 2004-09-29 11:22:20.000000000 +0200 @@ -0,0 +1,482 @@ +/* + * 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) \ + +extern int get_color(struct vc_data *vc, struct fb_info *info, + u16 c, int is_fg); + +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 + 7) >> 3); + unsigned int d = ypos * info->fix.line_length + xpos * bytespp; + unsigned int ds = (ypos * info->var.xres + xpos) * bytespp; + u16 dd2[4]; + + u8* splash_src = (u8 *)(info->splash.data + ds); + 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; + } + } + + dst += info->fix.line_length - width * bytespp; + splash_src += (info->var.xres - width) * bytespp; + } +} + +#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 fg_color, bg_color, transparent; + + u8 *src; + u32 bgx, fgx; + + u16 c = scr_readw(s); + + fg_color = get_color(vc, info, c, 1); + bg_color = get_color(vc, info, c, 0); + 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; + u32 bg_color = get_color(vc, info, c, 1); + u32 fg_color = get_color(vc, info, c, 0); + 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; + struct vc_data* vc; + u8 *src; + + 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); + } + info->cursor.image.depth = cursor->image.depth; + } + + info->cursor.image.data = cursor->image.data; + + src = kmalloc(64, GFP_ATOMIC); + if (!src) + return; + + 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++) + src[i] = cursor->image.data[i] ^ info->cursor.mask[i]; + break; + case ROP_COPY: + default: + for (i = 0; i < dsize; i++) + src[i] = cursor->image.data[i] & info->cursor.mask[i]; + break; + } + } else + memcpy(src, 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*)src, + cc2cx(info->cursor.image.fg_color), + cc2cx(info->cursor.image.bg_color), + info->cursor.image.bg_color == vc->vc_splash.bg_color); + + kfree(src); +} + +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 srclinebytes, 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 += srclinebytes; + } +} + +static void splashfill(struct fb_info *info, int sy, int sx, int height, + int width) +{ + int bytespp = ((info->var.bits_per_pixel + 7) >> 3); + int d = sy * info->fix.line_length + sx * bytespp; + int ds = (sy * info->var.xres + sx) * bytespp; + + fbsplash_copy((u8 *)(info->screen_base + d), (u8 *)(info->splash.data + ds), + height, width, info->fix.line_length, info->var.xres * bytespp, + 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 + 7) >> 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 --exclude='*.rej' --exclude='*.orig' linux-2.6.9-rc2-mm4/drivers/video/console/Makefile linux-2.6.9-rc2-mm4-fbsplash/drivers/video/console/Makefile --- linux-2.6.9-rc2-mm4/drivers/video/console/Makefile 2004-09-29 11:12:20.000000000 +0200 +++ linux-2.6.9-rc2-mm4-fbsplash/drivers/video/console/Makefile 2004-09-29 11:22:08.000000000 +0200 @@ -24,8 +24,7 @@ obj-$(CONFIG_STI_CONSOLE) += sticon.o sticore.o obj-$(CONFIG_VGA_CONSOLE) += vgacon.o obj-$(CONFIG_MDA_CONSOLE) += mdacon.o -obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon.o bitblit.o font.o -obj-$(CONFIG_FB_TILEBLITTING) += tileblit.o +obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon.o font.o obj-$(CONFIG_FB_STI) += sticore.o diff -Naur --exclude='*.rej' --exclude='*.orig' linux-2.6.9-rc2-mm4/drivers/video/console/bitblit.c linux-2.6.9-rc2-mm4-fbsplash/drivers/video/console/bitblit.c --- linux-2.6.9-rc2-mm4/drivers/video/console/bitblit.c 2004-09-29 11:12:20.000000000 +0200 +++ linux-2.6.9-rc2-mm4-fbsplash/drivers/video/console/bitblit.c 1970-01-01 02:00:00.000000000 +0200 @@ -1,370 +0,0 @@ -/* - * linux/drivers/video/console/bitblit.c -- BitBlitting Operation - * - * Originally from the 'accel_*' routines in drivers/video/console/fbcon.c - * - * Copyright (C) 2004 Antonino Daplas - * - * 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 "fbcon.h" - -/* - * Accelerated handlers. - */ -#define FBCON_ATTRIBUTE_UNDERLINE 1 -#define FBCON_ATTRIBUTE_REVERSE 2 -#define FBCON_ATTRIBUTE_BOLD 4 - -static inline int real_y(struct display *p, int ypos) -{ - int rows = p->vrows; - - ypos += p->yscroll; - return ypos < rows ? ypos : ypos - rows; -} - - -static inline int get_attribute(struct fb_info *info, u16 c) -{ - int attribute = 0; - - if (fb_get_color_depth(info) == 1) { - if (attr_underline(c)) - attribute |= FBCON_ATTRIBUTE_UNDERLINE; - if (attr_reverse(c)) - attribute |= FBCON_ATTRIBUTE_REVERSE; - if (attr_bold(c)) - attribute |= FBCON_ATTRIBUTE_BOLD; - } - - return attribute; -} - -static inline void update_attr(u8 *dst, u8 *src, int attribute, - struct vc_data *vc) -{ - int i, offset = (vc->vc_font.height < 10) ? 1 : 2; - int width = (vc->vc_font.width + 7) >> 3; - unsigned int cellsize = vc->vc_font.height * width; - u8 c; - - offset = cellsize - (offset * width); - for (i = 0; i < cellsize; i++) { - c = src[i]; - if (attribute & FBCON_ATTRIBUTE_UNDERLINE && i >= offset) - c = 0xff; - if (attribute & FBCON_ATTRIBUTE_BOLD) - c |= c >> 1; - if (attribute & FBCON_ATTRIBUTE_REVERSE) - c = ~c; - dst[i] = c; - } -} - -static void bit_bmove(struct vc_data *vc, struct fb_info *info, int sy, - int sx, int dy, int dx, int height, int width) -{ - struct fb_copyarea area; - - area.sx = sx * vc->vc_font.width; - area.sy = sy * vc->vc_font.height; - area.dx = dx * vc->vc_font.width; - area.dy = dy * vc->vc_font.height; - area.height = height * vc->vc_font.height; - area.width = width * vc->vc_font.width; - - info->fbops->fb_copyarea(info, &area); -} - -static void bit_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; - struct fb_fillrect region; - - region.color = attr_bgcol_ec(bgshift, vc); - region.dx = sx * vc->vc_font.width; - region.dy = sy * vc->vc_font.height; - region.width = width * vc->vc_font.width; - region.height = height * vc->vc_font.height; - region.rop = ROP_COPY; - - info->fbops->fb_fillrect(info, ®ion); -} - -static void bit_putcs(struct vc_data *vc, struct fb_info *info, - const unsigned short *s, int count, int yy, int xx, - int fg, int bg) -{ - void (*move_unaligned)(struct fb_info *info, struct fb_pixmap *buf, - u8 *dst, u32 d_pitch, u8 *src, u32 idx, - u32 height, u32 shift_high, u32 shift_low, - u32 mod); - void (*move_aligned)(struct fb_info *info, struct fb_pixmap *buf, - u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, - u32 height); - unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; - unsigned int width = (vc->vc_font.width + 7) >> 3; - unsigned int cellsize = vc->vc_font.height * width; - unsigned int maxcnt = info->pixmap.size/cellsize; - unsigned int scan_align = info->pixmap.scan_align - 1; - unsigned int buf_align = info->pixmap.buf_align - 1; - unsigned int shift_low = 0, mod = vc->vc_font.width % 8; - unsigned int shift_high = 8, pitch, cnt, size, k; - unsigned int idx = vc->vc_font.width >> 3; - unsigned int attribute = get_attribute(info, scr_readw(s)); - struct fb_image image; - u8 *src, *dst, *buf = NULL; - - if (attribute) { - buf = kmalloc(cellsize, GFP_KERNEL); - if (!buf) - return; - } - - image.fg_color = fg; - image.bg_color = bg; - - image.dx = xx * vc->vc_font.width; - image.dy = yy * vc->vc_font.height; - image.height = vc->vc_font.height; - image.depth = 1; - - if (info->pixmap.outbuf && info->pixmap.inbuf) { - move_aligned = fb_iomove_buf_aligned; - move_unaligned = fb_iomove_buf_unaligned; - } else { - move_aligned = fb_sysmove_buf_aligned; - move_unaligned = fb_sysmove_buf_unaligned; - } - while (count) { - if (count > maxcnt) - cnt = k = maxcnt; - else - cnt = k = count; - - image.width = vc->vc_font.width * cnt; - pitch = ((image.width + 7) >> 3) + scan_align; - pitch &= ~scan_align; - size = pitch * image.height + buf_align; - size &= ~buf_align; - dst = fb_get_buffer_offset(info, &info->pixmap, size); - image.data = dst; - if (mod) { - while (k--) { - src = vc->vc_font.data + (scr_readw(s++)& - charmask)*cellsize; - - if (attribute) { - update_attr(buf, src, attribute, vc); - src = buf; - } - - move_unaligned(info, &info->pixmap, dst, pitch, - src, idx, image.height, - shift_high, shift_low, mod); - shift_low += mod; - dst += (shift_low >= 8) ? width : width - 1; - shift_low &= 7; - shift_high = 8 - shift_low; - } - } else { - while (k--) { - src = vc->vc_font.data + (scr_readw(s++)& - charmask)*cellsize; - - if (attribute) { - update_attr(buf, src, attribute, vc); - src = buf; - } - - move_aligned(info, &info->pixmap, dst, pitch, - src, idx, image.height); - dst += width; - } - } - info->fbops->fb_imageblit(info, &image); - image.dx += cnt * vc->vc_font.width; - count -= cnt; - } - - if (buf) - kfree(buf); -} - -static void bit_clear_margins(struct vc_data *vc, struct fb_info *info, - int bottom_only) -{ - int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; - unsigned int cw = vc->vc_font.width; - unsigned int ch = vc->vc_font.height; - unsigned int rw = info->var.xres - (vc->vc_cols*cw); - unsigned int bh = info->var.yres - (vc->vc_rows*ch); - unsigned int rs = info->var.xres - rw; - unsigned int bs = info->var.yres - bh; - struct fb_fillrect region; - - region.color = attr_bgcol_ec(bgshift, vc); - region.rop = ROP_COPY; - - if (rw && !bottom_only) { - region.dx = info->var.xoffset + rs; - region.dy = 0; - region.width = rw; - region.height = info->var.yres_virtual; - info->fbops->fb_fillrect(info, ®ion); - } - - if (bh) { - region.dx = info->var.xoffset; - region.dy = info->var.yoffset + bs; - region.width = rs; - region.height = bh; - info->fbops->fb_fillrect(info, ®ion); - } -} - -static void bit_cursor(struct vc_data *vc, struct fb_info *info, - struct display *p, int mode, int fg, int bg) -{ - struct fb_cursor cursor; - unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; - int w = (vc->vc_font.width + 7) >> 3, c; - int y = real_y(p, vc->vc_y); - int attribute; - char *src; - - c = scr_readw((u16 *) vc->vc_pos); - attribute = get_attribute(info, c); - src = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height)); - if (attribute) { - u8 *dst; - - dst = kmalloc(w * vc->vc_font.height, GFP_ATOMIC); - if (!dst) - return; - if (info->cursor.data) - kfree(info->cursor.data); - info->cursor.data = dst; - update_attr(dst, src, attribute, vc); - src = dst; - } - - cursor.image.data = src; - cursor.set = FB_CUR_SETCUR; - cursor.image.depth = 1; - - switch (mode) { - case CM_ERASE: - if (info->cursor.rop == ROP_XOR) { - info->cursor.enable = 0; - info->cursor.rop = ROP_COPY; - info->fbops->fb_cursor(info, &cursor); - } - break; - case CM_MOVE: - case CM_DRAW: - info->cursor.enable = 1; - info->cursor.rop = ROP_XOR; - - if (info->cursor.image.fg_color != fg || - info->cursor.image.bg_color != bg) { - cursor.image.fg_color = fg; - cursor.image.bg_color = bg; - cursor.set |= FB_CUR_SETCMAP; - } - - if ((info->cursor.image.dx != (vc->vc_font.width * vc->vc_x)) || - (info->cursor.image.dy != (vc->vc_font.height * y))) { - cursor.image.dx = vc->vc_font.width * vc->vc_x; - cursor.image.dy = vc->vc_font.height * y; - cursor.set |= FB_CUR_SETPOS; - } - - if (info->cursor.image.height != vc->vc_font.height || - info->cursor.image.width != vc->vc_font.width) { - cursor.image.height = vc->vc_font.height; - cursor.image.width = vc->vc_font.width; - cursor.set |= FB_CUR_SETSIZE; - } - - if (info->cursor.hot.x || info->cursor.hot.y) { - cursor.hot.x = cursor.hot.y = 0; - cursor.set |= FB_CUR_SETHOT; - } - - if ((cursor.set & FB_CUR_SETSIZE) || - ((vc->vc_cursor_type & 0x0f) != p->cursor_shape) - || info->cursor.mask == NULL) { - char *mask = kmalloc(w*vc->vc_font.height, GFP_ATOMIC); - int cur_height, size, i = 0; - u8 msk = 0xff; - - if (!mask) - return; - - if (info->cursor.mask) - kfree(info->cursor.mask); - info->cursor.mask = mask; - p->cursor_shape = vc->vc_cursor_type & 0x0f; - cursor.set |= FB_CUR_SETSHAPE; - - switch (vc->vc_cursor_type & 0x0f) { - case CUR_NONE: - cur_height = 0; - break; - case CUR_UNDERLINE: - cur_height = (vc->vc_font.height < 10) ? 1 : 2; - break; - case CUR_LOWER_THIRD: - cur_height = vc->vc_font.height/3; - break; - case CUR_LOWER_HALF: - cur_height = vc->vc_font.height >> 1; - break; - case CUR_TWO_THIRDS: - cur_height = (vc->vc_font.height << 1)/3; - break; - case CUR_BLOCK: - default: - cur_height = vc->vc_font.height; - break; - } - size = (vc->vc_font.height - cur_height) * w; - while (size--) - mask[i++] = ~msk; - size = cur_height * w; - while (size--) - mask[i++] = msk; - } - info->fbops->fb_cursor(info, &cursor); - break; - } -} - -void fbcon_set_bitops(struct fbcon_ops *ops) -{ - ops->bmove = bit_bmove; - ops->clear = bit_clear; - ops->putcs = bit_putcs; - ops->clear_margins = bit_clear_margins; - ops->cursor = bit_cursor; -} - -EXPORT_SYMBOL(fbcon_set_bitops); - -MODULE_AUTHOR("Antonino Daplas "); -MODULE_DESCRIPTION("Bit Blitting Operation"); -MODULE_LICENSE("GPL"); - diff -Naur --exclude='*.rej' --exclude='*.orig' linux-2.6.9-rc2-mm4/drivers/video/console/fbcon.c linux-2.6.9-rc2-mm4-fbsplash/drivers/video/console/fbcon.c --- linux-2.6.9-rc2-mm4/drivers/video/console/fbcon.c 2004-09-29 11:12:20.000000000 +0200 +++ linux-2.6.9-rc2-mm4-fbsplash/drivers/video/console/fbcon.c 2004-09-29 11:24:54.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) @@ -120,7 +121,13 @@ static char fontname[40]; /* current fb_info */ -static int info_idx = -1; +static int info_idx = -1; + +#define REFCOUNT(fd) (((int *)(fd))[-1]) +#define FNTSIZE(fd) (((int *)(fd))[-2]) +#define FNTCHARCNT(fd) (((int *)(fd))[-3]) +#define FNTSUM(fd) (((int *)(fd))[-4]) +#define FONT_EXTRA_WORDS 4 #define CM_SOFTBACK (8) @@ -153,7 +160,6 @@ static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos); static void fbcon_putcs(struct vc_data *vc, const unsigned short *s, int count, int ypos, int xpos); -static void fbcon_clear_margins(struct vc_data *vc, int bottom_only); static void fbcon_cursor(struct vc_data *vc, int mode); static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, int count); @@ -163,6 +169,9 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch); static int fbcon_set_palette(struct vc_data *vc, unsigned char *table); static int fbcon_scrolldelta(struct vc_data *vc, int lines); +void accel_clear_margins(struct vc_data *vc, struct fb_info *info, + int bottom_only); + /* * Internal routines @@ -192,69 +201,26 @@ } #endif -static inline int get_color(struct vc_data *vc, struct fb_info *info, - u16 c, int is_fg) -{ - int depth = fb_get_color_depth(info); - int color = 0; - - if (depth != 1) - color = (is_fg) ? attr_fgcol((vc->vc_hi_font_mask) ? 9 : 8, c) - : attr_bgcol((vc->vc_hi_font_mask) ? 13 : 12, c); - - switch (depth) { - case 1: - { - /* 0 or 1 */ - int fg = (info->fix.visual != FB_VISUAL_MONO01) ? 1 : 0; - int bg = (info->fix.visual != FB_VISUAL_MONO01) ? 0 : 1; - - color = (is_fg) ? fg : bg; - break; - } - case 2: - /* - * Scale down 16-colors to 4 colors. Default 4-color palette - * is grayscale. - */ - color /= 4; - break; - case 3: - /* - * Last 8 entries of default 16-color palette is a more intense - * version of the first 8 (i.e., same chrominance, different - * luminance). - */ - color &= 7; - break; - } - - return color; -} - static void fb_flashcursor(void *private) { struct fb_info *info = (struct fb_info *) private; - struct fbcon_ops *ops = (struct fbcon_ops *) info->fbcon_par; - struct display *p; struct vc_data *vc = NULL; - int c; - int mode; if (info->currcon != -1) vc = vc_cons[info->currcon].d; if (info->state != FBINFO_STATE_RUNNING || - !vc || !CON_IS_VISIBLE(vc) || !info->cursor.flash || - vt_cons[vc->vc_num]->vc_mode != KD_TEXT || - registered_fb[(int) con2fb_map[vc->vc_num]] != info) + info->cursor.rop == ROP_COPY || !vc || !CON_IS_VISIBLE(vc) + || registered_fb[(int) con2fb_map[vc->vc_num]] != info) return; - p = &fb_display[vc->vc_num]; - c = scr_readw((u16 *) vc->vc_pos); + acquire_console_sem(); - mode = (info->cursor.enable) ? CM_ERASE : CM_DRAW; - ops->cursor(vc, info, p, mode, get_color(vc, info, c, 1), - get_color(vc, info, c, 0)); + info->cursor.enable ^= 1; + 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(); } @@ -379,6 +345,8 @@ info_idx = -1; } + fbsplash_init(); + return err; } @@ -389,6 +357,7 @@ int cnt, erase = vc->vc_video_erase_char, step; unsigned short *save = NULL, *r, *q; + /* * remove underline attribute from erase character * if black and white framebuffer. @@ -432,10 +401,9 @@ vc->vc_size_row * logo_lines); if (CON_IS_VISIBLE(vc) && vt_cons[vc->vc_num]->vc_mode == KD_TEXT) { - fbcon_clear_margins(vc, 0); + accel_clear_margins(vc, info, 0); update_screen(vc->vc_num); } - if (save) { q = (unsigned short *) (vc->vc_origin + vc->vc_size_row * @@ -445,7 +413,6 @@ vc->vc_pos += logo_lines * vc->vc_size_row; kfree(save); } - if (logo_lines > vc->vc_bottom) { logo_shown = -1; printk(KERN_INFO @@ -456,28 +423,6 @@ } } -#ifdef CONFIG_FB_TILEBLITTING -static void set_blitting_type(struct vc_data *vc, struct fb_info *info, - struct display *p) -{ - struct fbcon_ops *ops = (struct fbcon_ops *) info->fbcon_par; - - if ((info->flags & FBINFO_MISC_TILEBLITTING)) - fbcon_set_tileops(vc, info, p, ops); - else - fbcon_set_bitops(ops); -} -#else -static void set_blitting_type(struct vc_data *vc, struct fb_info *info, - struct display *p) -{ - struct fbcon_ops *ops = (struct fbcon_ops *) info->fbcon_par; - - info->flags &= ~FBINFO_MISC_TILEBLITTING; - fbcon_set_bitops(ops); -} -#endif /* CONFIG_MISC_TILEBLITTING */ - /** * set_con2fb_map - map console to frame buffer device * @unit: virtual console number to map @@ -513,35 +458,17 @@ acquire_console_sem(); con2fb_map[unit] = newidx; - if (!found) { - struct fbcon_ops *ops = NULL; - int err = 0; if (!try_module_get(info->fbops->owner)) { - err = -ENODEV; - } - - if (!err && info->fbops->fb_open && - info->fbops->fb_open(info, 0)) { - err = -ENODEV; - } - - if (!err) { - ops = kmalloc(sizeof(struct fbcon_ops), GFP_KERNEL); - if (!ops) - err = -ENOMEM; - } - - if (!err) { - info->fbcon_par = ops; - set_blitting_type(vc, info, NULL); - } - - if (err) { con2fb_map[unit] = oldidx; + release_console_sem(); + return -ENODEV; + } + if (info->fbops->fb_open && info->fbops->fb_open(info, 0)) { module_put(info->fbops->owner); + con2fb_map[unit] = oldidx; release_console_sem(); - return err; + return -ENODEV; } } @@ -560,11 +487,8 @@ release_console_sem(); return -ENODEV; } - if (oldinfo->queue.func == fb_flashcursor) del_timer_sync(&oldinfo->cursor_timer); - - kfree(oldinfo->fbcon_par); module_put(oldinfo->fbops->owner); } @@ -606,6 +530,277 @@ } /* + * Accelerated handlers. + */ +inline int get_color(struct vc_data *vc, struct fb_info *info, + u16 c, int is_fg) +{ + int depth = fb_get_color_depth(info); + int color = 0; + + if (depth != 1) + color = (is_fg) ? attr_fgcol((vc->vc_hi_font_mask) ? 9 : 8, c) + : attr_bgcol((vc->vc_hi_font_mask) ? 13 : 12, c); + + switch (depth) { + case 1: + { + /* 0 or 1 */ + int fg = (info->fix.visual != FB_VISUAL_MONO01) ? 1 : 0; + int bg = (info->fix.visual != FB_VISUAL_MONO01) ? 0 : 1; + + color = (is_fg) ? fg : bg; + break; + } + case 2: + /* + * Scale down 16-colors to 4 colors. Default 4-color palette + * is grayscale. + */ + color /= 4; + break; + case 3: + /* + * Last 8 entries of default 16-color palette is a more intense + * version of the first 8 (i.e., same chrominance, different + * luminance). + */ + color &= 7; + break; + } + + return color; +} + +#define FBCON_ATTRIBUTE_UNDERLINE 1 +#define FBCON_ATTRIBUTE_REVERSE 2 +#define FBCON_ATTRIBUTE_BOLD 4 + +static inline int get_attribute(struct fb_info *info, u16 c) +{ + int attribute = 0; + + if (fb_get_color_depth(info) == 1) { + if (attr_underline(c)) + attribute |= FBCON_ATTRIBUTE_UNDERLINE; + if (attr_reverse(c)) + attribute |= FBCON_ATTRIBUTE_REVERSE; + if (attr_bold(c)) + attribute |= FBCON_ATTRIBUTE_BOLD; + } + + return attribute; +} + +static inline void update_attr(u8 *dst, u8 *src, int attribute, + struct vc_data *vc) +{ + int i, offset = (vc->vc_font.height < 10) ? 1 : 2; + int width = (vc->vc_font.width + 7) >> 3; + unsigned int cellsize = vc->vc_font.height * width; + u8 c; + + offset = cellsize - (offset * width); + for (i = 0; i < cellsize; i++) { + c = src[i]; + if (attribute & FBCON_ATTRIBUTE_UNDERLINE && i >= offset) + c = 0xff; + if (attribute & FBCON_ATTRIBUTE_BOLD) + c |= c >> 1; + if (attribute & FBCON_ATTRIBUTE_REVERSE) + c = ~c; + dst[i] = c; + } +} + +void accel_bmove(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int dy, int dx, int height, int width) +{ + struct fb_copyarea area; + + area.sx = sx * vc->vc_font.width; + 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; + + info->fbops->fb_copyarea(info, &area); +} + +void accel_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; + 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; + region.width = width * vc->vc_font.width; + region.height = height * vc->vc_font.height; + region.rop = ROP_COPY; + + info->fbops->fb_fillrect(info, ®ion); +} + +void accel_putcs(struct vc_data *vc, struct fb_info *info, + const unsigned short *s, int count, int yy, int xx) +{ + void (*move_unaligned)(struct fb_info *info, struct fb_pixmap *buf, + u8 *dst, u32 d_pitch, u8 *src, u32 idx, + u32 height, u32 shift_high, u32 shift_low, + u32 mod); + void (*move_aligned)(struct fb_info *info, struct fb_pixmap *buf, + u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, + u32 height); + unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + unsigned int width = (vc->vc_font.width + 7) >> 3; + unsigned int cellsize = vc->vc_font.height * width; + unsigned int maxcnt = info->pixmap.size/cellsize; + unsigned int scan_align = info->pixmap.scan_align - 1; + unsigned int buf_align = info->pixmap.buf_align - 1; + unsigned int shift_low = 0, mod = vc->vc_font.width % 8; + unsigned int shift_high = 8, pitch, cnt, size, k; + unsigned int idx = vc->vc_font.width >> 3; + unsigned int attribute = get_attribute(info, scr_readw(s)); + struct fb_image image; + u8 *src, *dst, *buf = NULL; + + if (fbsplash_active(info, vc)) { + fbsplash_putcs(vc, info, s, count, yy, xx); + return; + } + + if (attribute) { + buf = kmalloc(cellsize, GFP_KERNEL); + if (!buf) + return; + } + + image.fg_color = get_color(vc, info, scr_readw(s), 1); + image.bg_color = get_color(vc, info, scr_readw(s), 0); + + image.dx = xx * vc->vc_font.width; + image.dy = yy * vc->vc_font.height; + image.height = vc->vc_font.height; + image.depth = 1; + + if (info->pixmap.outbuf && info->pixmap.inbuf) { + move_aligned = fb_iomove_buf_aligned; + move_unaligned = fb_iomove_buf_unaligned; + } else { + move_aligned = fb_sysmove_buf_aligned; + move_unaligned = fb_sysmove_buf_unaligned; + } + while (count) { + if (count > maxcnt) + cnt = k = maxcnt; + else + cnt = k = count; + + image.width = vc->vc_font.width * cnt; + pitch = ((image.width + 7) >> 3) + scan_align; + pitch &= ~scan_align; + size = pitch * image.height + buf_align; + size &= ~buf_align; + dst = fb_get_buffer_offset(info, &info->pixmap, size); + image.data = dst; + if (mod) { + while (k--) { + src = vc->vc_font.data + (scr_readw(s++)& + charmask)*cellsize; + + if (attribute) { + update_attr(buf, src, attribute, vc); + src = buf; + } + + move_unaligned(info, &info->pixmap, dst, pitch, + src, idx, image.height, + shift_high, shift_low, mod); + shift_low += mod; + dst += (shift_low >= 8) ? width : width - 1; + shift_low &= 7; + shift_high = 8 - shift_low; + } + } else { + while (k--) { + src = vc->vc_font.data + (scr_readw(s++)& + charmask)*cellsize; + + if (attribute) { + update_attr(buf, src, attribute, vc); + src = buf; + } + + move_aligned(info, &info->pixmap, dst, pitch, + src, idx, image.height); + dst += width; + } + } + info->fbops->fb_imageblit(info, &image); + image.dx += cnt * vc->vc_font.width; + count -= cnt; + } + + if (buf) + kfree(buf); +} + +void accel_clear_margins(struct vc_data *vc, struct fb_info *info, + int bottom_only) +{ + int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; + unsigned int cw = vc->vc_font.width; + unsigned int ch = vc->vc_font.height; + unsigned int rw = info->var.xres - (vc->vc_cols*cw); + unsigned int bh = info->var.yres - (vc->vc_rows*ch); + unsigned int rs = info->var.xres - rw; + unsigned int bs = info->var.yres - bh; + struct fb_fillrect region; + + if (fbsplash_active(info, vc)) { + if (!fbsplash_isverbose) + return; + fbsplash_clear_margins(vc, info, bottom_only); + return; + } + + region.color = attr_bgcol_ec(bgshift, vc); + region.rop = ROP_COPY; + + if (rw && !bottom_only) { + region.dx = info->var.xoffset + rs; + region.dy = 0; + region.width = rw; + region.height = info->var.yres_virtual; + info->fbops->fb_fillrect(info, ®ion); + } + + if (bh) { + region.dx = info->var.xoffset; + region.dy = info->var.yoffset + bs; + region.width = rs; + region.height = bh; + info->fbops->fb_fillrect(info, ®ion); + } +} + +/* * Low Level Operations */ /* NOTE: fbcon cannot be __init: it may be called from take_over_console later */ @@ -658,7 +853,6 @@ struct font_desc *font = NULL; struct module *owner; struct fb_info *info = NULL; - struct fbcon_ops *ops; int rows, cols; int irqres; @@ -685,16 +879,6 @@ module_put(owner); return NULL; } - - ops = kmalloc(sizeof(struct fbcon_ops), GFP_KERNEL); - if (!ops) { - module_put(owner); - return NULL; - } - - info->fbcon_par = ops; - set_blitting_type(vc, info, NULL); - if (info->fix.type != FB_TYPE_TEXT) { if (fbcon_softback_size) { if (!softback_buf) { @@ -724,7 +908,7 @@ if (!p->fontdata) { if (!fontname[0] || !(font = find_font(fontname))) font = get_default_font(info->var.xres, - info->var.yres); + info->var.yres); vc->vc_font.width = font->width; vc->vc_font.height = font->height; vc->vc_font.data = p->fontdata = font->data; @@ -733,6 +917,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); @@ -828,7 +1018,7 @@ if (info_idx == -1 || info == NULL) return; if (vc->vc_num != display_fg || logo_shown == -3 || - (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 */ @@ -859,7 +1049,6 @@ if (vc->vc_can_do_color) vc->vc_complement_mask <<= 1; } - cols = vc->vc_cols; rows = vc->vc_rows; new_cols = info->var.xres / vc->vc_font.width; @@ -923,7 +1112,7 @@ * This system is now divided into two levels because of complications * caused by hardware scrolling. Top level functions: * - * fbcon_bmove(), fbcon_clear(), fbcon_putc(), fbcon_clear_margins() + * fbcon_bmove(), fbcon_clear(), fbcon_putc() * * handles y values in range [0, scr_height-1] that correspond to real * screen positions. y_wrap shift means that first line of bitmap may be @@ -954,8 +1143,7 @@ int width) { struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; - struct fbcon_ops *ops = (struct fbcon_ops *) info->fbcon_par; - + struct display *p = &fb_display[vc->vc_num]; u_int y_break; @@ -972,11 +1160,11 @@ y_break = p->vrows - p->yscroll; if (sy < y_break && sy + height - 1 >= y_break) { u_int b = y_break - sy; - ops->clear(vc, info, real_y(p, sy), sx, b, width); - ops->clear(vc, info, real_y(p, sy + b), sx, height - b, + accel_clear(vc, info, real_y(p, sy), sx, b, width); + accel_clear(vc, info, real_y(p, sy + b), sx, height - b, width); } else - ops->clear(vc, info, real_y(p, sy), sx, height, width); + accel_clear(vc, info, real_y(p, sy), sx, height, width); } static void fbcon_putcs(struct vc_data *vc, const unsigned short *s, @@ -984,7 +1172,6 @@ { struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; struct display *p = &fb_display[vc->vc_num]; - struct fbcon_ops *ops = (struct fbcon_ops *) info->fbcon_par; if (!info->fbops->fb_blank && console_blanked) return; @@ -994,9 +1181,7 @@ if (vt_cons[vc->vc_num]->vc_mode != KD_TEXT) return; - ops->putcs(vc, info, s, count, real_y(p, ypos), xpos, - get_color(vc, info, scr_readw(s), 1), - get_color(vc, info, scr_readw(s), 0)); + accel_putcs(vc, info, s, count, real_y(p, ypos), xpos); } static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos) @@ -1004,39 +1189,145 @@ fbcon_putcs(vc, (const unsigned short *) &c, 1, ypos, xpos); } -static void fbcon_clear_margins(struct vc_data *vc, int bottom_only) -{ - struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; - struct fbcon_ops *ops = (struct fbcon_ops *) info->fbcon_par; - - ops->clear_margins(vc, info, bottom_only); -} - static void fbcon_cursor(struct vc_data *vc, int mode) { + struct fb_cursor cursor; struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; - struct fbcon_ops *ops = (struct fbcon_ops *) info->fbcon_par; + unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; struct display *p = &fb_display[vc->vc_num]; - int y = real_y(p, vc->vc_y); - int c = scr_readw((u16 *) vc->vc_pos); + int w = (vc->vc_font.width + 7) >> 3, c; + int y = real_y(p, vc->vc_y), fg, bg; + int attribute; + u8 *src; - info->cursor.flash = 1; if (mode & CM_SOFTBACK) { mode &= ~CM_SOFTBACK; if (softback_lines) { - if (y + softback_lines >= vc->vc_rows) { + if (y + softback_lines >= vc->vc_rows) mode = CM_ERASE; - info->cursor.flash = 0; - } else y += softback_lines; } } else if (softback_lines) fbcon_set_origin(vc); - ops->cursor(vc, info, p, mode, get_color(vc, info, c, 1), - get_color(vc, info, c, 0)); - vbl_cursor_cnt = CURSOR_DRAW_DELAY; + c = scr_readw((u16 *) vc->vc_pos); + attribute = get_attribute(info, c); + src = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height)); + if (attribute) { + u8 *dst; + + dst = kmalloc(w * vc->vc_font.height, GFP_ATOMIC); + if (!dst) + return; + if (info->cursor.data) + kfree(info->cursor.data); + info->cursor.data = dst; + update_attr(dst, src, attribute, vc); + src = dst; + } + + cursor.image.data = src; + cursor.set = FB_CUR_SETCUR; + cursor.image.depth = 1; + + switch (mode) { + case CM_ERASE: + if (info->cursor.rop == ROP_XOR) { + info->cursor.enable = 0; + info->cursor.rop = ROP_COPY; + if (fbsplash_active(info, vc)) { + fbsplash_cursor(info, &cursor); + } else { + info->fbops->fb_cursor(info, &cursor); + } + } + break; + case CM_MOVE: + case CM_DRAW: + info->cursor.enable = 1; + fg = get_color(vc, info, c, 1); + bg = get_color(vc, info, c, 0); + + if (info->cursor.image.fg_color != fg || + info->cursor.image.bg_color != bg) { + cursor.image.fg_color = fg; + cursor.image.bg_color = bg; + cursor.set |= FB_CUR_SETCMAP; + } + + if ((info->cursor.image.dx != (vc->vc_font.width * vc->vc_x)) || + (info->cursor.image.dy != (vc->vc_font.height * y))) { + cursor.image.dx = vc->vc_font.width * vc->vc_x; + cursor.image.dy = vc->vc_font.height * y; + cursor.set |= FB_CUR_SETPOS; + } + + if (info->cursor.image.height != vc->vc_font.height || + info->cursor.image.width != vc->vc_font.width) { + cursor.image.height = vc->vc_font.height; + cursor.image.width = vc->vc_font.width; + cursor.set |= FB_CUR_SETSIZE; + } + + if (info->cursor.hot.x || info->cursor.hot.y) { + cursor.hot.x = cursor.hot.y = 0; + cursor.set |= FB_CUR_SETHOT; + } + + if ((cursor.set & FB_CUR_SETSIZE) || + ((vc->vc_cursor_type & 0x0f) != p->cursor_shape) + || info->cursor.mask == NULL) { + char *mask = kmalloc(w*vc->vc_font.height, GFP_ATOMIC); + int cur_height, size, i = 0; + u8 msk = 0xff; + + if (!mask) + return; + + if (info->cursor.mask) + kfree(info->cursor.mask); + info->cursor.mask = mask; + p->cursor_shape = vc->vc_cursor_type & 0x0f; + cursor.set |= FB_CUR_SETSHAPE; + + switch (vc->vc_cursor_type & 0x0f) { + case CUR_NONE: + cur_height = 0; + break; + case CUR_UNDERLINE: + cur_height = (vc->vc_font.height < 10) ? 1 : 2; + break; + case CUR_LOWER_THIRD: + cur_height = vc->vc_font.height/3; + break; + case CUR_LOWER_HALF: + cur_height = vc->vc_font.height >> 1; + break; + case CUR_TWO_THIRDS: + cur_height = (vc->vc_font.height << 1)/3; + break; + case CUR_BLOCK: + default: + cur_height = vc->vc_font.height; + break; + } + size = (vc->vc_font.height - cur_height) * w; + while (size--) + mask[i++] = ~msk; + size = cur_height * w; + while (size--) + mask[i++] = msk; + } + info->cursor.rop = ROP_XOR; + if (fbsplash_active(info, vc)) { + fbsplash_cursor(info, &cursor); + } else { + info->fbops->fb_cursor(info, &cursor); + } + vbl_cursor_cnt = CURSOR_DRAW_DELAY; + break; + } } static int scrollback_phys_max = 0; @@ -1160,19 +1451,18 @@ { struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; struct display *p = &fb_display[vc->vc_num]; - struct fbcon_ops *ops = (struct fbcon_ops *) info->fbcon_par; - + p->yscroll += count; if (p->yscroll > p->vrows - vc->vc_rows) { - ops->bmove(vc, info, p->vrows - vc->vc_rows, - 0, 0, 0, vc->vc_rows, vc->vc_cols); + accel_bmove(vc, info, p->vrows - vc->vc_rows, + 0, 0, 0, vc->vc_rows, vc->vc_cols); p->yscroll -= p->vrows - vc->vc_rows; } info->var.xoffset = 0; info->var.yoffset = p->yscroll * vc->vc_font.height; info->var.vmode &= ~FB_VMODE_YWRAP; update_var(vc->vc_num, info); - fbcon_clear_margins(vc, 1); + accel_clear_margins(vc, info, 1); scrollback_max += count; if (scrollback_max > scrollback_phys_max) scrollback_max = scrollback_phys_max; @@ -1197,7 +1487,7 @@ if (redraw) fbcon_redraw_move(vc, p, t + count, vc->vc_rows - count, t); update_var(vc->vc_num, info); - fbcon_clear_margins(vc, 1); + accel_clear_margins(vc, info, 1); scrollback_max += count; if (scrollback_max > scrollback_phys_max) scrollback_max = scrollback_phys_max; @@ -1208,19 +1498,18 @@ { struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; struct display *p = &fb_display[vc->vc_num]; - struct fbcon_ops *ops = (struct fbcon_ops *) info->fbcon_par; p->yscroll -= count; if (p->yscroll < 0) { - ops->bmove(vc, info, 0, 0, p->vrows - vc->vc_rows, - 0, vc->vc_rows, vc->vc_cols); + accel_bmove(vc, info, 0, 0, p->vrows - vc->vc_rows, + 0, vc->vc_rows, vc->vc_cols); p->yscroll += p->vrows - vc->vc_rows; } info->var.xoffset = 0; info->var.yoffset = p->yscroll * vc->vc_font.height; info->var.vmode &= ~FB_VMODE_YWRAP; update_var(vc->vc_num, info); - fbcon_clear_margins(vc, 1); + accel_clear_margins(vc, info, 1); scrollback_max -= count; if (scrollback_max < 0) scrollback_max = 0; @@ -1244,7 +1533,7 @@ if (redraw) fbcon_redraw_move(vc, p, t, vc->vc_rows - count, t + count); update_var(vc->vc_num, info); - fbcon_clear_margins(vc, 1); + accel_clear_margins(vc, info, 1); scrollback_max -= count; if (scrollback_max < 0) scrollback_max = 0; @@ -1254,6 +1543,7 @@ static void fbcon_redraw_softback(struct vc_data *vc, struct display *p, long delta) { + struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; int count = vc->vc_rows; unsigned short *d, *s; unsigned long n; @@ -1310,16 +1600,16 @@ if (attr != (c & 0xff00)) { attr = c & 0xff00; if (s > start) { - fbcon_putcs(vc, start, s - start, - line, x); + accel_putcs(vc, info, start, s - start, + real_y(p, line), x); x += s - start; start = s; } } if (c == scr_readw(d)) { if (s > start) { - fbcon_putcs(vc, start, s - start, - line, x); + accel_putcs(vc, info, start, s - start, + real_y(p, line), x); x += s - start + 1; start = s + 1; } else { @@ -1331,7 +1621,8 @@ d++; } while (s < le); if (s > start) - fbcon_putcs(vc, start, s - start, line, x); + accel_putcs(vc, info, start, s - start, + real_y(p, line), x); line++; if (d == (u16 *) softback_end) d = (u16 *) softback_buf; @@ -1347,6 +1638,7 @@ static void fbcon_redraw_move(struct vc_data *vc, struct display *p, int line, int count, int dy) { + struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; unsigned short *s = (unsigned short *) (vc->vc_origin + vc->vc_size_row * line); @@ -1362,8 +1654,8 @@ if (attr != (c & 0xff00)) { attr = c & 0xff00; if (s > start) { - fbcon_putcs(vc, start, s - start, - dy, x); + accel_putcs(vc, info, start, s - start, + real_y(p, dy), x); x += s - start; start = s; } @@ -1372,7 +1664,8 @@ s++; } while (s < le); if (s > start) - fbcon_putcs(vc, start, s - start, dy, x); + accel_putcs(vc, info, start, s - start, + real_y(p, dy), x); console_conditional_schedule(); dy++; } @@ -1383,6 +1676,7 @@ { unsigned short *d = (unsigned short *) (vc->vc_origin + vc->vc_size_row * line); + struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; unsigned short *s = d + offset; while (count--) { @@ -1397,16 +1691,16 @@ if (attr != (c & 0xff00)) { attr = c & 0xff00; if (s > start) { - fbcon_putcs(vc, start, s - start, - line, x); + accel_putcs(vc, info, start, s - start, + real_y(p, line), x); x += s - start; start = s; } } if (c == scr_readw(d)) { if (s > start) { - fbcon_putcs(vc, start, s - start, - line, x); + accel_putcs(vc, info, start, s - start, + real_y(p, line), x); x += s - start + 1; start = s + 1; } else { @@ -1420,7 +1714,8 @@ d++; } while (s < le); if (s > start) - fbcon_putcs(vc, start, s - start, line, x); + accel_putcs(vc, info, start, s - start, + real_y(p, line), x); console_conditional_schedule(); if (offset > 0) line++; @@ -1463,7 +1758,6 @@ { struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; struct display *p = &fb_display[vc->vc_num]; - struct fbcon_ops *ops = (struct fbcon_ops *) info->fbcon_par; int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK; if (!info->fbops->fb_blank && console_blanked) @@ -1486,14 +1780,14 @@ 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: - ops->bmove(vc, info, t + count, 0, t, 0, - b - t - count, vc->vc_cols); - ops->clear(vc, info, b - count, 0, count, - vc->vc_cols); + accel_bmove(vc, info, t + count, 0, t, 0, + b - t - count, vc->vc_cols); + accel_clear(vc, info, b - count, 0, count, + vc->vc_cols); break; case SCROLL_WRAP_MOVE: @@ -1559,7 +1853,8 @@ redraw_up: fbcon_redraw(vc, p, t, b - t - count, count * vc->vc_cols); - fbcon_clear(vc, b - count, 0, count, vc->vc_cols); + accel_clear(vc, info, real_y(p, b - count), 0, + count, vc->vc_cols); scr_memsetw((unsigned short *) (vc->vc_origin + vc->vc_size_row * (b - count)), @@ -1572,11 +1867,13 @@ 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: - ops->bmove(vc, info, t, 0, t + count, 0, - b - t - count, vc->vc_cols); - ops->clear(vc, info, t, 0, count, vc->vc_cols); + accel_bmove(vc, info, t, 0, t + count, 0, + b - t - count, vc->vc_cols); + accel_clear(vc, info, t, 0, count, vc->vc_cols); break; case SCROLL_WRAP_MOVE: @@ -1640,7 +1937,8 @@ redraw_down: fbcon_redraw(vc, p, b - 1, b - t - count, -count * vc->vc_cols); - fbcon_clear(vc, t, 0, count, vc->vc_cols); + accel_clear(vc, info, real_y(p, t), 0, count, + vc->vc_cols); scr_memsetw((unsigned short *) (vc->vc_origin + vc->vc_size_row * t), @@ -1680,7 +1978,6 @@ int dy, int dx, int height, int width, u_int y_break) { struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; - struct fbcon_ops *ops = (struct fbcon_ops *) info->fbcon_par; u_int b; if (sy < y_break && sy + height > y_break) { @@ -1714,8 +2011,15 @@ } return; } - ops->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx, - height, width); + + 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); } static __inline__ void updatescrollmode(struct display *p, struct fb_info *info, @@ -1768,7 +2072,8 @@ 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) { struct fb_videomode *mode; DPRINTK("attempting resize %ix%i\n", var.xres, var.yres); @@ -1809,12 +2114,20 @@ static int fbcon_switch(struct vc_data *vc) { - struct fb_info *info; + struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; struct display *p = &fb_display[vc->vc_num]; struct fb_var_screeninfo var; int i, prev_console, do_set_par = 0; - info = registered_fb[(int) con2fb_map[vc->vc_num]]; + 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)) + fbsplash_disable(vc, 0); + } + } + if (softback_top) { int l = fbcon_softback_size / vc->vc_size_row; if (softback_lines) @@ -1855,6 +2168,7 @@ } memset(&var, 0, sizeof(struct fb_var_screeninfo)); + fb_videomode_to_var(&var, p->mode); display_to_var(&var, p); var.activate = FB_ACTIVATE_NOW; @@ -1876,8 +2190,6 @@ info->flags &= ~FBINFO_MISC_MODESWITCH; } - set_blitting_type(vc, info, p); - vc->vc_can_do_color = (fb_get_color_depth(info) != 1); vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; updatescrollmode(p, info, vc); @@ -1903,7 +2215,7 @@ fbcon_set_palette(vc, color_table); if (vt_cons[vc->vc_num]->vc_mode == KD_TEXT) - fbcon_clear_margins(vc, 0); + accel_clear_margins(vc, info, 0); if (logo_shown == -2) { logo_shown = fg_console; @@ -1951,9 +2263,14 @@ } fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW); - info->cursor.flash = (!blank); 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; @@ -1964,11 +2281,14 @@ height = vc->vc_rows; y_break = p->vrows - p->yscroll; if (height > y_break) { - fbcon_clear(vc, 0, 0, y_break, vc->vc_cols); - fbcon_clear(vc, y_break, 0, height - y_break, + accel_clear(vc, info, real_y(p, 0), + 0, y_break, vc->vc_cols); + accel_clear(vc, info, real_y(p, y_break), + 0, height - y_break, vc->vc_cols); } else - fbcon_clear(vc, 0, 0, height, vc->vc_cols); + accel_clear(vc, info, real_y(p, 0), + 0, height, vc->vc_cols); vc->vc_video_erase_char = oldc; } else update_screen(vc->vc_num); @@ -2119,9 +2439,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) @@ -2135,7 +2462,7 @@ } } else if (CON_IS_VISIBLE(vc) && vt_cons[vc->vc_num]->vc_mode == KD_TEXT) { - fbcon_clear_margins(vc, 0); + accel_clear_margins(vc, info, 0); update_screen(vc->vc_num); } @@ -2300,7 +2627,62 @@ } else fb_copy_cmap(fb_default_cmap(1 << depth), &palette_cmap); - return fb_set_cmap(&palette_cmap, 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, 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, info); + +out: return fb_set_cmap(&palette_cmap, info); } static u16 *fbcon_screen_pos(struct vc_data *vc, int offset) @@ -2478,14 +2860,12 @@ static void fbcon_suspended(struct fb_info *info) { - struct vc_data *vc = NULL; - - if (info->currcon < 0) - return; - vc = vc_cons[info->currcon].d; - /* Clear cursor, restore saved data */ - fbcon_cursor(vc, CM_ERASE); + info->cursor.enable = 0; + 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) @@ -2516,7 +2896,14 @@ var_to_display(p, &info->var, info); 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)) + fbsplash_disable(vc, 0); + } + updatescrollmode(p, info, vc); scrollback_max = 0; scrollback_current = 0; diff -Naur --exclude='*.rej' --exclude='*.orig' linux-2.6.9-rc2-mm4/drivers/video/console/fbcon.h linux-2.6.9-rc2-mm4-fbsplash/drivers/video/console/fbcon.h --- linux-2.6.9-rc2-mm4/drivers/video/console/fbcon.h 2004-09-29 11:12:20.000000000 +0200 +++ linux-2.6.9-rc2-mm4-fbsplash/drivers/video/console/fbcon.h 2004-09-29 11:22:08.000000000 +0200 @@ -48,19 +48,6 @@ struct fb_videomode *mode; }; -struct fbcon_ops { - void (*bmove)(struct vc_data *vc, struct fb_info *info, int sy, - int sx, int dy, int dx, int height, int width); - void (*clear)(struct vc_data *vc, struct fb_info *info, int sy, - int sx, int height, int width); - void (*putcs)(struct vc_data *vc, struct fb_info *info, - const unsigned short *s, int count, int yy, int xx, - int fg, int bg); - void (*clear_margins)(struct vc_data *vc, struct fb_info *info, - int bottom_only); - void (*cursor)(struct vc_data *vc, struct fb_info *info, - struct display *p, int mode, int fg, int bg); -}; /* * Attribute Decoding */ @@ -85,13 +72,6 @@ #define attr_blink(s) \ ((s) & 0x8000) -/* Font */ -#define REFCOUNT(fd) (((int *)(fd))[-1]) -#define FNTSIZE(fd) (((int *)(fd))[-2]) -#define FNTCHARCNT(fd) (((int *)(fd))[-3]) -#define FNTSUM(fd) (((int *)(fd))[-4]) -#define FONT_EXTRA_WORDS 4 - /* * Scroll Method */ @@ -149,9 +129,5 @@ #define SCROLL_PAN_REDRAW 0x005 extern int fb_console_init(void); -#ifdef CONFIG_FB_TILEBLITTING -extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info, - struct display *p, struct fbcon_ops *ops); -#endif -extern void fbcon_set_bitops(struct fbcon_ops *ops); + #endif /* _VIDEO_FBCON_H */ diff -Naur --exclude='*.rej' --exclude='*.orig' linux-2.6.9-rc2-mm4/drivers/video/console/tileblit.c linux-2.6.9-rc2-mm4-fbsplash/drivers/video/console/tileblit.c --- linux-2.6.9-rc2-mm4/drivers/video/console/tileblit.c 2004-09-29 11:12:20.000000000 +0200 +++ linux-2.6.9-rc2-mm4-fbsplash/drivers/video/console/tileblit.c 1970-01-01 02:00:00.000000000 +0200 @@ -1,146 +0,0 @@ -/* - * linux/drivers/video/console/tileblit.c -- Tile Blitting Operation - * - * Copyright (C) 2004 Antonino Daplas - * - * 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 "fbcon.h" - -static void tile_bmove(struct vc_data *vc, struct fb_info *info, int sy, - int sx, int dy, int dx, int height, int width) -{ - struct fb_tilearea area; - - area.sx = sx; - area.sy = sy; - area.dx = dx; - area.dy = dy; - area.height = height; - area.width = width; - - info->tileops->fb_tilecopy(info, &area); -} - -static void tile_clear(struct vc_data *vc, struct fb_info *info, int sy, - int sx, int height, int width) -{ - struct fb_tilerect rect; - int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; - int fgshift = (vc->vc_hi_font_mask) ? 9 : 8; - - rect.index = vc->vc_video_erase_char & - ((vc->vc_hi_font_mask) ? 0x1ff : 0xff); - rect.fg = attr_fgcol_ec(fgshift, vc); - rect.bg = attr_bgcol_ec(bgshift, vc); - rect.sx = sx; - rect.sy = sy; - rect.width = width; - rect.height = height; - rect.rop = ROP_COPY; - - info->tileops->fb_tilefill(info, &rect); -} - -static void tile_putcs(struct vc_data *vc, struct fb_info *info, - const unsigned short *s, int count, int yy, int xx, - int fg, int bg) -{ - struct fb_tileblit blit; - unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; - int size = sizeof(u32) * count, i; - - blit.sx = xx; - blit.sy = yy; - blit.width = count; - blit.height = 1; - blit.fg = fg; - blit.bg = bg; - blit.length = count; - blit.indices = (u32 *) fb_get_buffer_offset(info, &info->pixmap, size); - for (i = 0; i < count; i++) - blit.indices[i] = (u32)(scr_readw(s++) & charmask); - - info->tileops->fb_tileblit(info, &blit); -} - -static void tile_clear_margins(struct vc_data *vc, struct fb_info *info, - int bottom_only) -{ - return; -} - -static void tile_cursor(struct vc_data *vc, struct fb_info *info, - struct display *p, int mode, int fg, int bg) -{ - struct fb_tilecursor cursor; - - cursor.sx = vc->vc_x; - cursor.sy = vc->vc_y; - cursor.mode = (mode == CM_ERASE) ? 0 : 1; - cursor.fg = fg; - cursor.bg = bg; - - switch (vc->vc_cursor_type & 0x0f) { - case CUR_NONE: - cursor.shape = FB_TILE_CURSOR_NONE; - break; - case CUR_UNDERLINE: - cursor.shape = FB_TILE_CURSOR_UNDERLINE; - break; - case CUR_LOWER_THIRD: - cursor.shape = FB_TILE_CURSOR_LOWER_THIRD; - break; - case CUR_LOWER_HALF: - cursor.shape = FB_TILE_CURSOR_LOWER_HALF; - break; - case CUR_TWO_THIRDS: - cursor.shape = FB_TILE_CURSOR_TWO_THIRDS; - break; - case CUR_BLOCK: - default: - cursor.shape = FB_TILE_CURSOR_BLOCK; - break; - } - - info->tileops->fb_tilecursor(info, &cursor); -} - -void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info, - struct display *p, struct fbcon_ops *ops) -{ - struct fb_tilemap map; - - ops->bmove = tile_bmove; - ops->clear = tile_clear; - ops->putcs = tile_putcs; - ops->clear_margins = tile_clear_margins; - ops->cursor = tile_cursor; - - if (p) { - map.width = vc->vc_font.width; - map.height = vc->vc_font.height; - map.depth = 1; - map.length = (p->userfont) ? - FNTCHARCNT(p->fontdata) : 256; - map.data = p->fontdata; - info->tileops->fb_settile(info, &map); - } -} - -EXPORT_SYMBOL(fbcon_set_tileops); - -MODULE_AUTHOR("Antonino Daplas "); -MODULE_DESCRIPTION("Tile Blitting Operation"); -MODULE_LICENSE("GPL"); - diff -Naur --exclude='*.rej' --exclude='*.orig' linux-2.6.9-rc2-mm4/drivers/video/fbmem.c linux-2.6.9-rc2-mm4-fbsplash/drivers/video/fbmem.c --- linux-2.6.9-rc2-mm4/drivers/video/fbmem.c 2004-09-29 11:12:20.000000000 +0200 +++ linux-2.6.9-rc2-mm4-fbsplash/drivers/video/fbmem.c 2004-09-29 11:22:08.000000000 +0200 @@ -368,9 +368,6 @@ memset(&fb_logo, 0, sizeof(struct logo_data)); - if (info->flags & FBINFO_MISC_TILEBLITTING) - return 0; - if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) { depth = info->var.blue.length; if (info->var.red.length < depth) @@ -685,7 +682,6 @@ cursor.image.cmap.blue = info->cursor.image.cmap.blue; cursor.image.cmap.transp = info->cursor.image.cmap.transp; cursor.data = NULL; - cursor.flash = 0; if (cursor.set & FB_CUR_SETCUR) info->cursor.enable = 1; diff -Naur --exclude='*.rej' --exclude='*.orig' linux-2.6.9-rc2-mm4/drivers/video/fbsplash.c linux-2.6.9-rc2-mm4-fbsplash/drivers/video/fbsplash.c --- linux-2.6.9-rc2-mm4/drivers/video/fbsplash.c 1970-01-01 02:00:00.000000000 +0200 +++ linux-2.6.9-rc2-mm4-fbsplash/drivers/video/fbsplash.c 2004-09-29 11:22:20.000000000 +0200 @@ -0,0 +1,529 @@ +/* + * 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 + +#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 + +extern signed char con2fb_map[]; + +static void splash_work_verbose(void *data); +static int fbsplash_enable(struct vc_data *vc); + +DECLARE_WORK(splash_wq_verbose, splash_work_verbose, NULL); + +int fbsplash_mode = 0; +char fbsplash_path[KMOD_PATH_LEN] = "/sbin/splash_helper"; +static char fbsplash_theme[FB_SPLASH_THEME_LEN] __initdata = "default"; + +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[] = { + fbsplash_path, + "1", + cmd, + tcons, + tfb, + (fbsplash_mode == FB_SPLASH_MODE_SILENT) ? "s" : "v", + vc_cons[vc].d->vc_splash.theme, + NULL + }; + + snprintf(tfb,5,"%d",fb); + snprintf(tcons,5,"%d",vc); + + return call_usermodehelper(fbsplash_path, argv, envp, 1); +} + +int fbsplash_verbose(void) +{ + if (fbsplash_mode == FB_SPLASH_MODE_VERBOSE) + return 0; + + fbsplash_mode = FB_SPLASH_MODE_VERBOSE; + + /* We have to do the switch from a workqueue helper, because chances are this + * function gets 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]]; + + if (info == NULL) + return; + + printk(KERN_INFO "fbsplash: switching to verbose mode\n"); + + vt_cons[0]->vc_mode = KD_TEXT; + + acquire_console_sem(); + do_unblank_screen(0); + + if (info->splash.data) { + fbsplash_enable(vc); + } else { + fbsplash_disable(vc, 1); + } + release_console_sem(); +} + +/* Disables fbsplash on a virtual console; called with console sem held. */ +int fbsplash_disable(struct vc_data *vc, unsigned char redraw) +{ + struct fb_info* info; + + if (!vc->vc_splash.state) + return -EINVAL; + + info = registered_fb[(int) con2fb_map[vc->vc_num]]; + + if (info == NULL) + return -EINVAL; + + vc->vc_splash.state = 0; + 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) { + 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); + } + + printk(KERN_INFO "fbsplash: switched splash state to 'off' on console %d\n", + vc->vc_num); + + return 0; +} + +/* Enables fbsplash on a virtual console; called with console sem held. */ +static int fbsplash_enable(struct vc_data *vc) +{ + struct fb_info* info; + + info = registered_fb[(int) con2fb_map[vc->vc_num]]; + + if (vc->vc_splash.twidth == 0 || vc->vc_splash.theight == 0 || + info == NULL || !info->splash.data || vc->vc_splash.state) + return -EINVAL; + + vc->vc_splash.state = 1; + 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); + } + + printk(KERN_INFO "fbsplash: switched splash state to 'on' on console %d\n", + vc->vc_num); + + return 0; +} + +static int __init splash_setup(char *options) +{ + char *this_opt; + + while ((this_opt = strsep(&options, ",")) != NULL) { + + if (!strcmp(this_opt, "silent")) { + fbsplash_mode = FB_SPLASH_MODE_SILENT; + printk(KERN_INFO "fbsplash: silent\n"); + } else if (!strcmp(this_opt, "verbose")) { + fbsplash_mode = FB_SPLASH_MODE_VERBOSE; + printk(KERN_INFO "fbsplash: verbose\n"); + } else if (!strcmp(this_opt, "off")) { + fbsplash_mode = 0; + } else if (!strncmp(this_opt, "theme:", 6)) { + strncpy(fbsplash_theme, this_opt+6, 64); + printk(KERN_INFO "fbsplash: theme %s\n", fbsplash_theme); + } else { + printk(KERN_WARNING "fbsplash: unrecognized option %s\n", this_opt); + } + } + return 0; +} + +__setup("splash=", splash_setup); + +static int splash_get_info(char *buf, char **start, off_t fpos, int length) +{ + char *p = buf; + + p += sprintf(p, "Framebuffer splash v%s, mode: %s\n", SPLASH_VERSION, + ((fbsplash_mode == 2) ? "silent" : (fbsplash_mode == 1) ? "verbose" : "off")); + + return p - buf; +} + +static inline int fbsplash_ioctl_dosetstate(struct vc_data *vc, unsigned int __user* state, unsigned char origin) +{ + int tmp, ret; + + if (get_user(tmp, state)) + return -EFAULT; + + if (origin == FB_SPLASH_IO_ORIG_USER) + acquire_console_sem(); + if (!tmp) + ret = fbsplash_disable(vc, 1); + else + ret = fbsplash_enable(vc); + if (origin == FB_SPLASH_IO_ORIG_USER) + release_console_sem(); + + return ret; +} + +static inline int fbsplash_ioctl_dogetstate(struct vc_data *vc, unsigned int __user *state) +{ + return put_user(vc->vc_splash.state, (unsigned int __user*) state); +} + +static int fbsplash_ioctl_dosetcfg(struct vc_data *vc, struct vc_splash __user *arg, unsigned char origin) +{ + struct vc_splash cfg; + struct fb_info *info; + int len; + char *tmp; + + info = registered_fb[(int) con2fb_map[vc->vc_num]]; + + if (copy_from_user(&cfg, arg, sizeof(struct vc_splash))) + return -EFAULT; + if (info == NULL || !cfg.twidth || !cfg.theight || + cfg.tx + cfg.twidth > info->var.xres || + cfg.ty + cfg.theight > info->var.yres) + return -EINVAL; + + len = strlen_user(cfg.theme); + if (!len || len > FB_SPLASH_THEME_LEN) + return -EINVAL; + tmp = kmalloc(len, GFP_KERNEL); + if (!tmp) + return -ENOMEM; + if (copy_from_user(tmp, (void __user *)cfg.theme, len)) + return -EFAULT; + cfg.theme = tmp; + cfg.state = 0; + + /* If this ioctl is a response to a request from kernel, the console sem + * is already held; we also don't need to disable splash because either the + * new config and background picture will be successfully loaded, and the + * splash will stay on, or in case of a failure it'll be turned off in fbcon. */ + if (origin == FB_SPLASH_IO_ORIG_USER) { + acquire_console_sem(); + if (vc->vc_splash.state) + fbsplash_disable(vc, 1); + } + + if (vc->vc_splash.theme) + kfree(vc->vc_splash.theme); + + vc->vc_splash = cfg; + + if (origin == FB_SPLASH_IO_ORIG_USER) + release_console_sem(); + + printk(KERN_INFO "fbsplash: console %d using theme '%s'\n", + vc->vc_num, vc->vc_splash.theme); + return 0; +} + +static int fbsplash_ioctl_dogetcfg(struct vc_data *vc, struct vc_splash __user *arg) +{ + struct vc_splash splash; + char __user *tmp; + + if (get_user(tmp, &arg->theme)) + return -EFAULT; + + splash = vc->vc_splash; + splash.theme = tmp; + + if (vc->vc_splash.theme) { + if (copy_to_user(tmp, vc->vc_splash.theme, strlen(vc->vc_splash.theme) + 1)) + return -EFAULT; + } else + if (put_user(0, tmp)) + return -EFAULT; + + if (copy_to_user(arg, &splash, sizeof(struct vc_splash))) + return -EFAULT; + + return 0; +} + +static int fbsplash_ioctl_dosetpic(struct vc_data *vc, struct fb_image __user *arg, unsigned char origin) +{ + struct fb_image img; + struct fb_info *info; + int len; + u8 *tmp; + + if (vc->vc_num != fg_console) + return -EINVAL; + + info = registered_fb[(int) con2fb_map[vc->vc_num]]; + + if (info == NULL) + return -EINVAL; + + if (copy_from_user(&img, arg, sizeof(struct fb_image))) + return -EFAULT; + + if (img.width != info->var.xres || img.height != info->var.yres) { + printk(KERN_ERR "fbsplash: picture dimensions mismatch\n"); + return -EINVAL; + } + + if (img.depth != info->var.bits_per_pixel) { + printk(KERN_ERR "fbsplash: picture depth mismatch\n"); + return -EINVAL; + } + + if (img.depth == 8) { + if (!img.cmap.len || !img.cmap.red || !img.cmap.green || + !img.cmap.blue) + return -EINVAL; + + tmp = vmalloc(img.cmap.len * 3 * 2); + if (!tmp) + return -ENOMEM; + + if (copy_from_user(tmp, (void __user*)img.cmap.red, img.cmap.len * 2) || + copy_from_user(tmp + (img.cmap.len << 1), + (void __user*)img.cmap.green, (img.cmap.len << 1)) || + copy_from_user(tmp + (img.cmap.len << 2), + (void __user*)img.cmap.blue, (img.cmap.len << 1))) { + vfree(tmp); + return -EFAULT; + } + + img.cmap.transp = NULL; + img.cmap.red = (u16*)tmp; + img.cmap.green = img.cmap.red + img.cmap.len; + img.cmap.blue = img.cmap.green + img.cmap.len; + } else { + img.cmap.red = NULL; + } + + len = ((img.depth + 7) >> 3) * img.width * img.height; + tmp = vmalloc(len); + + if (!tmp) + goto out; + + if (copy_from_user(tmp, (void __user*)img.data, len)) + goto out; + + img.data = tmp; + + /* If this ioctl is a response to a request from kernel, the console sem + * is already held. */ + if (origin == FB_SPLASH_IO_ORIG_USER) + acquire_console_sem(); + + if (info->splash.data) + vfree((u8*)info->splash.data); + if (info->splash.cmap.red) + vfree(info->splash.cmap.red); + + info->splash = img; + + if (origin == FB_SPLASH_IO_ORIG_USER) + release_console_sem(); + + return 0; + +out: if (img.cmap.red) + vfree(img.cmap.red); + if (tmp) + vfree(tmp); + return -ENOMEM; +} + +static int splash_ioctl(struct inode * inode, struct file *filp, u_int cmd, + u_long arg) +{ + struct fb_splash_iowrapper __user *wrapper = (void __user*) arg; + struct vc_data *vc = NULL; + unsigned short vc_num = 0; + unsigned char origin = 0; + void __user *data = NULL; + + if (cmd != FBIOSPLASH_SETMODE && cmd != FBIOSPLASH_GETMODE) + { + if (verify_area(VERIFY_READ, wrapper, + sizeof(struct fb_splash_iowrapper))) + return -EFAULT; + + __get_user(vc_num, &wrapper->vc); + __get_user(origin, &wrapper->origin); + __get_user(data, &wrapper->data); + + if (!vc_cons_allocated(vc_num)) + return -EINVAL; + + vc = vc_cons[vc_num].d; + } + + switch (cmd) { + + case FBIOSPLASH_SETMODE: + if (arg != FB_SPLASH_MODE_SILENT && arg != FB_SPLASH_MODE_VERBOSE) + return -EINVAL; + + if (fbsplash_mode == arg) + return 0; + + fbsplash_mode = arg; + if (arg == FB_SPLASH_MODE_VERBOSE) + splash_work_verbose(NULL); + return 0; + + case FBIOSPLASH_GETMODE: + return put_user(fbsplash_mode, (unsigned int __user *)arg); + case FBIOSPLASH_SETPIC: + return fbsplash_ioctl_dosetpic(vc, (struct fb_image __user*)data, origin); + case FBIOSPLASH_SETCFG: + return fbsplash_ioctl_dosetcfg(vc, (struct vc_splash*)data, origin); + case FBIOSPLASH_GETCFG: + return fbsplash_ioctl_dogetcfg(vc, (struct vc_splash*)data); + case FBIOSPLASH_SETSTATE: + return fbsplash_ioctl_dosetstate(vc, (unsigned int *)data, origin); + case FBIOSPLASH_GETSTATE: + return fbsplash_ioctl_dogetstate(vc, (unsigned int *)data); + default: + return -ENOIOCTLCMD; + } +} + +static struct file_operations splash_ops = { + .owner = THIS_MODULE, + .ioctl = splash_ioctl +}; + +static struct miscdevice splash_dev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "fbsplash", + .fops = &splash_ops +}; + +int fbsplash_init(void) +{ + struct proc_dir_entry *splash_proc; + struct fb_info *info; + struct vc_data *vc; + int i; + + vc = vc_cons[0].d; + info = registered_fb[0]; + + 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 && vc_cons[i].d; i++) { + vc_cons[i].d->vc_splash.state = vc_cons[i].d->vc_splash.twidth = + vc_cons[i].d->vc_splash.theight = 0; + vc_cons[i].d->vc_splash.theme = NULL; + } + + i = misc_register(&splash_dev); + if (i) { + printk(KERN_ERR "fbsplash: failed to register device\n"); + return i; + } + +#ifdef CONFIG_PROC_FS + splash_proc = create_proc_info_entry("fbsplash", 0, NULL, splash_get_info); + if (splash_proc) + splash_proc->owner = THIS_MODULE; +#endif + + if (fbsplash_mode && info) { + vc->vc_splash.theme = kmalloc((strlen(fbsplash_theme)+1) * sizeof(char), GFP_KERNEL); + strcpy(vc->vc_splash.theme, fbsplash_theme); + if (fbsplash_call_helper("init", 0)) + fbsplash_mode = FB_SPLASH_MODE_VERBOSE; + } else { + fbsplash_mode = FB_SPLASH_MODE_VERBOSE; + } + + return 0; +} + +EXPORT_SYMBOL(fbsplash_path); diff -Naur --exclude='*.rej' --exclude='*.orig' linux-2.6.9-rc2-mm4/drivers/video/fbsplash.h linux-2.6.9-rc2-mm4-fbsplash/drivers/video/fbsplash.h --- linux-2.6.9-rc2-mm4/drivers/video/fbsplash.h 1970-01-01 02:00:00.000000000 +0200 +++ linux-2.6.9-rc2-mm4-fbsplash/drivers/video/fbsplash.h 2004-09-29 11:22:20.000000000 +0200 @@ -0,0 +1,75 @@ +/* + * linux/drivers/video/fbsplash.h -- Framebuffer splash headers + * + * Copyright (C) 2004 Michal Januszewski + * + */ + +#ifndef __FB_SPLASH_H +#define __FB_SPLASH_H + +#ifndef _LINUX_FB_H +#include +#endif + +struct fb_cursor; +struct fb_info; +struct vc_data; + +#ifdef CONFIG_FB_SPLASH +/* fbsplash.c */ +int fbsplash_init(void); +int fbsplash_verbose(void); +int fbsplash_call_helper(char* cmd, unsigned short cons); +int fbsplash_disable(struct vc_data *vc, unsigned char redraw); + +/* 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 srclinesbytes, int bpp); + +/* vt.c */ +void acquire_console_sem(void); +void release_console_sem(void); +void do_unblank_screen(int entering_gfx); + +extern int fbsplash_mode; +#define fbsplash_isverbose (fbsplash_mode == FB_SPLASH_MODE_VERBOSE) +#define fbsplash_issilent (fbsplash_mode == FB_SPLASH_MODE_SILENT) + +/* 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) + +#else /* 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; } +static inline int fbsplash_disable(struct vc_data *vc, unsigned char redraw) { return 0; } + +#define fbsplash_issilent (0) +#define fbsplash_isverbose (1) +#define fbsplash_active_vc(y) (0) +#define fbsplash_active(x,y) (0) + +#endif /* CONFIG_FB_SPLASH */ + +#endif /* __FB_SPLASH_H */ diff -Naur --exclude='*.rej' --exclude='*.orig' linux-2.6.9-rc2-mm4/include/linux/console_splash.h linux-2.6.9-rc2-mm4-fbsplash/include/linux/console_splash.h --- linux-2.6.9-rc2-mm4/include/linux/console_splash.h 1970-01-01 02:00:00.000000000 +0200 +++ linux-2.6.9-rc2-mm4-fbsplash/include/linux/console_splash.h 2004-09-29 11:22:20.000000000 +0200 @@ -0,0 +1,13 @@ +#ifndef _LINUX_CONSOLE_SPLASH_H_ +#define _LINUX_CONSOLE_SPLASH_H_ 1 + +/* 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; +}; + +#endif diff -Naur --exclude='*.rej' --exclude='*.orig' linux-2.6.9-rc2-mm4/include/linux/console_struct.h linux-2.6.9-rc2-mm4-fbsplash/include/linux/console_struct.h --- linux-2.6.9-rc2-mm4/include/linux/console_struct.h 2004-08-14 08:36:11.000000000 +0300 +++ linux-2.6.9-rc2-mm4-fbsplash/include/linux/console_struct.h 2004-09-29 11:22:20.000000000 +0200 @@ -10,6 +10,7 @@ */ #define NPAR 16 +#include struct vc_data { unsigned short vc_num; /* Console number */ @@ -87,6 +88,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 --exclude='*.rej' --exclude='*.orig' linux-2.6.9-rc2-mm4/include/linux/fb.h linux-2.6.9-rc2-mm4-fbsplash/include/linux/fb.h --- linux-2.6.9-rc2-mm4/include/linux/fb.h 2004-09-29 11:12:50.000000000 +0200 +++ linux-2.6.9-rc2-mm4-fbsplash/include/linux/fb.h 2004-09-29 11:22:20.000000000 +0200 @@ -8,6 +8,13 @@ #define FB_MAJOR 29 #define FB_MAX 32 /* sufficient for now */ +struct fb_splash_iowrapper +{ + unsigned short vc; /* Virtual console */ + unsigned char origin; /* Point of origin of the request */ + void *data; +}; + /* ioctls 0x46 is 'F' */ #define FBIOGET_VSCREENINFO 0x4600 @@ -35,7 +42,19 @@ #define FBIOGET_HWCINFO 0x4616 #define FBIOPUT_MODEINFO 0x4617 #define FBIOGET_DISPINFO 0x4618 - +#define FBIOSPLASH_SETCFG _IOWR('F', 0x19, struct fb_splash_iowrapper) +#define FBIOSPLASH_GETCFG _IOR('F', 0x1A, struct fb_splash_iowrapper) +#define FBIOSPLASH_SETSTATE _IOWR('F', 0x1B, struct fb_splash_iowrapper) +#define FBIOSPLASH_GETSTATE _IOR('F', 0x1C, struct fb_splash_iowrapper) +#define FBIOSPLASH_SETMODE _IOWR('F', 0x1D, unsigned int) +#define FBIOSPLASH_GETMODE _IOR('F', 0x1E, unsigned int) +#define FBIOSPLASH_SETPIC _IOWR('F', 0x1F, struct fb_splash_iowrapper) + +#define FB_SPLASH_MODE_VERBOSE 1 /* Verbose mode */ +#define FB_SPLASH_MODE_SILENT 2 /* Silent mode */ +#define FB_SPLASH_THEME_LEN 128 /* Maximum lenght of a theme name */ +#define FB_SPLASH_IO_ORIG_KERNEL 0 /* Kernel ioctl origin */ +#define FB_SPLASH_IO_ORIG_USER 1 /* User ioctl origin */ #define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */ #define FB_TYPE_PLANES 1 /* Non interleaved planes */ @@ -318,7 +337,6 @@ struct fbcurpos hot; /* cursor hot spot */ struct fb_image image; /* Cursor image */ /* all fields below are for fbcon use only */ - int flash; /* cursor blink */ char *data; /* copy of bitmap */ }; @@ -556,82 +574,6 @@ int (*fb_mmap)(struct fb_info *info, struct file *file, struct vm_area_struct *vma); }; -#ifdef CONFIG_FB_TILEBLITTING - -#define FB_TILE_CURSOR_NONE 0 -#define FB_TILE_CURSOR_UNDERLINE 1 -#define FB_TILE_CURSOR_LOWER_THIRD 2 -#define FB_TILE_CURSOR_LOWER_HALF 3 -#define FB_TILE_CURSOR_TWO_THIRDS 4 -#define FB_TILE_CURSOR_BLOCK 5 - -struct fb_tilemap { - __u32 width; /* width of each tile in pixels */ - __u32 height; /* height of each tile in scanlines */ - __u32 depth; /* color depth of each tile */ - __u32 length; /* number of tiles in the map */ - __u8 *data; /* actual tile map: a bitmap array, packed - to the nearest byte */ -}; - -struct fb_tilerect { - __u32 sx; /* origin in the x-axis */ - __u32 sy; /* origin in the y-axis */ - __u32 width; /* number of tiles in the x-axis */ - __u32 height; /* number of tiles in the y-axis */ - __u32 index; /* what tile to use: index to tile map */ - __u32 fg; /* foreground color */ - __u32 bg; /* background color */ - __u32 rop; /* raster operation */ -}; - -struct fb_tilearea { - __u32 sx; /* source origin in the x-axis */ - __u32 sy; /* source origin in the y-axis */ - __u32 dx; /* destination origin in the x-axis */ - __u32 dy; /* destination origin in the y-axis */ - __u32 width; /* number of tiles in the x-axis */ - __u32 height; /* number of tiles in the y-axis */ -}; - -struct fb_tileblit { - __u32 sx; /* origin in the x-axis */ - __u32 sy; /* origin in the y-axis */ - __u32 width; /* number of tiles in the x-axis */ - __u32 height; /* number of tiles in the y-axis */ - __u32 fg; /* foreground color */ - __u32 bg; /* background color */ - __u32 length; /* number of tiles to draw */ - __u32 *indices; /* array of indices to tile map */ -}; - -struct fb_tilecursor { - __u32 sx; /* cursor position in the x-axis */ - __u32 sy; /* cursor position in the y-axis */ - __u32 mode; /* 0 = erase, 1 = draw */ - __u32 shape; /* see FB_TILE_CURSOR_* */ - __u32 fg; /* foreground color */ - __u32 bg; /* background color */ -}; - -struct fb_tile_ops { - /* set tile characteristics */ - void (*fb_settile)(struct fb_info *info, struct fb_tilemap *map); - - /* all dimensions from hereon are in terms of tiles */ - - /* move a rectangular region of tiles from one area to another*/ - void (*fb_tilecopy)(struct fb_info *info, struct fb_tilearea *area); - /* fill a rectangular region with a tile */ - void (*fb_tilefill)(struct fb_info *info, struct fb_tilerect *rect); - /* copy an array of tiles */ - void (*fb_tileblit)(struct fb_info *info, struct fb_tileblit *blit); - /* cursor */ - void (*fb_tilecursor)(struct fb_info *info, - struct fb_tilecursor *cursor); -}; -#endif /* CONFIG_FB_TILEBLITTING */ - /* FBINFO_* = fb_info.flags bit flags */ #define FBINFO_MODULE 0x0001 /* Low-level driver is a module */ #define FBINFO_HWACCEL_DISABLED 0x0002 @@ -663,7 +605,6 @@ from userspace */ #define FBINFO_MISC_MODESWITCH 0x20000 /* mode switch */ #define FBINFO_MISC_MODESWITCHLATE 0x40000 /* init hardware later */ -#define FBINFO_MISC_TILEBLITTING 0x80000 /* use tile blitting */ struct fb_info { int node; @@ -680,9 +621,6 @@ struct list_head modelist; /* mode list */ struct fb_ops *fbops; struct device *device; -#ifdef CONFIG_FB_TILEBLITTING - struct fb_tile_ops *tileops; /* Tile Blitting */ -#endif char __iomem *screen_base; /* Virtual address */ unsigned long screen_size; /* Amount of ioremapped VRAM or 0 */ int currcon; /* Current VC. */ @@ -690,7 +628,9 @@ #define FBINFO_STATE_RUNNING 0 #define FBINFO_STATE_SUSPENDED 1 u32 state; /* Hardware state i.e suspend */ - void *fbcon_par; /* fbcon use-only private area */ + + struct fb_image splash; + /* From here on everything is device dependent */ void *par; }; diff -Naur --exclude='*.rej' --exclude='*.orig' linux-2.6.9-rc2-mm4/include/linux/sysctl.h linux-2.6.9-rc2-mm4-fbsplash/include/linux/sysctl.h --- linux-2.6.9-rc2-mm4/include/linux/sysctl.h 2004-09-29 11:12:57.000000000 +0200 +++ linux-2.6.9-rc2-mm4-fbsplash/include/linux/sysctl.h 2004-09-29 11:25:20.000000000 +0200 @@ -135,6 +135,7 @@ KERN_HZ_TIMER=65, /* int: hz timer on or off */ KERN_UNKNOWN_NMI_PANIC=66, /* int: unknown nmi panic flag */ KERN_CPU_SCHED=67, /* CPU scheduler stuff */ + KERN_FBSPLASH=68, /* string: path to fbsplash helper */ }; diff -Naur --exclude='*.rej' --exclude='*.orig' linux-2.6.9-rc2-mm4/kernel/panic.c linux-2.6.9-rc2-mm4-fbsplash/kernel/panic.c --- linux-2.6.9-rc2-mm4/kernel/panic.c 2004-09-29 11:13:01.000000000 +0200 +++ linux-2.6.9-rc2-mm4-fbsplash/kernel/panic.c 2004-09-29 11:25:52.000000000 +0200 @@ -20,6 +20,7 @@ #include #include #include +#include "../drivers/video/fbsplash.h" int panic_timeout; int panic_on_oops; @@ -82,6 +83,8 @@ * We can't use the "normal" timers since we just panicked.. */ printk(KERN_EMERG "Rebooting in %d seconds..",panic_timeout); + fbsplash_verbose(); + for (i = 0; i < panic_timeout; i++) { touch_nmi_watchdog(); mdelay(1000); @@ -105,6 +108,8 @@ disabled_wait(caller); #endif local_irq_enable(); + fbsplash_verbose(); + for (;;) ; } diff -Naur --exclude='*.rej' --exclude='*.orig' linux-2.6.9-rc2-mm4/kernel/power/console.c linux-2.6.9-rc2-mm4-fbsplash/kernel/power/console.c --- linux-2.6.9-rc2-mm4/kernel/power/console.c 2004-08-14 08:36:10.000000000 +0300 +++ linux-2.6.9-rc2-mm4-fbsplash/kernel/power/console.c 2004-09-29 11:22:20.000000000 +0200 @@ -9,6 +9,8 @@ #include #include "power.h" +#include "../drivers/video/fbsplash.h" + static int new_loglevel = 10; static int orig_loglevel; static int orig_fgconsole, orig_kmsg; @@ -19,6 +21,9 @@ console_loglevel = new_loglevel; #ifdef SUSPEND_CONSOLE + if (fbsplash_issilent) + fbsplash_verbose(); + acquire_console_sem(); orig_fgconsole = fg_console; diff -Naur --exclude='*.rej' --exclude='*.orig' linux-2.6.9-rc2-mm4/kernel/sysctl.c linux-2.6.9-rc2-mm4-fbsplash/kernel/sysctl.c --- linux-2.6.9-rc2-mm4/kernel/sysctl.c 2004-09-29 11:13:01.000000000 +0200 +++ linux-2.6.9-rc2-mm4-fbsplash/kernel/sysctl.c 2004-09-29 11:22:20.000000000 +0200 @@ -86,6 +86,9 @@ #ifdef CONFIG_HOTPLUG extern char hotplug_path[]; #endif +#ifdef CONFIG_FB_SPLASH +extern char fbsplash_path[]; +#endif #ifdef CONFIG_CHR_DEV_SG extern int sg_big_buff; #endif @@ -404,6 +407,17 @@ .strategy = &sysctl_string, }, #endif +#ifdef CONFIG_FB_SPLASH + { + .ctl_name = KERN_FBSPLASH, + .procname = "fbsplash", + .data = &fbsplash_path, + .maxlen = KMOD_PATH_LEN, + .mode = 0644, + .proc_handler = &proc_dostring, + .strategy = &sysctl_string, + }, +#endif #ifdef CONFIG_CHR_DEV_SG { .ctl_name = KERN_SG_BIG_BUFF,