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 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 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; 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 banksize = adp->va_window_size; 218 219 for (origin = 0; origin < sheight*sbpsl; origin += banksize) { 220 vidd_set_win_org(adp, origin); 221 bzero(vidmem, banksize); 222 } 223 224 x = (swidth - pcx_info.width) / 2; 225 y = (sheight - pcx_info.height) / 2; 226 origin = 0; 227 pos = y * sbpsl + x; 228 while (pos > banksize) { 229 pos -= banksize; 230 origin += banksize; 231 } 232 vidd_set_win_org(adp, origin); 233 234 for (scan = i = 0; scan < pcx_info.height; ++scan, ++y, pos += sbpsl) { 235 for (j = 0; j < pcx_info.bpsl && i < pcx_info.zlen; ++i) { 236 if ((pcx_info.zdata[i] & 0xc0) == 0xc0) { 237 c = pcx_info.zdata[i++] & 0x3f; 238 if (i >= pcx_info.zlen) 239 return (1); 240 } else { 241 c = 1; 242 } 243 if (j + c > pcx_info.bpsl) 244 return (1); 245 while (c--) 246 line[j++] = pcx_info.zdata[i]; 247 } 248 249 if (pos > banksize) { 250 origin += banksize; 251 pos -= banksize; 252 vidd_set_win_org(adp, origin); 253 } 254 255 if (pos + pcx_info.width > banksize) { 256 /* scanline crosses bank boundary */ 257 j = banksize - pos; 258 bcopy(line, vidmem + pos, j); 259 origin += banksize; 260 pos -= banksize; 261 vidd_set_win_org(adp, origin); 262 bcopy(line + j, vidmem, pcx_info.width - j); 263 } else { 264 bcopy(line, vidmem + pos, pcx_info.width); 265 } 266 } 267 268 return (0); 269 } 270