]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/dev/fb/splash_pcx.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / dev / fb / 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$
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 }