#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/linker.h>
#include <sys/fbio.h>
#include <dev/fb/fbreg.h>
#include <dev/fb/splashreg.h>
#include <dev/fb/vgareg.h>
#include <isa/isareg.h>
#define FADE_TIMEOUT 15
#define FADE_LEVELS 10
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);
static int bmp_Init(char *data, int swidth, int sheight, int sdepth);
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)
{
static int modes[] = {
M_VESA_CG640x480,
M_VESA_CG800x600,
M_VESA_CG1024x768,
M_CG640x480,
M_VGA_CG320,
-1,
};
video_info_t info;
int i;
if ((bmp_decoder.data == NULL) || (bmp_decoder.data_size <= 0)) {
printf("splash_bmp: No bitmap file found\n");
return ENODEV;
}
for (i = 0; modes[i] >= 0; ++i) {
if ((vidd_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];
if (splash_mode < 0)
printf("splash_bmp: No appropriate video mode found\n");
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)
{
return 0;
}
static int
bmp_splash(video_adapter_t *adp, int on)
{
static u_char pal[256*3];
static long time_stamp;
u_char tpal[256*3];
static int fading = TRUE, brightness = FADE_LEVELS;
struct timeval tv;
int i;
if (on) {
if (!splash_on) {
if (vidd_set_mode(adp, splash_mode))
return 1;
if (bmp_Draw(adp))
return 1;
vidd_save_palette(adp, pal);
time_stamp = 0;
splash_on = TRUE;
}
if (!cold) {
getmicrotime(&tv);
if (time_stamp == 0)
time_stamp = tv.tv_sec;
if (tv.tv_sec > time_stamp + FADE_TIMEOUT) {
if (fading)
if (brightness == 0) {
fading = FALSE;
brightness++;
}
else brightness--;
else
if (brightness == FADE_LEVELS) {
fading = TRUE;
brightness--;
}
else brightness++;
for (i = 0; i < sizeof(pal); ++i) {
tpal[i] = pal[i] * brightness / FADE_LEVELS;
}
vidd_load_palette(adp, tpal);
time_stamp = tv.tv_sec;
}
}
return 0;
} else {
splash_on = FALSE;
return 0;
}
}
typedef struct tagBITMAPFILEHEADER {
u_short bfType;
int bfSize;
u_short bfReserved1;
u_short bfReserved2;
int bfOffBits;
} __packed BITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER {
int biSize;
int biWidth;
int biHeight;
short biPlanes;
short biBitCount;
int biCompression;
int biSizeImage;
int biXPelsPerMeter;
int biYPelsPerMeter;
int biClrUsed;
int biClrImportant;
} __packed BITMAPINFOHEADER;
typedef struct tagRGBQUAD {
u_char rgbBlue;
u_char rgbGreen;
u_char rgbRed;
u_char rgbReserved;
} __packed RGBQUAD;
typedef struct tagBITMAPINFO {
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[256];
} __packed BITMAPINFO;
typedef struct tagBITMAPF
{
BITMAPFILEHEADER bmfh;
BITMAPINFO bmfi;
} __packed BITMAPF;
#define BI_RGB 0
#define BI_RLE8 1
#define BI_RLE4 2
typedef struct
{
int width,height;
int swidth,sheight;
u_char depth;
u_char sdepth;
int ncols;
u_char palette[256][3];
u_char format;
u_char *data;
u_char *index;
u_char *vidmem;
video_adapter_t *adp;
int bank;
} BMP_INFO;
static BMP_INFO bmp_info;
static void
bmp_SetPix(BMP_INFO *info, int x, int y, u_char val)
{
int sofs, bofs;
int newbank;
if ((x < 0) || (x >= info->swidth) || (y < 0) || (y >= info->sheight))
return;
sofs = ((info->height - (y+1) + (info->sheight - info->height) / 2)
* info->adp->va_line_width);
x += (info->swidth - info->width) / 2;
switch(info->sdepth) {
case 4:
case 1:
sofs += (x >> 3);
newbank = sofs/info->adp->va_window_size;
if (info->bank != newbank) {
vidd_set_win_org(info->adp, newbank*info->adp->va_window_size);
info->bank = newbank;
}
sofs %= info->adp->va_window_size;
bofs = x & 0x7;
outw(GDCIDX, (0x8000 >> bofs) | 0x08);
outw(GDCIDX, (val << 8) | 0x00);
*(info->vidmem + sofs) ^= 0xff;
break;
case 8:
sofs += x;
newbank = sofs/info->adp->va_window_size;
if (info->bank != newbank) {
vidd_set_win_org(info->adp, newbank*info->adp->va_window_size);
info->bank = newbank;
}
sofs %= info->adp->va_window_size;
*(info->vidmem+sofs) = val;
break;
}
}
static void
bmp_DecodeRLE4(BMP_INFO *info, int line)
{
int count;
u_char val;
int x,y;
x = 0;
y = line;
for (;;) {
if (*info->index) {
for (count = 0; count < *info->index; count++, x++) {
if (count & 1) {
bmp_SetPix(info, x, y, *(info->index+1) & 0x0f);
} else {
bmp_SetPix(info, x, y, (*(info->index+1) >>4) & 0x0f);
}
}
info->index += 2;
} else {
switch (*(info->index+1)) {
case 0:
info->index += 2;
return;
case 1:
info->index = NULL;
return;
case 2:
x += *(info->index + 2);
y += *(info->index + 3);
info->index += 4;
break;
default:
for (count = 0; count < *(info->index + 1); count++, x++) {
val = *(info->index + 2 + (count / 2));
if (count & 1) {
val &= 0xf;
} else {
val = (val >> 4);
}
bmp_SetPix(info, x, y, val);
}
info->index += 2 + ((count + 3) / 4) * 2;
break;
}
}
}
}
static void
bmp_DecodeRLE8(BMP_INFO *info, int line)
{
int count;
int x,y;
x = 0;
y = line;
for(;;) {
if (*info->index) {
for (count = 0; count < *info->index; count++, x++)
bmp_SetPix(info, x, y, *(info->index+1));
info->index += 2;
} else {
switch(*(info->index+1)) {
case 0:
info->index += 2;
return;
case 1:
info->index = NULL;
return;
case 2:
x += *(info->index + 2);
y += *(info->index + 3);
info->index += 4;
break;
default:
for (count = 0; count < *(info->index + 1); count++, x++)
bmp_SetPix(info, x, y, *(info->index + 2 + count));
info->index += 2 + count + (count & 1);
break;
}
}
}
}
static void
bmp_DecodeLine(BMP_INFO *info, int line)
{
int x;
u_char val, mask, *p;
switch(info->format) {
case BI_RGB:
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;
p++;
} else {
val = *p >> 4;
}
bmp_SetPix(info, x, line, val);
}
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);
}
info->index += ((x + 31) / 32) * 4;
break;
}
break;
case BI_RLE4:
bmp_DecodeRLE4(info, line);
break;
case BI_RLE8:
bmp_DecodeRLE8(info, line);
break;
}
}
static int
bmp_Init(char *data, int swidth, int sheight, int sdepth)
{
BITMAPF *bmf = (BITMAPF *)data;
int pind;
bmp_info.data = NULL;
if (bmf->bmfh.bfType != 0x4d42) {
printf("splash_bmp: not a BMP file\n");
return(1);
}
if (bmf->bmfi.bmiHeader.biSize > sizeof(bmf->bmfi.bmiHeader)) {
printf("splash_bmp: unsupported BMP format (size=%d)\n",
bmf->bmfi.bmiHeader.biSize);
return(1);
}
bmp_info.swidth = swidth;
bmp_info.sheight = sheight;
bmp_info.sdepth = sdepth;
bmp_info.data = (u_char *)data + bmf->bmfh.bfOffBits;
bmp_info.width = bmf->bmfi.bmiHeader.biWidth;
bmp_info.height = bmf->bmfi.bmiHeader.biHeight;
bmp_info.depth = bmf->bmfi.bmiHeader.biBitCount;
bmp_info.format = bmf->bmfi.bmiHeader.biCompression;
switch(bmp_info.format) {
case BI_RGB:
case BI_RLE4:
case BI_RLE8:
break;
default:
printf("splash_bmp: unsupported compression format\n");
return(1);
}
bmp_info.ncols = (bmf->bmfi.bmiHeader.biClrUsed);
bzero(bmp_info.palette,sizeof(bmp_info.palette));
if (bmp_info.ncols == 0) {
bmp_info.ncols = 1 << bmf->bmfi.bmiHeader.biBitCount;
}
if ((bmp_info.height > bmp_info.sheight) ||
(bmp_info.width > bmp_info.swidth) ||
(bmp_info.ncols > (1 << sdepth))) {
if (bootverbose)
printf("splash_bmp: beyond screen capacity (%dx%d, %d colors)\n",
bmp_info.width, bmp_info.height, bmp_info.ncols);
return(1);
}
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);
}
static int
bmp_Draw(video_adapter_t *adp)
{
int line;
#if 0
int i;
#endif
if (bmp_info.data == NULL) {
return(1);
}
bmp_info.vidmem = (u_char *)adp->va_window;
bmp_info.adp = adp;
vidd_clear(adp);
vidd_set_win_org(adp, 0);
bmp_info.bank = 0;
bmp_info.index = bmp_info.data;
vidd_load_palette(adp, (u_char *)&bmp_info.palette);
#if 0
if ((adp->va_type == KD_EGA) || (adp->va_type == KD_VGA)) {
inb(adp->va_crtc_addr + 6);
outb(ATC, 0x14);
outb(ATC, 0);
for (i = 0; i < 16; ++i) {
outb(ATC, i);
outb(ATC, i);
}
inb(adp->va_crtc_addr + 6);
outb(ATC, 0x20);
outw(GDCIDX, 0x0f01);
if (bmp_info.sdepth == 1)
outw(TSIDX, 0x0102);
}
#endif
for (line = 0; (line < bmp_info.height) && bmp_info.index; line++) {
bmp_DecodeLine(&bmp_info, line);
}
return(0);
}