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