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