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 } 274