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