2 * Copyright (c) 1999 Michael Smith <msmith@freebsd.org>
3 * Copyright (c) 1999 Kazutaka YOKOTA <yokota@freebsd.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * $FreeBSD: src/sys/modules/splash/bmp/splash_bmp.c,v 1.10.2.3 2000/10/31 08:00:06 nyan Exp $
28 * $DragonFly: src/sys/dev/video/fb/bmp/splash_bmp.c,v 1.9 2006/12/23 00:26:27 swildner Exp $
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/linker.h>
37 #include <dev/video/fb/fbreg.h>
38 #include <dev/video/fb/splashreg.h>
39 #include <dev/video/fb/vgareg.h>
41 #include <bus/isa/isareg.h>
43 #define FADE_TIMEOUT 15 /* sec */
44 #define FADE_LEVELS 10
46 static int splash_mode
= -1;
47 static int splash_on
= FALSE
;
49 static int bmp_start(video_adapter_t
*);
50 static int bmp_end(video_adapter_t
*);
51 static int bmp_splash(video_adapter_t
*, int);
52 static int bmp_Init(const char *, int, int, int);
53 static int bmp_Draw(video_adapter_t
*);
55 static splash_decoder_t bmp_decoder
= {
56 "splash_bmp", bmp_start
, bmp_end
, bmp_splash
, SPLASH_IMAGE
,
59 SPLASH_DECODER(splash_bmp
, bmp_decoder
);
62 bmp_start(video_adapter_t
*adp
)
64 /* currently only 256-color modes are supported XXX */
65 static int modes
[] = {
71 * As 320x200 doesn't generally look great,
72 * it's least preferred here.
80 if ((bmp_decoder
.data
== NULL
) || (bmp_decoder
.data_size
<= 0)) {
81 kprintf("splash_bmp: No bitmap file found\n");
84 for (i
= 0; modes
[i
] >= 0; ++i
) {
85 if (((*vidsw
[adp
->va_index
]->get_info
)(adp
, modes
[i
], &info
) == 0)
86 && (bmp_Init((u_char
*)bmp_decoder
.data
,
87 info
.vi_width
, info
.vi_height
, info
.vi_depth
) == 0))
90 splash_mode
= modes
[i
];
92 kprintf("splash_bmp: No appropriate video mode found\n");
94 kprintf("bmp_start(): splash_mode:%d\n", splash_mode
);
95 return ((splash_mode
< 0) ? ENODEV
: 0);
99 bmp_end(video_adapter_t
*adp
)
106 bmp_splash(video_adapter_t
*adp
, int on
)
108 static u_char pal
[256*3];
109 static long time_stamp
;
111 static int fading
= TRUE
, brightness
= FADE_LEVELS
;
117 /* set up the video mode and draw something */
118 if ((*vidsw
[adp
->va_index
]->set_mode
)(adp
, splash_mode
))
122 (*vidsw
[adp
->va_index
]->save_palette
)(adp
, pal
);
127 * This is a kludge to fade the image away. This section of the
128 * code takes effect only after the system is completely up.
129 * FADE_TIMEOUT should be configurable.
134 time_stamp
= tv
.tv_sec
;
135 if (tv
.tv_sec
> time_stamp
+ FADE_TIMEOUT
) {
137 if (brightness
== 0) {
143 if (brightness
== FADE_LEVELS
) {
148 for (i
= 0; i
< sizeof(pal
); ++i
) {
149 tpal
[i
] = pal
[i
] * brightness
/ FADE_LEVELS
;
151 (*vidsw
[adp
->va_index
]->load_palette
)(adp
, tpal
);
152 time_stamp
= tv
.tv_sec
;
157 /* the video mode will be restored by the caller */
164 ** Code to handle Microsoft DIB (".BMP") format images.
166 ** Blame me (msmith@freebsd.org) if this is broken, not Soren.
169 typedef struct tagBITMAPFILEHEADER
{ /* bmfh */
170 u_short bfType
__attribute__ ((packed
));
171 int bfSize
__attribute__ ((packed
));
172 u_short bfReserved1
__attribute__ ((packed
));
173 u_short bfReserved2
__attribute__ ((packed
));
174 int bfOffBits
__attribute__ ((packed
));
177 typedef struct tagBITMAPINFOHEADER
{ /* bmih */
178 int biSize
__attribute__ ((packed
));
179 int biWidth
__attribute__ ((packed
));
180 int biHeight
__attribute__ ((packed
));
181 short biPlanes
__attribute__ ((packed
));
182 short biBitCount
__attribute__ ((packed
));
183 int biCompression
__attribute__ ((packed
));
184 int biSizeImage
__attribute__ ((packed
));
185 int biXPelsPerMeter
__attribute__ ((packed
));
186 int biYPelsPerMeter
__attribute__ ((packed
));
187 int biClrUsed
__attribute__ ((packed
));
188 int biClrImportant
__attribute__ ((packed
));
191 typedef struct tagRGBQUAD
{ /* rgbq */
192 u_char rgbBlue
__attribute__ ((packed
));
193 u_char rgbGreen
__attribute__ ((packed
));
194 u_char rgbRed
__attribute__ ((packed
));
195 u_char rgbReserved
__attribute__ ((packed
));
198 typedef struct tagBITMAPINFO
{ /* bmi */
199 BITMAPINFOHEADER bmiHeader
__attribute__ ((packed
));
200 RGBQUAD bmiColors
[256] __attribute__ ((packed
));
203 typedef struct tagBITMAPF
205 BITMAPFILEHEADER bmfh
__attribute__ ((packed
));
206 BITMAPINFO bmfi
__attribute__ ((packed
));
214 ** all we actually care about the image
218 int width
,height
; /* image dimensions */
219 int swidth
,sheight
; /* screen dimensions for the current mode */
220 u_char depth
; /* image depth (1, 4, 8, 24 bits) */
221 u_char sdepth
; /* screen depth (1, 4, 8 bpp) */
222 int ncols
; /* number of colours */
223 u_char palette
[256][3]; /* raw palette data */
224 u_char format
; /* one of the BI_* constants above */
225 const u_char
*data
; /* pointer to the raw data */
226 const u_char
*index
; /* running pointer to the data while drawing */
227 u_char
*vidmem
; /* video memory allocated for drawing */
228 video_adapter_t
*adp
;
232 static BMP_INFO bmp_info
;
237 ** Given (info), set the pixel at (x),(y) to (val)
241 bmp_SetPix(BMP_INFO
*info
, int x
, int y
, u_char val
)
247 * range check to avoid explosions
249 if ((x
< 0) || (x
>= info
->swidth
) || (y
< 0) || (y
>= info
->sheight
))
253 * calculate offset into video memory;
254 * because 0,0 is bottom-left for DIB, we have to convert.
256 sofs
= ((info
->height
- (y
+1) + (info
->sheight
- info
->height
) / 2)
257 * info
->adp
->va_line_width
);
258 x
+= (info
->swidth
- info
->width
) / 2;
260 switch(info
->sdepth
) {
263 /* EGA/VGA planar modes */
265 newbank
= sofs
/info
->adp
->va_window_size
;
266 if (info
->bank
!= newbank
) {
267 (*vidsw
[info
->adp
->va_index
]->set_win_org
)(info
->adp
, newbank
*info
->adp
->va_window_size
);
268 info
->bank
= newbank
;
270 sofs
%= info
->adp
->va_window_size
;
271 bofs
= x
& 0x7; /* offset within byte */
272 outw(GDCIDX
, (0x8000 >> bofs
) | 0x08); /* bit mask */
273 outw(GDCIDX
, (val
<< 8) | 0x00); /* set/reset */
274 *(info
->vidmem
+ sofs
) ^= 0xff; /* read-modify-write */
279 newbank
= sofs
/info
->adp
->va_window_size
;
280 if (info
->bank
!= newbank
) {
281 (*vidsw
[info
->adp
->va_index
]->set_win_org
)(info
->adp
, newbank
*info
->adp
->va_window_size
);
282 info
->bank
= newbank
;
284 sofs
%= info
->adp
->va_window_size
;
285 *(info
->vidmem
+sofs
) = val
;
293 ** Given (data) pointing to a line of RLE4-format data and (line) being the starting
294 ** line onscreen, decode the line.
297 bmp_DecodeRLE4(BMP_INFO
*info
, int line
)
299 int count
; /* run count */
301 int x
,y
; /* screen position */
303 x
= 0; /* starting position */
306 /* loop reading data */
309 * encoded mode starts with a run length, and then a byte with
310 * two colour indexes to alternate between for the run
313 for (count
= 0; count
< *info
->index
; count
++, x
++) {
314 if (count
& 1) { /* odd count, low nybble */
315 bmp_SetPix(info
, x
, y
, *(info
->index
+1) & 0x0f);
316 } else { /* even count, high nybble */
317 bmp_SetPix(info
, x
, y
, (*(info
->index
+1) >>4) & 0x0f);
322 * A leading zero is an escape; it may signal the end of the
323 * bitmap, a cursor move, or some absolute data.
325 } else { /* zero tag may be absolute mode or an escape */
326 switch (*(info
->index
+1)) {
327 case 0: /* end of line */
330 case 1: /* end of bitmap */
334 x
+= *(info
->index
+ 2); /* new coords */
335 y
+= *(info
->index
+ 3);
338 default: /* literal bitmap data */
339 for (count
= 0; count
< *(info
->index
+ 1); count
++, x
++) {
340 val
= *(info
->index
+ 2 + (count
/ 2)); /* byte with nybbles */
342 val
&= 0xf; /* get low nybble */
344 val
= (val
>> 4); /* get high nybble */
346 bmp_SetPix(info
, x
, y
, val
);
348 /* warning, this depends on integer truncation, do not hand-optimise! */
349 info
->index
+= 2 + ((count
+ 3) / 4) * 2;
358 ** Given (data) pointing to a line of RLE8-format data and (line) being the starting
359 ** line onscreen, decode the line.
362 bmp_DecodeRLE8(BMP_INFO
*info
, int line
)
364 int count
; /* run count */
365 int x
,y
; /* screen position */
367 x
= 0; /* starting position */
370 /* loop reading data */
373 * encoded mode starts with a run length, and then a byte with
374 * two colour indexes to alternate between for the run
377 for (count
= 0; count
< *info
->index
; count
++, x
++)
378 bmp_SetPix(info
, x
, y
, *(info
->index
+1));
381 * A leading zero is an escape; it may signal the end of the
382 * bitmap, a cursor move, or some absolute data.
384 } else { /* zero tag may be absolute mode or an escape */
385 switch(*(info
->index
+1)) {
386 case 0: /* end of line */
389 case 1: /* end of bitmap */
393 x
+= *(info
->index
+ 2); /* new coords */
394 y
+= *(info
->index
+ 3);
397 default: /* literal bitmap data */
398 for (count
= 0; count
< *(info
->index
+ 1); count
++, x
++)
399 bmp_SetPix(info
, x
, y
, *(info
->index
+ 2 + count
));
400 /* must be an even count */
401 info
->index
+= 2 + count
+ (count
& 1);
411 ** Given (info) pointing to an image being decoded, (line) being the line currently
412 ** being displayed, decode a line of data.
415 bmp_DecodeLine(BMP_INFO
*info
, int line
)
421 switch(info
->format
) {
423 switch(info
->depth
) {
425 for (x
= 0; x
< info
->width
; x
++, info
->index
++)
426 bmp_SetPix(info
, x
, line
, *info
->index
);
427 info
->index
+= 3 - (--x
% 4);
431 for (x
= 0; x
< info
->width
; x
++) {
433 val
= *p
& 0xf; /* get low nybble */
436 val
= *p
>> 4; /* get high nybble */
438 bmp_SetPix(info
, x
, line
, val
);
440 /* warning, this depends on integer truncation, do not hand-optimise! */
441 info
->index
+= ((x
+ 7) / 8) * 4;
446 for (x
= 0; x
< info
->width
; x
++) {
447 val
= (*p
& mask
) ? 1 : 0;
453 bmp_SetPix(info
, x
, line
, val
);
455 /* warning, this depends on integer truncation, do not hand-optimise! */
456 info
->index
+= ((x
+ 31) / 32) * 4;
461 bmp_DecodeRLE4(info
, line
);
464 bmp_DecodeRLE8(info
, line
);
472 ** Given a pointer (data) to the image of a BMP file, fill in bmp_info with what
473 ** can be learnt from it. Return nonzero if the file isn't usable.
475 ** Take screen dimensions (swidth), (sheight) and (sdepth) and make sure we
476 ** can work with these.
479 bmp_Init(const char *data
, int swidth
, int sheight
, int sdepth
)
481 const BITMAPF
*bmf
= (const BITMAPF
*)data
;
484 bmp_info
.data
= NULL
; /* assume setup failed */
487 if (bmf
->bmfh
.bfType
!= 0x4d42) {
488 kprintf("splash_bmp: not a BMP file\n");
489 return(1); /* XXX check word ordering for big-endian ports? */
492 /* do we understand this bitmap format? */
493 if (bmf
->bmfi
.bmiHeader
.biSize
> sizeof(bmf
->bmfi
.bmiHeader
)) {
494 kprintf("splash_bmp: unsupported BMP format (size=%d)\n",
495 bmf
->bmfi
.bmiHeader
.biSize
);
499 /* save what we know about the screen */
500 bmp_info
.swidth
= swidth
;
501 bmp_info
.sheight
= sheight
;
502 bmp_info
.sdepth
= sdepth
;
504 /* where's the data? */
505 bmp_info
.data
= (const u_char
*)data
+ bmf
->bmfh
.bfOffBits
;
507 /* image parameters */
508 bmp_info
.width
= bmf
->bmfi
.bmiHeader
.biWidth
;
509 bmp_info
.height
= bmf
->bmfi
.bmiHeader
.biHeight
;
510 bmp_info
.depth
= bmf
->bmfi
.bmiHeader
.biBitCount
;
511 bmp_info
.format
= bmf
->bmfi
.bmiHeader
.biCompression
;
513 switch(bmp_info
.format
) { /* check compression format */
519 kprintf("splash_bmp: unsupported compression format\n");
520 return(1); /* unsupported compression format */
523 /* palette details */
524 bmp_info
.ncols
= (bmf
->bmfi
.bmiHeader
.biClrUsed
);
525 bzero(bmp_info
.palette
,sizeof(bmp_info
.palette
));
526 if (bmp_info
.ncols
== 0) { /* uses all of them */
527 bmp_info
.ncols
= 1 << bmf
->bmfi
.bmiHeader
.biBitCount
;
529 if ((bmp_info
.height
> bmp_info
.sheight
) ||
530 (bmp_info
.width
> bmp_info
.swidth
) ||
531 (bmp_info
.ncols
> (1 << sdepth
))) {
533 kprintf("splash_bmp: beyond screen capacity (%dx%d, %d colors)\n",
534 bmp_info
.width
, bmp_info
.height
, bmp_info
.ncols
);
539 for (pind
= 0; pind
< bmp_info
.ncols
; pind
++) {
540 bmp_info
.palette
[pind
][0] = bmf
->bmfi
.bmiColors
[pind
].rgbRed
;
541 bmp_info
.palette
[pind
][1] = bmf
->bmfi
.bmiColors
[pind
].rgbGreen
;
542 bmp_info
.palette
[pind
][2] = bmf
->bmfi
.bmiColors
[pind
].rgbBlue
;
550 ** Render the image. Return nonzero if that's not possible.
554 bmp_Draw(video_adapter_t
*adp
)
561 if (bmp_info
.data
== NULL
) { /* init failed, do nothing */
565 /* clear the screen */
566 bmp_info
.vidmem
= (u_char
*)adp
->va_window
;
568 (*vidsw
[adp
->va_index
]->clear
)(adp
);
569 (*vidsw
[adp
->va_index
]->set_win_org
)(adp
, 0);
572 /* initialise the info structure for drawing */
573 bmp_info
.index
= bmp_info
.data
;
575 /* set the palette for our image */
576 (*vidsw
[adp
->va_index
]->load_palette
)(adp
, (u_char
*)&bmp_info
.palette
);
579 /* XXX: this is ugly, but necessary for EGA/VGA 1bpp/4bpp modes */
580 if ((adp
->va_type
== KD_EGA
) || (adp
->va_type
== KD_VGA
)) {
581 inb(adp
->va_crtc_addr
+ 6); /* reset flip-flop */
584 for (i
= 0; i
< 16; ++i
) {
588 inb(adp
->va_crtc_addr
+ 6); /* reset flip-flop */
589 outb(ATC
, 0x20); /* enable palette */
591 outw(GDCIDX
, 0x0f01); /* set/reset enable */
593 if (bmp_info
.sdepth
== 1)
594 outw(TSIDX
, 0x0102); /* unmask plane #0 */
598 for (line
= 0; (line
< bmp_info
.height
) && bmp_info
.index
; line
++) {
599 bmp_DecodeLine(&bmp_info
, line
);