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