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