xref: /dragonfly/sys/dev/video/fb/pcx/splash_pcx.c (revision ce7a3582)
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: src/sys/modules/splash/pcx/splash_pcx.c,v 1.4 1999/08/28 00:47:39 peter Exp $
31  * $DragonFly: src/sys/dev/video/fb/pcx/splash_pcx.c,v 1.5 2006/12/22 23:26:27 swildner Exp $
32  */
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/linker.h>
38 #include <sys/fbio.h>
39 #include <sys/thread.h>
40 
41 #include <dev/video/fb/fbreg.h>
42 #include <dev/video/fb/splashreg.h>
43 
44 #define FADE_TIMEOUT	300	/* sec */
45 
46 static int splash_mode = -1;
47 static int splash_on = FALSE;
48 
49 static int pcx_start(video_adapter_t *);
50 static int pcx_end(video_adapter_t *);
51 static int pcx_splash(video_adapter_t *, int);
52 static int pcx_init(const char *, int);
53 static int pcx_draw(video_adapter_t *);
54 
55 static splash_decoder_t pcx_decoder = {
56     "splash_pcx", pcx_start, pcx_end, pcx_splash, SPLASH_IMAGE,
57 };
58 
59 SPLASH_DECODER(splash_pcx, pcx_decoder);
60 
61 static struct
62 {
63     int		  width, height, bpsl;
64     int		  bpp, planes, zlen;
65     const u_char *zdata, *palette;
66 } pcx_info;
67 
68 static int
69 pcx_start(video_adapter_t *adp)
70 {
71     static int modes[] = {
72 	M_VGA_CG320,
73 	M_VESA_CG640x480,
74 	M_VESA_CG800x600,
75 	M_VESA_CG1024x768,
76 	-1,
77     };
78     video_info_t info;
79     int	i;
80 
81     if (pcx_decoder.data == NULL
82 	|| pcx_decoder.data_size <= 0
83 	|| pcx_init((u_char *)pcx_decoder.data, pcx_decoder.data_size))
84 	return ENODEV;
85 
86     if (bootverbose)
87 	kprintf("splash_pcx: image good:\n"
88 	       "  width = %d\n"
89 	       "  height = %d\n"
90 	       "  depth = %d\n"
91 	       "  planes = %d\n",
92 	       pcx_info.width, pcx_info.height,
93 	       pcx_info.bpp, pcx_info.planes);
94 
95     for (i = 0; modes[i] >= 0; ++i) {
96 	if (get_mode_info(adp, modes[i], &info) != 0)
97 	    continue;
98 	if (bootverbose)
99 	    kprintf("splash_pcx: considering mode %d:\n"
100 		   "  vi_width = %d\n"
101 		   "  vi_height = %d\n"
102 		   "  vi_depth = %d\n"
103 		   "  vi_planes = %d\n",
104 		   modes[i],
105 		   info.vi_width, info.vi_height,
106 		   info.vi_depth, info.vi_planes);
107 	if (info.vi_width >= pcx_info.width
108 	    && info.vi_height >= pcx_info.height
109 	    && info.vi_depth == pcx_info.bpp
110 	    && info.vi_planes == pcx_info.planes)
111 	    break;
112     }
113 
114     splash_mode = modes[i];
115     if (splash_mode == -1)
116 	return ENODEV;
117     if (bootverbose)
118 	kprintf("pcx_splash: selecting mode %d\n", splash_mode);
119     return 0;
120 }
121 
122 static int
123 pcx_end(video_adapter_t *adp)
124 {
125     /* nothing to do */
126     return 0;
127 }
128 
129 static int
130 pcx_splash(video_adapter_t *adp, int on)
131 {
132     if (on) {
133 	if (!splash_on) {
134 	    if (set_video_mode(adp, splash_mode) || pcx_draw(adp))
135 		return 1;
136 	    splash_on = TRUE;
137 	}
138 	return 0;
139     } else {
140 	splash_on = FALSE;
141 	return 0;
142     }
143 }
144 
145 struct pcxheader {
146     u_char manufactor;
147     u_char version;
148     u_char encoding;
149     u_char bpp;
150     u_short xmin, ymin, xmax, ymax;
151     u_short hres, vres;
152     u_char colormap[48];
153     u_char rsvd;
154     u_char nplanes;
155     u_short bpsl;
156     u_short palinfo;
157     u_short hsize, vsize;
158 };
159 
160 #define MAXSCANLINE 1024
161 
162 static int
163 pcx_init(const char *data, int size)
164 {
165     const struct pcxheader *hdr;
166 
167     hdr = (const struct pcxheader *)data;
168 
169     if (size < 128 + 1 + 1 + 768
170 	|| hdr->manufactor != 10
171 	|| hdr->version != 5
172 	|| hdr->encoding != 1
173 	|| hdr->nplanes != 1
174 	|| hdr->bpp != 8
175 	|| hdr->bpsl > MAXSCANLINE
176 	|| data[size-769] != 12) {
177 	kprintf("splash_pcx: invalid PCX image\n");
178 	return 1;
179     }
180     pcx_info.width =  hdr->xmax - hdr->xmin + 1;
181     pcx_info.height =  hdr->ymax - hdr->ymin + 1;
182     pcx_info.bpsl = hdr->bpsl;
183     pcx_info.bpp = hdr->bpp;
184     pcx_info.planes = hdr->nplanes;
185     pcx_info.zlen = size - (128 + 1 + 768);
186     pcx_info.zdata = data + 128;
187     pcx_info.palette = data + size - 768;
188     return 0;
189 }
190 
191 static int
192 pcx_draw(video_adapter_t *adp)
193 {
194     u_char *vidmem;
195     int swidth, sheight, sbpsl, sdepth, splanes;
196     int banksize, origin;
197     int c, i, j, pos, scan, x, y;
198     u_char line[MAXSCANLINE];
199 
200     if (pcx_info.zlen < 1)
201 	return 1;
202 
203     load_palette(adp, pcx_info.palette);
204 
205     vidmem = (u_char *)adp->va_window;
206     swidth = adp->va_info.vi_width;
207     sheight = adp->va_info.vi_height;
208     sbpsl = adp->va_line_width;
209     sdepth = adp->va_info.vi_depth;
210     splanes = adp->va_info.vi_planes;
211     banksize = adp->va_window_size;
212 
213     for (origin = 0; origin < sheight*sbpsl; origin += banksize) {
214 	set_origin(adp, origin);
215 	bzero(vidmem, banksize);
216     }
217 
218     x = (swidth - pcx_info.width) / 2;
219     y = (sheight - pcx_info.height) / 2;
220     origin = 0;
221     pos = y * sbpsl + x;
222     while (pos > banksize) {
223 	pos -= banksize;
224 	origin += banksize;
225     }
226     set_origin(adp, origin);
227 
228     for (scan = i = 0; scan < pcx_info.height; ++scan, ++y, pos += sbpsl) {
229 	for (j = 0; j < pcx_info.bpsl && i < pcx_info.zlen; ++i) {
230 	    if ((pcx_info.zdata[i] & 0xc0) == 0xc0) {
231 		c = pcx_info.zdata[i++] & 0x3f;
232 		if (i >= pcx_info.zlen)
233 		    return 1;
234 	    } else {
235 		c = 1;
236 	    }
237 	    if (j + c > pcx_info.bpsl)
238 		return 1;
239 	    while (c--)
240 		line[j++] = pcx_info.zdata[i];
241 	}
242 
243 	if (pos > banksize) {
244 	    origin += banksize;
245 	    pos -= banksize;
246 	    set_origin(adp, origin);
247 	}
248 
249 	if (pos + pcx_info.width > banksize) {
250 	    /* scanline crosses bank boundary */
251 	    j = banksize - pos;
252 	    bcopy(line, vidmem + pos, j);
253 	    origin += banksize;
254 	    pos -= banksize;
255 	    set_origin(adp, origin);
256 	    bcopy(line + j, vidmem, pcx_info.width - j);
257 	} else {
258 	    bcopy(line, vidmem + pos, pcx_info.width);
259 	}
260     }
261 
262     return 0;
263 }
264