1 /* $NetBSD: splash.c,v 1.6 2008/05/10 15:31:05 martin 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.6 2008/05/10 15:31:05 martin 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