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