1999-01-11 03:34:56 +00:00
|
|
|
/*-
|
|
|
|
* Copyright (c) 1999 Michael Smith <msmith@freebsd.org>
|
|
|
|
* Copyright (c) 1999 Kazutaka YOKOTA <yokota@freebsd.org>
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*
|
1999-08-28 01:08:13 +00:00
|
|
|
* $FreeBSD$
|
1999-01-11 03:34:56 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
#include <sys/linker.h>
|
The second phase of syscons reorganization.
- Split syscons source code into manageable chunks and reorganize
some of complicated functions.
- Many static variables are moved to the softc structure.
- Added a new key function, PREV. When this key is pressed, the vty
immediately before the current vty will become foreground. Analogue
to PREV, which is usually assigned to the PrntScrn key.
PR: kern/10113
Submitted by: Christian Weisgerber <naddy@mips.rhein-neckar.de>
- Modified the kernel console input function sccngetc() so that it
handles function keys properly.
- Reorganized the screen update routine.
- VT switching code is reorganized. It now should be slightly more
robust than before.
- Added the DEVICE_RESUME function so that syscons no longer hooks the
APM resume event directly.
- New kernel configuration options: SC_NO_CUTPASTE, SC_NO_FONT_LOADING,
SC_NO_HISTORY and SC_NO_SYSMOUSE.
Various parts of syscons can be omitted so that the kernel size is
reduced.
SC_PIXEL_MODE
Made the VESA 800x600 mode an option, rather than a standard part of
syscons.
SC_DISABLE_DDBKEY
Disables the `debug' key combination.
SC_ALT_MOUSE_IMAGE
Inverse the character cell at the mouse cursor position in the text
console, rather than drawing an arrow on the screen.
Submitted by: Nick Hibma (n_hibma@FreeBSD.ORG)
SC_DFLT_FONT
makeoptions "SC_DFLT_FONT=_font_name_"
Include the named font as the default font of syscons. 16-line,
14-line and 8-line font data will be compiled in. This option replaces
the existing STD8X16FONT option, which loads 16-line font data only.
- The VGA driver is split into /sys/dev/fb/vga.c and /sys/isa/vga_isa.c.
- The video driver provides a set of ioctl commands to manipulate the
frame buffer.
- New kernel configuration option: VGA_WIDTH90
Enables 90 column modes: 90x25, 90x30, 90x43, 90x50, 90x60. These
modes are mot always supported by the video card.
PR: i386/7510
Submitted by: kbyanc@freedomnet.com and alexv@sui.gda.itesm.mx.
- The header file machine/console.h is reorganized; its contents is now
split into sys/fbio.h, sys/kbio.h (a new file) and sys/consio.h
(another new file). machine/console.h is still maintained for
compatibility reasons.
- Kernel console selection/installation routines are fixed and
slightly rebumped so that it should now be possible to switch between
the interanl kernel console (sc or vt) and a remote kernel console
(sio) again, as it was in 2.x, 3.0 and 3.1.
- Screen savers and splash screen decoders
Because of the header file reorganization described above, screen
savers and splash screen decoders are slightly modified. After this
update, /sys/modules/syscons/saver.h is no longer necessary and is
removed.
1999-06-22 14:14:06 +00:00
|
|
|
#include <sys/fbio.h>
|
1999-01-11 03:34:56 +00:00
|
|
|
|
|
|
|
#include <dev/fb/fbreg.h>
|
|
|
|
#include <dev/fb/splashreg.h>
|
2000-04-27 13:37:40 +00:00
|
|
|
#ifndef PC98
|
2000-04-24 10:09:42 +00:00
|
|
|
#include <dev/fb/vgareg.h>
|
|
|
|
|
|
|
|
#include <isa/isareg.h>
|
2000-04-27 13:37:40 +00:00
|
|
|
#endif
|
1999-01-11 03:34:56 +00:00
|
|
|
|
1999-03-29 15:13:53 +00:00
|
|
|
#define FADE_TIMEOUT 15 /* sec */
|
|
|
|
#define FADE_LEVELS 10
|
1999-01-11 03:34:56 +00:00
|
|
|
|
|
|
|
static int splash_mode = -1;
|
|
|
|
static int splash_on = FALSE;
|
|
|
|
|
|
|
|
static int bmp_start(video_adapter_t *adp);
|
|
|
|
static int bmp_end(video_adapter_t *adp);
|
|
|
|
static int bmp_splash(video_adapter_t *adp, int on);
|
2002-11-11 10:17:01 +00:00
|
|
|
static int bmp_Init(char *data, int swidth, int sheight, int sdepth);
|
1999-01-11 03:34:56 +00:00
|
|
|
static int bmp_Draw(video_adapter_t *adp);
|
|
|
|
|
|
|
|
static splash_decoder_t bmp_decoder = {
|
|
|
|
"splash_bmp", bmp_start, bmp_end, bmp_splash, SPLASH_IMAGE,
|
|
|
|
};
|
|
|
|
|
|
|
|
SPLASH_DECODER(splash_bmp, bmp_decoder);
|
|
|
|
|
|
|
|
static int
|
|
|
|
bmp_start(video_adapter_t *adp)
|
|
|
|
{
|
1999-01-21 18:29:33 +00:00
|
|
|
/* currently only 256-color modes are supported XXX */
|
1999-01-11 03:34:56 +00:00
|
|
|
static int modes[] = {
|
2000-04-27 13:37:40 +00:00
|
|
|
#ifdef PC98
|
|
|
|
/*
|
|
|
|
* As 640x400 doesn't generally look great,
|
|
|
|
* it's least preferred here.
|
|
|
|
*/
|
|
|
|
M_PC98_PEGC640x400,
|
|
|
|
M_PC98_PEGC640x480,
|
|
|
|
M_PC98_EGC640x400,
|
|
|
|
#else
|
1999-01-21 18:29:33 +00:00
|
|
|
M_VESA_CG640x480,
|
|
|
|
M_VESA_CG800x600,
|
|
|
|
M_VESA_CG1024x768,
|
2000-04-24 10:09:42 +00:00
|
|
|
M_CG640x480,
|
1999-01-21 18:29:33 +00:00
|
|
|
/*
|
|
|
|
* As 320x200 doesn't generally look great,
|
|
|
|
* it's least preferred here.
|
|
|
|
*/
|
1999-01-11 03:34:56 +00:00
|
|
|
M_VGA_CG320,
|
2000-04-27 13:37:40 +00:00
|
|
|
#endif
|
1999-01-11 03:34:56 +00:00
|
|
|
-1,
|
|
|
|
};
|
|
|
|
video_info_t info;
|
|
|
|
int i;
|
|
|
|
|
1999-06-16 14:04:45 +00:00
|
|
|
if ((bmp_decoder.data == NULL) || (bmp_decoder.data_size <= 0)) {
|
|
|
|
printf("splash_bmp: No bitmap file found\n");
|
1999-01-11 03:34:56 +00:00
|
|
|
return ENODEV;
|
1999-06-16 14:04:45 +00:00
|
|
|
}
|
1999-01-11 03:34:56 +00:00
|
|
|
for (i = 0; modes[i] >= 0; ++i) {
|
|
|
|
if (((*vidsw[adp->va_index]->get_info)(adp, modes[i], &info) == 0)
|
|
|
|
&& (bmp_Init((u_char *)bmp_decoder.data,
|
|
|
|
info.vi_width, info.vi_height, info.vi_depth) == 0))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
splash_mode = modes[i];
|
1999-06-16 14:04:45 +00:00
|
|
|
if (splash_mode < 0)
|
|
|
|
printf("splash_bmp: No appropriate video mode found\n");
|
1999-01-11 03:34:56 +00:00
|
|
|
if (bootverbose)
|
|
|
|
printf("bmp_start(): splash_mode:%d\n", splash_mode);
|
|
|
|
return ((splash_mode < 0) ? ENODEV : 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
bmp_end(video_adapter_t *adp)
|
|
|
|
{
|
|
|
|
/* nothing to do */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
bmp_splash(video_adapter_t *adp, int on)
|
|
|
|
{
|
|
|
|
static u_char pal[256*3];
|
|
|
|
static long time_stamp;
|
1999-03-29 15:13:53 +00:00
|
|
|
u_char tpal[256*3];
|
|
|
|
static int fading = TRUE, brightness = FADE_LEVELS;
|
1999-01-11 03:34:56 +00:00
|
|
|
struct timeval tv;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (on) {
|
|
|
|
if (!splash_on) {
|
|
|
|
/* set up the video mode and draw something */
|
|
|
|
if ((*vidsw[adp->va_index]->set_mode)(adp, splash_mode))
|
|
|
|
return 1;
|
|
|
|
if (bmp_Draw(adp))
|
|
|
|
return 1;
|
|
|
|
(*vidsw[adp->va_index]->save_palette)(adp, pal);
|
|
|
|
time_stamp = 0;
|
|
|
|
splash_on = TRUE;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* This is a kludge to fade the image away. This section of the
|
|
|
|
* code takes effect only after the system is completely up.
|
1999-01-21 18:29:33 +00:00
|
|
|
* FADE_TIMEOUT should be configurable.
|
1999-01-11 03:34:56 +00:00
|
|
|
*/
|
|
|
|
if (!cold) {
|
|
|
|
getmicrotime(&tv);
|
|
|
|
if (time_stamp == 0)
|
|
|
|
time_stamp = tv.tv_sec;
|
|
|
|
if (tv.tv_sec > time_stamp + FADE_TIMEOUT) {
|
1999-03-29 15:13:53 +00:00
|
|
|
if (fading)
|
|
|
|
if (brightness == 0) {
|
|
|
|
fading = FALSE;
|
|
|
|
brightness++;
|
|
|
|
}
|
|
|
|
else brightness--;
|
|
|
|
else
|
|
|
|
if (brightness == FADE_LEVELS) {
|
|
|
|
fading = TRUE;
|
|
|
|
brightness--;
|
|
|
|
}
|
|
|
|
else brightness++;
|
1999-01-11 03:34:56 +00:00
|
|
|
for (i = 0; i < sizeof(pal); ++i) {
|
1999-03-29 15:13:53 +00:00
|
|
|
tpal[i] = pal[i] * brightness / FADE_LEVELS;
|
1999-01-11 03:34:56 +00:00
|
|
|
}
|
1999-03-29 15:13:53 +00:00
|
|
|
(*vidsw[adp->va_index]->load_palette)(adp, tpal);
|
|
|
|
time_stamp = tv.tv_sec;
|
1999-01-11 03:34:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
/* the video mode will be restored by the caller */
|
|
|
|
splash_on = FALSE;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
** Code to handle Microsoft DIB (".BMP") format images.
|
|
|
|
**
|
|
|
|
** Blame me (msmith@freebsd.org) if this is broken, not Soren.
|
|
|
|
*/
|
|
|
|
|
|
|
|
typedef struct tagBITMAPFILEHEADER { /* bmfh */
|
2002-09-23 18:54:32 +00:00
|
|
|
u_short bfType __packed;
|
|
|
|
int bfSize __packed;
|
|
|
|
u_short bfReserved1 __packed;
|
|
|
|
u_short bfReserved2 __packed;
|
|
|
|
int bfOffBits __packed;
|
1999-01-11 03:34:56 +00:00
|
|
|
} BITMAPFILEHEADER;
|
|
|
|
|
|
|
|
typedef struct tagBITMAPINFOHEADER { /* bmih */
|
2002-09-23 18:54:32 +00:00
|
|
|
int biSize __packed;
|
|
|
|
int biWidth __packed;
|
|
|
|
int biHeight __packed;
|
|
|
|
short biPlanes __packed;
|
|
|
|
short biBitCount __packed;
|
|
|
|
int biCompression __packed;
|
|
|
|
int biSizeImage __packed;
|
|
|
|
int biXPelsPerMeter __packed;
|
|
|
|
int biYPelsPerMeter __packed;
|
|
|
|
int biClrUsed __packed;
|
|
|
|
int biClrImportant __packed;
|
1999-01-11 03:34:56 +00:00
|
|
|
} BITMAPINFOHEADER;
|
|
|
|
|
|
|
|
typedef struct tagRGBQUAD { /* rgbq */
|
2002-09-23 18:54:32 +00:00
|
|
|
u_char rgbBlue __packed;
|
|
|
|
u_char rgbGreen __packed;
|
|
|
|
u_char rgbRed __packed;
|
|
|
|
u_char rgbReserved __packed;
|
1999-01-11 03:34:56 +00:00
|
|
|
} RGBQUAD;
|
|
|
|
|
|
|
|
typedef struct tagBITMAPINFO { /* bmi */
|
2002-09-23 18:54:32 +00:00
|
|
|
BITMAPINFOHEADER bmiHeader __packed;
|
|
|
|
RGBQUAD bmiColors[256] __packed;
|
1999-01-11 03:34:56 +00:00
|
|
|
} BITMAPINFO;
|
|
|
|
|
|
|
|
typedef struct tagBITMAPF
|
|
|
|
{
|
2002-09-23 18:54:32 +00:00
|
|
|
BITMAPFILEHEADER bmfh __packed;
|
|
|
|
BITMAPINFO bmfi __packed;
|
1999-01-11 03:34:56 +00:00
|
|
|
} BITMAPF;
|
|
|
|
|
|
|
|
#define BI_RGB 0
|
|
|
|
#define BI_RLE8 1
|
|
|
|
#define BI_RLE4 2
|
|
|
|
|
|
|
|
/*
|
|
|
|
** all we actually care about the image
|
|
|
|
*/
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
int width,height; /* image dimensions */
|
|
|
|
int swidth,sheight; /* screen dimensions for the current mode */
|
2000-04-24 10:09:42 +00:00
|
|
|
u_char depth; /* image depth (1, 4, 8, 24 bits) */
|
1999-01-11 03:34:56 +00:00
|
|
|
u_char sdepth; /* screen depth (1, 4, 8 bpp) */
|
|
|
|
int ncols; /* number of colours */
|
|
|
|
u_char palette[256][3]; /* raw palette data */
|
|
|
|
u_char format; /* one of the BI_* constants above */
|
|
|
|
u_char *data; /* pointer to the raw data */
|
|
|
|
u_char *index; /* running pointer to the data while drawing */
|
|
|
|
u_char *vidmem; /* video memory allocated for drawing */
|
1999-01-21 18:29:33 +00:00
|
|
|
video_adapter_t *adp;
|
|
|
|
int bank;
|
2000-04-27 13:37:40 +00:00
|
|
|
#ifdef PC98
|
|
|
|
u_char prev_val;
|
|
|
|
#endif
|
1999-01-11 03:34:56 +00:00
|
|
|
} BMP_INFO;
|
|
|
|
|
|
|
|
static BMP_INFO bmp_info;
|
|
|
|
|
|
|
|
/*
|
|
|
|
** bmp_SetPix
|
|
|
|
**
|
|
|
|
** Given (info), set the pixel at (x),(y) to (val)
|
|
|
|
**
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
bmp_SetPix(BMP_INFO *info, int x, int y, u_char val)
|
|
|
|
{
|
|
|
|
int sofs, bofs;
|
1999-01-21 18:29:33 +00:00
|
|
|
int newbank;
|
1999-01-11 03:34:56 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* range check to avoid explosions
|
|
|
|
*/
|
|
|
|
if ((x < 0) || (x >= info->swidth) || (y < 0) || (y >= info->sheight))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* calculate offset into video memory;
|
|
|
|
* because 0,0 is bottom-left for DIB, we have to convert.
|
|
|
|
*/
|
|
|
|
sofs = ((info->height - (y+1) + (info->sheight - info->height) / 2)
|
1999-02-05 11:52:13 +00:00
|
|
|
* info->adp->va_line_width);
|
2000-04-24 10:09:42 +00:00
|
|
|
x += (info->swidth - info->width) / 2;
|
1999-01-11 03:34:56 +00:00
|
|
|
|
|
|
|
switch(info->sdepth) {
|
2000-04-27 13:37:40 +00:00
|
|
|
#ifdef PC98
|
|
|
|
case 4:
|
|
|
|
sofs += (x >> 3);
|
|
|
|
bofs = x & 0x7; /* offset within byte */
|
|
|
|
|
|
|
|
outb(0x7c, 0x80 | 0x40); /* GRCG on & RMW mode */
|
|
|
|
if (val != info->prev_val) {
|
|
|
|
outb(0x7e, (val & 1) ? 0xff : 0); /* tile B */
|
|
|
|
outb(0x7e, (val & 2) ? 0xff : 0); /* tile R */
|
|
|
|
outb(0x7e, (val & 4) ? 0xff : 0); /* tile G */
|
|
|
|
outb(0x7e, (val & 8) ? 0xff : 0); /* tile I */
|
|
|
|
|
|
|
|
info->prev_val = val;
|
|
|
|
}
|
|
|
|
|
|
|
|
*(info->vidmem+sofs) = (0x80 >> bofs); /* write new bit */
|
|
|
|
outb(0x7c, 0); /* GRCG off */
|
|
|
|
break;
|
|
|
|
#else
|
2000-04-24 10:09:42 +00:00
|
|
|
case 4:
|
1999-01-11 03:34:56 +00:00
|
|
|
case 1:
|
2000-04-24 10:09:42 +00:00
|
|
|
/* EGA/VGA planar modes */
|
|
|
|
sofs += (x >> 3);
|
|
|
|
newbank = sofs/info->adp->va_window_size;
|
|
|
|
if (info->bank != newbank) {
|
|
|
|
(*vidsw[info->adp->va_index]->set_win_org)(info->adp, newbank*info->adp->va_window_size);
|
|
|
|
info->bank = newbank;
|
|
|
|
}
|
|
|
|
sofs %= info->adp->va_window_size;
|
1999-01-11 03:34:56 +00:00
|
|
|
bofs = x & 0x7; /* offset within byte */
|
2000-04-24 10:09:42 +00:00
|
|
|
outw(GDCIDX, (0x8000 >> bofs) | 0x08); /* bit mask */
|
|
|
|
outw(GDCIDX, (val << 8) | 0x00); /* set/reset */
|
|
|
|
*(info->vidmem + sofs) ^= 0xff; /* read-modify-write */
|
1999-01-11 03:34:56 +00:00
|
|
|
break;
|
2000-04-27 13:37:40 +00:00
|
|
|
#endif
|
1999-01-11 03:34:56 +00:00
|
|
|
|
|
|
|
case 8:
|
2000-04-24 10:09:42 +00:00
|
|
|
sofs += x;
|
1999-01-21 18:29:33 +00:00
|
|
|
newbank = sofs/info->adp->va_window_size;
|
|
|
|
if (info->bank != newbank) {
|
|
|
|
(*vidsw[info->adp->va_index]->set_win_org)(info->adp, newbank*info->adp->va_window_size);
|
|
|
|
info->bank = newbank;
|
|
|
|
}
|
|
|
|
sofs %= info->adp->va_window_size;
|
1999-01-11 03:34:56 +00:00
|
|
|
*(info->vidmem+sofs) = val;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
** bmp_DecodeRLE4
|
|
|
|
**
|
|
|
|
** Given (data) pointing to a line of RLE4-format data and (line) being the starting
|
|
|
|
** line onscreen, decode the line.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
bmp_DecodeRLE4(BMP_INFO *info, int line)
|
|
|
|
{
|
|
|
|
int count; /* run count */
|
|
|
|
u_char val;
|
|
|
|
int x,y; /* screen position */
|
|
|
|
|
|
|
|
x = 0; /* starting position */
|
|
|
|
y = line;
|
|
|
|
|
|
|
|
/* loop reading data */
|
|
|
|
for (;;) {
|
|
|
|
/*
|
|
|
|
* encoded mode starts with a run length, and then a byte with
|
|
|
|
* two colour indexes to alternate between for the run
|
|
|
|
*/
|
|
|
|
if (*info->index) {
|
|
|
|
for (count = 0; count < *info->index; count++, x++) {
|
|
|
|
if (count & 1) { /* odd count, low nybble */
|
|
|
|
bmp_SetPix(info, x, y, *(info->index+1) & 0x0f);
|
|
|
|
} else { /* even count, high nybble */
|
|
|
|
bmp_SetPix(info, x, y, (*(info->index+1) >>4) & 0x0f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
info->index += 2;
|
|
|
|
/*
|
|
|
|
* A leading zero is an escape; it may signal the end of the
|
|
|
|
* bitmap, a cursor move, or some absolute data.
|
|
|
|
*/
|
|
|
|
} else { /* zero tag may be absolute mode or an escape */
|
|
|
|
switch (*(info->index+1)) {
|
|
|
|
case 0: /* end of line */
|
|
|
|
info->index += 2;
|
|
|
|
return;
|
|
|
|
case 1: /* end of bitmap */
|
|
|
|
info->index = NULL;
|
|
|
|
return;
|
|
|
|
case 2: /* move */
|
|
|
|
x += *(info->index + 2); /* new coords */
|
|
|
|
y += *(info->index + 3);
|
|
|
|
info->index += 4;
|
|
|
|
break;
|
|
|
|
default: /* literal bitmap data */
|
|
|
|
for (count = 0; count < *(info->index + 1); count++, x++) {
|
|
|
|
val = *(info->index + 2 + (count / 2)); /* byte with nybbles */
|
|
|
|
if (count & 1) {
|
|
|
|
val &= 0xf; /* get low nybble */
|
|
|
|
} else {
|
|
|
|
val = (val >> 4); /* get high nybble */
|
|
|
|
}
|
|
|
|
bmp_SetPix(info, x, y, val);
|
|
|
|
}
|
|
|
|
/* warning, this depends on integer truncation, do not hand-optimise! */
|
|
|
|
info->index += 2 + ((count + 3) / 4) * 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
** bmp_DecodeRLE8
|
2000-04-24 10:09:42 +00:00
|
|
|
** Given (data) pointing to a line of RLE8-format data and (line) being the starting
|
1999-01-11 03:34:56 +00:00
|
|
|
** line onscreen, decode the line.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
bmp_DecodeRLE8(BMP_INFO *info, int line)
|
|
|
|
{
|
|
|
|
int count; /* run count */
|
|
|
|
int x,y; /* screen position */
|
|
|
|
|
|
|
|
x = 0; /* starting position */
|
|
|
|
y = line;
|
|
|
|
|
|
|
|
/* loop reading data */
|
|
|
|
for(;;) {
|
|
|
|
/*
|
|
|
|
* encoded mode starts with a run length, and then a byte with
|
|
|
|
* two colour indexes to alternate between for the run
|
|
|
|
*/
|
|
|
|
if (*info->index) {
|
|
|
|
for (count = 0; count < *info->index; count++, x++)
|
|
|
|
bmp_SetPix(info, x, y, *(info->index+1));
|
|
|
|
info->index += 2;
|
|
|
|
/*
|
|
|
|
* A leading zero is an escape; it may signal the end of the
|
|
|
|
* bitmap, a cursor move, or some absolute data.
|
|
|
|
*/
|
|
|
|
} else { /* zero tag may be absolute mode or an escape */
|
|
|
|
switch(*(info->index+1)) {
|
|
|
|
case 0: /* end of line */
|
|
|
|
info->index += 2;
|
|
|
|
return;
|
|
|
|
case 1: /* end of bitmap */
|
|
|
|
info->index = NULL;
|
|
|
|
return;
|
|
|
|
case 2: /* move */
|
|
|
|
x += *(info->index + 2); /* new coords */
|
|
|
|
y += *(info->index + 3);
|
|
|
|
info->index += 4;
|
|
|
|
break;
|
|
|
|
default: /* literal bitmap data */
|
|
|
|
for (count = 0; count < *(info->index + 1); count++, x++)
|
|
|
|
bmp_SetPix(info, x, y, *(info->index + 2 + count));
|
|
|
|
/* must be an even count */
|
|
|
|
info->index += 2 + count + (count & 1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
** bmp_DecodeLine
|
|
|
|
**
|
|
|
|
** Given (info) pointing to an image being decoded, (line) being the line currently
|
|
|
|
** being displayed, decode a line of data.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
bmp_DecodeLine(BMP_INFO *info, int line)
|
|
|
|
{
|
|
|
|
int x;
|
2000-04-24 10:09:42 +00:00
|
|
|
u_char val, mask, *p;
|
1999-01-11 03:34:56 +00:00
|
|
|
|
|
|
|
switch(info->format) {
|
|
|
|
case BI_RGB:
|
2000-04-24 10:09:42 +00:00
|
|
|
switch(info->depth) {
|
|
|
|
case 8:
|
|
|
|
for (x = 0; x < info->width; x++, info->index++)
|
|
|
|
bmp_SetPix(info, x, line, *info->index);
|
|
|
|
info->index += 3 - (--x % 4);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
p = info->index;
|
|
|
|
for (x = 0; x < info->width; x++) {
|
|
|
|
if (x & 1) {
|
|
|
|
val = *p & 0xf; /* get low nybble */
|
|
|
|
p++;
|
|
|
|
} else {
|
|
|
|
val = *p >> 4; /* get high nybble */
|
|
|
|
}
|
|
|
|
bmp_SetPix(info, x, line, val);
|
|
|
|
}
|
|
|
|
/* warning, this depends on integer truncation, do not hand-optimise! */
|
|
|
|
info->index += ((x + 7) / 8) * 4;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
p = info->index;
|
|
|
|
mask = 0x80;
|
|
|
|
for (x = 0; x < info->width; x++) {
|
|
|
|
val = (*p & mask) ? 1 : 0;
|
|
|
|
mask >>= 1;
|
|
|
|
if (mask == 0) {
|
|
|
|
mask = 0x80;
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
bmp_SetPix(info, x, line, val);
|
|
|
|
}
|
|
|
|
/* warning, this depends on integer truncation, do not hand-optimise! */
|
|
|
|
info->index += ((x + 31) / 32) * 4;
|
|
|
|
break;
|
|
|
|
}
|
1999-01-11 03:34:56 +00:00
|
|
|
break;
|
|
|
|
case BI_RLE4:
|
|
|
|
bmp_DecodeRLE4(info, line);
|
|
|
|
break;
|
|
|
|
case BI_RLE8:
|
|
|
|
bmp_DecodeRLE8(info, line);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
** bmp_Init
|
|
|
|
**
|
|
|
|
** Given a pointer (data) to the image of a BMP file, fill in bmp_info with what
|
|
|
|
** can be learnt from it. Return nonzero if the file isn't usable.
|
|
|
|
**
|
|
|
|
** Take screen dimensions (swidth), (sheight) and (sdepth) and make sure we
|
|
|
|
** can work with these.
|
|
|
|
*/
|
|
|
|
static int
|
2002-11-11 10:17:01 +00:00
|
|
|
bmp_Init(char *data, int swidth, int sheight, int sdepth)
|
1999-01-11 03:34:56 +00:00
|
|
|
{
|
|
|
|
BITMAPF *bmf = (BITMAPF *)data;
|
|
|
|
int pind;
|
|
|
|
|
|
|
|
bmp_info.data = NULL; /* assume setup failed */
|
|
|
|
|
|
|
|
/* check file ID */
|
|
|
|
if (bmf->bmfh.bfType != 0x4d42) {
|
1999-06-16 14:04:45 +00:00
|
|
|
printf("splash_bmp: not a BMP file\n");
|
1999-01-11 03:34:56 +00:00
|
|
|
return(1); /* XXX check word ordering for big-endian ports? */
|
|
|
|
}
|
|
|
|
|
1999-06-16 14:04:45 +00:00
|
|
|
/* do we understand this bitmap format? */
|
|
|
|
if (bmf->bmfi.bmiHeader.biSize > sizeof(bmf->bmfi.bmiHeader)) {
|
|
|
|
printf("splash_bmp: unsupported BMP format (size=%d)\n",
|
|
|
|
bmf->bmfi.bmiHeader.biSize);
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
1999-01-11 03:34:56 +00:00
|
|
|
/* save what we know about the screen */
|
|
|
|
bmp_info.swidth = swidth;
|
|
|
|
bmp_info.sheight = sheight;
|
|
|
|
bmp_info.sdepth = sdepth;
|
|
|
|
|
|
|
|
/* where's the data? */
|
|
|
|
bmp_info.data = (u_char *)data + bmf->bmfh.bfOffBits;
|
|
|
|
|
|
|
|
/* image parameters */
|
|
|
|
bmp_info.width = bmf->bmfi.bmiHeader.biWidth;
|
|
|
|
bmp_info.height = bmf->bmfi.bmiHeader.biHeight;
|
2000-04-24 10:09:42 +00:00
|
|
|
bmp_info.depth = bmf->bmfi.bmiHeader.biBitCount;
|
1999-01-11 03:34:56 +00:00
|
|
|
bmp_info.format = bmf->bmfi.bmiHeader.biCompression;
|
|
|
|
|
|
|
|
switch(bmp_info.format) { /* check compression format */
|
|
|
|
case BI_RGB:
|
|
|
|
case BI_RLE4:
|
|
|
|
case BI_RLE8:
|
|
|
|
break;
|
|
|
|
default:
|
1999-06-16 14:04:45 +00:00
|
|
|
printf("splash_bmp: unsupported compression format\n");
|
1999-01-11 03:34:56 +00:00
|
|
|
return(1); /* unsupported compression format */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* palette details */
|
|
|
|
bmp_info.ncols = (bmf->bmfi.bmiHeader.biClrUsed);
|
|
|
|
bzero(bmp_info.palette,sizeof(bmp_info.palette));
|
|
|
|
if (bmp_info.ncols == 0) { /* uses all of them */
|
1999-01-13 09:59:30 +00:00
|
|
|
bmp_info.ncols = 1 << bmf->bmfi.bmiHeader.biBitCount;
|
1999-01-11 03:34:56 +00:00
|
|
|
}
|
|
|
|
if ((bmp_info.height > bmp_info.sheight) ||
|
|
|
|
(bmp_info.width > bmp_info.swidth) ||
|
|
|
|
(bmp_info.ncols > (1 << sdepth))) {
|
2000-04-24 10:09:42 +00:00
|
|
|
if (bootverbose)
|
|
|
|
printf("splash_bmp: beyond screen capacity (%dx%d, %d colors)\n",
|
|
|
|
bmp_info.width, bmp_info.height, bmp_info.ncols);
|
|
|
|
return(1);
|
1999-01-11 03:34:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* read palette */
|
|
|
|
for (pind = 0; pind < bmp_info.ncols; pind++) {
|
|
|
|
bmp_info.palette[pind][0] = bmf->bmfi.bmiColors[pind].rgbRed;
|
|
|
|
bmp_info.palette[pind][1] = bmf->bmfi.bmiColors[pind].rgbGreen;
|
|
|
|
bmp_info.palette[pind][2] = bmf->bmfi.bmiColors[pind].rgbBlue;
|
|
|
|
}
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
** bmp_Draw
|
|
|
|
**
|
|
|
|
** Render the image. Return nonzero if that's not possible.
|
|
|
|
**
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
bmp_Draw(video_adapter_t *adp)
|
|
|
|
{
|
|
|
|
int line;
|
2001-03-06 03:07:58 +00:00
|
|
|
#if 0
|
|
|
|
#ifndef PC98
|
2000-04-24 10:09:42 +00:00
|
|
|
int i;
|
2001-03-06 03:07:58 +00:00
|
|
|
#endif
|
|
|
|
#endif
|
1999-01-11 03:34:56 +00:00
|
|
|
|
|
|
|
if (bmp_info.data == NULL) { /* init failed, do nothing */
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* clear the screen */
|
|
|
|
bmp_info.vidmem = (u_char *)adp->va_window;
|
1999-01-21 18:29:33 +00:00
|
|
|
bmp_info.adp = adp;
|
2000-04-24 10:09:42 +00:00
|
|
|
(*vidsw[adp->va_index]->clear)(adp);
|
1999-01-21 18:29:33 +00:00
|
|
|
(*vidsw[adp->va_index]->set_win_org)(adp, 0);
|
|
|
|
bmp_info.bank = 0;
|
1999-01-11 03:34:56 +00:00
|
|
|
|
|
|
|
/* initialise the info structure for drawing */
|
|
|
|
bmp_info.index = bmp_info.data;
|
2000-04-27 13:37:40 +00:00
|
|
|
#ifdef PC98
|
|
|
|
bmp_info.prev_val = 255;
|
|
|
|
#endif
|
1999-01-11 03:34:56 +00:00
|
|
|
|
|
|
|
/* set the palette for our image */
|
|
|
|
(*vidsw[adp->va_index]->load_palette)(adp, (u_char *)&bmp_info.palette);
|
|
|
|
|
2000-10-31 07:58:34 +00:00
|
|
|
#if 0
|
2000-04-27 13:37:40 +00:00
|
|
|
#ifndef PC98
|
2000-04-24 10:09:42 +00:00
|
|
|
/* XXX: this is ugly, but necessary for EGA/VGA 1bpp/4bpp modes */
|
|
|
|
if ((adp->va_type == KD_EGA) || (adp->va_type == KD_VGA)) {
|
|
|
|
inb(adp->va_crtc_addr + 6); /* reset flip-flop */
|
|
|
|
outb(ATC, 0x14);
|
|
|
|
outb(ATC, 0);
|
|
|
|
for (i = 0; i < 16; ++i) {
|
|
|
|
outb(ATC, i);
|
|
|
|
outb(ATC, i);
|
|
|
|
}
|
|
|
|
inb(adp->va_crtc_addr + 6); /* reset flip-flop */
|
|
|
|
outb(ATC, 0x20); /* enable palette */
|
|
|
|
|
|
|
|
outw(GDCIDX, 0x0f01); /* set/reset enable */
|
|
|
|
|
|
|
|
if (bmp_info.sdepth == 1)
|
|
|
|
outw(TSIDX, 0x0102); /* unmask plane #0 */
|
|
|
|
}
|
2000-10-31 07:58:34 +00:00
|
|
|
#endif
|
2000-04-27 13:37:40 +00:00
|
|
|
#endif
|
2000-04-24 10:09:42 +00:00
|
|
|
|
1999-01-11 03:34:56 +00:00
|
|
|
for (line = 0; (line < bmp_info.height) && bmp_info.index; line++) {
|
|
|
|
bmp_DecodeLine(&bmp_info, line);
|
|
|
|
}
|
|
|
|
return(0);
|
|
|
|
}
|