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