1 /* $NetBSD: splash.c,v 1.8 2010/02/22 05:55:10 ahoka Exp $ */ 2 3 /*- 4 * Copyright (c) 2006 Jared D. McNeill <jmcneill@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.8 2010/02/22 05:55:10 ahoka 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/device.h> 48 #include <sys/systm.h> 49 #include <sys/types.h> 50 #include <sys/kernel.h> 51 #include <sys/kthread.h> 52 53 #include <dev/splash/splash.h> 54 55 #if !defined(SPLASHSCREEN) && defined(SPLASHSCREEN_PROGRESS) 56 #error "options SPLASHSCREEN_PROGRESS requires SPLASHSCREEN" 57 #endif 58 59 #ifdef __HAVE_CPU_COUNTER 60 #include <sys/cpu.h> 61 #include <machine/cpu_counter.h> 62 #endif 63 64 #ifndef SPLASHSCREEN_IMAGE 65 #define SPLASHSCREEN_IMAGE "dev/splash/images/netbsd.h" 66 #endif 67 68 #ifdef SPLASHSCREEN 69 #include SPLASHSCREEN_IMAGE 70 71 #ifdef SPLASHSCREEN_PROGRESS 72 struct splash_progress *splash_progress_state; 73 #ifdef __HAVE_CPU_COUNTER 74 static uint64_t splash_last_update; 75 #endif 76 #endif 77 78 #if NSPLASH8 > 0 79 static void splash_render8(struct splash_info *, const char *, int, 80 int, int, int, int); 81 #endif 82 #if NSPLASH16 > 0 83 static void splash_render16(struct splash_info *, const char *, int, 84 int, int, int, int); 85 #endif 86 #if NSPLASH32 > 0 87 static void splash_render32(struct splash_info *, const char *, int, 88 int, int, int, int); 89 #endif 90 91 void 92 splash_render(struct splash_info *si, int flg) 93 { 94 int xoff, yoff; 95 96 /* XXX */ 97 if (flg & SPLASH_F_CENTER) { 98 xoff = (si->si_width - _splash_width) / 2; 99 yoff = (si->si_height - _splash_height) / 2; 100 } else 101 xoff = yoff = 0; 102 103 switch (si->si_depth) { 104 #if NSPLASH8 > 0 105 case 8: 106 splash_render8(si, _splash_header_data, xoff, yoff, 107 _splash_width, _splash_height, flg); 108 break; 109 #endif 110 #if NSPLASH16 > 0 111 case 16: 112 splash_render16(si, _splash_header_data, xoff, yoff, 113 _splash_width, _splash_height, flg); 114 break; 115 #endif 116 #if NSPLASH32 > 0 117 case 32: 118 splash_render32(si, _splash_header_data, xoff, yoff, 119 _splash_width, _splash_height, flg); 120 break; 121 #endif 122 default: 123 aprint_error("WARNING: Splash not supported at %dbpp\n", 124 si->si_depth); 125 break; 126 } 127 128 return; 129 } 130 131 #if NSPLASH8 > 0 132 static void 133 splash_render8(struct splash_info *si, const char *data, int xoff, int yoff, 134 int swidth, int sheight, int flg) 135 { 136 const char *p; 137 u_char *fb, pix; 138 int x, y, i; 139 int filled; 140 141 fb = si->si_bits; 142 if (flg & SPLASH_F_FILL) 143 filled = 0; 144 else 145 filled = 1; 146 147 p = data; 148 fb += xoff + (yoff * si->si_width); 149 for (y = 0; y < sheight; y++) { 150 for (x = 0; x < swidth; x++) { 151 pix = *p++; 152 pix += SPLASH_CMAP_OFFSET; 153 if (filled == 0) { 154 for (i = 0; i < (si->si_width * si->si_height); 155 i++) 156 si->si_bits[i] = pix; 157 filled = 1; 158 } 159 fb[x] = pix; 160 } 161 fb += si->si_width; 162 } 163 164 /* If we've just written to the shadow fb, copy it to the display */ 165 if (si->si_hwbits) { 166 if (flg & SPLASH_F_FILL) { 167 memcpy(si->si_hwbits, si->si_bits, 168 si->si_width*si->si_height); 169 } else { 170 u_char *rp, *hrp; 171 172 rp = si->si_bits + xoff + (yoff * si->si_width); 173 hrp = si->si_hwbits + xoff + (yoff * si->si_width); 174 175 for (y = 0; y < sheight; y++) { 176 memcpy(hrp, rp, swidth); 177 hrp += si->si_stride; 178 rp += si->si_stride; 179 } 180 } 181 } 182 183 return; 184 } 185 #endif /* !NSPLASH8 > 0 */ 186 187 #if NSPLASH16 > 0 188 #define RGBTO16(b, o, x, c) \ 189 do { \ 190 uint16_t *_ptr = (uint16_t *)(&(b)[(o)]); \ 191 *_ptr = (((c)[(x)*3+0] / 8) << 11) | \ 192 (((c)[(x)*3+1] / 4) << 5) | \ 193 (((c)[(x)*3+2] / 8) << 0); \ 194 } while (0) 195 196 static void 197 splash_render16(struct splash_info *si, const char *data, int xoff, int yoff, 198 int swidth, int sheight, int flg) 199 { 200 const char *d; 201 u_char *fb, *p; 202 u_char pix[3]; 203 int x, y, i; 204 int filled; 205 206 fb = si->si_bits; 207 208 if (flg & SPLASH_F_FILL) 209 filled = 0; 210 else 211 filled = 1; 212 213 d = data; 214 fb += xoff * 2 + yoff * si->si_stride; 215 216 for (y = 0; y < sheight; y++) { 217 for (x = 0; x < swidth; x++) { 218 _SPLASH_HEADER_PIXEL(d, pix); 219 if (filled == 0) { 220 p = si->si_bits; 221 i = 0; 222 while (i < si->si_height*si->si_stride) { 223 RGBTO16(p, i, 0, pix); 224 i += 2; 225 } 226 filled = 1; 227 } 228 RGBTO16(fb, x*2, 0, pix); 229 } 230 fb += si->si_stride; 231 } 232 233 /* If we've just written to the shadow fb, copy it to the display */ 234 if (si->si_hwbits) { 235 if (flg & SPLASH_F_FILL) { 236 memcpy(si->si_hwbits, si->si_bits, 237 si->si_height*si->si_stride); 238 } else { 239 u_char *rp, *hrp; 240 241 rp = si->si_bits + (xoff * 2) + (yoff * si->si_stride); 242 hrp = si->si_hwbits + (xoff * 2) + 243 (yoff * si->si_stride); 244 245 for (y = 0; y < sheight; y++) { 246 memcpy(hrp, rp, swidth * 2); 247 rp += si->si_stride; 248 hrp += si->si_stride; 249 } 250 } 251 } 252 253 return; 254 } 255 #undef RGBTO16 256 #endif /* !NSPLASH16 > 0 */ 257 258 #if NSPLASH32 > 0 259 static void 260 splash_render32(struct splash_info *si, const char *data, int xoff, int yoff, 261 int swidth, int sheight, int flg) 262 { 263 const char *d; 264 u_char *fb, *p; 265 u_char pix[3]; 266 int x, y, i; 267 int filled; 268 269 fb = si->si_bits; 270 271 if (flg & SPLASH_F_FILL) 272 filled = 0; 273 else 274 filled = 1; 275 276 d = data; 277 fb += xoff * 4 + yoff * si->si_stride; 278 279 for (y = 0; y < sheight; y++) { 280 for (x = 0; x < swidth; x++) { 281 _SPLASH_HEADER_PIXEL(d, pix); 282 if (filled == 0) { 283 p = si->si_bits; 284 i = 0; 285 while (i < si->si_height*si->si_stride) { 286 p[i++] = pix[2]; 287 p[i++] = pix[1]; 288 p[i++] = pix[0]; 289 p[i++] = 0; 290 } 291 filled = 1; 292 } 293 fb[x*4+0] = pix[2]; 294 fb[x*4+1] = pix[1]; 295 fb[x*4+2] = pix[0]; 296 fb[x*4+3] = 0; 297 } 298 fb += si->si_stride; 299 } 300 301 /* If we've just written to the shadow fb, copy it to the display */ 302 if (si->si_hwbits) { 303 if (flg & SPLASH_F_FILL) { 304 memcpy(si->si_hwbits, si->si_bits, 305 si->si_height*si->si_stride); 306 } else { 307 u_char *rp, *hrp; 308 309 rp = si->si_bits + (xoff * 4) + (yoff * si->si_stride); 310 hrp = si->si_hwbits + (xoff * 4) + 311 (yoff * si->si_stride); 312 313 for (y = 0; y < sheight; y++) { 314 memcpy(hrp, rp, swidth * 4); 315 rp += si->si_stride; 316 hrp += si->si_stride; 317 } 318 } 319 } 320 321 return; 322 } 323 #endif /* !NSPLASH32 > 0 */ 324 325 #ifdef SPLASHSCREEN_PROGRESS 326 327 static void 328 splash_progress_render(struct splash_progress *sp) 329 { 330 struct splash_info *si; 331 int i; 332 int w; 333 int spacing; 334 int xoff; 335 int yoff; 336 int flg; 337 338 si = sp->sp_si; 339 flg = 0; 340 341 /* where should we draw the pulsers? */ 342 yoff = (si->si_height / 8) * 7; 343 w = _pulse_off_width * SPLASH_PROGRESS_NSTATES; 344 xoff = (si->si_width / 4) * 3; 345 spacing = _pulse_off_width; /* XXX */ 346 347 for (i = 0; i < SPLASH_PROGRESS_NSTATES; i++) { 348 const char *d = (sp->sp_state == i ? _pulse_on_header_data : 349 _pulse_off_header_data); 350 switch (si->si_depth) { 351 #if NSPLASH8 > 0 352 case 8: 353 splash_render8(si, d, (xoff + (i * spacing)), 354 yoff, _pulse_off_width, _pulse_off_height, flg); 355 break; 356 #endif 357 #if NSPLASH16 > 0 358 case 16: 359 splash_render16(si, d, (xoff + (i * spacing)), 360 yoff, _pulse_off_width, _pulse_off_height, flg); 361 break; 362 #endif 363 #if NSPLASH32 > 0 364 case 32: 365 splash_render32(si, d, (xoff + (i * spacing)), 366 yoff, _pulse_off_width, _pulse_off_height, flg); 367 break; 368 #endif 369 default: 370 /* do nothing */ 371 break; 372 } 373 } 374 } 375 376 static int 377 splash_progress_stop(device_t dev) 378 { 379 struct splash_progress *sp; 380 381 sp = (struct splash_progress *)dev; 382 sp->sp_running = 0; 383 384 return 0; 385 } 386 387 void 388 splash_progress_init(struct splash_progress *sp) 389 { 390 #ifdef __HAVE_CPU_COUNTER 391 if (cpu_hascounter()) 392 splash_last_update = cpu_counter(); 393 else 394 splash_last_update = 0; 395 #endif 396 397 sp->sp_running = 1; 398 sp->sp_force = 0; 399 splash_progress_state = sp; 400 splash_progress_render(sp); 401 config_finalize_register((device_t)sp, splash_progress_stop); 402 403 return; 404 } 405 406 void 407 splash_progress_update(struct splash_progress *sp) 408 { 409 if (sp->sp_running == 0 && sp->sp_force == 0) 410 return; 411 412 #ifdef __HAVE_CPU_COUNTER 413 if (cpu_hascounter()) { 414 uint64_t now; 415 416 if (splash_last_update == 0) { 417 splash_last_update = cpu_counter(); 418 } else { 419 now = cpu_counter(); 420 if (splash_last_update + cpu_frequency(curcpu())/4 > 421 now) 422 return; 423 splash_last_update = now; 424 } 425 } 426 #endif 427 sp->sp_state++; 428 if (sp->sp_state >= SPLASH_PROGRESS_NSTATES) 429 sp->sp_state = 0; 430 431 splash_progress_render(sp); 432 } 433 434 #endif /* !SPLASHSCREEN_PROGRESS */ 435 436 #endif /* !SPLASHSCREEN */ 437