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