145617Sdes/*- 245617Sdes * Copyright (c) 1999 Michael Smith <msmith@freebsd.org> 345617Sdes * Copyright (c) 1999 Kazutaka YOKOTA <yokota@freebsd.org> 4230132Suqs * Copyright (c) 1999 Dag-Erling Co��dan Sm��rgrav 545617Sdes * All rights reserved. 645617Sdes * 745617Sdes * Redistribution and use in source and binary forms, with or without 845617Sdes * modification, are permitted provided that the following conditions 945617Sdes * are met: 1045617Sdes * 1. Redistributions of source code must retain the above copyright 1145617Sdes * notice, this list of conditions and the following disclaimer 1245617Sdes * in this position and unchanged. 1345617Sdes * 2. Redistributions in binary form must reproduce the above copyright 1445617Sdes * notice, this list of conditions and the following disclaimer in the 1545617Sdes * documentation and/or other materials provided with the distribution. 1645617Sdes * 3. The name of the author may not be used to endorse or promote products 1745617Sdes * derived from this software without specific prior written permission 1845617Sdes * 1945617Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2045617Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2145617Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2245617Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2345617Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2445617Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2545617Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2645617Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2745617Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2845617Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2945617Sdes * 3050477Speter * $FreeBSD$ 3145617Sdes */ 3245617Sdes 3345617Sdes#include <sys/param.h> 3445617Sdes#include <sys/systm.h> 3545617Sdes#include <sys/kernel.h> 3645617Sdes#include <sys/linker.h> 37129880Sphk#include <sys/module.h> 3848104Syokota#include <sys/fbio.h> 3945617Sdes 4045617Sdes#include <dev/fb/fbreg.h> 4145617Sdes#include <dev/fb/splashreg.h> 4245617Sdes 4345617Sdesstatic int splash_mode = -1; 4445617Sdesstatic int splash_on = FALSE; 4545617Sdes 4645617Sdesstatic int pcx_start(video_adapter_t *adp); 4745617Sdesstatic int pcx_end(video_adapter_t *adp); 4845617Sdesstatic int pcx_splash(video_adapter_t *adp, int on); 49133227Sdesstatic int pcx_init(void *data, int sdepth); 5045617Sdesstatic int pcx_draw(video_adapter_t *adp); 5145617Sdes 5245617Sdesstatic splash_decoder_t pcx_decoder = { 53133227Sdes .name = "splash_pcx", 54133227Sdes .init = pcx_start, 55133227Sdes .term = pcx_end, 56133227Sdes .splash = pcx_splash, 57133227Sdes .data_type = SPLASH_IMAGE, 5845617Sdes}; 5945617Sdes 6045617SdesSPLASH_DECODER(splash_pcx, pcx_decoder); 6145617Sdes 62133227Sdesstatic struct { 63133227Sdes int width; 64133227Sdes int height; 65133227Sdes int bpsl; 66133227Sdes int bpp; 67133227Sdes int planes; 68133227Sdes int zlen; 69133227Sdes const uint8_t *zdata; 70133227Sdes uint8_t *palette; 7145617Sdes} pcx_info; 7245617Sdes 73133227Sdesstatic int 7445617Sdespcx_start(video_adapter_t *adp) 7545617Sdes{ 76133227Sdes static int modes[] = { 77133227Sdes M_VGA_CG320, 78133227Sdes M_VESA_CG640x480, 79133227Sdes M_VESA_CG800x600, 80133227Sdes M_VESA_CG1024x768, 81133227Sdes -1, 82133227Sdes }; 83133227Sdes video_info_t info; 84133227Sdes int i; 8545617Sdes 86133227Sdes if (pcx_decoder.data == NULL || 87133227Sdes pcx_decoder.data_size <= 0 || 88133227Sdes pcx_init(pcx_decoder.data, pcx_decoder.data_size)) 89133227Sdes return (ENODEV); 9045617Sdes 9145617Sdes if (bootverbose) 92133227Sdes printf("splash_pcx: image good:\n" 93133227Sdes " width = %d\n" 94133227Sdes " height = %d\n" 95133227Sdes " depth = %d\n" 96133227Sdes " planes = %d\n", 97133227Sdes pcx_info.width, pcx_info.height, 98133227Sdes pcx_info.bpp, pcx_info.planes); 99133227Sdes 100133227Sdes for (i = 0; modes[i] >= 0; ++i) { 101174985Swkoszek if (vidd_get_info(adp, modes[i], &info) != 0) 102133227Sdes continue; 103133227Sdes if (bootverbose) 104133227Sdes printf("splash_pcx: considering mode %d:\n" 105133227Sdes " vi_width = %d\n" 106133227Sdes " vi_height = %d\n" 107133227Sdes " vi_depth = %d\n" 108133227Sdes " vi_planes = %d\n", 109133227Sdes modes[i], 110133227Sdes info.vi_width, info.vi_height, 111133227Sdes info.vi_depth, info.vi_planes); 112133227Sdes if (info.vi_width >= pcx_info.width 113133227Sdes && info.vi_height >= pcx_info.height 114133227Sdes && info.vi_depth == pcx_info.bpp 115133227Sdes && info.vi_planes == pcx_info.planes) 116133227Sdes break; 117133227Sdes } 118133227Sdes 119133227Sdes splash_mode = modes[i]; 120133227Sdes if (splash_mode == -1) 121133227Sdes return (ENODEV); 122133227Sdes if (bootverbose) 123133227Sdes printf("splash_pcx: selecting mode %d\n", splash_mode); 124133227Sdes return (0); 12545617Sdes} 12645617Sdes 12745617Sdesstatic int 12845617Sdespcx_end(video_adapter_t *adp) 12945617Sdes{ 130133227Sdes /* nothing to do */ 131133227Sdes return (0); 13245617Sdes} 13345617Sdes 13445617Sdesstatic int 13545617Sdespcx_splash(video_adapter_t *adp, int on) 13645617Sdes{ 137133227Sdes if (on) { 138133227Sdes if (!splash_on) { 139174985Swkoszek if (vidd_set_mode(adp, splash_mode) || pcx_draw(adp)) 140133227Sdes return 1; 141133227Sdes splash_on = TRUE; 142133227Sdes } 143133227Sdes return (0); 144133227Sdes } else { 145133227Sdes splash_on = FALSE; 146133227Sdes return (0); 14745617Sdes } 14845617Sdes} 14945617Sdes 150133227Sdesstruct pcx_header { 151133227Sdes uint8_t manufactor; 152133227Sdes uint8_t version; 153133227Sdes uint8_t encoding; 154133227Sdes uint8_t bpp; 155133227Sdes uint16_t xmin; 156133227Sdes uint16_t ymin; 157133227Sdes uint16_t xmax; 158133227Sdes uint16_t ymax; 159133227Sdes uint16_t hres; 160133227Sdes uint16_t vres; 161133227Sdes uint8_t colormap[48]; 162133227Sdes uint8_t rsvd; 163133227Sdes uint8_t nplanes; 164133227Sdes uint16_t bpsl; 165133227Sdes uint16_t palinfo; 166133227Sdes uint16_t hsize; 167133227Sdes uint16_t vsize; 16845617Sdes}; 16945617Sdes 17045617Sdes#define MAXSCANLINE 1024 17145617Sdes 17245617Sdesstatic int 173133227Sdespcx_init(void *data, int size) 17445617Sdes{ 175133227Sdes const struct pcx_header *hdr = data; 17645617Sdes 177133227Sdes if (size < 128 + 1 + 1 + 768 || 178133227Sdes hdr->manufactor != 10 || 179133227Sdes hdr->version != 5 || 180133227Sdes hdr->encoding != 1 || 181133227Sdes hdr->nplanes != 1 || 182133227Sdes hdr->bpp != 8 || 183133227Sdes hdr->bpsl > MAXSCANLINE || 184133227Sdes ((uint8_t *)data)[size - 769] != 12) { 185133227Sdes printf("splash_pcx: invalid PCX image\n"); 186133227Sdes return (1); 187133227Sdes } 188133227Sdes pcx_info.width = hdr->xmax - hdr->xmin + 1; 189133227Sdes pcx_info.height = hdr->ymax - hdr->ymin + 1; 190133227Sdes pcx_info.bpsl = hdr->bpsl; 191133227Sdes pcx_info.bpp = hdr->bpp; 192133227Sdes pcx_info.planes = hdr->nplanes; 193133227Sdes pcx_info.zlen = size - (128 + 1 + 768); 194133227Sdes pcx_info.zdata = (uint8_t *)data + 128; 195133227Sdes pcx_info.palette = (uint8_t *)data + size - 768; 196133227Sdes return (0); 19745617Sdes} 19845617Sdes 19945617Sdesstatic int 20045617Sdespcx_draw(video_adapter_t *adp) 20145617Sdes{ 202133227Sdes uint8_t *vidmem; 203133227Sdes int swidth, sheight, sbpsl, sdepth, splanes; 204133227Sdes int banksize, origin; 205133227Sdes int c, i, j, pos, scan, x, y; 206133227Sdes uint8_t line[MAXSCANLINE]; 20745617Sdes 208133227Sdes if (pcx_info.zlen < 1) 209133227Sdes return (1); 210133227Sdes 211174985Swkoszek vidd_load_palette(adp, pcx_info.palette); 212133227Sdes 213133227Sdes vidmem = (uint8_t *)adp->va_window; 214133227Sdes swidth = adp->va_info.vi_width; 215133227Sdes sheight = adp->va_info.vi_height; 216133227Sdes sbpsl = adp->va_line_width; 217133227Sdes sdepth = adp->va_info.vi_depth; 218133227Sdes splanes = adp->va_info.vi_planes; 219133227Sdes banksize = adp->va_window_size; 220133227Sdes 221133227Sdes for (origin = 0; origin < sheight*sbpsl; origin += banksize) { 222174985Swkoszek vidd_set_win_org(adp, origin); 223133227Sdes bzero(vidmem, banksize); 22445617Sdes } 22545617Sdes 226133227Sdes x = (swidth - pcx_info.width) / 2; 227133227Sdes y = (sheight - pcx_info.height) / 2; 228133227Sdes origin = 0; 229133227Sdes pos = y * sbpsl + x; 230133227Sdes while (pos > banksize) { 231133227Sdes pos -= banksize; 232133227Sdes origin += banksize; 23345617Sdes } 234174985Swkoszek vidd_set_win_org(adp, origin); 23545617Sdes 236133227Sdes for (scan = i = 0; scan < pcx_info.height; ++scan, ++y, pos += sbpsl) { 237133227Sdes for (j = 0; j < pcx_info.bpsl && i < pcx_info.zlen; ++i) { 238133227Sdes if ((pcx_info.zdata[i] & 0xc0) == 0xc0) { 239133227Sdes c = pcx_info.zdata[i++] & 0x3f; 240133227Sdes if (i >= pcx_info.zlen) 241133227Sdes return (1); 242133227Sdes } else { 243133227Sdes c = 1; 244133227Sdes } 245133227Sdes if (j + c > pcx_info.bpsl) 246133227Sdes return (1); 247133227Sdes while (c--) 248133227Sdes line[j++] = pcx_info.zdata[i]; 249133227Sdes } 250133227Sdes 251133227Sdes if (pos > banksize) { 252133227Sdes origin += banksize; 253133227Sdes pos -= banksize; 254174985Swkoszek vidd_set_win_org(adp, origin); 255133227Sdes } 256133227Sdes 257133227Sdes if (pos + pcx_info.width > banksize) { 258133227Sdes /* scanline crosses bank boundary */ 259133227Sdes j = banksize - pos; 260133227Sdes bcopy(line, vidmem + pos, j); 261133227Sdes origin += banksize; 262133227Sdes pos -= banksize; 263174985Swkoszek vidd_set_win_org(adp, origin); 264133227Sdes bcopy(line + j, vidmem, pcx_info.width - j); 265133227Sdes } else { 266133227Sdes bcopy(line, vidmem + pos, pcx_info.width); 267133227Sdes } 26845617Sdes } 26945617Sdes 270133227Sdes return (0); 27145617Sdes} 272