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/fbio.h> 38 39 #include <dev/fb/fbreg.h> 40 #include <dev/fb/splashreg.h> 41 42 #define FADE_TIMEOUT 300 /* sec */ 43 44 static int splash_mode = -1; 45 static int splash_on = FALSE; 46 47 static int pcx_start(video_adapter_t *adp); 48 static int pcx_end(video_adapter_t *adp); 49 static int pcx_splash(video_adapter_t *adp, int on); 50 static int pcx_init(const char *data, int sdepth); 51 static int pcx_draw(video_adapter_t *adp); 52 53 static splash_decoder_t pcx_decoder = { 54 "splash_pcx", pcx_start, pcx_end, pcx_splash, SPLASH_IMAGE, 55 }; 56 57 SPLASH_DECODER(splash_pcx, pcx_decoder); 58 59 static struct 60 { 61 int width, height, bpsl; 62 int bpp, planes, zlen; 63 const u_char *zdata, *palette; 64 } pcx_info; 65 66 static int 67 pcx_start(video_adapter_t *adp) 68 { 69 static int modes[] = { 70 M_VGA_CG320, 71 M_VESA_CG640x480, 72 M_VESA_CG800x600, 73 M_VESA_CG1024x768, 74 -1, 75 }; 76 video_info_t info; 77 int i; 78 79 if (pcx_decoder.data == NULL 80 || pcx_decoder.data_size <= 0 81 || pcx_init((u_char *)pcx_decoder.data, pcx_decoder.data_size)) 82 return ENODEV; 83 84 if (bootverbose) 85 printf("splash_pcx: image good:\n" 86 " width = %d\n" 87 " height = %d\n" 88 " depth = %d\n" 89 " planes = %d\n", 90 pcx_info.width, pcx_info.height, 91 pcx_info.bpp, pcx_info.planes); 92 93 for (i = 0; modes[i] >= 0; ++i) { 94 if (get_mode_info(adp, modes[i], &info) != 0) 95 continue; 96 if (bootverbose) 97 printf("splash_pcx: considering mode %d:\n" 98 " vi_width = %d\n" 99 " vi_height = %d\n" 100 " vi_depth = %d\n" 101 " vi_planes = %d\n", 102 modes[i], 103 info.vi_width, info.vi_height, 104 info.vi_depth, info.vi_planes); 105 if (info.vi_width >= pcx_info.width 106 && info.vi_height >= pcx_info.height 107 && info.vi_depth == pcx_info.bpp 108 && info.vi_planes == pcx_info.planes) 109 break; 110 } 111 112 splash_mode = modes[i]; 113 if (splash_mode == -1) 114 return ENODEV; 115 if (bootverbose) 116 printf("pcx_splash: selecting mode %d\n", splash_mode); 117 return 0; 118 } 119 120 static int 121 pcx_end(video_adapter_t *adp) 122 { 123 /* nothing to do */ 124 return 0; 125 } 126 127 static int 128 pcx_splash(video_adapter_t *adp, int on) 129 { 130 if (on) { 131 if (!splash_on) { 132 if (set_video_mode(adp, splash_mode) || pcx_draw(adp)) 133 return 1; 134 splash_on = TRUE; 135 } 136 return 0; 137 } else { 138 splash_on = FALSE; 139 return 0; 140 } 141 } 142 143 struct pcxheader { 144 u_char manufactor; 145 u_char version; 146 u_char encoding; 147 u_char bpp; 148 u_short xmin, ymin, xmax, ymax; 149 u_short hres, vres; 150 u_char colormap[48]; 151 u_char rsvd; 152 u_char nplanes; 153 u_short bpsl; 154 u_short palinfo; 155 u_short hsize, vsize; 156 }; 157 158 #define MAXSCANLINE 1024 159 160 static int 161 pcx_init(const char *data, int size) 162 { 163 const struct pcxheader *hdr; 164 165 hdr = (const struct pcxheader *)data; 166 167 if (size < 128 + 1 + 1 + 768 168 || hdr->manufactor != 10 169 || hdr->version != 5 170 || hdr->encoding != 1 171 || hdr->nplanes != 1 172 || hdr->bpp != 8 173 || hdr->bpsl > MAXSCANLINE 174 || data[size-769] != 12) { 175 printf("splash_pcx: invalid PCX image\n"); 176 return 1; 177 } 178 pcx_info.width = hdr->xmax - hdr->xmin + 1; 179 pcx_info.height = hdr->ymax - hdr->ymin + 1; 180 pcx_info.bpsl = hdr->bpsl; 181 pcx_info.bpp = hdr->bpp; 182 pcx_info.planes = hdr->nplanes; 183 pcx_info.zlen = size - (128 + 1 + 768); 184 pcx_info.zdata = data + 128; 185 pcx_info.palette = data + size - 768; 186 return 0; 187 } 188 189 static int 190 pcx_draw(video_adapter_t *adp) 191 { 192 u_char *vidmem; 193 int swidth, sheight, sbpsl, sdepth, splanes; 194 int banksize, origin; 195 int c, i, j, pos, scan, x, y; 196 u_char line[MAXSCANLINE]; 197 198 if (pcx_info.zlen < 1) 199 return 1; 200 201 load_palette(adp, pcx_info.palette); 202 203 vidmem = (u_char *)adp->va_window; 204 swidth = adp->va_info.vi_width; 205 sheight = adp->va_info.vi_height; 206 sbpsl = adp->va_line_width; 207 sdepth = adp->va_info.vi_depth; 208 splanes = adp->va_info.vi_planes; 209 banksize = adp->va_window_size; 210 211 for (origin = 0; origin < sheight*sbpsl; origin += banksize) { 212 set_origin(adp, origin); 213 bzero(vidmem, banksize); 214 } 215 216 x = (swidth - pcx_info.width) / 2; 217 y = (sheight - pcx_info.height) / 2; 218 origin = 0; 219 pos = y * sbpsl + x; 220 while (pos > banksize) { 221 pos -= banksize; 222 origin += banksize; 223 } 224 set_origin(adp, origin); 225 226 for (scan = i = 0; scan < pcx_info.height; ++scan, ++y, pos += sbpsl) { 227 for (j = 0; j < pcx_info.bpsl && i < pcx_info.zlen; ++i) { 228 if ((pcx_info.zdata[i] & 0xc0) == 0xc0) { 229 c = pcx_info.zdata[i++] & 0x3f; 230 if (i >= pcx_info.zlen) 231 return 1; 232 } else { 233 c = 1; 234 } 235 if (j + c > pcx_info.bpsl) 236 return 1; 237 while (c--) 238 line[j++] = pcx_info.zdata[i]; 239 } 240 241 if (pos > banksize) { 242 origin += banksize; 243 pos -= banksize; 244 set_origin(adp, origin); 245 } 246 247 if (pos + pcx_info.width > banksize) { 248 /* scanline crosses bank boundary */ 249 j = banksize - pos; 250 bcopy(line, vidmem + pos, j); 251 origin += banksize; 252 pos -= banksize; 253 set_origin(adp, origin); 254 bcopy(line + j, vidmem, pcx_info.width - j); 255 } else { 256 bcopy(line, vidmem + pos, pcx_info.width); 257 } 258 } 259 260 return 0; 261 } 262