]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/fb/splash_pcx.c
sys/{x86,amd64}: remove one of doubled ;s
[FreeBSD/FreeBSD.git] / sys / dev / fb / splash_pcx.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1999 Michael Smith <msmith@freebsd.org>
5  * Copyright (c) 1999 Kazutaka YOKOTA <yokota@freebsd.org>
6  * Copyright (c) 1999 Dag-Erling Coïdan Smørgrav
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer
14  *    in this position and unchanged.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  * $FreeBSD$
33  */
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/linker.h>
39 #include <sys/module.h>
40 #include <sys/fbio.h>
41
42 #include <dev/fb/fbreg.h>
43 #include <dev/fb/splashreg.h>
44
45 static int splash_mode = -1;
46 static int splash_on = FALSE;
47
48 static int pcx_start(video_adapter_t *adp);
49 static int pcx_end(video_adapter_t *adp);
50 static int pcx_splash(video_adapter_t *adp, int on);
51 static int pcx_init(void *data, int sdepth);
52 static int pcx_draw(video_adapter_t *adp);
53
54 static splash_decoder_t pcx_decoder = {
55         .name = "splash_pcx",
56         .init = pcx_start,
57         .term = pcx_end,
58         .splash = pcx_splash,
59         .data_type = SPLASH_IMAGE,
60 };
61
62 SPLASH_DECODER(splash_pcx, pcx_decoder);
63
64 static struct {
65         int              width;
66         int              height;
67         int              bpsl;
68         int              bpp;
69         int              planes;
70         int              zlen;
71         const uint8_t   *zdata;
72         uint8_t         *palette;
73 } pcx_info;
74
75 static int
76 pcx_start(video_adapter_t *adp)
77 {
78         static int modes[] = {
79                 M_VGA_CG320,
80                 M_VESA_CG640x480,
81                 M_VESA_CG800x600,
82                 M_VESA_CG1024x768,
83                 -1,
84         };
85         video_info_t info;
86         int i;
87
88         if (pcx_decoder.data == NULL ||
89             pcx_decoder.data_size <= 0 ||
90             pcx_init(pcx_decoder.data, pcx_decoder.data_size))
91                 return (ENODEV);
92
93         if (bootverbose)
94                 printf("splash_pcx: image good:\n"
95                     "  width = %d\n"
96                     "  height = %d\n"
97                     "  depth = %d\n"
98                     "  planes = %d\n",
99                     pcx_info.width, pcx_info.height,
100                     pcx_info.bpp, pcx_info.planes);
101
102         for (i = 0; modes[i] >= 0; ++i) {
103                 if (vidd_get_info(adp, modes[i], &info) != 0)
104                         continue;
105                 if (bootverbose)
106                         printf("splash_pcx: considering mode %d:\n"
107                             "  vi_width = %d\n"
108                             "  vi_height = %d\n"
109                             "  vi_depth = %d\n"
110                             "  vi_planes = %d\n",
111                             modes[i],
112                             info.vi_width, info.vi_height,
113                             info.vi_depth, info.vi_planes);
114                 if (info.vi_width >= pcx_info.width
115                     && info.vi_height >= pcx_info.height
116                     && info.vi_depth == pcx_info.bpp
117                     && info.vi_planes == pcx_info.planes)
118                         break;
119         }
120
121         splash_mode = modes[i];
122         if (splash_mode == -1)
123                 return (ENODEV);
124         if (bootverbose)
125                 printf("splash_pcx: selecting mode %d\n", splash_mode);
126         return (0);
127 }
128
129 static int
130 pcx_end(video_adapter_t *adp)
131 {
132         /* nothing to do */
133         return (0);
134 }
135
136 static int
137 pcx_splash(video_adapter_t *adp, int on)
138 {
139         if (on) {
140                 if (!splash_on) {
141                         if (vidd_set_mode(adp, splash_mode) || pcx_draw(adp))
142                                 return 1;
143                         splash_on = TRUE;
144                 }
145                 return (0);
146         } else {
147                 splash_on = FALSE;
148                 return (0);
149         }
150 }
151
152 struct pcx_header {
153         uint8_t          manufactor;
154         uint8_t          version;
155         uint8_t          encoding;
156         uint8_t          bpp;
157         uint16_t         xmin;
158         uint16_t         ymin;
159         uint16_t         xmax;
160         uint16_t         ymax;
161         uint16_t         hres;
162         uint16_t         vres;
163         uint8_t          colormap[48];
164         uint8_t          rsvd;
165         uint8_t          nplanes;
166         uint16_t         bpsl;
167         uint16_t         palinfo;
168         uint16_t         hsize;
169         uint16_t         vsize;
170 };
171
172 #define MAXSCANLINE 1024
173
174 static int
175 pcx_init(void *data, int size)
176 {
177         const struct pcx_header *hdr = data;
178
179         if (size < 128 + 1 + 1 + 768 ||
180             hdr->manufactor != 10 ||
181             hdr->version != 5 ||
182             hdr->encoding != 1 ||
183             hdr->nplanes != 1 ||
184             hdr->bpp != 8 ||
185             hdr->bpsl > MAXSCANLINE ||
186             ((uint8_t *)data)[size - 769] != 12) {
187                 printf("splash_pcx: invalid PCX image\n");
188                 return (1);
189         }
190         pcx_info.width = hdr->xmax - hdr->xmin + 1;
191         pcx_info.height = hdr->ymax - hdr->ymin + 1;
192         pcx_info.bpsl = hdr->bpsl;
193         pcx_info.bpp = hdr->bpp;
194         pcx_info.planes = hdr->nplanes;
195         pcx_info.zlen = size - (128 + 1 + 768);
196         pcx_info.zdata = (uint8_t *)data + 128;
197         pcx_info.palette = (uint8_t *)data + size - 768;
198         return (0);
199 }
200
201 static int
202 pcx_draw(video_adapter_t *adp)
203 {
204         uint8_t *vidmem;
205         int swidth, sheight, sbpsl, sdepth, splanes;
206         int banksize, origin;
207         int c, i, j, pos, scan, x, y;
208         uint8_t line[MAXSCANLINE];
209
210         if (pcx_info.zlen < 1)
211                 return (1);
212
213         vidd_load_palette(adp, pcx_info.palette);
214
215         vidmem = (uint8_t *)adp->va_window;
216         swidth = adp->va_info.vi_width;
217         sheight = adp->va_info.vi_height;
218         sbpsl = adp->va_line_width;
219         sdepth = adp->va_info.vi_depth;
220         splanes = adp->va_info.vi_planes;
221         banksize = adp->va_window_size;
222
223         for (origin = 0; origin < sheight*sbpsl; origin += banksize) {
224                 vidd_set_win_org(adp, origin);
225                 bzero(vidmem, banksize);
226         }
227
228         x = (swidth - pcx_info.width) / 2;
229         y = (sheight - pcx_info.height) / 2;
230         origin = 0;
231         pos = y * sbpsl + x;
232         while (pos > banksize) {
233                 pos -= banksize;
234                 origin += banksize;
235         }
236         vidd_set_win_org(adp, origin);
237
238         for (scan = i = 0; scan < pcx_info.height; ++scan, ++y, pos += sbpsl) {
239                 for (j = 0; j < pcx_info.bpsl && i < pcx_info.zlen; ++i) {
240                         if ((pcx_info.zdata[i] & 0xc0) == 0xc0) {
241                                 c = pcx_info.zdata[i++] & 0x3f;
242                                 if (i >= pcx_info.zlen)
243                                         return (1);
244                         } else {
245                                 c = 1;
246                         }
247                         if (j + c > pcx_info.bpsl)
248                                 return (1);
249                         while (c--)
250                                 line[j++] = pcx_info.zdata[i];
251                 }
252
253                 if (pos > banksize) {
254                         origin += banksize;
255                         pos -= banksize;
256                         vidd_set_win_org(adp, origin);
257                 }
258
259                 if (pos + pcx_info.width > banksize) {
260                         /* scanline crosses bank boundary */
261                         j = banksize - pos;
262                         bcopy(line, vidmem + pos, j);
263                         origin += banksize;
264                         pos -= banksize;
265                         vidd_set_win_org(adp, origin);
266                         bcopy(line + j, vidmem, pcx_info.width - j);
267                 } else {
268                         bcopy(line, vidmem + pos, pcx_info.width);
269                 }
270         }
271
272         return (0);
273 }