17a19b7edSDag-Erling Smørgrav /*- 27a19b7edSDag-Erling Smørgrav * Copyright (c) 1999 Michael Smith <msmith@freebsd.org> 37a19b7edSDag-Erling Smørgrav * Copyright (c) 1999 Kazutaka YOKOTA <yokota@freebsd.org> 47a19b7edSDag-Erling Smørgrav * Copyright (c) 1999 Dag-Erling Co�dan Sm�rgrav 57a19b7edSDag-Erling Smørgrav * All rights reserved. 67a19b7edSDag-Erling Smørgrav * 77a19b7edSDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 87a19b7edSDag-Erling Smørgrav * modification, are permitted provided that the following conditions 97a19b7edSDag-Erling Smørgrav * are met: 107a19b7edSDag-Erling Smørgrav * 1. Redistributions of source code must retain the above copyright 117a19b7edSDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer 127a19b7edSDag-Erling Smørgrav * in this position and unchanged. 137a19b7edSDag-Erling Smørgrav * 2. Redistributions in binary form must reproduce the above copyright 147a19b7edSDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer in the 157a19b7edSDag-Erling Smørgrav * documentation and/or other materials provided with the distribution. 167a19b7edSDag-Erling Smørgrav * 3. The name of the author may not be used to endorse or promote products 177a19b7edSDag-Erling Smørgrav * derived from this software without specific prior written permission 187a19b7edSDag-Erling Smørgrav * 197a19b7edSDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 207a19b7edSDag-Erling Smørgrav * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 217a19b7edSDag-Erling Smørgrav * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 227a19b7edSDag-Erling Smørgrav * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 237a19b7edSDag-Erling Smørgrav * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 247a19b7edSDag-Erling Smørgrav * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 257a19b7edSDag-Erling Smørgrav * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 267a19b7edSDag-Erling Smørgrav * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 277a19b7edSDag-Erling Smørgrav * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 287a19b7edSDag-Erling Smørgrav * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 297a19b7edSDag-Erling Smørgrav * 30c3aac50fSPeter Wemm * $FreeBSD$ 317a19b7edSDag-Erling Smørgrav */ 327a19b7edSDag-Erling Smørgrav 337a19b7edSDag-Erling Smørgrav #include <sys/param.h> 347a19b7edSDag-Erling Smørgrav #include <sys/systm.h> 357a19b7edSDag-Erling Smørgrav #include <sys/kernel.h> 367a19b7edSDag-Erling Smørgrav #include <sys/linker.h> 375dba30f1SPoul-Henning Kamp #include <sys/module.h> 386e8394b8SKazutaka YOKOTA #include <sys/fbio.h> 397a19b7edSDag-Erling Smørgrav 407a19b7edSDag-Erling Smørgrav #include <dev/fb/fbreg.h> 417a19b7edSDag-Erling Smørgrav #include <dev/fb/splashreg.h> 427a19b7edSDag-Erling Smørgrav 437a19b7edSDag-Erling Smørgrav static int splash_mode = -1; 447a19b7edSDag-Erling Smørgrav static int splash_on = FALSE; 457a19b7edSDag-Erling Smørgrav 467a19b7edSDag-Erling Smørgrav static int pcx_start(video_adapter_t *adp); 477a19b7edSDag-Erling Smørgrav static int pcx_end(video_adapter_t *adp); 487a19b7edSDag-Erling Smørgrav static int pcx_splash(video_adapter_t *adp, int on); 49c930712aSDag-Erling Smørgrav static int pcx_init(void *data, int sdepth); 507a19b7edSDag-Erling Smørgrav static int pcx_draw(video_adapter_t *adp); 517a19b7edSDag-Erling Smørgrav 527a19b7edSDag-Erling Smørgrav static splash_decoder_t pcx_decoder = { 53c930712aSDag-Erling Smørgrav .name = "splash_pcx", 54c930712aSDag-Erling Smørgrav .init = pcx_start, 55c930712aSDag-Erling Smørgrav .term = pcx_end, 56c930712aSDag-Erling Smørgrav .splash = pcx_splash, 57c930712aSDag-Erling Smørgrav .data_type = SPLASH_IMAGE, 587a19b7edSDag-Erling Smørgrav }; 597a19b7edSDag-Erling Smørgrav 607a19b7edSDag-Erling Smørgrav SPLASH_DECODER(splash_pcx, pcx_decoder); 617a19b7edSDag-Erling Smørgrav 62c930712aSDag-Erling Smørgrav static struct { 63c930712aSDag-Erling Smørgrav int width; 64c930712aSDag-Erling Smørgrav int height; 65c930712aSDag-Erling Smørgrav int bpsl; 66c930712aSDag-Erling Smørgrav int bpp; 67c930712aSDag-Erling Smørgrav int planes; 68c930712aSDag-Erling Smørgrav int zlen; 69c930712aSDag-Erling Smørgrav const uint8_t *zdata; 70c930712aSDag-Erling Smørgrav uint8_t *palette; 717a19b7edSDag-Erling Smørgrav } pcx_info; 727a19b7edSDag-Erling Smørgrav 737a19b7edSDag-Erling Smørgrav static int 747a19b7edSDag-Erling Smørgrav pcx_start(video_adapter_t *adp) 757a19b7edSDag-Erling Smørgrav { 767a19b7edSDag-Erling Smørgrav static int modes[] = { 777a19b7edSDag-Erling Smørgrav M_VGA_CG320, 787a19b7edSDag-Erling Smørgrav M_VESA_CG640x480, 797a19b7edSDag-Erling Smørgrav M_VESA_CG800x600, 807a19b7edSDag-Erling Smørgrav M_VESA_CG1024x768, 817a19b7edSDag-Erling Smørgrav -1, 827a19b7edSDag-Erling Smørgrav }; 837a19b7edSDag-Erling Smørgrav video_info_t info; 847a19b7edSDag-Erling Smørgrav int i; 857a19b7edSDag-Erling Smørgrav 86c930712aSDag-Erling Smørgrav if (pcx_decoder.data == NULL || 87c930712aSDag-Erling Smørgrav pcx_decoder.data_size <= 0 || 88c930712aSDag-Erling Smørgrav pcx_init(pcx_decoder.data, pcx_decoder.data_size)) 89c930712aSDag-Erling Smørgrav return (ENODEV); 907a19b7edSDag-Erling Smørgrav 917a19b7edSDag-Erling Smørgrav if (bootverbose) 927a19b7edSDag-Erling Smørgrav printf("splash_pcx: image good:\n" 937a19b7edSDag-Erling Smørgrav " width = %d\n" 947a19b7edSDag-Erling Smørgrav " height = %d\n" 957a19b7edSDag-Erling Smørgrav " depth = %d\n" 967a19b7edSDag-Erling Smørgrav " planes = %d\n", 977a19b7edSDag-Erling Smørgrav pcx_info.width, pcx_info.height, 987a19b7edSDag-Erling Smørgrav pcx_info.bpp, pcx_info.planes); 997a19b7edSDag-Erling Smørgrav 1007a19b7edSDag-Erling Smørgrav for (i = 0; modes[i] >= 0; ++i) { 1017a19b7edSDag-Erling Smørgrav if (get_mode_info(adp, modes[i], &info) != 0) 1027a19b7edSDag-Erling Smørgrav continue; 1037a19b7edSDag-Erling Smørgrav if (bootverbose) 1047a19b7edSDag-Erling Smørgrav printf("splash_pcx: considering mode %d:\n" 1057a19b7edSDag-Erling Smørgrav " vi_width = %d\n" 1067a19b7edSDag-Erling Smørgrav " vi_height = %d\n" 1077a19b7edSDag-Erling Smørgrav " vi_depth = %d\n" 1087a19b7edSDag-Erling Smørgrav " vi_planes = %d\n", 1097a19b7edSDag-Erling Smørgrav modes[i], 1107a19b7edSDag-Erling Smørgrav info.vi_width, info.vi_height, 1117a19b7edSDag-Erling Smørgrav info.vi_depth, info.vi_planes); 1127a19b7edSDag-Erling Smørgrav if (info.vi_width >= pcx_info.width 1137a19b7edSDag-Erling Smørgrav && info.vi_height >= pcx_info.height 1147a19b7edSDag-Erling Smørgrav && info.vi_depth == pcx_info.bpp 1157a19b7edSDag-Erling Smørgrav && info.vi_planes == pcx_info.planes) 1167a19b7edSDag-Erling Smørgrav break; 1177a19b7edSDag-Erling Smørgrav } 1187a19b7edSDag-Erling Smørgrav 1197a19b7edSDag-Erling Smørgrav splash_mode = modes[i]; 1207a19b7edSDag-Erling Smørgrav if (splash_mode == -1) 121c930712aSDag-Erling Smørgrav return (ENODEV); 1227a19b7edSDag-Erling Smørgrav if (bootverbose) 123c930712aSDag-Erling Smørgrav printf("splash_pcx: selecting mode %d\n", splash_mode); 124c930712aSDag-Erling Smørgrav return (0); 1257a19b7edSDag-Erling Smørgrav } 1267a19b7edSDag-Erling Smørgrav 1277a19b7edSDag-Erling Smørgrav static int 1287a19b7edSDag-Erling Smørgrav pcx_end(video_adapter_t *adp) 1297a19b7edSDag-Erling Smørgrav { 1307a19b7edSDag-Erling Smørgrav /* nothing to do */ 131c930712aSDag-Erling Smørgrav return (0); 1327a19b7edSDag-Erling Smørgrav } 1337a19b7edSDag-Erling Smørgrav 1347a19b7edSDag-Erling Smørgrav static int 1357a19b7edSDag-Erling Smørgrav pcx_splash(video_adapter_t *adp, int on) 1367a19b7edSDag-Erling Smørgrav { 1377a19b7edSDag-Erling Smørgrav if (on) { 1387a19b7edSDag-Erling Smørgrav if (!splash_on) { 1397a19b7edSDag-Erling Smørgrav if (set_video_mode(adp, splash_mode) || pcx_draw(adp)) 1407a19b7edSDag-Erling Smørgrav return 1; 1417a19b7edSDag-Erling Smørgrav splash_on = TRUE; 1427a19b7edSDag-Erling Smørgrav } 143c930712aSDag-Erling Smørgrav return (0); 1447a19b7edSDag-Erling Smørgrav } else { 1457a19b7edSDag-Erling Smørgrav splash_on = FALSE; 146c930712aSDag-Erling Smørgrav return (0); 1477a19b7edSDag-Erling Smørgrav } 1487a19b7edSDag-Erling Smørgrav } 1497a19b7edSDag-Erling Smørgrav 150c930712aSDag-Erling Smørgrav struct pcx_header { 151c930712aSDag-Erling Smørgrav uint8_t manufactor; 152c930712aSDag-Erling Smørgrav uint8_t version; 153c930712aSDag-Erling Smørgrav uint8_t encoding; 154c930712aSDag-Erling Smørgrav uint8_t bpp; 155c930712aSDag-Erling Smørgrav uint16_t xmin; 156c930712aSDag-Erling Smørgrav uint16_t ymin; 157c930712aSDag-Erling Smørgrav uint16_t xmax; 158c930712aSDag-Erling Smørgrav uint16_t ymax; 159c930712aSDag-Erling Smørgrav uint16_t hres; 160c930712aSDag-Erling Smørgrav uint16_t vres; 161c930712aSDag-Erling Smørgrav uint8_t colormap[48]; 162c930712aSDag-Erling Smørgrav uint8_t rsvd; 163c930712aSDag-Erling Smørgrav uint8_t nplanes; 164c930712aSDag-Erling Smørgrav uint16_t bpsl; 165c930712aSDag-Erling Smørgrav uint16_t palinfo; 166c930712aSDag-Erling Smørgrav uint16_t hsize; 167c930712aSDag-Erling Smørgrav uint16_t vsize; 1687a19b7edSDag-Erling Smørgrav }; 1697a19b7edSDag-Erling Smørgrav 1707a19b7edSDag-Erling Smørgrav #define MAXSCANLINE 1024 1717a19b7edSDag-Erling Smørgrav 1727a19b7edSDag-Erling Smørgrav static int 173c930712aSDag-Erling Smørgrav pcx_init(void *data, int size) 1747a19b7edSDag-Erling Smørgrav { 175c930712aSDag-Erling Smørgrav const struct pcx_header *hdr = data; 1767a19b7edSDag-Erling Smørgrav 177c930712aSDag-Erling Smørgrav if (size < 128 + 1 + 1 + 768 || 178c930712aSDag-Erling Smørgrav hdr->manufactor != 10 || 179c930712aSDag-Erling Smørgrav hdr->version != 5 || 180c930712aSDag-Erling Smørgrav hdr->encoding != 1 || 181c930712aSDag-Erling Smørgrav hdr->nplanes != 1 || 182c930712aSDag-Erling Smørgrav hdr->bpp != 8 || 183c930712aSDag-Erling Smørgrav hdr->bpsl > MAXSCANLINE || 184c930712aSDag-Erling Smørgrav ((uint8_t *)data)[size - 769] != 12) { 1857a19b7edSDag-Erling Smørgrav printf("splash_pcx: invalid PCX image\n"); 186c930712aSDag-Erling Smørgrav return (1); 1877a19b7edSDag-Erling Smørgrav } 1887a19b7edSDag-Erling Smørgrav pcx_info.width = hdr->xmax - hdr->xmin + 1; 1897a19b7edSDag-Erling Smørgrav pcx_info.height = hdr->ymax - hdr->ymin + 1; 1907a19b7edSDag-Erling Smørgrav pcx_info.bpsl = hdr->bpsl; 1917a19b7edSDag-Erling Smørgrav pcx_info.bpp = hdr->bpp; 1927a19b7edSDag-Erling Smørgrav pcx_info.planes = hdr->nplanes; 1937a19b7edSDag-Erling Smørgrav pcx_info.zlen = size - (128 + 1 + 768); 194c930712aSDag-Erling Smørgrav pcx_info.zdata = (uint8_t *)data + 128; 195c930712aSDag-Erling Smørgrav pcx_info.palette = (uint8_t *)data + size - 768; 196c930712aSDag-Erling Smørgrav return (0); 1977a19b7edSDag-Erling Smørgrav } 1987a19b7edSDag-Erling Smørgrav 1997a19b7edSDag-Erling Smørgrav static int 2007a19b7edSDag-Erling Smørgrav pcx_draw(video_adapter_t *adp) 2017a19b7edSDag-Erling Smørgrav { 202c930712aSDag-Erling Smørgrav uint8_t *vidmem; 2037a19b7edSDag-Erling Smørgrav int swidth, sheight, sbpsl, sdepth, splanes; 2047a19b7edSDag-Erling Smørgrav int banksize, origin; 2057a19b7edSDag-Erling Smørgrav int c, i, j, pos, scan, x, y; 206c930712aSDag-Erling Smørgrav uint8_t line[MAXSCANLINE]; 2077a19b7edSDag-Erling Smørgrav 2087a19b7edSDag-Erling Smørgrav if (pcx_info.zlen < 1) 209c930712aSDag-Erling Smørgrav return (1); 2107a19b7edSDag-Erling Smørgrav 2117a19b7edSDag-Erling Smørgrav load_palette(adp, pcx_info.palette); 2127a19b7edSDag-Erling Smørgrav 213c930712aSDag-Erling Smørgrav vidmem = (uint8_t *)adp->va_window; 2147a19b7edSDag-Erling Smørgrav swidth = adp->va_info.vi_width; 2157a19b7edSDag-Erling Smørgrav sheight = adp->va_info.vi_height; 2167a19b7edSDag-Erling Smørgrav sbpsl = adp->va_line_width; 2177a19b7edSDag-Erling Smørgrav sdepth = adp->va_info.vi_depth; 2187a19b7edSDag-Erling Smørgrav splanes = adp->va_info.vi_planes; 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) { 2227a19b7edSDag-Erling Smørgrav set_origin(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 } 2347a19b7edSDag-Erling Smørgrav set_origin(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; 2547a19b7edSDag-Erling Smørgrav set_origin(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; 2637a19b7edSDag-Erling Smørgrav set_origin(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