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