1185029Spjd/*- 2185029Spjd * Copyright (c) 1999 Michael Smith <msmith@freebsd.org> 3185029Spjd * Copyright (c) 1999 Kazutaka YOKOTA <yokota@freebsd.org> 4185029Spjd * Copyright (c) 1999 Dag-Erling Co��dan Sm��rgrav 5185029Spjd * All rights reserved. 6185029Spjd * 7185029Spjd * Redistribution and use in source and binary forms, with or without 8185029Spjd * modification, are permitted provided that the following conditions 9185029Spjd * are met: 10185029Spjd * 1. Redistributions of source code must retain the above copyright 11185029Spjd * notice, this list of conditions and the following disclaimer 12185029Spjd * in this position and unchanged. 13185029Spjd * 2. Redistributions in binary form must reproduce the above copyright 14185029Spjd * notice, this list of conditions and the following disclaimer in the 15185029Spjd * documentation and/or other materials provided with the distribution. 16185029Spjd * 3. The name of the author may not be used to endorse or promote products 17185029Spjd * derived from this software without specific prior written permission 18185029Spjd * 19185029Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20185029Spjd * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21185029Spjd * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22185096Sdfr * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23185096Sdfr * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24185096Sdfr * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25185029Spjd * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26185029Spjd * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27185029Spjd * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28185029Spjd * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29185029Spjd * 30200309Sjhb * $FreeBSD$ 31185029Spjd */ 32185029Spjd 33185029Spjd#include <sys/param.h> 34185029Spjd#include <sys/systm.h> 35185029Spjd#include <sys/kernel.h> 36185029Spjd#include <sys/linker.h> 37185029Spjd#include <sys/module.h> 38185029Spjd#include <sys/fbio.h> 39185029Spjd 40213136Spjd#include <dev/fb/fbreg.h> 41213136Spjd#include <dev/fb/splashreg.h> 42213136Spjd 43213136Spjdstatic int splash_mode = -1; 44237756Savgstatic int splash_on = FALSE; 45185029Spjd 46237766Savgstatic int pcx_start(video_adapter_t *adp); 47237766Savgstatic int pcx_end(video_adapter_t *adp); 48231287Sbaptstatic int pcx_splash(video_adapter_t *adp, int on); 49231287Sbaptstatic int pcx_init(void *data, int sdepth); 50199714Srnolandstatic int pcx_draw(video_adapter_t *adp); 51185029Spjd 52185029Spjdstatic splash_decoder_t pcx_decoder = { 53185029Spjd .name = "splash_pcx", 54185029Spjd .init = pcx_start, 55185029Spjd .term = pcx_end, 56185029Spjd .splash = pcx_splash, 57212805Spjd .data_type = SPLASH_IMAGE, 58185029Spjd}; 59185029Spjd 60185029SpjdSPLASH_DECODER(splash_pcx, pcx_decoder); 61185029Spjd 62185029Spjdstatic struct { 63185029Spjd int width; 64185029Spjd int height; 65185029Spjd int bpsl; 66185029Spjd int bpp; 67185029Spjd int planes; 68185096Sdfr int zlen; 69185096Sdfr const uint8_t *zdata; 70185096Sdfr uint8_t *palette; 71185029Spjd} pcx_info; 72185029Spjd 73185029Spjdstatic int 74185029Spjdpcx_start(video_adapter_t *adp) 75185029Spjd{ 76185029Spjd static int modes[] = { 77185029Spjd M_VGA_CG320, 78185029Spjd M_VESA_CG640x480, 79185029Spjd M_VESA_CG800x600, 80185029Spjd M_VESA_CG1024x768, 81185029Spjd -1, 82185029Spjd }; 83185029Spjd video_info_t info; 84185029Spjd int i; 85185029Spjd 86185029Spjd if (pcx_decoder.data == NULL || 87185029Spjd pcx_decoder.data_size <= 0 || 88213136Spjd pcx_init(pcx_decoder.data, pcx_decoder.data_size)) 89185029Spjd return (ENODEV); 90185029Spjd 91185029Spjd if (bootverbose) 92185029Spjd printf("splash_pcx: image good:\n" 93185029Spjd " width = %d\n" 94234679Savg " height = %d\n" 95185029Spjd " depth = %d\n" 96237766Savg " planes = %d\n", 97185029Spjd pcx_info.width, pcx_info.height, 98185029Spjd pcx_info.bpp, pcx_info.planes); 99185029Spjd 100237766Savg for (i = 0; modes[i] >= 0; ++i) { 101237766Savg if (vidd_get_info(adp, modes[i], &info) != 0) 102185029Spjd continue; 103200309Sjhb if (bootverbose) 104200309Sjhb printf("splash_pcx: considering mode %d:\n" 105200309Sjhb " vi_width = %d\n" 106200309Sjhb " vi_height = %d\n" 107200309Sjhb " vi_depth = %d\n" 108200309Sjhb " vi_planes = %d\n", 109200309Sjhb modes[i], 110200309Sjhb info.vi_width, info.vi_height, 111200309Sjhb info.vi_depth, info.vi_planes); 112200309Sjhb if (info.vi_width >= pcx_info.width 113200309Sjhb && info.vi_height >= pcx_info.height 114200309Sjhb && info.vi_depth == pcx_info.bpp 115200309Sjhb && info.vi_planes == pcx_info.planes) 116185029Spjd break; 117185029Spjd } 118185029Spjd 119185029Spjd splash_mode = modes[i]; 120185029Spjd if (splash_mode == -1) 121185029Spjd return (ENODEV); 122185029Spjd if (bootverbose) 123185029Spjd printf("splash_pcx: selecting mode %d\n", splash_mode); 124185029Spjd return (0); 125185029Spjd} 126185029Spjd 127200309Sjhbstatic int 128185029Spjdpcx_end(video_adapter_t *adp) 129185029Spjd{ 130185029Spjd /* nothing to do */ 131185029Spjd return (0); 132185029Spjd} 133185029Spjd 134185029Spjdstatic int 135185029Spjdpcx_splash(video_adapter_t *adp, int on) 136185029Spjd{ 137185029Spjd if (on) { 138185029Spjd if (!splash_on) { 139185029Spjd if (vidd_set_mode(adp, splash_mode) || pcx_draw(adp)) 140185029Spjd return 1; 141185029Spjd splash_on = TRUE; 142185029Spjd } 143185029Spjd return (0); 144185029Spjd } else { 145185029Spjd splash_on = FALSE; 146185029Spjd return (0); 147185029Spjd } 148185029Spjd} 149185029Spjd 150185029Spjdstruct pcx_header { 151185029Spjd uint8_t manufactor; 152185029Spjd uint8_t version; 153185029Spjd uint8_t encoding; 154185029Spjd uint8_t bpp; 155185029Spjd uint16_t xmin; 156185029Spjd uint16_t ymin; 157185029Spjd uint16_t xmax; 158185029Spjd uint16_t ymax; 159185029Spjd uint16_t hres; 160185029Spjd uint16_t vres; 161185029Spjd uint8_t colormap[48]; 162185029Spjd uint8_t rsvd; 163185029Spjd uint8_t nplanes; 164185029Spjd uint16_t bpsl; 165185029Spjd uint16_t palinfo; 166185029Spjd uint16_t hsize; 167185029Spjd uint16_t vsize; 168185029Spjd}; 169185029Spjd 170185029Spjd#define MAXSCANLINE 1024 171185029Spjd 172185029Spjdstatic int 173185029Spjdpcx_init(void *data, int size) 174185029Spjd{ 175185029Spjd const struct pcx_header *hdr = data; 176185029Spjd 177185029Spjd if (size < 128 + 1 + 1 + 768 || 178237766Savg hdr->manufactor != 10 || 179242241Savg hdr->version != 5 || 180242241Savg hdr->encoding != 1 || 181185029Spjd hdr->nplanes != 1 || 182185029Spjd hdr->bpp != 8 || 183185029Spjd hdr->bpsl > MAXSCANLINE || 184185029Spjd ((uint8_t *)data)[size - 769] != 12) { 185185029Spjd printf("splash_pcx: invalid PCX image\n"); 186185029Spjd return (1); 187185029Spjd } 188185029Spjd pcx_info.width = hdr->xmax - hdr->xmin + 1; 189185029Spjd pcx_info.height = hdr->ymax - hdr->ymin + 1; 190199579Sjhb pcx_info.bpsl = hdr->bpsl; 191199579Sjhb pcx_info.bpp = hdr->bpp; 192185029Spjd pcx_info.planes = hdr->nplanes; 193185029Spjd pcx_info.zlen = size - (128 + 1 + 768); 194185029Spjd pcx_info.zdata = (uint8_t *)data + 128; 195185029Spjd pcx_info.palette = (uint8_t *)data + size - 768; 196185029Spjd return (0); 197185029Spjd} 198185029Spjd 199213136Spjdstatic int 200185029Spjdpcx_draw(video_adapter_t *adp) 201185029Spjd{ 202185029Spjd uint8_t *vidmem; 203185029Spjd int swidth, sheight, sbpsl, sdepth, splanes; 204185029Spjd int banksize, origin; 205185029Spjd int c, i, j, pos, scan, x, y; 206185029Spjd uint8_t line[MAXSCANLINE]; 207185029Spjd 208185029Spjd if (pcx_info.zlen < 1) 209185029Spjd return (1); 210185029Spjd 211185029Spjd vidd_load_palette(adp, pcx_info.palette); 212185029Spjd 213185029Spjd vidmem = (uint8_t *)adp->va_window; 214185029Spjd swidth = adp->va_info.vi_width; 215185029Spjd sheight = adp->va_info.vi_height; 216185029Spjd sbpsl = adp->va_line_width; 217185029Spjd sdepth = adp->va_info.vi_depth; 218185029Spjd splanes = adp->va_info.vi_planes; 219237766Savg banksize = adp->va_window_size; 220185029Spjd 221185029Spjd for (origin = 0; origin < sheight*sbpsl; origin += banksize) { 222185029Spjd vidd_set_win_org(adp, origin); 223185029Spjd bzero(vidmem, banksize); 224185029Spjd } 225200309Sjhb 226200309Sjhb x = (swidth - pcx_info.width) / 2; 227185029Spjd y = (sheight - pcx_info.height) / 2; 228200309Sjhb origin = 0; 229185029Spjd pos = y * sbpsl + x; 230200309Sjhb while (pos > banksize) { 231200309Sjhb pos -= banksize; 232200309Sjhb origin += banksize; 233200309Sjhb } 234200309Sjhb vidd_set_win_org(adp, origin); 235200309Sjhb 236200309Sjhb for (scan = i = 0; scan < pcx_info.height; ++scan, ++y, pos += sbpsl) { 237200309Sjhb for (j = 0; j < pcx_info.bpsl && i < pcx_info.zlen; ++i) { 238200309Sjhb if ((pcx_info.zdata[i] & 0xc0) == 0xc0) { 239200309Sjhb c = pcx_info.zdata[i++] & 0x3f; 240200309Sjhb if (i >= pcx_info.zlen) 241200309Sjhb return (1); 242200309Sjhb } else { 243200309Sjhb c = 1; 244200309Sjhb } 245200309Sjhb if (j + c > pcx_info.bpsl) 246200309Sjhb return (1); 247200309Sjhb while (c--) 248200309Sjhb line[j++] = pcx_info.zdata[i]; 249200309Sjhb } 250200309Sjhb 251200309Sjhb if (pos > banksize) { 252200309Sjhb origin += banksize; 253200309Sjhb pos -= banksize; 254200309Sjhb vidd_set_win_org(adp, origin); 255200309Sjhb } 256200309Sjhb 257200309Sjhb if (pos + pcx_info.width > banksize) { 258200309Sjhb /* scanline crosses bank boundary */ 259200309Sjhb j = banksize - pos; 260200309Sjhb bcopy(line, vidmem + pos, j); 261200309Sjhb origin += banksize; 262200309Sjhb pos -= banksize; 263200309Sjhb vidd_set_win_org(adp, origin); 264200309Sjhb bcopy(line + j, vidmem, pcx_info.width - j); 265200309Sjhb } else { 266200309Sjhb bcopy(line, vidmem + pos, pcx_info.width); 267200309Sjhb } 268200309Sjhb } 269200309Sjhb 270200309Sjhb return (0); 271200309Sjhb} 272200309Sjhb