xref: /freebsd/sys/dev/fb/splash_pcx.c (revision e738085b94631f90e21a49852538ac95974baf44)
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>
6*e738085bSDag-Erling Smørgrav  * Copyright (c) 1999 Dag-Erling 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  */
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
pcx_start(video_adapter_t * adp)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) {
1019336e069SWojciech A. Koszek 		if (vidd_get_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
pcx_end(video_adapter_t * adp)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
pcx_splash(video_adapter_t * adp,int on)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) {
1399336e069SWojciech A. Koszek 			if (vidd_set_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
pcx_init(void * data,int size)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
pcx_draw(video_adapter_t * adp)2007a19b7edSDag-Erling Smørgrav pcx_draw(video_adapter_t *adp)
2017a19b7edSDag-Erling Smørgrav {
202c930712aSDag-Erling Smørgrav 	uint8_t *vidmem;
2032d9ae66dSJohn Baldwin 	int swidth, sheight, sbpsl;
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 
2119336e069SWojciech A. Koszek 	vidd_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;
217af5c746aSDag-Erling Smørgrav 	banksize = adp->va_window_size;
2187a19b7edSDag-Erling Smørgrav 
2197a19b7edSDag-Erling Smørgrav 	for (origin = 0; origin < sheight*sbpsl; origin += banksize) {
2209336e069SWojciech A. Koszek 		vidd_set_win_org(adp, origin);
2217a19b7edSDag-Erling Smørgrav 		bzero(vidmem, banksize);
2227a19b7edSDag-Erling Smørgrav 	}
2237a19b7edSDag-Erling Smørgrav 
2247a19b7edSDag-Erling Smørgrav 	x = (swidth - pcx_info.width) / 2;
2257a19b7edSDag-Erling Smørgrav 	y = (sheight - pcx_info.height) / 2;
2267a19b7edSDag-Erling Smørgrav 	origin = 0;
2277a19b7edSDag-Erling Smørgrav 	pos = y * sbpsl + x;
2287a19b7edSDag-Erling Smørgrav 	while (pos > banksize) {
2297a19b7edSDag-Erling Smørgrav 		pos -= banksize;
2307a19b7edSDag-Erling Smørgrav 		origin += banksize;
2317a19b7edSDag-Erling Smørgrav 	}
2329336e069SWojciech A. Koszek 	vidd_set_win_org(adp, origin);
2337a19b7edSDag-Erling Smørgrav 
2347a19b7edSDag-Erling Smørgrav 	for (scan = i = 0; scan < pcx_info.height; ++scan, ++y, pos += sbpsl) {
2357a19b7edSDag-Erling Smørgrav 		for (j = 0; j < pcx_info.bpsl && i < pcx_info.zlen; ++i) {
2367a19b7edSDag-Erling Smørgrav 			if ((pcx_info.zdata[i] & 0xc0) == 0xc0) {
2377a19b7edSDag-Erling Smørgrav 				c = pcx_info.zdata[i++] & 0x3f;
2387a19b7edSDag-Erling Smørgrav 				if (i >= pcx_info.zlen)
239c930712aSDag-Erling Smørgrav 					return (1);
2407a19b7edSDag-Erling Smørgrav 			} else {
2417a19b7edSDag-Erling Smørgrav 				c = 1;
2427a19b7edSDag-Erling Smørgrav 			}
2437a19b7edSDag-Erling Smørgrav 			if (j + c > pcx_info.bpsl)
244c930712aSDag-Erling Smørgrav 				return (1);
2457a19b7edSDag-Erling Smørgrav 			while (c--)
2467a19b7edSDag-Erling Smørgrav 				line[j++] = pcx_info.zdata[i];
2477a19b7edSDag-Erling Smørgrav 		}
2487a19b7edSDag-Erling Smørgrav 
2497a19b7edSDag-Erling Smørgrav 		if (pos > banksize) {
2507a19b7edSDag-Erling Smørgrav 			origin += banksize;
2517a19b7edSDag-Erling Smørgrav 			pos -= banksize;
2529336e069SWojciech A. Koszek 			vidd_set_win_org(adp, origin);
2537a19b7edSDag-Erling Smørgrav 		}
2547a19b7edSDag-Erling Smørgrav 
2557a19b7edSDag-Erling Smørgrav 		if (pos + pcx_info.width > banksize) {
2567a19b7edSDag-Erling Smørgrav 			/* scanline crosses bank boundary */
2577a19b7edSDag-Erling Smørgrav 			j = banksize - pos;
2587a19b7edSDag-Erling Smørgrav 			bcopy(line, vidmem + pos, j);
2597a19b7edSDag-Erling Smørgrav 			origin += banksize;
2607a19b7edSDag-Erling Smørgrav 			pos -= banksize;
2619336e069SWojciech A. Koszek 			vidd_set_win_org(adp, origin);
2627a19b7edSDag-Erling Smørgrav 			bcopy(line + j, vidmem, pcx_info.width - j);
2637a19b7edSDag-Erling Smørgrav 		} else {
2647a19b7edSDag-Erling Smørgrav 			bcopy(line, vidmem + pos, pcx_info.width);
2657a19b7edSDag-Erling Smørgrav 		}
2667a19b7edSDag-Erling Smørgrav 	}
2677a19b7edSDag-Erling Smørgrav 
268c930712aSDag-Erling Smørgrav 	return (0);
2697a19b7edSDag-Erling Smørgrav }
270