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