Line 0
Link Here
|
|
|
1 |
/* |
2 |
* linux/drivers/video/fbcon-splash.c - splash screen handling functions. |
3 |
* |
4 |
* (w) 2001-2003 by Volker Poplawski, <volker@suse.de> |
5 |
* Stefan Reinauer, <stepan@suse.de> |
6 |
* Steffen Winterfeldt, <snwint@suse.de> |
7 |
* |
8 |
* Ideas & SuSE screen work by Ken Wimer, <wimer@suse.de> |
9 |
*/ |
10 |
|
11 |
#include <linux/version.h> |
12 |
#include <linux/config.h> |
13 |
#include <linux/module.h> |
14 |
#include <linux/fb.h> |
15 |
#include <linux/vt_kern.h> |
16 |
#include <linux/vmalloc.h> |
17 |
|
18 |
#include <asm/irq.h> |
19 |
#include <asm/system.h> |
20 |
|
21 |
#include <video/fbcon.h> |
22 |
#include <video/font.h> |
23 |
#include <video/fbcon-cfb16.h> /* for fbcon_cfb16 */ |
24 |
|
25 |
#include "fbcon-splash.h" |
26 |
#include "fbcon-jpegdec.h" |
27 |
|
28 |
#define SPLASH_VERSION "3.0.7-2003/03/10" |
29 |
|
30 |
#ifdef CONFIG_BLK_DEV_INITRD |
31 |
unsigned char signature[] = "BOOTSPL1SPL2SPL3"; |
32 |
#endif |
33 |
|
34 |
/* from drivers/char/console.c */ |
35 |
extern void con_remap_def_color(int currcons, int new_color); |
36 |
|
37 |
/* from drivers/video/fbcon-splash16.c */ |
38 |
extern void splashfill(u8 *dest, u8 *src, int width, int height, |
39 |
int dest_linesize, int src_linesize); |
40 |
|
41 |
/* internal control states and data pointers */ |
42 |
struct splash_data splash_data; |
43 |
|
44 |
unsigned char *linux_splash; /* decoded picture */ |
45 |
int linux_splash_size = 0; |
46 |
|
47 |
static struct jpeg_decdata *decdata = 0; /* private decoder data */ |
48 |
|
49 |
int splash_bytes; /* bytes per line in linux_splash */ |
50 |
int splash_shown = 0; /* is the splash onscreen? */ |
51 |
int splash_usesilent = 0; /* shall we display the silentjpeg */ |
52 |
int splash_default = 0xf01; |
53 |
|
54 |
static int splash_status(struct display *p); |
55 |
static int splash_recolor(struct display *p); |
56 |
static int splash_check_jpeg(unsigned char *jpeg, int width, int height, int depth); |
57 |
|
58 |
extern struct display_switch fbcon_splash16; |
59 |
|
60 |
int __init splash_init(char *options) |
61 |
{ |
62 |
if(!strncmp("silent",options,6)) { |
63 |
printk(KERN_INFO "bootsplash: silent mode.\n"); |
64 |
splash_usesilent = 1; |
65 |
/* skip "silent," */ |
66 |
if (strlen(options)==6) |
67 |
return 0; |
68 |
options+=7; |
69 |
} |
70 |
if(!strncmp("verbose",options,7)) { |
71 |
printk(KERN_INFO "bootsplash: verbose mode.\n"); |
72 |
splash_usesilent = 0; |
73 |
return 0; |
74 |
} |
75 |
|
76 |
splash_default = simple_strtoul(options, NULL, 0); |
77 |
|
78 |
return 0; |
79 |
} |
80 |
|
81 |
__setup("splash=", splash_init); |
82 |
|
83 |
|
84 |
static int splash_hasinter(unsigned char *buf, int num) |
85 |
{ |
86 |
unsigned char *bufend = buf + num * 12; |
87 |
while(buf < bufend) { |
88 |
if (buf[1] > 127) /* inter? */ |
89 |
return 1; |
90 |
buf += buf[3] > 127 ? 24 : 12; /* blend? */ |
91 |
} |
92 |
return 0; |
93 |
} |
94 |
|
95 |
static int boxextract(unsigned char *buf, unsigned short *dp, unsigned char *cols, int *blendp) |
96 |
{ |
97 |
dp[0] = buf[0] | buf[1] << 8; |
98 |
dp[1] = buf[2] | buf[3] << 8; |
99 |
dp[2] = buf[4] | buf[5] << 8; |
100 |
dp[3] = buf[6] | buf[7] << 8; |
101 |
*(unsigned int *)(cols + 0) = |
102 |
*(unsigned int *)(cols + 4) = |
103 |
*(unsigned int *)(cols + 8) = |
104 |
*(unsigned int *)(cols + 12) = *(unsigned int *)(buf + 8); |
105 |
if (dp[1] > 32767) { |
106 |
dp[1] = ~dp[1]; |
107 |
*(unsigned int *)(cols + 4) = *(unsigned int *)(buf + 12); |
108 |
*(unsigned int *)(cols + 8) = *(unsigned int *)(buf + 16); |
109 |
*(unsigned int *)(cols + 12) = *(unsigned int *)(buf + 20); |
110 |
*blendp = 1; |
111 |
return 24; |
112 |
} |
113 |
return 12; |
114 |
} |
115 |
|
116 |
static void boxit(unsigned char *pic, int bytes, unsigned char *buf, int num, int percent, int overpaint) |
117 |
{ |
118 |
int x, y, i, p, doblend, r, g, b, a, add; |
119 |
unsigned short data1[4]; |
120 |
unsigned char cols1[16]; |
121 |
unsigned short data2[4]; |
122 |
unsigned char cols2[16]; |
123 |
unsigned char *bufend; |
124 |
unsigned short *picp; |
125 |
|
126 |
if (num == 0) |
127 |
return; |
128 |
bufend = buf + num * 12; |
129 |
while(buf < bufend) { |
130 |
doblend = 0; |
131 |
buf += boxextract(buf, data1, cols1, &doblend); |
132 |
if (data1[0] > 32767) |
133 |
buf += boxextract(buf, data2, cols2, &doblend); |
134 |
if (data1[2] > 32767) { |
135 |
if (overpaint) |
136 |
continue; |
137 |
data1[2] = ~data1[2]; |
138 |
} |
139 |
if (data1[3] > 32767) { |
140 |
if (percent == 65536) |
141 |
continue; |
142 |
data1[3] = ~data1[3]; |
143 |
} |
144 |
if (data1[0] > 32767) { |
145 |
data1[0] = ~data1[0]; |
146 |
for (i = 0; i < 4; i++) |
147 |
data1[i] = (data1[i] * (65536 - percent) + data2[i] * percent) >> 16; |
148 |
for (i = 0; i < 16; i++) |
149 |
cols1[i] = (cols1[i] * (65536 - percent) + cols2[i] * percent) >> 16; |
150 |
} |
151 |
*(unsigned int *)cols2 = *(unsigned int *)cols1; |
152 |
a = cols2[3]; |
153 |
if (a == 0 && !doblend) |
154 |
continue; |
155 |
for (y = data1[1]; y <= data1[3]; y++) { |
156 |
if (doblend) { |
157 |
if ((p = data1[3] - data1[1]) != 0) |
158 |
p = ((y - data1[1]) << 16) / p; |
159 |
for (i = 0; i < 8; i++) |
160 |
cols2[i + 8] = (cols1[i] * (65536 - p) + cols1[i + 8] * p) >> 16; |
161 |
} |
162 |
add = (data1[0] & 1); |
163 |
add ^= (add ^ y) & 1 ? 1 : 3; /* 2x2 ordered dithering */ |
164 |
picp = (unsigned short *)(pic + data1[0] * 2 + y * bytes); |
165 |
for (x = data1[0]; x <= data1[2]; x++) { |
166 |
if (doblend) { |
167 |
if ((p = data1[2] - data1[0]) != 0) |
168 |
p = ((x - data1[0]) << 16) / p; |
169 |
for (i = 0; i < 4; i++) |
170 |
cols2[i] = (cols2[i + 8] * (65536 - p) + cols2[i + 12] * p) >> 16; |
171 |
a = cols2[3]; |
172 |
} |
173 |
r = cols2[0]; |
174 |
g = cols2[1]; |
175 |
b = cols2[2]; |
176 |
if (a != 255) { |
177 |
i = *picp; |
178 |
r = ((i >> 8 & 0xf8) * (255 - a) + r * a) / 255; |
179 |
g = ((i >> 3 & 0xfc) * (255 - a) + g * a) / 255; |
180 |
b = ((i << 3 & 0xf8) * (255 - a) + b * a) / 255; |
181 |
} |
182 |
#define CLAMP(x) ((x) >= 256 ? 255 : (x)) |
183 |
i = ((CLAMP(r + add*2+1) & 0xf8) << 8) | |
184 |
((CLAMP(g + add ) & 0xfc) << 3) | |
185 |
((CLAMP(b + add*2+1) ) >> 3); |
186 |
*picp++ = i; |
187 |
add ^= 3; |
188 |
} |
189 |
} |
190 |
} |
191 |
} |
192 |
|
193 |
static int splash_check_jpeg(unsigned char *jpeg, int width, int height, int depth) |
194 |
{ |
195 |
int size, err; |
196 |
unsigned char *mem; |
197 |
|
198 |
size = ((width + 15) & ~15) * ((height + 15) & ~15) * (depth >> 3); |
199 |
mem = vmalloc(size); |
200 |
if (!mem) { |
201 |
printk(KERN_INFO "No memory for decoded picture!\n"); |
202 |
return -1; |
203 |
} |
204 |
if (!decdata) |
205 |
decdata = vmalloc(sizeof(*decdata)); |
206 |
if ((err = jpeg_decode(jpeg, mem, ((width + 15) & ~15), ((height + 15) & ~15), depth, decdata))) |
207 |
printk(KERN_INFO "error %d while decompressing picture.\n",err); |
208 |
vfree(mem); |
209 |
return err ? -1 : 0; |
210 |
} |
211 |
|
212 |
static void splash_free(struct display * p) |
213 |
{ |
214 |
if (!p->splash_data) |
215 |
return; |
216 |
if (p->splash_data->oldscreen_base) |
217 |
p->screen_base = p->splash_data->oldscreen_base; |
218 |
if (p->splash_data->olddispsw) |
219 |
p->dispsw = p->splash_data->olddispsw; |
220 |
if (p->splash_data->splash_silentjpeg) |
221 |
vfree(p->splash_data->splash_sboxes); |
222 |
vfree(p->splash_data); |
223 |
p->splash_data = 0; |
224 |
} |
225 |
|
226 |
static int splash_mkpenguin(struct splash_data *data, int pxo, int pyo, int pwi, int phe, int pr, int pg, int pb) |
227 |
{ |
228 |
unsigned char *buf; |
229 |
int i; |
230 |
|
231 |
if (pwi ==0 || phe == 0) |
232 |
return 0; |
233 |
buf = (unsigned char *)data + sizeof(*data); |
234 |
pwi += pxo - 1; |
235 |
phe += pyo - 1; |
236 |
*buf++ = pxo; |
237 |
*buf++ = pxo >> 8; |
238 |
*buf++ = pyo; |
239 |
*buf++ = pyo >> 8; |
240 |
*buf++ = pwi; |
241 |
*buf++ = pwi >> 8; |
242 |
*buf++ = phe; |
243 |
*buf++ = phe >> 8; |
244 |
*buf++ = pr; |
245 |
*buf++ = pg; |
246 |
*buf++ = pb; |
247 |
*buf++ = 0; |
248 |
for (i = 0; i < 12; i++, buf++) |
249 |
*buf = buf[-12]; |
250 |
buf[-24] ^= 0xff; |
251 |
buf[-23] ^= 0xff; |
252 |
buf[-1] = 0xff; |
253 |
return 2; |
254 |
} |
255 |
|
256 |
int splash_getraw(unsigned char *start, unsigned char *end) |
257 |
{ |
258 |
unsigned char *ndata; |
259 |
int found = 0; |
260 |
int splash_size = 0; |
261 |
void *splash_start = 0; |
262 |
int unit = 0; |
263 |
int width = 0, height = 0; |
264 |
int silentsize; |
265 |
int boxcount = 0; |
266 |
int sboxcount = 0; |
267 |
int palcnt = 0; |
268 |
struct display *p; |
269 |
|
270 |
printk(KERN_INFO "Looking for splash picture..."); |
271 |
|
272 |
p = &fb_display[0]; |
273 |
silentsize = 0; |
274 |
|
275 |
for (ndata = start; ndata < end; ndata++) { |
276 |
if (*((unsigned int *)ndata) != *((unsigned int *)signature)) |
277 |
continue; |
278 |
if (*((unsigned int *)(ndata+4))==*((unsigned int *)(signature+4))) { |
279 |
printk("."); |
280 |
unit = 0; |
281 |
p = &fb_display[0]; |
282 |
width = p->var.xres; |
283 |
height = p->var.yres; |
284 |
|
285 |
splash_size = ndata[16] + (ndata[17] << 8) + (ndata[18] << 16) + (ndata[19] << 24); |
286 |
if (ndata + 20 + splash_size > end) { |
287 |
printk(" found, but truncated!\n"); |
288 |
return -1; |
289 |
} |
290 |
if (!jpeg_check_size(ndata + 20, width, height)) { |
291 |
ndata += 20 - 1 + splash_size; |
292 |
continue; |
293 |
} |
294 |
if (splash_check_jpeg(ndata + 20, width, height, p->var.bits_per_pixel)) |
295 |
return -1; |
296 |
if (p->splash_data) |
297 |
splash_free(p); |
298 |
p->splash_data = vmalloc(sizeof(*p->splash_data) + splash_size + 24); |
299 |
if (!p->splash_data) |
300 |
break; |
301 |
|
302 |
p->splash_data->oldscreen_base = 0; |
303 |
p->splash_data->olddispsw = 0; |
304 |
p->splash_data->splash_silentjpeg = 0; |
305 |
|
306 |
p->splash_data->splash_text_xo = ndata[ 8] + (ndata[ 9] << 8); |
307 |
p->splash_data->splash_text_yo = ndata[10] + (ndata[11] << 8); |
308 |
p->splash_data->splash_text_wi = ndata[12] + (ndata[13] << 8); |
309 |
p->splash_data->splash_text_he = ndata[14] + (ndata[15] << 8); |
310 |
/* use 8x16 font... */ |
311 |
p->splash_data->splash_text_xo *= 8; |
312 |
p->splash_data->splash_text_wi *= 8; |
313 |
p->splash_data->splash_text_yo *= 16; |
314 |
p->splash_data->splash_text_he *= 16; |
315 |
p->splash_data->splash_color = (splash_default >> 8) & 0x0f; |
316 |
p->splash_data->splash_fg_color = (splash_default >> 4) & 0x0f; |
317 |
p->splash_data->splash_state = splash_default & 1; |
318 |
p->splash_data->splash_percent = 0; |
319 |
p->splash_data->splash_overpaintok = 0; |
320 |
boxcount = splash_mkpenguin(p->splash_data, p->splash_data->splash_text_xo + 10, p->splash_data->splash_text_yo + 10, p->splash_data->splash_text_wi - 20, p->splash_data->splash_text_he - 20, 0xf0, 0xf0, 0xf0); |
321 |
splash_start = ndata + 20; |
322 |
found = 1; |
323 |
break; |
324 |
} |
325 |
if (*((unsigned int *)(ndata + 4)) == *((unsigned int *)(signature+8))) { |
326 |
printk("."); |
327 |
unit = ndata[8]; |
328 |
if (unit >= MAX_NR_CONSOLES) |
329 |
continue; |
330 |
if (unit) |
331 |
vc_allocate(unit); |
332 |
p = &fb_display[unit]; |
333 |
width = fb_display[unit].var.xres; |
334 |
height = fb_display[unit].var.yres; |
335 |
splash_size = ndata[12] + (ndata[13] << 8) + (ndata[14] << 16) + (ndata[15] << 24); |
336 |
if (splash_size == -1) { |
337 |
printk(" found, updating values.\n"); |
338 |
if (p->splash_data) { |
339 |
if (ndata[9] != 255) |
340 |
p->splash_data->splash_state = ndata[9]; |
341 |
if (ndata[10] != 255) |
342 |
p->splash_data->splash_fg_color = ndata[10]; |
343 |
if (ndata[11] != 255) |
344 |
p->splash_data->splash_color = ndata[11]; |
345 |
} |
346 |
return unit; |
347 |
} |
348 |
if (splash_size == 0) { |
349 |
printk(" found, freeing memory.\n"); |
350 |
if (p->splash_data) |
351 |
splash_free(p); |
352 |
return unit; |
353 |
} |
354 |
if (ndata + 35 + splash_size > end) { |
355 |
printk(" found, but truncated!\n"); |
356 |
return -1; |
357 |
} |
358 |
if (!jpeg_check_size(ndata + 35, width, height)) { |
359 |
ndata += 35 - 1 + splash_size; |
360 |
continue; |
361 |
} |
362 |
if (splash_check_jpeg(ndata + 35, width, height, p->var.bits_per_pixel)) |
363 |
return -1; |
364 |
if (p->splash_data) |
365 |
splash_free(p); |
366 |
p->splash_data = vmalloc(sizeof(*p->splash_data) + splash_size + 24); |
367 |
if (!p->splash_data) |
368 |
break; |
369 |
|
370 |
p->splash_data->oldscreen_base = 0; |
371 |
p->splash_data->olddispsw = 0; |
372 |
p->splash_data->splash_silentjpeg = 0; |
373 |
|
374 |
p->splash_data->splash_state = ndata[9]; |
375 |
p->splash_data->splash_fg_color = ndata[10]; |
376 |
p->splash_data->splash_color = ndata[11]; |
377 |
p->splash_data->splash_text_xo = ndata[16] + (ndata[17] << 8); |
378 |
p->splash_data->splash_text_yo = ndata[18] + (ndata[19] << 8); |
379 |
p->splash_data->splash_text_wi = ndata[20] + (ndata[21] << 8); |
380 |
p->splash_data->splash_text_he = ndata[22] + (ndata[23] << 8); |
381 |
p->splash_data->splash_percent = 0; |
382 |
p->splash_data->splash_overpaintok = 0; |
383 |
boxcount = splash_mkpenguin(p->splash_data, ndata[24] + (ndata[25] << 8), ndata[26] + (ndata[27] << 8), ndata[28] + (ndata[29] << 8), ndata[30] + (ndata[31] << 8), ndata[32], ndata[33], ndata[34]); |
384 |
splash_start = ndata + 35; |
385 |
found = 2; |
386 |
break; |
387 |
} |
388 |
if (*((unsigned int *)(ndata + 4)) == *((unsigned int *)(signature+12))) { |
389 |
printk("."); |
390 |
unit = ndata[8]; |
391 |
if (unit >= MAX_NR_CONSOLES) |
392 |
continue; |
393 |
if (unit) |
394 |
vc_allocate(unit); |
395 |
p = &fb_display[unit]; |
396 |
width = p->var.xres; |
397 |
height = p->var.yres; |
398 |
splash_size = ndata[12] + (ndata[13] << 8) + (ndata[14] << 16) + (ndata[15] << 24); |
399 |
if (splash_size == -1) { |
400 |
printk(" found, updating values.\n"); |
401 |
if (p->splash_data) { |
402 |
if (ndata[9] != 255) |
403 |
p->splash_data->splash_state = ndata[9]; |
404 |
if (ndata[10] != 255) |
405 |
p->splash_data->splash_fg_color = ndata[10]; |
406 |
if (ndata[11] != 255) |
407 |
p->splash_data->splash_color = ndata[11]; |
408 |
} |
409 |
return unit; |
410 |
} |
411 |
if (splash_size == 0) { |
412 |
printk(" found, freeing memory.\n"); |
413 |
if (p->splash_data) |
414 |
splash_free(p); |
415 |
return unit; |
416 |
} |
417 |
boxcount = ndata[24] + (ndata[25] << 8); |
418 |
palcnt = ndata[37] * 3; |
419 |
if (ndata + 38 + splash_size > end) { |
420 |
printk(" found, but truncated!\n"); |
421 |
return -1; |
422 |
} |
423 |
if (!jpeg_check_size(ndata + 38 + boxcount * 12 + palcnt, width, height)) { |
424 |
ndata += 38 - 1 + splash_size; |
425 |
continue; |
426 |
} |
427 |
if (splash_check_jpeg(ndata + 38 + boxcount * 12 + palcnt, width, height, p->var.bits_per_pixel)) |
428 |
return -1; |
429 |
silentsize = ndata[28] + (ndata[29] << 8) + (ndata[30] << 16) + (ndata[31] << 24); |
430 |
if (silentsize) |
431 |
printk(" silenjpeg size %d bytes,", silentsize); |
432 |
if (silentsize >= splash_size) { |
433 |
printk(" bigger than splashsize!\n"); |
434 |
return -1; |
435 |
} |
436 |
splash_size -= silentsize; |
437 |
if (!splash_usesilent || !p->fb_info->fbops->fb_get_fix ) { |
438 |
silentsize = 0; |
439 |
} else { |
440 |
struct fb_fix_screeninfo fix; |
441 |
p->fb_info->fbops->fb_get_fix(&fix, unit, 0); |
442 |
if (height * 2 * p->next_line > fix.smem_len) { |
443 |
printk(" does not fit into framebuffer.\n"); |
444 |
silentsize = 0; |
445 |
} |
446 |
} |
447 |
|
448 |
sboxcount = ndata[32] + (ndata[33] << 8); |
449 |
if (silentsize) { |
450 |
char *simage=ndata + 38 + splash_size + 12 * sboxcount; |
451 |
if (!jpeg_check_size(simage, width, height) || |
452 |
splash_check_jpeg(simage, width, height, p->var.bits_per_pixel)) { |
453 |
printk(" error in silent jpeg.\n"); |
454 |
silentsize = 0; |
455 |
} |
456 |
} |
457 |
if (p->splash_data) |
458 |
splash_free(p); |
459 |
p->splash_data = vmalloc(sizeof(*p->splash_data) + splash_size); |
460 |
if (!p->splash_data) |
461 |
break; |
462 |
p->splash_data->oldscreen_base = 0; |
463 |
p->splash_data->olddispsw = 0; |
464 |
p->splash_data->splash_silentjpeg = 0; |
465 |
if (silentsize) { |
466 |
p->splash_data->splash_silentjpeg = vmalloc(silentsize); |
467 |
if (p->splash_data->splash_silentjpeg) { |
468 |
memcpy(p->splash_data->splash_silentjpeg, ndata + 38 + splash_size, silentsize); |
469 |
p->splash_data->splash_sboxes = p->splash_data->splash_silentjpeg; |
470 |
p->splash_data->splash_silentjpeg += 12 * sboxcount; |
471 |
p->splash_data->splash_sboxcount = sboxcount; |
472 |
} |
473 |
} |
474 |
p->splash_data->splash_state = ndata[9]; |
475 |
p->splash_data->splash_fg_color = ndata[10]; |
476 |
p->splash_data->splash_color = ndata[11]; |
477 |
p->splash_data->splash_overpaintok = ndata[36]; |
478 |
p->splash_data->splash_text_xo = ndata[16] + (ndata[17] << 8); |
479 |
p->splash_data->splash_text_yo = ndata[18] + (ndata[19] << 8); |
480 |
p->splash_data->splash_text_wi = ndata[20] + (ndata[21] << 8); |
481 |
p->splash_data->splash_text_he = ndata[22] + (ndata[23] << 8); |
482 |
p->splash_data->splash_percent = ndata[34] + (ndata[35] << 8); |
483 |
p->splash_data->splash_percent += p->splash_data->splash_percent > 32767; |
484 |
splash_start = ndata + 38; |
485 |
found = 3; |
486 |
break; |
487 |
} |
488 |
} |
489 |
|
490 |
if (!found) { |
491 |
printk(" no good signature found.\n"); |
492 |
return -1; |
493 |
} |
494 |
if (p->splash_data->splash_text_xo + p->splash_data->splash_text_wi > width || p->splash_data->splash_text_yo + p->splash_data->splash_text_he > height) { |
495 |
splash_free(p); |
496 |
p->splash_data = 0; |
497 |
printk(" found, but has oversized text area!\n"); |
498 |
return -1; |
499 |
} |
500 |
if (p->dispsw->setup != fbcon_cfb16.setup) { |
501 |
splash_free(p); |
502 |
p->splash_data = 0; |
503 |
printk(" found, but framebuffer can't handle it!\n"); |
504 |
return -1; |
505 |
} |
506 |
printk(" found (%dx%d, %d bytes, v%d).\n", width, height, splash_size, found); |
507 |
|
508 |
if (found==1) { |
509 |
printk(KERN_WARNING "bootsplash: Using deprecated v1 header. Updating your splash utility recommended.\n"); |
510 |
printk(KERN_INFO "bootsplash: Find the latest version at ftp.suse.com/pub/people/stepan/bootsplash/\n"); |
511 |
} |
512 |
|
513 |
/* copy data so that initrd memory can be freed. */ |
514 |
memcpy((char *)p->splash_data + sizeof(*p->splash_data) + (found < 3 ? boxcount * 12 : 0), splash_start, splash_size); |
515 |
p->splash_data->splash_boxcount = boxcount; |
516 |
p->splash_data->splash_boxes = (unsigned char *)p->splash_data + sizeof(*p->splash_data); |
517 |
p->splash_data->splash_jpeg = (unsigned char *)p->splash_data + sizeof(*p->splash_data) + boxcount * 12 + palcnt; |
518 |
p->splash_data->splash_palette = (unsigned char *)p->splash_data + sizeof(*p->splash_data) + boxcount * 12; |
519 |
p->splash_data->splash_palcnt = palcnt / 3; |
520 |
p->splash_data->splash_dosilent = p->splash_data->splash_silentjpeg != 0; |
521 |
return unit; |
522 |
} |
523 |
|
524 |
int splash_verbose(void) |
525 |
{ |
526 |
struct display *p; |
527 |
|
528 |
p = &fb_display[0]; |
529 |
if (!p || !p->splash_data || !p->splash_data->splash_state || !p->conp) |
530 |
return 0; |
531 |
if (fg_console != p->conp->vc_num) |
532 |
return 0; |
533 |
if (!p->splash_data->splash_silentjpeg || !p->splash_data->splash_dosilent) |
534 |
return 0; |
535 |
if (!p->splash_data->oldscreen_base) |
536 |
return 0; |
537 |
|
538 |
p->splash_data->splash_dosilent = 0; |
539 |
|
540 |
splashfill(p->splash_data->oldscreen_base, p->screen_base, p->var.xres, p->var.yres, p->next_line, p->next_line); |
541 |
p->screen_base = p->splash_data->oldscreen_base; |
542 |
|
543 |
return 1; |
544 |
} |
545 |
|
546 |
static void splash_off(struct display *p) |
547 |
{ |
548 |
if (p->splash_data && p->splash_data->oldscreen_base) |
549 |
p->screen_base = p->splash_data->oldscreen_base; |
550 |
if (p->splash_data && p->splash_data->olddispsw) |
551 |
p->dispsw = p->splash_data->olddispsw; |
552 |
splash_shown = 0; |
553 |
} |
554 |
|
555 |
int splash_prepare(struct display *p) |
556 |
{ |
557 |
int err; |
558 |
int width, height, depth, size, sbytes; |
559 |
|
560 |
if (!p->splash_data || !p->splash_data->splash_state) { |
561 |
if (linux_splash) |
562 |
vfree(linux_splash); |
563 |
if (decdata) |
564 |
vfree(decdata); |
565 |
linux_splash = 0; |
566 |
decdata = 0; |
567 |
linux_splash_size = 0; |
568 |
splash_off(p); |
569 |
return -1; |
570 |
} |
571 |
|
572 |
width = p->var.xres; |
573 |
height = p->var.yres; |
574 |
depth = p->var.bits_per_pixel; |
575 |
if (depth != 16) { /* Other targets might need fixing */ |
576 |
splash_off(p); |
577 |
return -2; |
578 |
} |
579 |
|
580 |
sbytes = ((width + 15) & ~15) * (depth >> 3); |
581 |
size = sbytes * ((height + 15) & ~15); |
582 |
if (size != linux_splash_size) { |
583 |
if (linux_splash) |
584 |
vfree(linux_splash); |
585 |
linux_splash_size = 0; |
586 |
linux_splash = 0; |
587 |
splash_off(p); |
588 |
} |
589 |
if (!linux_splash) |
590 |
linux_splash = vmalloc(size); |
591 |
|
592 |
if (!linux_splash) { |
593 |
linux_splash_size = 0; |
594 |
printk(KERN_INFO "Not enough memory for splash screen.\n"); |
595 |
splash_off(p); |
596 |
return -3; |
597 |
} |
598 |
|
599 |
if (!decdata) |
600 |
decdata = vmalloc(sizeof(*decdata)); |
601 |
|
602 |
if (!p->splash_data->oldscreen_base) |
603 |
p->splash_data->oldscreen_base = p->screen_base; |
604 |
|
605 |
if (p->splash_data->splash_silentjpeg && p->splash_data->splash_dosilent) { |
606 |
printk(KERN_INFO "Got silent jpeg.\n"); |
607 |
/* fill area after framebuffer with other jpeg */ |
608 |
if ((err = jpeg_decode(p->splash_data->splash_silentjpeg, linux_splash, |
609 |
((width + 15) & ~15), ((height + 15) & ~15), depth, decdata))) { |
610 |
printk(KERN_INFO "Error %d while decompressing silent jpeg.\n", err); |
611 |
p->screen_base = p->splash_data->oldscreen_base; |
612 |
p->splash_data->splash_dosilent = 0; |
613 |
} else { |
614 |
if (p->splash_data->splash_sboxcount) |
615 |
boxit(linux_splash, sbytes, p->splash_data->splash_sboxes, |
616 |
p->splash_data->splash_sboxcount, p->splash_data->splash_percent, 0); |
617 |
|
618 |
splashfill(p->screen_base, linux_splash, p->var.xres, p->var.yres, p->next_line, sbytes); |
619 |
p->screen_base = p->splash_data->oldscreen_base + p->next_line * p->var.yres; |
620 |
} |
621 |
} else |
622 |
p->screen_base = p->splash_data->oldscreen_base; |
623 |
|
624 |
if ((err = jpeg_decode(p->splash_data->splash_jpeg, linux_splash, |
625 |
((width + 15) & ~15), ((height + 15) & ~15), depth, decdata))) { |
626 |
printk(KERN_INFO "Error %d while decompressing splash screen.\n", err); |
627 |
vfree(linux_splash); |
628 |
linux_splash = 0; |
629 |
linux_splash_size = 0; |
630 |
splash_off(p); |
631 |
return -4; |
632 |
} |
633 |
linux_splash_size = size; |
634 |
splash_bytes = sbytes; |
635 |
if (p->splash_data->splash_boxcount) |
636 |
boxit(linux_splash, sbytes, p->splash_data->splash_boxes, p->splash_data->splash_boxcount, p->splash_data->splash_percent, 0); |
637 |
splash_data = *p->splash_data; |
638 |
splash_shown = p->splash_data->splash_state; |
639 |
if (splash_shown) { |
640 |
if (p->dispsw != &fbcon_splash16) |
641 |
p->splash_data->olddispsw = p->dispsw; |
642 |
p->dispsw = &fbcon_splash16; |
643 |
} else |
644 |
splash_off(p); |
645 |
return 0; |
646 |
} |
647 |
|
648 |
|
649 |
#ifdef CONFIG_PROC_FS |
650 |
#include <linux/proc_fs.h> |
651 |
|
652 |
struct proc_dir_entry *proc_splash; |
653 |
int splash_read_proc(char *buffer, char **start, off_t offset, int size, |
654 |
int *eof, void *data); |
655 |
int splash_write_proc(struct file *file, const char *buffer, |
656 |
unsigned long count, void *data); |
657 |
|
658 |
int splash_read_proc(char *buffer, char **start, off_t offset, int size, |
659 |
int *eof, void *data) |
660 |
{ |
661 |
int len = 0; |
662 |
|
663 |
off_t begin = 0; |
664 |
struct display *p = &fb_display[0]; |
665 |
|
666 |
int color = p->splash_data ? p->splash_data->splash_color << 4 | |
667 |
p->splash_data->splash_fg_color : splash_default >> 4; |
668 |
int status = p->splash_data ? p->splash_data->splash_state & 1 : 0; |
669 |
len += sprintf(buffer + len, "Splash screen v%s (0x%02x, %dx%d%s): %s\n", |
670 |
SPLASH_VERSION, color, p->var.xres, p->var.yres, |
671 |
(p->splash_data ? p->splash_data->splash_dosilent : 0)? ", silent" : "", |
672 |
status ? "on" : "off"); |
673 |
if (offset >= begin + len) |
674 |
return 0; |
675 |
|
676 |
*start = buffer + (begin - offset); |
677 |
|
678 |
return (size < begin + len - offset ? size : begin + len - offset); |
679 |
} |
680 |
|
681 |
static int splash_recolor(struct display *p) |
682 |
{ |
683 |
if (!p->splash_data) |
684 |
return -1; |
685 |
if (!p->splash_data->splash_state) |
686 |
return 0; |
687 |
con_remap_def_color(p->conp->vc_num, p->splash_data->splash_color << 4 | p->splash_data->splash_fg_color); |
688 |
if (fg_console == p->conp->vc_num) { |
689 |
splash_data = *p->splash_data; |
690 |
update_region(fg_console, |
691 |
p->conp->vc_origin + |
692 |
p->conp->vc_size_row * |
693 |
p->conp->vc_top, |
694 |
p->conp->vc_size_row * |
695 |
(p->conp->vc_bottom - |
696 |
p->conp->vc_top) / 2); |
697 |
} |
698 |
return 0; |
699 |
} |
700 |
|
701 |
static int splash_status(struct display *p) |
702 |
{ |
703 |
printk(KERN_INFO "Splash status on console %d changed to %s\n", p->conp->vc_num, p->splash_data && p->splash_data->splash_state ? "on" : "off"); |
704 |
|
705 |
if (fg_console == p->conp->vc_num) |
706 |
splash_prepare(p); |
707 |
if (p->splash_data && p->splash_data->splash_state) { |
708 |
con_remap_def_color(p->conp->vc_num, p->splash_data->splash_color << 4 | p->splash_data->splash_fg_color); |
709 |
/* resize_con also calls con_switch which resets yscroll */ |
710 |
vc_resize_con(p->splash_data->splash_text_he / fontheight(p), |
711 |
p->splash_data->splash_text_wi / fontwidth(p), |
712 |
p->conp->vc_num); |
713 |
if (fg_console == p->conp->vc_num) { |
714 |
update_region(fg_console, |
715 |
p->conp->vc_origin + |
716 |
p->conp->vc_size_row * |
717 |
p->conp->vc_top, |
718 |
p->conp->vc_size_row * |
719 |
(p->conp->vc_bottom - |
720 |
p->conp->vc_top) / 2); |
721 |
fbcon_splash16.clear_margins(p->conp, p, 0); |
722 |
} |
723 |
} else { |
724 |
/* Switch bootsplash off */ |
725 |
con_remap_def_color(p->conp->vc_num, 0x07); |
726 |
vc_resize_con(p->var.yres / fontheight(p), |
727 |
p->var.xres / fontwidth(p), |
728 |
p->conp->vc_num); |
729 |
} |
730 |
return 0; |
731 |
} |
732 |
|
733 |
int splash_write_proc(struct file *file, const char *buffer, |
734 |
unsigned long count, void *data) |
735 |
{ |
736 |
int new, unit; |
737 |
struct display *p; |
738 |
|
739 |
if (!buffer || !splash_default) |
740 |
return count; |
741 |
|
742 |
if (!strncmp(buffer, "show", 4) || !strncmp(buffer, "hide", 4)) { |
743 |
int pe; |
744 |
|
745 |
p = &fb_display[0]; |
746 |
if (buffer[4] == ' ' && buffer[5] == 'p') |
747 |
pe = 0; |
748 |
else if (buffer[4] == '\n') |
749 |
pe = 65535; |
750 |
else |
751 |
pe = simple_strtoul(buffer + 5, NULL, 0); |
752 |
if (pe < 0) |
753 |
pe = 0; |
754 |
if (pe > 65535) |
755 |
pe = 65535; |
756 |
if (*buffer == 'h') |
757 |
pe = 65535 - pe; |
758 |
pe += pe > 32767; |
759 |
if (p->splash_data && p->splash_data->splash_percent != pe) { |
760 |
p->splash_data->splash_percent = pe; |
761 |
if (fg_console != p->conp->vc_num || !p->splash_data->splash_state) |
762 |
return count; |
763 |
if (!p->splash_data->splash_overpaintok || p->splash_data->splash_percent == 65536) { |
764 |
if (splash_hasinter(p->splash_data->splash_boxes, p->splash_data->splash_boxcount)) |
765 |
splash_status(p); |
766 |
else |
767 |
splash_prepare(p); |
768 |
} else { |
769 |
if (p->splash_data->splash_silentjpeg && p->splash_data->splash_dosilent && p->splash_data->oldscreen_base) |
770 |
boxit(p->splash_data->oldscreen_base, p->next_line, p->splash_data->splash_sboxes, p->splash_data->splash_sboxcount, p->splash_data->splash_percent, 1); |
771 |
boxit(p->screen_base, p->next_line, p->splash_data->splash_boxes, p->splash_data->splash_boxcount, p->splash_data->splash_percent, 1); |
772 |
} |
773 |
} |
774 |
return count; |
775 |
} |
776 |
if (!strncmp(buffer,"silent\n",7) || !strncmp(buffer,"verbose\n",8)) { |
777 |
p = &fb_display[0]; |
778 |
if (p->splash_data && p->splash_data->splash_silentjpeg) { |
779 |
if (p->splash_data->splash_dosilent != (buffer[0] == 's')) { |
780 |
p->splash_data->splash_dosilent = buffer[0] == 's'; |
781 |
splash_status(p); |
782 |
} |
783 |
} |
784 |
return count; |
785 |
} |
786 |
if (!strncmp(buffer,"freesilent\n",11)) { |
787 |
p = &fb_display[0]; |
788 |
if (p->splash_data && p->splash_data->splash_silentjpeg) { |
789 |
printk(KERN_INFO "bootsplash: freeing silent jpeg\n"); |
790 |
p->splash_data->splash_silentjpeg = 0; |
791 |
vfree(p->splash_data->splash_sboxes); |
792 |
p->splash_data->splash_sboxes = 0; |
793 |
p->splash_data->splash_sboxcount = 0; |
794 |
if (p->splash_data->splash_dosilent) |
795 |
splash_status(p); |
796 |
p->splash_data->splash_dosilent = 0; |
797 |
} |
798 |
return count; |
799 |
} |
800 |
|
801 |
if (!strncmp(buffer, signature, 7)) { |
802 |
unit = splash_getraw((unsigned char *)buffer, (unsigned char *)buffer + count); |
803 |
if (unit >= 0) { |
804 |
p = &fb_display[unit]; |
805 |
splash_status(p); |
806 |
} |
807 |
return count; |
808 |
} |
809 |
p = &fb_display[0]; |
810 |
if (!p->splash_data) |
811 |
return count; |
812 |
if (buffer[0] == 't') { |
813 |
p->splash_data->splash_state ^= 1; |
814 |
splash_status(p); |
815 |
return count; |
816 |
} |
817 |
new = simple_strtoul(buffer, NULL, 0); |
818 |
if (new > 1) { |
819 |
/* expert user */ |
820 |
p->splash_data->splash_color = new >> 8 & 0xff; |
821 |
p->splash_data->splash_fg_color = new >> 4 & 0x0f; |
822 |
} |
823 |
if ((new & 1) == p->splash_data->splash_state) |
824 |
splash_recolor(p); |
825 |
else { |
826 |
p->splash_data->splash_state = new & 1; |
827 |
splash_status(p); |
828 |
} |
829 |
return count; |
830 |
} |
831 |
|
832 |
int splash_proc_register(void) |
833 |
{ |
834 |
if ((proc_splash = create_proc_entry("splash", 0, 0))) { |
835 |
proc_splash->read_proc = splash_read_proc; |
836 |
proc_splash->write_proc = splash_write_proc; |
837 |
return 0; |
838 |
} |
839 |
return 1; |
840 |
} |
841 |
|
842 |
int splash_proc_unregister(void) |
843 |
{ |
844 |
if (proc_splash) |
845 |
remove_proc_entry("splash", 0); |
846 |
return 0; |
847 |
} |
848 |
#endif |