xref: /freebsd/sys/dev/fb/splash_pcx.c (revision 6e8394b8baa7d5d9153ab90de6824bcd19b3b4e1)
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  *
306e8394b8SKazutaka YOKOTA  *	$Id: splash_pcx.c,v 1.1 1999/04/12 13:39:11 des Exp $
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>
376e8394b8SKazutaka YOKOTA #include <sys/fbio.h>
387a19b7edSDag-Erling Smørgrav 
397a19b7edSDag-Erling Smørgrav #include <dev/fb/fbreg.h>
407a19b7edSDag-Erling Smørgrav #include <dev/fb/splashreg.h>
417a19b7edSDag-Erling Smørgrav 
427a19b7edSDag-Erling Smørgrav #define FADE_TIMEOUT	300	/* sec */
437a19b7edSDag-Erling Smørgrav 
447a19b7edSDag-Erling Smørgrav static int splash_mode = -1;
457a19b7edSDag-Erling Smørgrav static int splash_on = FALSE;
467a19b7edSDag-Erling Smørgrav 
477a19b7edSDag-Erling Smørgrav static int pcx_start(video_adapter_t *adp);
487a19b7edSDag-Erling Smørgrav static int pcx_end(video_adapter_t *adp);
497a19b7edSDag-Erling Smørgrav static int pcx_splash(video_adapter_t *adp, int on);
507a19b7edSDag-Erling Smørgrav static int pcx_init(const char *data, int sdepth);
517a19b7edSDag-Erling Smørgrav static int pcx_draw(video_adapter_t *adp);
527a19b7edSDag-Erling Smørgrav 
537a19b7edSDag-Erling Smørgrav static splash_decoder_t pcx_decoder = {
547a19b7edSDag-Erling Smørgrav     "splash_pcx", pcx_start, pcx_end, pcx_splash, SPLASH_IMAGE,
557a19b7edSDag-Erling Smørgrav };
567a19b7edSDag-Erling Smørgrav 
577a19b7edSDag-Erling Smørgrav SPLASH_DECODER(splash_pcx, pcx_decoder);
587a19b7edSDag-Erling Smørgrav 
597a19b7edSDag-Erling Smørgrav static struct
607a19b7edSDag-Erling Smørgrav {
617a19b7edSDag-Erling Smørgrav     int		  width, height, bpsl;
627a19b7edSDag-Erling Smørgrav     int		  bpp, planes, zlen;
637a19b7edSDag-Erling Smørgrav     const u_char *zdata, *palette;
647a19b7edSDag-Erling Smørgrav } pcx_info;
657a19b7edSDag-Erling Smørgrav 
667a19b7edSDag-Erling Smørgrav static int
677a19b7edSDag-Erling Smørgrav pcx_start(video_adapter_t *adp)
687a19b7edSDag-Erling Smørgrav {
697a19b7edSDag-Erling Smørgrav     static int modes[] = {
707a19b7edSDag-Erling Smørgrav 	M_VGA_CG320,
717a19b7edSDag-Erling Smørgrav 	M_VESA_CG640x480,
727a19b7edSDag-Erling Smørgrav 	M_VESA_CG800x600,
737a19b7edSDag-Erling Smørgrav 	M_VESA_CG1024x768,
747a19b7edSDag-Erling Smørgrav 	-1,
757a19b7edSDag-Erling Smørgrav     };
767a19b7edSDag-Erling Smørgrav     video_info_t info;
777a19b7edSDag-Erling Smørgrav     int	i;
787a19b7edSDag-Erling Smørgrav 
797a19b7edSDag-Erling Smørgrav     if (pcx_decoder.data == NULL
807a19b7edSDag-Erling Smørgrav 	|| pcx_decoder.data_size <= 0
817a19b7edSDag-Erling Smørgrav 	|| pcx_init((u_char *)pcx_decoder.data, pcx_decoder.data_size))
827a19b7edSDag-Erling Smørgrav 	return ENODEV;
837a19b7edSDag-Erling Smørgrav 
847a19b7edSDag-Erling Smørgrav     if (bootverbose)
857a19b7edSDag-Erling Smørgrav 	printf("splash_pcx: image good:\n"
867a19b7edSDag-Erling Smørgrav 	       "  width = %d\n"
877a19b7edSDag-Erling Smørgrav 	       "  height = %d\n"
887a19b7edSDag-Erling Smørgrav 	       "  depth = %d\n"
897a19b7edSDag-Erling Smørgrav 	       "  planes = %d\n",
907a19b7edSDag-Erling Smørgrav 	       pcx_info.width, pcx_info.height,
917a19b7edSDag-Erling Smørgrav 	       pcx_info.bpp, pcx_info.planes);
927a19b7edSDag-Erling Smørgrav 
937a19b7edSDag-Erling Smørgrav     for (i = 0; modes[i] >= 0; ++i) {
947a19b7edSDag-Erling Smørgrav 	if (get_mode_info(adp, modes[i], &info) != 0)
957a19b7edSDag-Erling Smørgrav 	    continue;
967a19b7edSDag-Erling Smørgrav 	if (bootverbose)
977a19b7edSDag-Erling Smørgrav 	    printf("splash_pcx: considering mode %d:\n"
987a19b7edSDag-Erling Smørgrav 		   "  vi_width = %d\n"
997a19b7edSDag-Erling Smørgrav 		   "  vi_height = %d\n"
1007a19b7edSDag-Erling Smørgrav 		   "  vi_depth = %d\n"
1017a19b7edSDag-Erling Smørgrav 		   "  vi_planes = %d\n",
1027a19b7edSDag-Erling Smørgrav 		   modes[i],
1037a19b7edSDag-Erling Smørgrav 		   info.vi_width, info.vi_height,
1047a19b7edSDag-Erling Smørgrav 		   info.vi_depth, info.vi_planes);
1057a19b7edSDag-Erling Smørgrav 	if (info.vi_width >= pcx_info.width
1067a19b7edSDag-Erling Smørgrav 	    && info.vi_height >= pcx_info.height
1077a19b7edSDag-Erling Smørgrav 	    && info.vi_depth == pcx_info.bpp
1087a19b7edSDag-Erling Smørgrav 	    && info.vi_planes == pcx_info.planes)
1097a19b7edSDag-Erling Smørgrav 	    break;
1107a19b7edSDag-Erling Smørgrav     }
1117a19b7edSDag-Erling Smørgrav 
1127a19b7edSDag-Erling Smørgrav     splash_mode = modes[i];
1137a19b7edSDag-Erling Smørgrav     if (splash_mode == -1)
1147a19b7edSDag-Erling Smørgrav 	return ENODEV;
1157a19b7edSDag-Erling Smørgrav     if (bootverbose)
1167a19b7edSDag-Erling Smørgrav 	printf("pcx_splash: selecting mode %d\n", splash_mode);
1177a19b7edSDag-Erling Smørgrav     return 0;
1187a19b7edSDag-Erling Smørgrav }
1197a19b7edSDag-Erling Smørgrav 
1207a19b7edSDag-Erling Smørgrav static int
1217a19b7edSDag-Erling Smørgrav pcx_end(video_adapter_t *adp)
1227a19b7edSDag-Erling Smørgrav {
1237a19b7edSDag-Erling Smørgrav     /* nothing to do */
1247a19b7edSDag-Erling Smørgrav     return 0;
1257a19b7edSDag-Erling Smørgrav }
1267a19b7edSDag-Erling Smørgrav 
1277a19b7edSDag-Erling Smørgrav static int
1287a19b7edSDag-Erling Smørgrav pcx_splash(video_adapter_t *adp, int on)
1297a19b7edSDag-Erling Smørgrav {
1307a19b7edSDag-Erling Smørgrav     if (on) {
1317a19b7edSDag-Erling Smørgrav 	if (!splash_on) {
1327a19b7edSDag-Erling Smørgrav 	    if (set_video_mode(adp, splash_mode) || pcx_draw(adp))
1337a19b7edSDag-Erling Smørgrav 		return 1;
1347a19b7edSDag-Erling Smørgrav 	    splash_on = TRUE;
1357a19b7edSDag-Erling Smørgrav 	}
1367a19b7edSDag-Erling Smørgrav 	return 0;
1377a19b7edSDag-Erling Smørgrav     } else {
1387a19b7edSDag-Erling Smørgrav 	splash_on = FALSE;
1397a19b7edSDag-Erling Smørgrav 	return 0;
1407a19b7edSDag-Erling Smørgrav     }
1417a19b7edSDag-Erling Smørgrav }
1427a19b7edSDag-Erling Smørgrav 
1437a19b7edSDag-Erling Smørgrav struct pcxheader {
1447a19b7edSDag-Erling Smørgrav     u_char manufactor;
1457a19b7edSDag-Erling Smørgrav     u_char version;
1467a19b7edSDag-Erling Smørgrav     u_char encoding;
1477a19b7edSDag-Erling Smørgrav     u_char bpp;
1487a19b7edSDag-Erling Smørgrav     u_short xmin, ymin, xmax, ymax;
1497a19b7edSDag-Erling Smørgrav     u_short hres, vres;
1507a19b7edSDag-Erling Smørgrav     u_char colormap[48];
1517a19b7edSDag-Erling Smørgrav     u_char rsvd;
1527a19b7edSDag-Erling Smørgrav     u_char nplanes;
1537a19b7edSDag-Erling Smørgrav     u_short bpsl;
1547a19b7edSDag-Erling Smørgrav     u_short palinfo;
1557a19b7edSDag-Erling Smørgrav     u_short hsize, vsize;
1567a19b7edSDag-Erling Smørgrav };
1577a19b7edSDag-Erling Smørgrav 
1587a19b7edSDag-Erling Smørgrav #define MAXSCANLINE 1024
1597a19b7edSDag-Erling Smørgrav 
1607a19b7edSDag-Erling Smørgrav static int
1617a19b7edSDag-Erling Smørgrav pcx_init(const char *data, int size)
1627a19b7edSDag-Erling Smørgrav {
1637a19b7edSDag-Erling Smørgrav     const struct pcxheader *hdr;
1647a19b7edSDag-Erling Smørgrav 
1657a19b7edSDag-Erling Smørgrav     hdr = (const struct pcxheader *)data;
1667a19b7edSDag-Erling Smørgrav 
1677a19b7edSDag-Erling Smørgrav     if (size < 128 + 1 + 1 + 768
1687a19b7edSDag-Erling Smørgrav 	|| hdr->manufactor != 10
1697a19b7edSDag-Erling Smørgrav 	|| hdr->version != 5
1707a19b7edSDag-Erling Smørgrav 	|| hdr->encoding != 1
1717a19b7edSDag-Erling Smørgrav 	|| hdr->nplanes != 1
1727a19b7edSDag-Erling Smørgrav 	|| hdr->bpp != 8
1737a19b7edSDag-Erling Smørgrav 	|| hdr->bpsl > MAXSCANLINE
1747a19b7edSDag-Erling Smørgrav 	|| data[size-769] != 12) {
1757a19b7edSDag-Erling Smørgrav 	printf("splash_pcx: invalid PCX image\n");
1767a19b7edSDag-Erling Smørgrav 	return 1;
1777a19b7edSDag-Erling Smørgrav     }
1787a19b7edSDag-Erling Smørgrav     pcx_info.width =  hdr->xmax - hdr->xmin + 1;
1797a19b7edSDag-Erling Smørgrav     pcx_info.height =  hdr->ymax - hdr->ymin + 1;
1807a19b7edSDag-Erling Smørgrav     pcx_info.bpsl = hdr->bpsl;
1817a19b7edSDag-Erling Smørgrav     pcx_info.bpp = hdr->bpp;
1827a19b7edSDag-Erling Smørgrav     pcx_info.planes = hdr->nplanes;
1837a19b7edSDag-Erling Smørgrav     pcx_info.zlen = size - (128 + 1 + 768);
1847a19b7edSDag-Erling Smørgrav     pcx_info.zdata = data + 128;
1857a19b7edSDag-Erling Smørgrav     pcx_info.palette = data + size - 768;
1867a19b7edSDag-Erling Smørgrav     return 0;
1877a19b7edSDag-Erling Smørgrav }
1887a19b7edSDag-Erling Smørgrav 
1897a19b7edSDag-Erling Smørgrav static int
1907a19b7edSDag-Erling Smørgrav pcx_draw(video_adapter_t *adp)
1917a19b7edSDag-Erling Smørgrav {
1927a19b7edSDag-Erling Smørgrav     u_char *vidmem;
1937a19b7edSDag-Erling Smørgrav     int swidth, sheight, sbpsl, sdepth, splanes;
1947a19b7edSDag-Erling Smørgrav     int banksize, origin;
1957a19b7edSDag-Erling Smørgrav     int c, i, j, pos, scan, x, y;
1967a19b7edSDag-Erling Smørgrav     u_char line[MAXSCANLINE];
1977a19b7edSDag-Erling Smørgrav 
1987a19b7edSDag-Erling Smørgrav     if (pcx_info.zlen < 1)
1997a19b7edSDag-Erling Smørgrav 	return 1;
2007a19b7edSDag-Erling Smørgrav 
2017a19b7edSDag-Erling Smørgrav     load_palette(adp, pcx_info.palette);
2027a19b7edSDag-Erling Smørgrav 
2037a19b7edSDag-Erling Smørgrav     vidmem = (u_char *)adp->va_window;
2047a19b7edSDag-Erling Smørgrav     swidth = adp->va_info.vi_width;
2057a19b7edSDag-Erling Smørgrav     sheight = adp->va_info.vi_height;
2067a19b7edSDag-Erling Smørgrav     sbpsl = adp->va_line_width;
2077a19b7edSDag-Erling Smørgrav     sdepth = adp->va_info.vi_depth;
2087a19b7edSDag-Erling Smørgrav     splanes = adp->va_info.vi_planes;
2097a19b7edSDag-Erling Smørgrav     banksize = adp->va_info.vi_window_size;
2107a19b7edSDag-Erling Smørgrav 
2117a19b7edSDag-Erling Smørgrav     for (origin = 0; origin < sheight*sbpsl; origin += banksize) {
2127a19b7edSDag-Erling Smørgrav 	set_origin(adp, origin);
2137a19b7edSDag-Erling Smørgrav 	bzero(vidmem, banksize);
2147a19b7edSDag-Erling Smørgrav     }
2157a19b7edSDag-Erling Smørgrav 
2167a19b7edSDag-Erling Smørgrav     x = (swidth - pcx_info.width) / 2;
2177a19b7edSDag-Erling Smørgrav     y = (sheight - pcx_info.height) / 2;
2187a19b7edSDag-Erling Smørgrav     origin = 0;
2197a19b7edSDag-Erling Smørgrav     pos = y * sbpsl + x;
2207a19b7edSDag-Erling Smørgrav     while (pos > banksize) {
2217a19b7edSDag-Erling Smørgrav 	pos -= banksize;
2227a19b7edSDag-Erling Smørgrav 	origin += banksize;
2237a19b7edSDag-Erling Smørgrav     }
2247a19b7edSDag-Erling Smørgrav     set_origin(adp, origin);
2257a19b7edSDag-Erling Smørgrav 
2267a19b7edSDag-Erling Smørgrav     for (scan = i = 0; scan < pcx_info.height; ++scan, ++y, pos += sbpsl) {
2277a19b7edSDag-Erling Smørgrav 	for (j = 0; j < pcx_info.bpsl && i < pcx_info.zlen; ++i) {
2287a19b7edSDag-Erling Smørgrav 	    if ((pcx_info.zdata[i] & 0xc0) == 0xc0) {
2297a19b7edSDag-Erling Smørgrav 		c = pcx_info.zdata[i++] & 0x3f;
2307a19b7edSDag-Erling Smørgrav 		if (i >= pcx_info.zlen)
2317a19b7edSDag-Erling Smørgrav 		    return 1;
2327a19b7edSDag-Erling Smørgrav 	    } else {
2337a19b7edSDag-Erling Smørgrav 		c = 1;
2347a19b7edSDag-Erling Smørgrav 	    }
2357a19b7edSDag-Erling Smørgrav 	    if (j + c > pcx_info.bpsl)
2367a19b7edSDag-Erling Smørgrav 		return 1;
2377a19b7edSDag-Erling Smørgrav 	    while (c--)
2387a19b7edSDag-Erling Smørgrav 		line[j++] = pcx_info.zdata[i];
2397a19b7edSDag-Erling Smørgrav 	}
2407a19b7edSDag-Erling Smørgrav 
2417a19b7edSDag-Erling Smørgrav 	if (pos > banksize) {
2427a19b7edSDag-Erling Smørgrav 	    origin += banksize;
2437a19b7edSDag-Erling Smørgrav 	    pos -= banksize;
2447a19b7edSDag-Erling Smørgrav 	    set_origin(adp, origin);
2457a19b7edSDag-Erling Smørgrav 	}
2467a19b7edSDag-Erling Smørgrav 
2477a19b7edSDag-Erling Smørgrav 	if (pos + pcx_info.width > banksize) {
2487a19b7edSDag-Erling Smørgrav 	    /* scanline crosses bank boundary */
2497a19b7edSDag-Erling Smørgrav 	    j = banksize - pos;
2507a19b7edSDag-Erling Smørgrav 	    bcopy(line, vidmem + pos, j);
2517a19b7edSDag-Erling Smørgrav 	    origin += banksize;
2527a19b7edSDag-Erling Smørgrav 	    pos -= banksize;
2537a19b7edSDag-Erling Smørgrav 	    set_origin(adp, origin);
2547a19b7edSDag-Erling Smørgrav 	    bcopy(line + j, vidmem, pcx_info.width - j);
2557a19b7edSDag-Erling Smørgrav 	} else {
2567a19b7edSDag-Erling Smørgrav 	    bcopy(line, vidmem + pos, pcx_info.width);
2577a19b7edSDag-Erling Smørgrav 	}
2587a19b7edSDag-Erling Smørgrav     }
2597a19b7edSDag-Erling Smørgrav 
2607a19b7edSDag-Erling Smørgrav     return 0;
2617a19b7edSDag-Erling Smørgrav }
262