xref: /freebsd/sys/dev/fb/splash_bmp.c (revision 5dba30f15ae1cec2dcdc19be3f3efa0331755f42)
11243dad0SKazutaka YOKOTA /*-
21243dad0SKazutaka YOKOTA  * Copyright (c) 1999 Michael Smith <msmith@freebsd.org>
31243dad0SKazutaka YOKOTA  * Copyright (c) 1999 Kazutaka YOKOTA <yokota@freebsd.org>
41243dad0SKazutaka YOKOTA  * All rights reserved.
51243dad0SKazutaka YOKOTA  *
61243dad0SKazutaka YOKOTA  * Redistribution and use in source and binary forms, with or without
71243dad0SKazutaka YOKOTA  * modification, are permitted provided that the following conditions
81243dad0SKazutaka YOKOTA  * are met:
91243dad0SKazutaka YOKOTA  * 1. Redistributions of source code must retain the above copyright
101243dad0SKazutaka YOKOTA  *    notice, this list of conditions and the following disclaimer.
111243dad0SKazutaka YOKOTA  * 2. Redistributions in binary form must reproduce the above copyright
121243dad0SKazutaka YOKOTA  *    notice, this list of conditions and the following disclaimer in the
131243dad0SKazutaka YOKOTA  *    documentation and/or other materials provided with the distribution.
141243dad0SKazutaka YOKOTA  *
151243dad0SKazutaka YOKOTA  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
161243dad0SKazutaka YOKOTA  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
171243dad0SKazutaka YOKOTA  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
181243dad0SKazutaka YOKOTA  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
191243dad0SKazutaka YOKOTA  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
201243dad0SKazutaka YOKOTA  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
211243dad0SKazutaka YOKOTA  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
221243dad0SKazutaka YOKOTA  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
231243dad0SKazutaka YOKOTA  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
241243dad0SKazutaka YOKOTA  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
251243dad0SKazutaka YOKOTA  * SUCH DAMAGE.
261243dad0SKazutaka YOKOTA  *
27c3aac50fSPeter Wemm  * $FreeBSD$
281243dad0SKazutaka YOKOTA  */
291243dad0SKazutaka YOKOTA 
301243dad0SKazutaka YOKOTA #include <sys/param.h>
311243dad0SKazutaka YOKOTA #include <sys/systm.h>
321243dad0SKazutaka YOKOTA #include <sys/kernel.h>
335dba30f1SPoul-Henning Kamp #include <sys/module.h>
341243dad0SKazutaka YOKOTA #include <sys/linker.h>
356e8394b8SKazutaka YOKOTA #include <sys/fbio.h>
361243dad0SKazutaka YOKOTA 
371243dad0SKazutaka YOKOTA #include <dev/fb/fbreg.h>
381243dad0SKazutaka YOKOTA #include <dev/fb/splashreg.h>
39cb4860b7SYoshihiro Takahashi #ifndef PC98
4099feb462SKazutaka YOKOTA #include <dev/fb/vgareg.h>
4199feb462SKazutaka YOKOTA 
4299feb462SKazutaka YOKOTA #include <isa/isareg.h>
43cb4860b7SYoshihiro Takahashi #endif
441243dad0SKazutaka YOKOTA 
45ccd48159SKazutaka YOKOTA #define FADE_TIMEOUT	15	/* sec */
46ccd48159SKazutaka YOKOTA #define FADE_LEVELS	10
471243dad0SKazutaka YOKOTA 
481243dad0SKazutaka YOKOTA static int splash_mode = -1;
491243dad0SKazutaka YOKOTA static int splash_on = FALSE;
501243dad0SKazutaka YOKOTA 
511243dad0SKazutaka YOKOTA static int bmp_start(video_adapter_t *adp);
521243dad0SKazutaka YOKOTA static int bmp_end(video_adapter_t *adp);
531243dad0SKazutaka YOKOTA static int bmp_splash(video_adapter_t *adp, int on);
5497be736aSMaxime Henrion static int bmp_Init(char *data, int swidth, int sheight, int sdepth);
551243dad0SKazutaka YOKOTA static int bmp_Draw(video_adapter_t *adp);
561243dad0SKazutaka YOKOTA 
571243dad0SKazutaka YOKOTA static splash_decoder_t bmp_decoder = {
581243dad0SKazutaka YOKOTA     "splash_bmp", bmp_start, bmp_end, bmp_splash, SPLASH_IMAGE,
591243dad0SKazutaka YOKOTA };
601243dad0SKazutaka YOKOTA 
611243dad0SKazutaka YOKOTA SPLASH_DECODER(splash_bmp, bmp_decoder);
621243dad0SKazutaka YOKOTA 
631243dad0SKazutaka YOKOTA static int
641243dad0SKazutaka YOKOTA bmp_start(video_adapter_t *adp)
651243dad0SKazutaka YOKOTA {
66325fca90SKazutaka YOKOTA     /* currently only 256-color modes are supported XXX */
671243dad0SKazutaka YOKOTA     static int		modes[] = {
68cb4860b7SYoshihiro Takahashi #ifdef PC98
69cb4860b7SYoshihiro Takahashi     			/*
70cb4860b7SYoshihiro Takahashi 			 * As 640x400 doesn't generally look great,
71cb4860b7SYoshihiro Takahashi 			 * it's least preferred here.
72cb4860b7SYoshihiro Takahashi 			 */
73cb4860b7SYoshihiro Takahashi 			M_PC98_PEGC640x400,
74cb4860b7SYoshihiro Takahashi 			M_PC98_PEGC640x480,
75cb4860b7SYoshihiro Takahashi 			M_PC98_EGC640x400,
76cb4860b7SYoshihiro Takahashi #else
77325fca90SKazutaka YOKOTA 			M_VESA_CG640x480,
78325fca90SKazutaka YOKOTA 			M_VESA_CG800x600,
79325fca90SKazutaka YOKOTA 			M_VESA_CG1024x768,
8099feb462SKazutaka YOKOTA 			M_CG640x480,
81325fca90SKazutaka YOKOTA     			/*
82325fca90SKazutaka YOKOTA 			 * As 320x200 doesn't generally look great,
83325fca90SKazutaka YOKOTA 			 * it's least preferred here.
84325fca90SKazutaka YOKOTA 			 */
851243dad0SKazutaka YOKOTA 			M_VGA_CG320,
86cb4860b7SYoshihiro Takahashi #endif
871243dad0SKazutaka YOKOTA 			-1,
881243dad0SKazutaka YOKOTA     };
891243dad0SKazutaka YOKOTA     video_info_t 	info;
901243dad0SKazutaka YOKOTA     int			i;
911243dad0SKazutaka YOKOTA 
925c539f03SKazutaka YOKOTA     if ((bmp_decoder.data == NULL) || (bmp_decoder.data_size <= 0)) {
935c539f03SKazutaka YOKOTA 	printf("splash_bmp: No bitmap file found\n");
941243dad0SKazutaka YOKOTA 	return ENODEV;
955c539f03SKazutaka YOKOTA     }
961243dad0SKazutaka YOKOTA     for (i = 0; modes[i] >= 0; ++i) {
971243dad0SKazutaka YOKOTA 	if (((*vidsw[adp->va_index]->get_info)(adp, modes[i], &info) == 0)
981243dad0SKazutaka YOKOTA 	    && (bmp_Init((u_char *)bmp_decoder.data,
991243dad0SKazutaka YOKOTA 			 info.vi_width, info.vi_height, info.vi_depth) == 0))
1001243dad0SKazutaka YOKOTA 	    break;
1011243dad0SKazutaka YOKOTA     }
1021243dad0SKazutaka YOKOTA     splash_mode = modes[i];
1035c539f03SKazutaka YOKOTA     if (splash_mode < 0)
1045c539f03SKazutaka YOKOTA 	printf("splash_bmp: No appropriate video mode found\n");
1051243dad0SKazutaka YOKOTA     if (bootverbose)
1061243dad0SKazutaka YOKOTA 	printf("bmp_start(): splash_mode:%d\n", splash_mode);
1071243dad0SKazutaka YOKOTA     return ((splash_mode < 0) ? ENODEV : 0);
1081243dad0SKazutaka YOKOTA }
1091243dad0SKazutaka YOKOTA 
1101243dad0SKazutaka YOKOTA static int
1111243dad0SKazutaka YOKOTA bmp_end(video_adapter_t *adp)
1121243dad0SKazutaka YOKOTA {
1131243dad0SKazutaka YOKOTA     /* nothing to do */
1141243dad0SKazutaka YOKOTA     return 0;
1151243dad0SKazutaka YOKOTA }
1161243dad0SKazutaka YOKOTA 
1171243dad0SKazutaka YOKOTA static int
1181243dad0SKazutaka YOKOTA bmp_splash(video_adapter_t *adp, int on)
1191243dad0SKazutaka YOKOTA {
1201243dad0SKazutaka YOKOTA     static u_char	pal[256*3];
1211243dad0SKazutaka YOKOTA     static long		time_stamp;
122ccd48159SKazutaka YOKOTA     u_char		tpal[256*3];
123ccd48159SKazutaka YOKOTA     static int		fading = TRUE, brightness = FADE_LEVELS;
1241243dad0SKazutaka YOKOTA     struct timeval	tv;
1251243dad0SKazutaka YOKOTA     int			i;
1261243dad0SKazutaka YOKOTA 
1271243dad0SKazutaka YOKOTA     if (on) {
1281243dad0SKazutaka YOKOTA 	if (!splash_on) {
1291243dad0SKazutaka YOKOTA 	    /* set up the video mode and draw something */
1301243dad0SKazutaka YOKOTA 	    if ((*vidsw[adp->va_index]->set_mode)(adp, splash_mode))
1311243dad0SKazutaka YOKOTA 		return 1;
1321243dad0SKazutaka YOKOTA 	    if (bmp_Draw(adp))
1331243dad0SKazutaka YOKOTA 		return 1;
1341243dad0SKazutaka YOKOTA 	    (*vidsw[adp->va_index]->save_palette)(adp, pal);
1351243dad0SKazutaka YOKOTA 	    time_stamp = 0;
1361243dad0SKazutaka YOKOTA 	    splash_on = TRUE;
1371243dad0SKazutaka YOKOTA 	}
1381243dad0SKazutaka YOKOTA 	/*
1391243dad0SKazutaka YOKOTA 	 * This is a kludge to fade the image away.  This section of the
1401243dad0SKazutaka YOKOTA 	 * code takes effect only after the system is completely up.
141325fca90SKazutaka YOKOTA 	 * FADE_TIMEOUT should be configurable.
1421243dad0SKazutaka YOKOTA 	 */
1431243dad0SKazutaka YOKOTA 	if (!cold) {
1441243dad0SKazutaka YOKOTA 	    getmicrotime(&tv);
1451243dad0SKazutaka YOKOTA 	    if (time_stamp == 0)
1461243dad0SKazutaka YOKOTA 		time_stamp = tv.tv_sec;
1471243dad0SKazutaka YOKOTA 	    if (tv.tv_sec > time_stamp + FADE_TIMEOUT) {
148ccd48159SKazutaka YOKOTA 		if (fading)
149ccd48159SKazutaka YOKOTA 		    if (brightness == 0) {
150ccd48159SKazutaka YOKOTA 			fading = FALSE;
151ccd48159SKazutaka YOKOTA 			brightness++;
1521243dad0SKazutaka YOKOTA 		    }
153ccd48159SKazutaka YOKOTA 		    else brightness--;
154ccd48159SKazutaka YOKOTA 		else
155ccd48159SKazutaka YOKOTA 		    if (brightness == FADE_LEVELS) {
156ccd48159SKazutaka YOKOTA 			fading = TRUE;
157ccd48159SKazutaka YOKOTA 			brightness--;
158ccd48159SKazutaka YOKOTA 		    }
159ccd48159SKazutaka YOKOTA 		    else brightness++;
160ccd48159SKazutaka YOKOTA 		for (i = 0; i < sizeof(pal); ++i) {
161ccd48159SKazutaka YOKOTA 		    tpal[i] = pal[i] * brightness / FADE_LEVELS;
162ccd48159SKazutaka YOKOTA 		}
163ccd48159SKazutaka YOKOTA 		(*vidsw[adp->va_index]->load_palette)(adp, tpal);
164ccd48159SKazutaka YOKOTA 		time_stamp = tv.tv_sec;
1651243dad0SKazutaka YOKOTA 	    }
1661243dad0SKazutaka YOKOTA 	}
1671243dad0SKazutaka YOKOTA 	return 0;
1681243dad0SKazutaka YOKOTA     } else {
1691243dad0SKazutaka YOKOTA 	/* the video mode will be restored by the caller */
1701243dad0SKazutaka YOKOTA 	splash_on = FALSE;
1711243dad0SKazutaka YOKOTA 	return 0;
1721243dad0SKazutaka YOKOTA     }
1731243dad0SKazutaka YOKOTA }
1741243dad0SKazutaka YOKOTA 
1751243dad0SKazutaka YOKOTA /*
1761243dad0SKazutaka YOKOTA ** Code to handle Microsoft DIB (".BMP") format images.
1771243dad0SKazutaka YOKOTA **
1781243dad0SKazutaka YOKOTA ** Blame me (msmith@freebsd.org) if this is broken, not Soren.
1791243dad0SKazutaka YOKOTA */
1801243dad0SKazutaka YOKOTA 
1811243dad0SKazutaka YOKOTA typedef struct tagBITMAPFILEHEADER {    /* bmfh */
1824f492bfaSAlfred Perlstein     u_short	bfType		__packed;
1834f492bfaSAlfred Perlstein     int		bfSize		__packed;
1844f492bfaSAlfred Perlstein     u_short	bfReserved1	__packed;
1854f492bfaSAlfred Perlstein     u_short	bfReserved2	__packed;
1864f492bfaSAlfred Perlstein     int		bfOffBits	__packed;
1871243dad0SKazutaka YOKOTA } BITMAPFILEHEADER;
1881243dad0SKazutaka YOKOTA 
1891243dad0SKazutaka YOKOTA typedef struct tagBITMAPINFOHEADER {    /* bmih */
1904f492bfaSAlfred Perlstein     int		biSize		__packed;
1914f492bfaSAlfred Perlstein     int		biWidth		__packed;
1924f492bfaSAlfred Perlstein     int		biHeight	__packed;
1934f492bfaSAlfred Perlstein     short	biPlanes	__packed;
1944f492bfaSAlfred Perlstein     short	biBitCount	__packed;
1954f492bfaSAlfred Perlstein     int		biCompression	__packed;
1964f492bfaSAlfred Perlstein     int		biSizeImage	__packed;
1974f492bfaSAlfred Perlstein     int		biXPelsPerMeter	__packed;
1984f492bfaSAlfred Perlstein     int		biYPelsPerMeter	__packed;
1994f492bfaSAlfred Perlstein     int		biClrUsed	__packed;
2004f492bfaSAlfred Perlstein     int		biClrImportant	__packed;
2011243dad0SKazutaka YOKOTA } BITMAPINFOHEADER;
2021243dad0SKazutaka YOKOTA 
2031243dad0SKazutaka YOKOTA typedef struct tagRGBQUAD {     /* rgbq */
2044f492bfaSAlfred Perlstein     u_char	rgbBlue		__packed;
2054f492bfaSAlfred Perlstein     u_char	rgbGreen	__packed;
2064f492bfaSAlfred Perlstein     u_char	rgbRed		__packed;
2074f492bfaSAlfred Perlstein     u_char	rgbReserved	__packed;
2081243dad0SKazutaka YOKOTA } RGBQUAD;
2091243dad0SKazutaka YOKOTA 
2101243dad0SKazutaka YOKOTA typedef struct tagBITMAPINFO {  /* bmi */
2114f492bfaSAlfred Perlstein     BITMAPINFOHEADER	bmiHeader	__packed;
2124f492bfaSAlfred Perlstein     RGBQUAD		bmiColors[256]	__packed;
2131243dad0SKazutaka YOKOTA } BITMAPINFO;
2141243dad0SKazutaka YOKOTA 
2151243dad0SKazutaka YOKOTA typedef struct tagBITMAPF
2161243dad0SKazutaka YOKOTA {
2174f492bfaSAlfred Perlstein     BITMAPFILEHEADER	bmfh	__packed;
2184f492bfaSAlfred Perlstein     BITMAPINFO		bmfi	__packed;
2191243dad0SKazutaka YOKOTA } BITMAPF;
2201243dad0SKazutaka YOKOTA 
2211243dad0SKazutaka YOKOTA #define BI_RGB		0
2221243dad0SKazutaka YOKOTA #define BI_RLE8		1
2231243dad0SKazutaka YOKOTA #define BI_RLE4		2
2241243dad0SKazutaka YOKOTA 
2251243dad0SKazutaka YOKOTA /*
2261243dad0SKazutaka YOKOTA ** all we actually care about the image
2271243dad0SKazutaka YOKOTA */
2281243dad0SKazutaka YOKOTA typedef struct
2291243dad0SKazutaka YOKOTA {
2301243dad0SKazutaka YOKOTA     int		width,height;		/* image dimensions */
2311243dad0SKazutaka YOKOTA     int		swidth,sheight;		/* screen dimensions for the current mode */
23299feb462SKazutaka YOKOTA     u_char	depth;			/* image depth (1, 4, 8, 24 bits) */
2331243dad0SKazutaka YOKOTA     u_char	sdepth;			/* screen depth (1, 4, 8 bpp) */
2341243dad0SKazutaka YOKOTA     int		ncols;			/* number of colours */
2351243dad0SKazutaka YOKOTA     u_char	palette[256][3];	/* raw palette data */
2361243dad0SKazutaka YOKOTA     u_char	format;			/* one of the BI_* constants above */
2371243dad0SKazutaka YOKOTA     u_char	*data;			/* pointer to the raw data */
2381243dad0SKazutaka YOKOTA     u_char	*index;			/* running pointer to the data while drawing */
2391243dad0SKazutaka YOKOTA     u_char	*vidmem;		/* video memory allocated for drawing */
240325fca90SKazutaka YOKOTA     video_adapter_t *adp;
241325fca90SKazutaka YOKOTA     int		bank;
242cb4860b7SYoshihiro Takahashi #ifdef PC98
243cb4860b7SYoshihiro Takahashi     u_char	prev_val;
244cb4860b7SYoshihiro Takahashi #endif
2451243dad0SKazutaka YOKOTA } BMP_INFO;
2461243dad0SKazutaka YOKOTA 
2471243dad0SKazutaka YOKOTA static BMP_INFO bmp_info;
2481243dad0SKazutaka YOKOTA 
2491243dad0SKazutaka YOKOTA /*
2501243dad0SKazutaka YOKOTA ** bmp_SetPix
2511243dad0SKazutaka YOKOTA **
2521243dad0SKazutaka YOKOTA ** Given (info), set the pixel at (x),(y) to (val)
2531243dad0SKazutaka YOKOTA **
2541243dad0SKazutaka YOKOTA */
2551243dad0SKazutaka YOKOTA static void
2561243dad0SKazutaka YOKOTA bmp_SetPix(BMP_INFO *info, int x, int y, u_char val)
2571243dad0SKazutaka YOKOTA {
2581243dad0SKazutaka YOKOTA     int		sofs, bofs;
259325fca90SKazutaka YOKOTA     int		newbank;
2601243dad0SKazutaka YOKOTA 
2611243dad0SKazutaka YOKOTA     /*
2621243dad0SKazutaka YOKOTA      * range check to avoid explosions
2631243dad0SKazutaka YOKOTA      */
2641243dad0SKazutaka YOKOTA     if ((x < 0) || (x >= info->swidth) || (y < 0) || (y >= info->sheight))
2651243dad0SKazutaka YOKOTA 	return;
2661243dad0SKazutaka YOKOTA 
2671243dad0SKazutaka YOKOTA     /*
2681243dad0SKazutaka YOKOTA      * calculate offset into video memory;
2691243dad0SKazutaka YOKOTA      * because 0,0 is bottom-left for DIB, we have to convert.
2701243dad0SKazutaka YOKOTA      */
2711243dad0SKazutaka YOKOTA     sofs = ((info->height - (y+1) + (info->sheight - info->height) / 2)
2721c27745fSKazutaka YOKOTA 		* info->adp->va_line_width);
27399feb462SKazutaka YOKOTA     x += (info->swidth - info->width) / 2;
2741243dad0SKazutaka YOKOTA 
2751243dad0SKazutaka YOKOTA     switch(info->sdepth) {
276cb4860b7SYoshihiro Takahashi #ifdef PC98
277cb4860b7SYoshihiro Takahashi     case 4:
278cb4860b7SYoshihiro Takahashi 	sofs += (x >> 3);
279cb4860b7SYoshihiro Takahashi 	bofs = x & 0x7;				/* offset within byte */
280cb4860b7SYoshihiro Takahashi 
281cb4860b7SYoshihiro Takahashi 	outb(0x7c, 0x80 | 0x40);	/* GRCG on & RMW mode */
282cb4860b7SYoshihiro Takahashi 	if (val != info->prev_val) {
283cb4860b7SYoshihiro Takahashi 	    outb(0x7e, (val & 1) ? 0xff : 0);	/* tile B */
284cb4860b7SYoshihiro Takahashi 	    outb(0x7e, (val & 2) ? 0xff : 0);	/* tile R */
285cb4860b7SYoshihiro Takahashi 	    outb(0x7e, (val & 4) ? 0xff : 0);	/* tile G */
286cb4860b7SYoshihiro Takahashi 	    outb(0x7e, (val & 8) ? 0xff : 0);	/* tile I */
287cb4860b7SYoshihiro Takahashi 
288cb4860b7SYoshihiro Takahashi 	    info->prev_val = val;
289cb4860b7SYoshihiro Takahashi 	}
290cb4860b7SYoshihiro Takahashi 
291cb4860b7SYoshihiro Takahashi 	*(info->vidmem+sofs) = (0x80 >> bofs);	/* write new bit */
292cb4860b7SYoshihiro Takahashi 	outb(0x7c, 0);		/* GRCG off */
293cb4860b7SYoshihiro Takahashi 	break;
294cb4860b7SYoshihiro Takahashi #else
2951243dad0SKazutaka YOKOTA     case 4:
29699feb462SKazutaka YOKOTA     case 1:
29799feb462SKazutaka YOKOTA 	/* EGA/VGA planar modes */
29899feb462SKazutaka YOKOTA 	sofs += (x >> 3);
29999feb462SKazutaka YOKOTA 	newbank = sofs/info->adp->va_window_size;
30099feb462SKazutaka YOKOTA 	if (info->bank != newbank) {
30199feb462SKazutaka YOKOTA 	    (*vidsw[info->adp->va_index]->set_win_org)(info->adp, newbank*info->adp->va_window_size);
30299feb462SKazutaka YOKOTA 	    info->bank = newbank;
30399feb462SKazutaka YOKOTA 	}
30499feb462SKazutaka YOKOTA 	sofs %= info->adp->va_window_size;
30599feb462SKazutaka YOKOTA 	bofs = x & 0x7;				/* offset within byte */
30699feb462SKazutaka YOKOTA 	outw(GDCIDX, (0x8000 >> bofs) | 0x08);	/* bit mask */
30799feb462SKazutaka YOKOTA 	outw(GDCIDX, (val << 8) | 0x00);	/* set/reset */
30899feb462SKazutaka YOKOTA 	*(info->vidmem + sofs) ^= 0xff;		/* read-modify-write */
3091243dad0SKazutaka YOKOTA 	break;
310cb4860b7SYoshihiro Takahashi #endif
3111243dad0SKazutaka YOKOTA 
3121243dad0SKazutaka YOKOTA     case 8:
31399feb462SKazutaka YOKOTA 	sofs += x;
314325fca90SKazutaka YOKOTA 	newbank = sofs/info->adp->va_window_size;
315325fca90SKazutaka YOKOTA 	if (info->bank != newbank) {
316325fca90SKazutaka YOKOTA 	    (*vidsw[info->adp->va_index]->set_win_org)(info->adp, newbank*info->adp->va_window_size);
317325fca90SKazutaka YOKOTA 	    info->bank = newbank;
318325fca90SKazutaka YOKOTA 	}
319325fca90SKazutaka YOKOTA 	sofs %= info->adp->va_window_size;
3201243dad0SKazutaka YOKOTA 	*(info->vidmem+sofs) = val;
3211243dad0SKazutaka YOKOTA 	break;
3221243dad0SKazutaka YOKOTA     }
3231243dad0SKazutaka YOKOTA }
3241243dad0SKazutaka YOKOTA 
3251243dad0SKazutaka YOKOTA /*
3261243dad0SKazutaka YOKOTA ** bmp_DecodeRLE4
3271243dad0SKazutaka YOKOTA **
3281243dad0SKazutaka YOKOTA ** Given (data) pointing to a line of RLE4-format data and (line) being the starting
3291243dad0SKazutaka YOKOTA ** line onscreen, decode the line.
3301243dad0SKazutaka YOKOTA */
3311243dad0SKazutaka YOKOTA static void
3321243dad0SKazutaka YOKOTA bmp_DecodeRLE4(BMP_INFO *info, int line)
3331243dad0SKazutaka YOKOTA {
3341243dad0SKazutaka YOKOTA     int		count;		/* run count */
3351243dad0SKazutaka YOKOTA     u_char	val;
3361243dad0SKazutaka YOKOTA     int		x,y;		/* screen position */
3371243dad0SKazutaka YOKOTA 
3381243dad0SKazutaka YOKOTA     x = 0;			/* starting position */
3391243dad0SKazutaka YOKOTA     y = line;
3401243dad0SKazutaka YOKOTA 
3411243dad0SKazutaka YOKOTA     /* loop reading data */
3421243dad0SKazutaka YOKOTA     for (;;) {
3431243dad0SKazutaka YOKOTA 	/*
3441243dad0SKazutaka YOKOTA 	 * encoded mode starts with a run length, and then a byte with
3451243dad0SKazutaka YOKOTA 	 * two colour indexes to alternate between for the run
3461243dad0SKazutaka YOKOTA 	 */
3471243dad0SKazutaka YOKOTA 	if (*info->index) {
3481243dad0SKazutaka YOKOTA 	    for (count = 0; count < *info->index; count++, x++) {
3491243dad0SKazutaka YOKOTA 		if (count & 1) {		/* odd count, low nybble */
3501243dad0SKazutaka YOKOTA 		    bmp_SetPix(info, x, y, *(info->index+1) & 0x0f);
3511243dad0SKazutaka YOKOTA 		} else {			/* even count, high nybble */
3521243dad0SKazutaka YOKOTA 		    bmp_SetPix(info, x, y, (*(info->index+1) >>4) & 0x0f);
3531243dad0SKazutaka YOKOTA 		}
3541243dad0SKazutaka YOKOTA 	    }
3551243dad0SKazutaka YOKOTA 	    info->index += 2;
3561243dad0SKazutaka YOKOTA         /*
3571243dad0SKazutaka YOKOTA 	 * A leading zero is an escape; it may signal the end of the
3581243dad0SKazutaka YOKOTA 	 * bitmap, a cursor move, or some absolute data.
3591243dad0SKazutaka YOKOTA 	 */
3601243dad0SKazutaka YOKOTA 	} else {	/* zero tag may be absolute mode or an escape */
3611243dad0SKazutaka YOKOTA 	    switch (*(info->index+1)) {
3621243dad0SKazutaka YOKOTA 	    case 0:				/* end of line */
3631243dad0SKazutaka YOKOTA 		info->index += 2;
3641243dad0SKazutaka YOKOTA 		return;
3651243dad0SKazutaka YOKOTA 	    case 1:				/* end of bitmap */
3661243dad0SKazutaka YOKOTA 		info->index = NULL;
3671243dad0SKazutaka YOKOTA 		return;
3681243dad0SKazutaka YOKOTA 	    case 2:				/* move */
3691243dad0SKazutaka YOKOTA 		x += *(info->index + 2);	/* new coords */
3701243dad0SKazutaka YOKOTA 		y += *(info->index + 3);
3711243dad0SKazutaka YOKOTA 		info->index += 4;
3721243dad0SKazutaka YOKOTA 		break;
3731243dad0SKazutaka YOKOTA 	    default:				/* literal bitmap data */
3741243dad0SKazutaka YOKOTA 		for (count = 0; count < *(info->index + 1); count++, x++) {
3751243dad0SKazutaka YOKOTA 		    val = *(info->index + 2 + (count / 2));	/* byte with nybbles */
3761243dad0SKazutaka YOKOTA 		    if (count & 1) {
3771243dad0SKazutaka YOKOTA 			val &= 0xf;		/* get low nybble */
3781243dad0SKazutaka YOKOTA 		    } else {
3791243dad0SKazutaka YOKOTA 			val = (val >> 4);	/* get high nybble */
3801243dad0SKazutaka YOKOTA 		    }
3811243dad0SKazutaka YOKOTA 		    bmp_SetPix(info, x, y, val);
3821243dad0SKazutaka YOKOTA 		}
3831243dad0SKazutaka YOKOTA 		/* warning, this depends on integer truncation, do not hand-optimise! */
3841243dad0SKazutaka YOKOTA 		info->index += 2 + ((count + 3) / 4) * 2;
3851243dad0SKazutaka YOKOTA 		break;
3861243dad0SKazutaka YOKOTA 	    }
3871243dad0SKazutaka YOKOTA 	}
3881243dad0SKazutaka YOKOTA     }
3891243dad0SKazutaka YOKOTA }
3901243dad0SKazutaka YOKOTA 
3911243dad0SKazutaka YOKOTA /*
3921243dad0SKazutaka YOKOTA ** bmp_DecodeRLE8
39399feb462SKazutaka YOKOTA ** Given (data) pointing to a line of RLE8-format data and (line) being the starting
3941243dad0SKazutaka YOKOTA ** line onscreen, decode the line.
3951243dad0SKazutaka YOKOTA */
3961243dad0SKazutaka YOKOTA static void
3971243dad0SKazutaka YOKOTA bmp_DecodeRLE8(BMP_INFO *info, int line)
3981243dad0SKazutaka YOKOTA {
3991243dad0SKazutaka YOKOTA     int		count;		/* run count */
4001243dad0SKazutaka YOKOTA     int		x,y;		/* screen position */
4011243dad0SKazutaka YOKOTA 
4021243dad0SKazutaka YOKOTA     x = 0;			/* starting position */
4031243dad0SKazutaka YOKOTA     y = line;
4041243dad0SKazutaka YOKOTA 
4051243dad0SKazutaka YOKOTA     /* loop reading data */
4061243dad0SKazutaka YOKOTA     for(;;) {
4071243dad0SKazutaka YOKOTA 	/*
4081243dad0SKazutaka YOKOTA 	 * encoded mode starts with a run length, and then a byte with
4091243dad0SKazutaka YOKOTA 	 * two colour indexes to alternate between for the run
4101243dad0SKazutaka YOKOTA 	 */
4111243dad0SKazutaka YOKOTA 	if (*info->index) {
4121243dad0SKazutaka YOKOTA 	    for (count = 0; count < *info->index; count++, x++)
4131243dad0SKazutaka YOKOTA 		bmp_SetPix(info, x, y, *(info->index+1));
4141243dad0SKazutaka YOKOTA 	    info->index += 2;
4151243dad0SKazutaka YOKOTA         /*
4161243dad0SKazutaka YOKOTA 	 * A leading zero is an escape; it may signal the end of the
4171243dad0SKazutaka YOKOTA 	 * bitmap, a cursor move, or some absolute data.
4181243dad0SKazutaka YOKOTA 	 */
4191243dad0SKazutaka YOKOTA 	} else {	/* zero tag may be absolute mode or an escape */
4201243dad0SKazutaka YOKOTA 	    switch(*(info->index+1)) {
4211243dad0SKazutaka YOKOTA 	    case 0:				/* end of line */
4221243dad0SKazutaka YOKOTA 		info->index += 2;
4231243dad0SKazutaka YOKOTA 		return;
4241243dad0SKazutaka YOKOTA 	    case 1:				/* end of bitmap */
4251243dad0SKazutaka YOKOTA 		info->index = NULL;
4261243dad0SKazutaka YOKOTA 		return;
4271243dad0SKazutaka YOKOTA 	    case 2:				/* move */
4281243dad0SKazutaka YOKOTA 		x += *(info->index + 2);	/* new coords */
4291243dad0SKazutaka YOKOTA 		y += *(info->index + 3);
4301243dad0SKazutaka YOKOTA 		info->index += 4;
4311243dad0SKazutaka YOKOTA 		break;
4321243dad0SKazutaka YOKOTA 	    default:				/* literal bitmap data */
4331243dad0SKazutaka YOKOTA 		for (count = 0; count < *(info->index + 1); count++, x++)
4341243dad0SKazutaka YOKOTA 		    bmp_SetPix(info, x, y, *(info->index + 2 + count));
4351243dad0SKazutaka YOKOTA 		/* must be an even count */
4361243dad0SKazutaka YOKOTA 		info->index += 2 + count + (count & 1);
4371243dad0SKazutaka YOKOTA 		break;
4381243dad0SKazutaka YOKOTA 	    }
4391243dad0SKazutaka YOKOTA 	}
4401243dad0SKazutaka YOKOTA     }
4411243dad0SKazutaka YOKOTA }
4421243dad0SKazutaka YOKOTA 
4431243dad0SKazutaka YOKOTA /*
4441243dad0SKazutaka YOKOTA ** bmp_DecodeLine
4451243dad0SKazutaka YOKOTA **
4461243dad0SKazutaka YOKOTA ** Given (info) pointing to an image being decoded, (line) being the line currently
4471243dad0SKazutaka YOKOTA ** being displayed, decode a line of data.
4481243dad0SKazutaka YOKOTA */
4491243dad0SKazutaka YOKOTA static void
4501243dad0SKazutaka YOKOTA bmp_DecodeLine(BMP_INFO *info, int line)
4511243dad0SKazutaka YOKOTA {
4521243dad0SKazutaka YOKOTA     int		x;
45399feb462SKazutaka YOKOTA     u_char	val, mask, *p;
4541243dad0SKazutaka YOKOTA 
4551243dad0SKazutaka YOKOTA     switch(info->format) {
4561243dad0SKazutaka YOKOTA     case BI_RGB:
45799feb462SKazutaka YOKOTA     	switch(info->depth) {
45899feb462SKazutaka YOKOTA 	case 8:
4591243dad0SKazutaka YOKOTA 	    for (x = 0; x < info->width; x++, info->index++)
4601243dad0SKazutaka YOKOTA 		bmp_SetPix(info, x, line, *info->index);
46161329bceSKazutaka YOKOTA 	    info->index += 3 - (--x % 4);
4621243dad0SKazutaka YOKOTA 	    break;
46399feb462SKazutaka YOKOTA 	case 4:
46499feb462SKazutaka YOKOTA 	    p = info->index;
46599feb462SKazutaka YOKOTA 	    for (x = 0; x < info->width; x++) {
46699feb462SKazutaka YOKOTA 		if (x & 1) {
46799feb462SKazutaka YOKOTA 		    val = *p & 0xf;	/* get low nybble */
46899feb462SKazutaka YOKOTA 		    p++;
46999feb462SKazutaka YOKOTA 		} else {
47099feb462SKazutaka YOKOTA 		    val = *p >> 4;	/* get high nybble */
47199feb462SKazutaka YOKOTA 		}
47299feb462SKazutaka YOKOTA 		bmp_SetPix(info, x, line, val);
47399feb462SKazutaka YOKOTA 	    }
47499feb462SKazutaka YOKOTA 	    /* warning, this depends on integer truncation, do not hand-optimise! */
47599feb462SKazutaka YOKOTA 	    info->index += ((x + 7) / 8) * 4;
47699feb462SKazutaka YOKOTA 	    break;
47799feb462SKazutaka YOKOTA 	case 1:
47899feb462SKazutaka YOKOTA 	    p = info->index;
47999feb462SKazutaka YOKOTA 	    mask = 0x80;
48099feb462SKazutaka YOKOTA 	    for (x = 0; x < info->width; x++) {
48199feb462SKazutaka YOKOTA 		val = (*p & mask) ? 1 : 0;
48299feb462SKazutaka YOKOTA 		mask >>= 1;
48399feb462SKazutaka YOKOTA 		if (mask == 0) {
48499feb462SKazutaka YOKOTA 		    mask = 0x80;
48599feb462SKazutaka YOKOTA 		    p++;
48699feb462SKazutaka YOKOTA 		}
48799feb462SKazutaka YOKOTA 		bmp_SetPix(info, x, line, val);
48899feb462SKazutaka YOKOTA 	    }
48999feb462SKazutaka YOKOTA 	    /* warning, this depends on integer truncation, do not hand-optimise! */
49099feb462SKazutaka YOKOTA 	    info->index += ((x + 31) / 32) * 4;
49199feb462SKazutaka YOKOTA 	    break;
49299feb462SKazutaka YOKOTA 	}
49399feb462SKazutaka YOKOTA 	break;
4941243dad0SKazutaka YOKOTA     case BI_RLE4:
4951243dad0SKazutaka YOKOTA 	bmp_DecodeRLE4(info, line);
4961243dad0SKazutaka YOKOTA 	break;
4971243dad0SKazutaka YOKOTA     case BI_RLE8:
4981243dad0SKazutaka YOKOTA 	bmp_DecodeRLE8(info, line);
4991243dad0SKazutaka YOKOTA 	break;
5001243dad0SKazutaka YOKOTA     }
5011243dad0SKazutaka YOKOTA }
5021243dad0SKazutaka YOKOTA 
5031243dad0SKazutaka YOKOTA /*
5041243dad0SKazutaka YOKOTA ** bmp_Init
5051243dad0SKazutaka YOKOTA **
5061243dad0SKazutaka YOKOTA ** Given a pointer (data) to the image of a BMP file, fill in bmp_info with what
5071243dad0SKazutaka YOKOTA ** can be learnt from it.  Return nonzero if the file isn't usable.
5081243dad0SKazutaka YOKOTA **
5091243dad0SKazutaka YOKOTA ** Take screen dimensions (swidth), (sheight) and (sdepth) and make sure we
5101243dad0SKazutaka YOKOTA ** can work with these.
5111243dad0SKazutaka YOKOTA */
5121243dad0SKazutaka YOKOTA static int
51397be736aSMaxime Henrion bmp_Init(char *data, int swidth, int sheight, int sdepth)
5141243dad0SKazutaka YOKOTA {
5151243dad0SKazutaka YOKOTA     BITMAPF	*bmf = (BITMAPF *)data;
5161243dad0SKazutaka YOKOTA     int		pind;
5171243dad0SKazutaka YOKOTA 
5181243dad0SKazutaka YOKOTA     bmp_info.data = NULL;	/* assume setup failed */
5191243dad0SKazutaka YOKOTA 
5201243dad0SKazutaka YOKOTA     /* check file ID */
5211243dad0SKazutaka YOKOTA     if (bmf->bmfh.bfType != 0x4d42) {
5225c539f03SKazutaka YOKOTA 	printf("splash_bmp: not a BMP file\n");
5231243dad0SKazutaka YOKOTA 	return(1);		/* XXX check word ordering for big-endian ports? */
5241243dad0SKazutaka YOKOTA     }
5251243dad0SKazutaka YOKOTA 
5265c539f03SKazutaka YOKOTA     /* do we understand this bitmap format? */
5275c539f03SKazutaka YOKOTA     if (bmf->bmfi.bmiHeader.biSize > sizeof(bmf->bmfi.bmiHeader)) {
5285c539f03SKazutaka YOKOTA 	printf("splash_bmp: unsupported BMP format (size=%d)\n",
5295c539f03SKazutaka YOKOTA 		bmf->bmfi.bmiHeader.biSize);
5305c539f03SKazutaka YOKOTA 	return(1);
5315c539f03SKazutaka YOKOTA     }
5325c539f03SKazutaka YOKOTA 
5331243dad0SKazutaka YOKOTA     /* save what we know about the screen */
5341243dad0SKazutaka YOKOTA     bmp_info.swidth = swidth;
5351243dad0SKazutaka YOKOTA     bmp_info.sheight = sheight;
5361243dad0SKazutaka YOKOTA     bmp_info.sdepth = sdepth;
5371243dad0SKazutaka YOKOTA 
5381243dad0SKazutaka YOKOTA     /* where's the data? */
5391243dad0SKazutaka YOKOTA     bmp_info.data = (u_char *)data + bmf->bmfh.bfOffBits;
5401243dad0SKazutaka YOKOTA 
5411243dad0SKazutaka YOKOTA     /* image parameters */
5421243dad0SKazutaka YOKOTA     bmp_info.width = bmf->bmfi.bmiHeader.biWidth;
5431243dad0SKazutaka YOKOTA     bmp_info.height = bmf->bmfi.bmiHeader.biHeight;
54499feb462SKazutaka YOKOTA     bmp_info.depth = bmf->bmfi.bmiHeader.biBitCount;
5451243dad0SKazutaka YOKOTA     bmp_info.format = bmf->bmfi.bmiHeader.biCompression;
5461243dad0SKazutaka YOKOTA 
5471243dad0SKazutaka YOKOTA     switch(bmp_info.format) {	/* check compression format */
5481243dad0SKazutaka YOKOTA     case BI_RGB:
5491243dad0SKazutaka YOKOTA     case BI_RLE4:
5501243dad0SKazutaka YOKOTA     case BI_RLE8:
5511243dad0SKazutaka YOKOTA 	break;
5521243dad0SKazutaka YOKOTA     default:
5535c539f03SKazutaka YOKOTA 	printf("splash_bmp: unsupported compression format\n");
5541243dad0SKazutaka YOKOTA 	return(1);		/* unsupported compression format */
5551243dad0SKazutaka YOKOTA     }
5561243dad0SKazutaka YOKOTA 
5571243dad0SKazutaka YOKOTA     /* palette details */
5581243dad0SKazutaka YOKOTA     bmp_info.ncols = (bmf->bmfi.bmiHeader.biClrUsed);
5591243dad0SKazutaka YOKOTA     bzero(bmp_info.palette,sizeof(bmp_info.palette));
5601243dad0SKazutaka YOKOTA     if (bmp_info.ncols == 0) {	/* uses all of them */
56115401862SKazutaka YOKOTA 	bmp_info.ncols = 1 << bmf->bmfi.bmiHeader.biBitCount;
5621243dad0SKazutaka YOKOTA     }
5631243dad0SKazutaka YOKOTA     if ((bmp_info.height > bmp_info.sheight) ||
5641243dad0SKazutaka YOKOTA 	(bmp_info.width > bmp_info.swidth) ||
5651243dad0SKazutaka YOKOTA 	(bmp_info.ncols > (1 << sdepth))) {
56699feb462SKazutaka YOKOTA 	if (bootverbose)
56799feb462SKazutaka YOKOTA 	    printf("splash_bmp: beyond screen capacity (%dx%d, %d colors)\n",
56899feb462SKazutaka YOKOTA 		   bmp_info.width, bmp_info.height, bmp_info.ncols);
56999feb462SKazutaka YOKOTA 	return(1);
5701243dad0SKazutaka YOKOTA     }
5711243dad0SKazutaka YOKOTA 
5721243dad0SKazutaka YOKOTA     /* read palette */
5731243dad0SKazutaka YOKOTA     for (pind = 0; pind < bmp_info.ncols; pind++) {
5741243dad0SKazutaka YOKOTA 	bmp_info.palette[pind][0] = bmf->bmfi.bmiColors[pind].rgbRed;
5751243dad0SKazutaka YOKOTA 	bmp_info.palette[pind][1] = bmf->bmfi.bmiColors[pind].rgbGreen;
5761243dad0SKazutaka YOKOTA 	bmp_info.palette[pind][2] = bmf->bmfi.bmiColors[pind].rgbBlue;
5771243dad0SKazutaka YOKOTA     }
5781243dad0SKazutaka YOKOTA     return(0);
5791243dad0SKazutaka YOKOTA }
5801243dad0SKazutaka YOKOTA 
5811243dad0SKazutaka YOKOTA /*
5821243dad0SKazutaka YOKOTA ** bmp_Draw
5831243dad0SKazutaka YOKOTA **
5841243dad0SKazutaka YOKOTA ** Render the image.  Return nonzero if that's not possible.
5851243dad0SKazutaka YOKOTA **
5861243dad0SKazutaka YOKOTA */
5871243dad0SKazutaka YOKOTA static int
5881243dad0SKazutaka YOKOTA bmp_Draw(video_adapter_t *adp)
5891243dad0SKazutaka YOKOTA {
5901243dad0SKazutaka YOKOTA     int		line;
591b67cb277SJohn Baldwin #if 0
592b67cb277SJohn Baldwin #ifndef PC98
59399feb462SKazutaka YOKOTA     int		i;
594b67cb277SJohn Baldwin #endif
595b67cb277SJohn Baldwin #endif
5961243dad0SKazutaka YOKOTA 
5971243dad0SKazutaka YOKOTA     if (bmp_info.data == NULL) {	/* init failed, do nothing */
5981243dad0SKazutaka YOKOTA 	return(1);
5991243dad0SKazutaka YOKOTA     }
6001243dad0SKazutaka YOKOTA 
6011243dad0SKazutaka YOKOTA     /* clear the screen */
6021243dad0SKazutaka YOKOTA     bmp_info.vidmem = (u_char *)adp->va_window;
603325fca90SKazutaka YOKOTA     bmp_info.adp = adp;
60499feb462SKazutaka YOKOTA     (*vidsw[adp->va_index]->clear)(adp);
605325fca90SKazutaka YOKOTA     (*vidsw[adp->va_index]->set_win_org)(adp, 0);
606325fca90SKazutaka YOKOTA     bmp_info.bank = 0;
6071243dad0SKazutaka YOKOTA 
6081243dad0SKazutaka YOKOTA     /* initialise the info structure for drawing */
6091243dad0SKazutaka YOKOTA     bmp_info.index = bmp_info.data;
610cb4860b7SYoshihiro Takahashi #ifdef PC98
611cb4860b7SYoshihiro Takahashi     bmp_info.prev_val = 255;
612cb4860b7SYoshihiro Takahashi #endif
6131243dad0SKazutaka YOKOTA 
6141243dad0SKazutaka YOKOTA     /* set the palette for our image */
6151243dad0SKazutaka YOKOTA     (*vidsw[adp->va_index]->load_palette)(adp, (u_char *)&bmp_info.palette);
6161243dad0SKazutaka YOKOTA 
617168d542eSYoshihiro Takahashi #if 0
618cb4860b7SYoshihiro Takahashi #ifndef PC98
61999feb462SKazutaka YOKOTA     /* XXX: this is ugly, but necessary for EGA/VGA 1bpp/4bpp modes */
62099feb462SKazutaka YOKOTA     if ((adp->va_type == KD_EGA) || (adp->va_type == KD_VGA)) {
62199feb462SKazutaka YOKOTA 	inb(adp->va_crtc_addr + 6);		/* reset flip-flop */
62299feb462SKazutaka YOKOTA 	outb(ATC, 0x14);
62399feb462SKazutaka YOKOTA 	outb(ATC, 0);
62499feb462SKazutaka YOKOTA 	for (i = 0; i < 16; ++i) {
62599feb462SKazutaka YOKOTA 	    outb(ATC, i);
62699feb462SKazutaka YOKOTA 	    outb(ATC, i);
62799feb462SKazutaka YOKOTA 	}
62899feb462SKazutaka YOKOTA 	inb(adp->va_crtc_addr + 6);		/* reset flip-flop */
62999feb462SKazutaka YOKOTA 	outb(ATC, 0x20);			/* enable palette */
63099feb462SKazutaka YOKOTA 
63199feb462SKazutaka YOKOTA 	outw(GDCIDX, 0x0f01);			/* set/reset enable */
63299feb462SKazutaka YOKOTA 
63399feb462SKazutaka YOKOTA 	if (bmp_info.sdepth == 1)
63499feb462SKazutaka YOKOTA 	    outw(TSIDX, 0x0102);		/* unmask plane #0 */
63599feb462SKazutaka YOKOTA     }
636cb4860b7SYoshihiro Takahashi #endif
637168d542eSYoshihiro Takahashi #endif
63899feb462SKazutaka YOKOTA 
6391243dad0SKazutaka YOKOTA     for (line = 0; (line < bmp_info.height) && bmp_info.index; line++) {
6401243dad0SKazutaka YOKOTA 	bmp_DecodeLine(&bmp_info, line);
6411243dad0SKazutaka YOKOTA     }
6421243dad0SKazutaka YOKOTA     return(0);
6431243dad0SKazutaka YOKOTA }
644