splash_pcx.c revision 106766
1/*-
2 * Copyright (c) 1999 Michael Smith <msmith@freebsd.org>
3 * Copyright (c) 1999 Kazutaka YOKOTA <yokota@freebsd.org>
4 * Copyright (c) 1999 Dag-Erling Co�dan Sm�rgrav
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer
12 *    in this position and unchanged.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 *    derived from this software without specific prior written permission
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * $FreeBSD: head/sys/dev/fb/splash_pcx.c 106766 2002-11-11 10:28:44Z mux $
31 */
32
33#include <sys/param.h>
34#include <sys/systm.h>
35#include <sys/kernel.h>
36#include <sys/linker.h>
37#include <sys/fbio.h>
38
39#include <dev/fb/fbreg.h>
40#include <dev/fb/splashreg.h>
41
42#define FADE_TIMEOUT	300	/* sec */
43
44static int splash_mode = -1;
45static int splash_on = FALSE;
46
47static int pcx_start(video_adapter_t *adp);
48static int pcx_end(video_adapter_t *adp);
49static int pcx_splash(video_adapter_t *adp, int on);
50static int pcx_init(char *data, int sdepth);
51static int pcx_draw(video_adapter_t *adp);
52
53static splash_decoder_t pcx_decoder = {
54    "splash_pcx", pcx_start, pcx_end, pcx_splash, SPLASH_IMAGE,
55};
56
57SPLASH_DECODER(splash_pcx, pcx_decoder);
58
59static struct
60{
61    int		  width, height, bpsl;
62    int		  bpp, planes, zlen;
63    const u_char *zdata;
64    u_char	 *palette;
65} pcx_info;
66
67static int
68pcx_start(video_adapter_t *adp)
69{
70    static int modes[] = {
71	M_VGA_CG320,
72	M_VESA_CG640x480,
73	M_VESA_CG800x600,
74	M_VESA_CG1024x768,
75	-1,
76    };
77    video_info_t info;
78    int	i;
79
80    if (pcx_decoder.data == NULL
81	|| pcx_decoder.data_size <= 0
82	|| pcx_init((u_char *)pcx_decoder.data, pcx_decoder.data_size))
83	return ENODEV;
84
85    if (bootverbose)
86	printf("splash_pcx: image good:\n"
87	       "  width = %d\n"
88	       "  height = %d\n"
89	       "  depth = %d\n"
90	       "  planes = %d\n",
91	       pcx_info.width, pcx_info.height,
92	       pcx_info.bpp, pcx_info.planes);
93
94    for (i = 0; modes[i] >= 0; ++i) {
95	if (get_mode_info(adp, modes[i], &info) != 0)
96	    continue;
97	if (bootverbose)
98	    printf("splash_pcx: considering mode %d:\n"
99		   "  vi_width = %d\n"
100		   "  vi_height = %d\n"
101		   "  vi_depth = %d\n"
102		   "  vi_planes = %d\n",
103		   modes[i],
104		   info.vi_width, info.vi_height,
105		   info.vi_depth, info.vi_planes);
106	if (info.vi_width >= pcx_info.width
107	    && info.vi_height >= pcx_info.height
108	    && info.vi_depth == pcx_info.bpp
109	    && info.vi_planes == pcx_info.planes)
110	    break;
111    }
112
113    splash_mode = modes[i];
114    if (splash_mode == -1)
115	return ENODEV;
116    if (bootverbose)
117	printf("pcx_splash: selecting mode %d\n", splash_mode);
118    return 0;
119}
120
121static int
122pcx_end(video_adapter_t *adp)
123{
124    /* nothing to do */
125    return 0;
126}
127
128static int
129pcx_splash(video_adapter_t *adp, int on)
130{
131    if (on) {
132	if (!splash_on) {
133	    if (set_video_mode(adp, splash_mode) || pcx_draw(adp))
134		return 1;
135	    splash_on = TRUE;
136	}
137	return 0;
138    } else {
139	splash_on = FALSE;
140	return 0;
141    }
142}
143
144struct pcxheader {
145    u_char manufactor;
146    u_char version;
147    u_char encoding;
148    u_char bpp;
149    u_short xmin, ymin, xmax, ymax;
150    u_short hres, vres;
151    u_char colormap[48];
152    u_char rsvd;
153    u_char nplanes;
154    u_short bpsl;
155    u_short palinfo;
156    u_short hsize, vsize;
157};
158
159#define MAXSCANLINE 1024
160
161static int
162pcx_init(char *data, int size)
163{
164    const struct pcxheader *hdr;
165
166    hdr = (const struct pcxheader *)data;
167
168    if (size < 128 + 1 + 1 + 768
169	|| hdr->manufactor != 10
170	|| hdr->version != 5
171	|| hdr->encoding != 1
172	|| hdr->nplanes != 1
173	|| hdr->bpp != 8
174	|| hdr->bpsl > MAXSCANLINE
175	|| data[size-769] != 12) {
176	printf("splash_pcx: invalid PCX image\n");
177	return 1;
178    }
179    pcx_info.width =  hdr->xmax - hdr->xmin + 1;
180    pcx_info.height =  hdr->ymax - hdr->ymin + 1;
181    pcx_info.bpsl = hdr->bpsl;
182    pcx_info.bpp = hdr->bpp;
183    pcx_info.planes = hdr->nplanes;
184    pcx_info.zlen = size - (128 + 1 + 768);
185    pcx_info.zdata = data + 128;
186    pcx_info.palette = data + size - 768;
187    return 0;
188}
189
190static int
191pcx_draw(video_adapter_t *adp)
192{
193    u_char *vidmem;
194    int swidth, sheight, sbpsl, sdepth, splanes;
195    int banksize, origin;
196    int c, i, j, pos, scan, x, y;
197    u_char line[MAXSCANLINE];
198
199    if (pcx_info.zlen < 1)
200	return 1;
201
202    load_palette(adp, pcx_info.palette);
203
204    vidmem = (u_char *)adp->va_window;
205    swidth = adp->va_info.vi_width;
206    sheight = adp->va_info.vi_height;
207    sbpsl = adp->va_line_width;
208    sdepth = adp->va_info.vi_depth;
209    splanes = adp->va_info.vi_planes;
210    banksize = adp->va_window_size;
211
212    for (origin = 0; origin < sheight*sbpsl; origin += banksize) {
213	set_origin(adp, origin);
214	bzero(vidmem, banksize);
215    }
216
217    x = (swidth - pcx_info.width) / 2;
218    y = (sheight - pcx_info.height) / 2;
219    origin = 0;
220    pos = y * sbpsl + x;
221    while (pos > banksize) {
222	pos -= banksize;
223	origin += banksize;
224    }
225    set_origin(adp, origin);
226
227    for (scan = i = 0; scan < pcx_info.height; ++scan, ++y, pos += sbpsl) {
228	for (j = 0; j < pcx_info.bpsl && i < pcx_info.zlen; ++i) {
229	    if ((pcx_info.zdata[i] & 0xc0) == 0xc0) {
230		c = pcx_info.zdata[i++] & 0x3f;
231		if (i >= pcx_info.zlen)
232		    return 1;
233	    } else {
234		c = 1;
235	    }
236	    if (j + c > pcx_info.bpsl)
237		return 1;
238	    while (c--)
239		line[j++] = pcx_info.zdata[i];
240	}
241
242	if (pos > banksize) {
243	    origin += banksize;
244	    pos -= banksize;
245	    set_origin(adp, origin);
246	}
247
248	if (pos + pcx_info.width > banksize) {
249	    /* scanline crosses bank boundary */
250	    j = banksize - pos;
251	    bcopy(line, vidmem + pos, j);
252	    origin += banksize;
253	    pos -= banksize;
254	    set_origin(adp, origin);
255	    bcopy(line + j, vidmem, pcx_info.width - j);
256	} else {
257	    bcopy(line, vidmem + pos, pcx_info.width);
258	}
259    }
260
261    return 0;
262}
263