17a19b7edSDag-Erling Smørgrav /*- 2718cf2ccSPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 3718cf2ccSPedro F. Giffuni * 47a19b7edSDag-Erling Smørgrav * Copyright (c) 1999 Michael Smith <msmith@freebsd.org> 57a19b7edSDag-Erling Smørgrav * Copyright (c) 1999 Kazutaka YOKOTA <yokota@freebsd.org> 69a14aa01SUlrich Spörlein * Copyright (c) 1999 Dag-Erling Coïdan Smørgrav 77a19b7edSDag-Erling Smørgrav * All rights reserved. 87a19b7edSDag-Erling Smørgrav * 97a19b7edSDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 107a19b7edSDag-Erling Smørgrav * modification, are permitted provided that the following conditions 117a19b7edSDag-Erling Smørgrav * are met: 127a19b7edSDag-Erling Smørgrav * 1. Redistributions of source code must retain the above copyright 137a19b7edSDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer 147a19b7edSDag-Erling Smørgrav * in this position and unchanged. 157a19b7edSDag-Erling Smørgrav * 2. Redistributions in binary form must reproduce the above copyright 167a19b7edSDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer in the 177a19b7edSDag-Erling Smørgrav * documentation and/or other materials provided with the distribution. 187a19b7edSDag-Erling Smørgrav * 3. The name of the author may not be used to endorse or promote products 197a19b7edSDag-Erling Smørgrav * derived from this software without specific prior written permission 207a19b7edSDag-Erling Smørgrav * 217a19b7edSDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 227a19b7edSDag-Erling Smørgrav * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 237a19b7edSDag-Erling Smørgrav * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 247a19b7edSDag-Erling Smørgrav * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 257a19b7edSDag-Erling Smørgrav * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 267a19b7edSDag-Erling Smørgrav * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 277a19b7edSDag-Erling Smørgrav * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 287a19b7edSDag-Erling Smørgrav * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 297a19b7edSDag-Erling Smørgrav * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 307a19b7edSDag-Erling Smørgrav * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 317a19b7edSDag-Erling Smørgrav * 32c3aac50fSPeter Wemm * $FreeBSD$ 337a19b7edSDag-Erling Smørgrav */ 347a19b7edSDag-Erling Smørgrav 357a19b7edSDag-Erling Smørgrav #include <sys/param.h> 367a19b7edSDag-Erling Smørgrav #include <sys/systm.h> 377a19b7edSDag-Erling Smørgrav #include <sys/kernel.h> 387a19b7edSDag-Erling Smørgrav #include <sys/linker.h> 395dba30f1SPoul-Henning Kamp #include <sys/module.h> 406e8394b8SKazutaka YOKOTA #include <sys/fbio.h> 417a19b7edSDag-Erling Smørgrav 427a19b7edSDag-Erling Smørgrav #include <dev/fb/fbreg.h> 437a19b7edSDag-Erling Smørgrav #include <dev/fb/splashreg.h> 447a19b7edSDag-Erling Smørgrav 457a19b7edSDag-Erling Smørgrav static int splash_mode = -1; 467a19b7edSDag-Erling Smørgrav static int splash_on = FALSE; 477a19b7edSDag-Erling Smørgrav 487a19b7edSDag-Erling Smørgrav static int pcx_start(video_adapter_t *adp); 497a19b7edSDag-Erling Smørgrav static int pcx_end(video_adapter_t *adp); 507a19b7edSDag-Erling Smørgrav static int pcx_splash(video_adapter_t *adp, int on); 51c930712aSDag-Erling Smørgrav static int pcx_init(void *data, int sdepth); 527a19b7edSDag-Erling Smørgrav static int pcx_draw(video_adapter_t *adp); 537a19b7edSDag-Erling Smørgrav 547a19b7edSDag-Erling Smørgrav static splash_decoder_t pcx_decoder = { 55c930712aSDag-Erling Smørgrav .name = "splash_pcx", 56c930712aSDag-Erling Smørgrav .init = pcx_start, 57c930712aSDag-Erling Smørgrav .term = pcx_end, 58c930712aSDag-Erling Smørgrav .splash = pcx_splash, 59c930712aSDag-Erling Smørgrav .data_type = SPLASH_IMAGE, 607a19b7edSDag-Erling Smørgrav }; 617a19b7edSDag-Erling Smørgrav 627a19b7edSDag-Erling Smørgrav SPLASH_DECODER(splash_pcx, pcx_decoder); 637a19b7edSDag-Erling Smørgrav 64c930712aSDag-Erling Smørgrav static struct { 65c930712aSDag-Erling Smørgrav int width; 66c930712aSDag-Erling Smørgrav int height; 67c930712aSDag-Erling Smørgrav int bpsl; 68c930712aSDag-Erling Smørgrav int bpp; 69c930712aSDag-Erling Smørgrav int planes; 70c930712aSDag-Erling Smørgrav int zlen; 71c930712aSDag-Erling Smørgrav const uint8_t *zdata; 72c930712aSDag-Erling Smørgrav uint8_t *palette; 737a19b7edSDag-Erling Smørgrav } pcx_info; 747a19b7edSDag-Erling Smørgrav 757a19b7edSDag-Erling Smørgrav static int 767a19b7edSDag-Erling Smørgrav pcx_start(video_adapter_t *adp) 777a19b7edSDag-Erling Smørgrav { 787a19b7edSDag-Erling Smørgrav static int modes[] = { 797a19b7edSDag-Erling Smørgrav M_VGA_CG320, 807a19b7edSDag-Erling Smørgrav M_VESA_CG640x480, 817a19b7edSDag-Erling Smørgrav M_VESA_CG800x600, 827a19b7edSDag-Erling Smørgrav M_VESA_CG1024x768, 837a19b7edSDag-Erling Smørgrav -1, 847a19b7edSDag-Erling Smørgrav }; 857a19b7edSDag-Erling Smørgrav video_info_t info; 867a19b7edSDag-Erling Smørgrav int i; 877a19b7edSDag-Erling Smørgrav 88c930712aSDag-Erling Smørgrav if (pcx_decoder.data == NULL || 89c930712aSDag-Erling Smørgrav pcx_decoder.data_size <= 0 || 90c930712aSDag-Erling Smørgrav pcx_init(pcx_decoder.data, pcx_decoder.data_size)) 91c930712aSDag-Erling Smørgrav return (ENODEV); 927a19b7edSDag-Erling Smørgrav 937a19b7edSDag-Erling Smørgrav if (bootverbose) 947a19b7edSDag-Erling Smørgrav printf("splash_pcx: image good:\n" 957a19b7edSDag-Erling Smørgrav " width = %d\n" 967a19b7edSDag-Erling Smørgrav " height = %d\n" 977a19b7edSDag-Erling Smørgrav " depth = %d\n" 987a19b7edSDag-Erling Smørgrav " planes = %d\n", 997a19b7edSDag-Erling Smørgrav pcx_info.width, pcx_info.height, 1007a19b7edSDag-Erling Smørgrav pcx_info.bpp, pcx_info.planes); 1017a19b7edSDag-Erling Smørgrav 1027a19b7edSDag-Erling Smørgrav for (i = 0; modes[i] >= 0; ++i) { 1039336e069SWojciech A. Koszek if (vidd_get_info(adp, modes[i], &info) != 0) 1047a19b7edSDag-Erling Smørgrav continue; 1057a19b7edSDag-Erling Smørgrav if (bootverbose) 1067a19b7edSDag-Erling Smørgrav printf("splash_pcx: considering mode %d:\n" 1077a19b7edSDag-Erling Smørgrav " vi_width = %d\n" 1087a19b7edSDag-Erling Smørgrav " vi_height = %d\n" 1097a19b7edSDag-Erling Smørgrav " vi_depth = %d\n" 1107a19b7edSDag-Erling Smørgrav " vi_planes = %d\n", 1117a19b7edSDag-Erling Smørgrav modes[i], 1127a19b7edSDag-Erling Smørgrav info.vi_width, info.vi_height, 1137a19b7edSDag-Erling Smørgrav info.vi_depth, info.vi_planes); 1147a19b7edSDag-Erling Smørgrav if (info.vi_width >= pcx_info.width 1157a19b7edSDag-Erling Smørgrav && info.vi_height >= pcx_info.height 1167a19b7edSDag-Erling Smørgrav && info.vi_depth == pcx_info.bpp 1177a19b7edSDag-Erling Smørgrav && info.vi_planes == pcx_info.planes) 1187a19b7edSDag-Erling Smørgrav break; 1197a19b7edSDag-Erling Smørgrav } 1207a19b7edSDag-Erling Smørgrav 1217a19b7edSDag-Erling Smørgrav splash_mode = modes[i]; 1227a19b7edSDag-Erling Smørgrav if (splash_mode == -1) 123c930712aSDag-Erling Smørgrav return (ENODEV); 1247a19b7edSDag-Erling Smørgrav if (bootverbose) 125c930712aSDag-Erling Smørgrav printf("splash_pcx: selecting mode %d\n", splash_mode); 126c930712aSDag-Erling Smørgrav return (0); 1277a19b7edSDag-Erling Smørgrav } 1287a19b7edSDag-Erling Smørgrav 1297a19b7edSDag-Erling Smørgrav static int 1307a19b7edSDag-Erling Smørgrav pcx_end(video_adapter_t *adp) 1317a19b7edSDag-Erling Smørgrav { 1327a19b7edSDag-Erling Smørgrav /* nothing to do */ 133c930712aSDag-Erling Smørgrav return (0); 1347a19b7edSDag-Erling Smørgrav } 1357a19b7edSDag-Erling Smørgrav 1367a19b7edSDag-Erling Smørgrav static int 1377a19b7edSDag-Erling Smørgrav pcx_splash(video_adapter_t *adp, int on) 1387a19b7edSDag-Erling Smørgrav { 1397a19b7edSDag-Erling Smørgrav if (on) { 1407a19b7edSDag-Erling Smørgrav if (!splash_on) { 1419336e069SWojciech A. Koszek if (vidd_set_mode(adp, splash_mode) || pcx_draw(adp)) 1427a19b7edSDag-Erling Smørgrav return 1; 1437a19b7edSDag-Erling Smørgrav splash_on = TRUE; 1447a19b7edSDag-Erling Smørgrav } 145c930712aSDag-Erling Smørgrav return (0); 1467a19b7edSDag-Erling Smørgrav } else { 1477a19b7edSDag-Erling Smørgrav splash_on = FALSE; 148c930712aSDag-Erling Smørgrav return (0); 1497a19b7edSDag-Erling Smørgrav } 1507a19b7edSDag-Erling Smørgrav } 1517a19b7edSDag-Erling Smørgrav 152c930712aSDag-Erling Smørgrav struct pcx_header { 153c930712aSDag-Erling Smørgrav uint8_t manufactor; 154c930712aSDag-Erling Smørgrav uint8_t version; 155c930712aSDag-Erling Smørgrav uint8_t encoding; 156c930712aSDag-Erling Smørgrav uint8_t bpp; 157c930712aSDag-Erling Smørgrav uint16_t xmin; 158c930712aSDag-Erling Smørgrav uint16_t ymin; 159c930712aSDag-Erling Smørgrav uint16_t xmax; 160c930712aSDag-Erling Smørgrav uint16_t ymax; 161c930712aSDag-Erling Smørgrav uint16_t hres; 162c930712aSDag-Erling Smørgrav uint16_t vres; 163c930712aSDag-Erling Smørgrav uint8_t colormap[48]; 164c930712aSDag-Erling Smørgrav uint8_t rsvd; 165c930712aSDag-Erling Smørgrav uint8_t nplanes; 166c930712aSDag-Erling Smørgrav uint16_t bpsl; 167c930712aSDag-Erling Smørgrav uint16_t palinfo; 168c930712aSDag-Erling Smørgrav uint16_t hsize; 169c930712aSDag-Erling Smørgrav uint16_t vsize; 1707a19b7edSDag-Erling Smørgrav }; 1717a19b7edSDag-Erling Smørgrav 1727a19b7edSDag-Erling Smørgrav #define MAXSCANLINE 1024 1737a19b7edSDag-Erling Smørgrav 1747a19b7edSDag-Erling Smørgrav static int 175c930712aSDag-Erling Smørgrav pcx_init(void *data, int size) 1767a19b7edSDag-Erling Smørgrav { 177c930712aSDag-Erling Smørgrav const struct pcx_header *hdr = data; 1787a19b7edSDag-Erling Smørgrav 179c930712aSDag-Erling Smørgrav if (size < 128 + 1 + 1 + 768 || 180c930712aSDag-Erling Smørgrav hdr->manufactor != 10 || 181c930712aSDag-Erling Smørgrav hdr->version != 5 || 182c930712aSDag-Erling Smørgrav hdr->encoding != 1 || 183c930712aSDag-Erling Smørgrav hdr->nplanes != 1 || 184c930712aSDag-Erling Smørgrav hdr->bpp != 8 || 185c930712aSDag-Erling Smørgrav hdr->bpsl > MAXSCANLINE || 186c930712aSDag-Erling Smørgrav ((uint8_t *)data)[size - 769] != 12) { 1877a19b7edSDag-Erling Smørgrav printf("splash_pcx: invalid PCX image\n"); 188c930712aSDag-Erling Smørgrav return (1); 1897a19b7edSDag-Erling Smørgrav } 1907a19b7edSDag-Erling Smørgrav pcx_info.width = hdr->xmax - hdr->xmin + 1; 1917a19b7edSDag-Erling Smørgrav pcx_info.height = hdr->ymax - hdr->ymin + 1; 1927a19b7edSDag-Erling Smørgrav pcx_info.bpsl = hdr->bpsl; 1937a19b7edSDag-Erling Smørgrav pcx_info.bpp = hdr->bpp; 1947a19b7edSDag-Erling Smørgrav pcx_info.planes = hdr->nplanes; 1957a19b7edSDag-Erling Smørgrav pcx_info.zlen = size - (128 + 1 + 768); 196c930712aSDag-Erling Smørgrav pcx_info.zdata = (uint8_t *)data + 128; 197c930712aSDag-Erling Smørgrav pcx_info.palette = (uint8_t *)data + size - 768; 198c930712aSDag-Erling Smørgrav return (0); 1997a19b7edSDag-Erling Smørgrav } 2007a19b7edSDag-Erling Smørgrav 2017a19b7edSDag-Erling Smørgrav static int 2027a19b7edSDag-Erling Smørgrav pcx_draw(video_adapter_t *adp) 2037a19b7edSDag-Erling Smørgrav { 204c930712aSDag-Erling Smørgrav uint8_t *vidmem; 205*2d9ae66dSJohn Baldwin int swidth, sheight, sbpsl; 2067a19b7edSDag-Erling Smørgrav int banksize, origin; 2077a19b7edSDag-Erling Smørgrav int c, i, j, pos, scan, x, y; 208c930712aSDag-Erling Smørgrav uint8_t line[MAXSCANLINE]; 2097a19b7edSDag-Erling Smørgrav 2107a19b7edSDag-Erling Smørgrav if (pcx_info.zlen < 1) 211c930712aSDag-Erling Smørgrav return (1); 2127a19b7edSDag-Erling Smørgrav 2139336e069SWojciech A. Koszek vidd_load_palette(adp, pcx_info.palette); 2147a19b7edSDag-Erling Smørgrav 215c930712aSDag-Erling Smørgrav vidmem = (uint8_t *)adp->va_window; 2167a19b7edSDag-Erling Smørgrav swidth = adp->va_info.vi_width; 2177a19b7edSDag-Erling Smørgrav sheight = adp->va_info.vi_height; 2187a19b7edSDag-Erling Smørgrav sbpsl = adp->va_line_width; 219af5c746aSDag-Erling Smørgrav banksize = adp->va_window_size; 2207a19b7edSDag-Erling Smørgrav 2217a19b7edSDag-Erling Smørgrav for (origin = 0; origin < sheight*sbpsl; origin += banksize) { 2229336e069SWojciech A. Koszek vidd_set_win_org(adp, origin); 2237a19b7edSDag-Erling Smørgrav bzero(vidmem, banksize); 2247a19b7edSDag-Erling Smørgrav } 2257a19b7edSDag-Erling Smørgrav 2267a19b7edSDag-Erling Smørgrav x = (swidth - pcx_info.width) / 2; 2277a19b7edSDag-Erling Smørgrav y = (sheight - pcx_info.height) / 2; 2287a19b7edSDag-Erling Smørgrav origin = 0; 2297a19b7edSDag-Erling Smørgrav pos = y * sbpsl + x; 2307a19b7edSDag-Erling Smørgrav while (pos > banksize) { 2317a19b7edSDag-Erling Smørgrav pos -= banksize; 2327a19b7edSDag-Erling Smørgrav origin += banksize; 2337a19b7edSDag-Erling Smørgrav } 2349336e069SWojciech A. Koszek vidd_set_win_org(adp, origin); 2357a19b7edSDag-Erling Smørgrav 2367a19b7edSDag-Erling Smørgrav for (scan = i = 0; scan < pcx_info.height; ++scan, ++y, pos += sbpsl) { 2377a19b7edSDag-Erling Smørgrav for (j = 0; j < pcx_info.bpsl && i < pcx_info.zlen; ++i) { 2387a19b7edSDag-Erling Smørgrav if ((pcx_info.zdata[i] & 0xc0) == 0xc0) { 2397a19b7edSDag-Erling Smørgrav c = pcx_info.zdata[i++] & 0x3f; 2407a19b7edSDag-Erling Smørgrav if (i >= pcx_info.zlen) 241c930712aSDag-Erling Smørgrav return (1); 2427a19b7edSDag-Erling Smørgrav } else { 2437a19b7edSDag-Erling Smørgrav c = 1; 2447a19b7edSDag-Erling Smørgrav } 2457a19b7edSDag-Erling Smørgrav if (j + c > pcx_info.bpsl) 246c930712aSDag-Erling Smørgrav return (1); 2477a19b7edSDag-Erling Smørgrav while (c--) 2487a19b7edSDag-Erling Smørgrav line[j++] = pcx_info.zdata[i]; 2497a19b7edSDag-Erling Smørgrav } 2507a19b7edSDag-Erling Smørgrav 2517a19b7edSDag-Erling Smørgrav if (pos > banksize) { 2527a19b7edSDag-Erling Smørgrav origin += banksize; 2537a19b7edSDag-Erling Smørgrav pos -= banksize; 2549336e069SWojciech A. Koszek vidd_set_win_org(adp, origin); 2557a19b7edSDag-Erling Smørgrav } 2567a19b7edSDag-Erling Smørgrav 2577a19b7edSDag-Erling Smørgrav if (pos + pcx_info.width > banksize) { 2587a19b7edSDag-Erling Smørgrav /* scanline crosses bank boundary */ 2597a19b7edSDag-Erling Smørgrav j = banksize - pos; 2607a19b7edSDag-Erling Smørgrav bcopy(line, vidmem + pos, j); 2617a19b7edSDag-Erling Smørgrav origin += banksize; 2627a19b7edSDag-Erling Smørgrav pos -= banksize; 2639336e069SWojciech A. Koszek vidd_set_win_org(adp, origin); 2647a19b7edSDag-Erling Smørgrav bcopy(line + j, vidmem, pcx_info.width - j); 2657a19b7edSDag-Erling Smørgrav } else { 2667a19b7edSDag-Erling Smørgrav bcopy(line, vidmem + pos, pcx_info.width); 2677a19b7edSDag-Erling Smørgrav } 2687a19b7edSDag-Erling Smørgrav } 2697a19b7edSDag-Erling Smørgrav 270c930712aSDag-Erling Smørgrav return (0); 2717a19b7edSDag-Erling Smørgrav } 272