Home | History | Annotate | Line # | Download | only in splash
splash.c revision 1.5
      1 /* $NetBSD: splash.c,v 1.5 2008/04/28 20:23:58 martin Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2006 Jared D. McNeill <jmcneill (at) invisible.ca>
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  * POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 __KERNEL_RCSID(0, "$NetBSD: splash.c,v 1.5 2008/04/28 20:23:58 martin Exp $");
     31 
     32 #include "opt_splash.h"
     33 
     34 /* XXX */
     35 #define	NSPLASH8 1
     36 #define	NSPLASH16 1
     37 #define	NSPLASH32 1
     38 
     39 #include <sys/param.h>
     40 #include <sys/systm.h>
     41 #include <sys/types.h>
     42 #include <sys/kernel.h>
     43 #include <sys/kthread.h>
     44 
     45 #include <dev/splash/splash.h>
     46 
     47 #if !defined(SPLASHSCREEN) && defined(SPLASHSCREEN_PROGRESS)
     48 #error "options SPLASHSCREEN_PROGRESS requires SPLASHSCREEN"
     49 #endif
     50 
     51 #ifdef __HAVE_CPU_COUNTER
     52 #include <sys/cpu.h>
     53 #include <machine/cpu_counter.h>
     54 #endif
     55 
     56 #ifndef SPLASHSCREEN_IMAGE
     57 #define SPLASHSCREEN_IMAGE "dev/splash/images/netbsd.h"
     58 #endif
     59 
     60 #ifdef SPLASHSCREEN
     61 #include SPLASHSCREEN_IMAGE
     62 
     63 #ifdef SPLASHSCREEN_PROGRESS
     64 struct splash_progress *splash_progress_state;
     65 #ifdef __HAVE_CPU_COUNTER
     66 static uint64_t splash_last_update;
     67 #endif
     68 #endif
     69 
     70 #if NSPLASH8 > 0
     71 static void	splash_render8(struct splash_info *, const char *, int,
     72 			       int, int, int, int);
     73 #endif
     74 #if NSPLASH16 > 0
     75 static void	splash_render16(struct splash_info *, const char *, int,
     76 				int, int, int, int);
     77 #endif
     78 #if NSPLASH32 > 0
     79 static void	splash_render32(struct splash_info *, const char *, int,
     80 				int, int, int, int);
     81 #endif
     82 
     83 void
     84 splash_render(struct splash_info *si, int flg)
     85 {
     86 	int xoff, yoff;
     87 
     88 	/* XXX */
     89 	if (flg & SPLASH_F_CENTER) {
     90 		xoff = (si->si_width - _splash_width) / 2;
     91 		yoff = (si->si_height - _splash_height) / 2;
     92 	} else
     93 		xoff = yoff = 0;
     94 
     95 	switch (si->si_depth) {
     96 #if NSPLASH8 > 0
     97 	case 8:
     98 		splash_render8(si, _splash_header_data, xoff, yoff,
     99 		    _splash_width, _splash_height, flg);
    100 		break;
    101 #endif
    102 #if NSPLASH16 > 0
    103 	case 16:
    104 		splash_render16(si, _splash_header_data, xoff, yoff,
    105 		    _splash_width, _splash_height, flg);
    106 		break;
    107 #endif
    108 #if NSPLASH32 > 0
    109 	case 32:
    110 		splash_render32(si, _splash_header_data, xoff, yoff,
    111 		    _splash_width, _splash_height, flg);
    112 		break;
    113 #endif
    114 	default:
    115 		aprint_error("WARNING: Splash not supported at %dbpp\n",
    116 		    si->si_depth);
    117 		break;
    118 	}
    119 
    120 	return;
    121 }
    122 
    123 #if NSPLASH8 > 0
    124 static void
    125 splash_render8(struct splash_info *si, const char *data, int xoff, int yoff,
    126 	       int swidth, int sheight, int flg)
    127 {
    128 	const char *p;
    129 	u_char *fb, pix;
    130 	int x, y, i;
    131 	int filled;
    132 
    133 	fb = si->si_bits;
    134 	if (flg & SPLASH_F_FILL)
    135 		filled = 0;
    136 	else
    137 		filled = 1;
    138 
    139 	p = data;
    140 	fb += xoff + (yoff * si->si_width);
    141 	for (y = 0; y < sheight; y++) {
    142 		for (x = 0; x < swidth; x++) {
    143 			pix = *p++;
    144 			pix += SPLASH_CMAP_OFFSET;
    145 			if (filled == 0) {
    146 				for (i = 0; i < (si->si_width * si->si_height);
    147 				     i++)
    148 					si->si_bits[i] = pix;
    149 				filled = 1;
    150 			}
    151 			fb[x] = pix;
    152 		}
    153 		fb += si->si_width;
    154 	}
    155 
    156 	/* If we've just written to the shadow fb, copy it to the display */
    157 	if (si->si_hwbits) {
    158 		if (flg & SPLASH_F_FILL) {
    159 			memcpy(si->si_hwbits, si->si_bits,
    160 			    si->si_width*si->si_height);
    161 		} else {
    162 			u_char *rp, *hrp;
    163 
    164 			rp = si->si_bits + xoff + (yoff * si->si_width);
    165 			hrp = si->si_hwbits + xoff + (yoff * si->si_width);
    166 
    167 			for (y = 0; y < sheight; y++) {
    168 				memcpy(hrp, rp, swidth);
    169 				hrp += si->si_stride;
    170 				rp += si->si_stride;
    171 			}
    172 		}
    173 	}
    174 
    175 	return;
    176 }
    177 #endif /* !NSPLASH8 > 0 */
    178 
    179 #if NSPLASH16 > 0
    180 #define RGBTO16(b, o, x, c)					\
    181 	do {							\
    182 		uint16_t *_ptr = (uint16_t *)(&(b)[(o)]);	\
    183 		*_ptr = (((c)[(x)*3+0] / 8) << 11) |		\
    184 			(((c)[(x)*3+1] / 4) << 5) |		\
    185 			(((c)[(x)*3+2] / 8) << 0);		\
    186 	} while (0)
    187 
    188 static void
    189 splash_render16(struct splash_info *si, const char *data, int xoff, int yoff,
    190 		int swidth, int sheight, int flg)
    191 {
    192 	const char *d;
    193 	u_char *fb, *p;
    194 	u_char pix[3];
    195 	int x, y, i;
    196 	int filled;
    197 
    198 	fb = si->si_bits;
    199 
    200 	if (flg & SPLASH_F_FILL)
    201 		filled = 0;
    202 	else
    203 		filled = 1;
    204 
    205 	d = data;
    206 	fb += xoff * 2 + yoff * si->si_stride;
    207 
    208 	for (y = 0; y < sheight; y++) {
    209 		for (x = 0; x < swidth; x++) {
    210 			_SPLASH_HEADER_PIXEL(d, pix);
    211 			if (filled == 0) {
    212 				p = si->si_bits;
    213 				i = 0;
    214 				while (i < si->si_height*si->si_stride) {
    215 					RGBTO16(p, i, 0, pix);
    216 					i += 2;
    217 				}
    218 				filled = 1;
    219 			}
    220 			RGBTO16(fb, x*2, 0, pix);
    221 		}
    222 		fb += si->si_stride;
    223 	}
    224 
    225 	/* If we've just written to the shadow fb, copy it to the display */
    226 	if (si->si_hwbits) {
    227 		if (flg & SPLASH_F_FILL) {
    228 			memcpy(si->si_hwbits, si->si_bits,
    229 			    si->si_height*si->si_stride);
    230 		} else {
    231 			u_char *rp, *hrp;
    232 
    233 			rp = si->si_bits + (xoff * 2) + (yoff * si->si_stride);
    234 			hrp = si->si_hwbits + (xoff * 2) +
    235 			    (yoff * si->si_stride);
    236 
    237 			for (y = 0; y < sheight; y++) {
    238 				memcpy(hrp, rp, swidth * 2);
    239 				rp += si->si_stride;
    240 				hrp += si->si_stride;
    241 			}
    242 		}
    243 	}
    244 
    245 	return;
    246 }
    247 #undef RGBTO16
    248 #endif /* !NSPLASH16 > 0 */
    249 
    250 #if NSPLASH32 > 0
    251 static void
    252 splash_render32(struct splash_info *si, const char *data, int xoff, int yoff,
    253 		int swidth, int sheight, int flg)
    254 {
    255 	const char *d;
    256 	u_char *fb, *p;
    257 	u_char pix[3];
    258 	int x, y, i;
    259 	int filled;
    260 
    261 	fb = si->si_bits;
    262 
    263 	if (flg & SPLASH_F_FILL)
    264 		filled = 0;
    265 	else
    266 		filled = 1;
    267 
    268 	d = data;
    269 	fb += xoff * 4 + yoff * si->si_stride;
    270 
    271 	for (y = 0; y < sheight; y++) {
    272 		for (x = 0; x < swidth; x++) {
    273 			_SPLASH_HEADER_PIXEL(d, pix);
    274 			if (filled == 0) {
    275 				p = si->si_bits;
    276 				i = 0;
    277 				while (i < si->si_height*si->si_stride) {
    278 					p[i++] = pix[2];
    279 					p[i++] = pix[1];
    280 					p[i++] = pix[0];
    281 					p[i++] = 0;
    282 				}
    283 				filled = 1;
    284 			}
    285 			fb[x*4+0] = pix[2];
    286 			fb[x*4+1] = pix[1];
    287 			fb[x*4+2] = pix[0];
    288 			fb[x*4+3] = 0;
    289 		}
    290 		fb += si->si_stride;
    291 	}
    292 
    293 	/* If we've just written to the shadow fb, copy it to the display */
    294 	if (si->si_hwbits) {
    295 		if (flg & SPLASH_F_FILL) {
    296 			memcpy(si->si_hwbits, si->si_bits,
    297 			    si->si_height*si->si_stride);
    298 		} else {
    299 			u_char *rp, *hrp;
    300 
    301 			rp = si->si_bits + (xoff * 4) + (yoff * si->si_stride);
    302 			hrp = si->si_hwbits + (xoff * 4) +
    303 			    (yoff * si->si_stride);
    304 
    305 			for (y = 0; y < sheight; y++) {
    306 				memcpy(hrp, rp, swidth * 4);
    307 				rp += si->si_stride;
    308 				hrp += si->si_stride;
    309 			}
    310 		}
    311 	}
    312 
    313 	return;
    314 }
    315 #endif /* !NSPLASH32 > 0 */
    316 
    317 #ifdef SPLASHSCREEN_PROGRESS
    318 
    319 static void
    320 splash_progress_render(struct splash_progress *sp)
    321 {
    322 	struct splash_info *si;
    323 	int i;
    324 	int w;
    325 	int spacing;
    326 	int xoff;
    327 	int yoff;
    328 	int flg;
    329 
    330 	si = sp->sp_si;
    331 	flg = 0;
    332 
    333 	/* where should we draw the pulsers? */
    334 	yoff = (si->si_height / 8) * 7;
    335 	w = _pulse_off_width * SPLASH_PROGRESS_NSTATES;
    336 	xoff = (si->si_width / 4) * 3;
    337 	spacing = _pulse_off_width; /* XXX */
    338 
    339 	for (i = 0; i < SPLASH_PROGRESS_NSTATES; i++) {
    340 		const char *d = (sp->sp_state == i ? _pulse_on_header_data :
    341 				 _pulse_off_header_data);
    342 		switch (si->si_depth) {
    343 #if NSPLASH8 > 0
    344 		case 8:
    345 			splash_render8(si, d, (xoff + (i * spacing)),
    346 			    yoff, _pulse_off_width, _pulse_off_height, flg);
    347 			break;
    348 #endif
    349 #if NSPLASH16 > 0
    350 		case 16:
    351 			splash_render16(si, d, (xoff + (i * spacing)),
    352 			    yoff, _pulse_off_width, _pulse_off_height, flg);
    353 			break;
    354 #endif
    355 #if NSPLASH32 > 0
    356 		case 32:
    357 			splash_render32(si, d, (xoff + (i * spacing)),
    358 			    yoff, _pulse_off_width, _pulse_off_height, flg);
    359 			break;
    360 #endif
    361 		default:
    362 			/* do nothing */
    363 			break;
    364 		}
    365 	}
    366 }
    367 
    368 static int
    369 splash_progress_stop(struct device *dev)
    370 {
    371 	struct splash_progress *sp;
    372 
    373 	sp = (struct splash_progress *)dev;
    374 	sp->sp_running = 0;
    375 
    376 	return 0;
    377 }
    378 
    379 void
    380 splash_progress_init(struct splash_progress *sp)
    381 {
    382 #ifdef __HAVE_CPU_COUNTER
    383 	if (cpu_hascounter())
    384 		splash_last_update = cpu_counter();
    385 	else
    386 		splash_last_update = 0;
    387 #endif
    388 
    389 	sp->sp_running = 1;
    390 	sp->sp_force = 0;
    391 	splash_progress_state = sp;
    392 	splash_progress_render(sp);
    393 	config_finalize_register((struct device *)sp, splash_progress_stop);
    394 
    395 	return;
    396 }
    397 
    398 void
    399 splash_progress_update(struct splash_progress *sp)
    400 {
    401 	if (sp->sp_running == 0 && sp->sp_force == 0)
    402 		return;
    403 
    404 #ifdef __HAVE_CPU_COUNTER
    405 	if (cpu_hascounter()) {
    406 		uint64_t now;
    407 
    408 		if (splash_last_update == 0) {
    409 			splash_last_update = cpu_counter();
    410 		} else {
    411 			now = cpu_counter();
    412 			if (splash_last_update + cpu_frequency(curcpu())/4 >
    413 			    now)
    414 				return;
    415 			splash_last_update = now;
    416 		}
    417 	}
    418 #endif
    419 	sp->sp_state++;
    420 	if (sp->sp_state >= SPLASH_PROGRESS_NSTATES)
    421 		sp->sp_state = 0;
    422 
    423 	splash_progress_render(sp);
    424 }
    425 
    426 #endif /* !SPLASHSCREEN_PROGRESS */
    427 
    428 #endif /* !SPLASHSCREEN */
    429