Line 0
Link Here
|
|
|
1 |
/* |
2 |
* linux/drivers/video/bootsplash/bootsplash.c - |
3 |
* splash screen handling functions. |
4 |
* |
5 |
* (w) 2001-2004 by Volker Poplawski, <volker@poplawski.de>, |
6 |
* Stefan Reinauer, <stepan@suse.de>, |
7 |
* Steffen Winterfeldt, <snwint@suse.de>, |
8 |
* Michael Schroeder <mls@suse.de> |
9 |
* |
10 |
* Ideas & SuSE screen work by Ken Wimer, <wimer@suse.de> |
11 |
* |
12 |
* For more information on this code check http://www.bootsplash.org/ |
13 |
*/ |
14 |
|
15 |
#include <linux/module.h> |
16 |
#include <linux/types.h> |
17 |
#include <linux/fb.h> |
18 |
#include <linux/vt_kern.h> |
19 |
#include <linux/vmalloc.h> |
20 |
#include <linux/unistd.h> |
21 |
#include <linux/syscalls.h> |
22 |
|
23 |
#include <asm/irq.h> |
24 |
#include <asm/system.h> |
25 |
|
26 |
#include "../console/fbcon.h" |
27 |
#include "bootsplash.h" |
28 |
#include "decode-jpg.h" |
29 |
|
30 |
/* extern struct fb_ops vesafb_ops; */ |
31 |
extern signed char con2fb_map[MAX_NR_CONSOLES]; |
32 |
|
33 |
#define SPLASH_VERSION "3.1.6-2004/03/31" |
34 |
|
35 |
/* These errors have to match fbcon-jpegdec.h */ |
36 |
static unsigned char *jpg_errors[] = { |
37 |
"no SOI found", |
38 |
"not 8 bit", |
39 |
"height mismatch", |
40 |
"width mismatch", |
41 |
"bad width or height", |
42 |
"too many COMPPs", |
43 |
"illegal HV", |
44 |
"quant table selector", |
45 |
"picture is not YCBCR 221111", |
46 |
"unknow CID in scan", |
47 |
"dct not sequential", |
48 |
"wrong marker", |
49 |
"no EOI", |
50 |
"bad tables", |
51 |
"depth mismatch" |
52 |
}; |
53 |
|
54 |
static struct jpeg_decdata *decdata = 0; /* private decoder data */ |
55 |
|
56 |
static int splash_registered = 0; |
57 |
static int splash_usesilent = 0; /* shall we display the silentjpeg? */ |
58 |
int splash_default = 0xf01; |
59 |
|
60 |
static int splash_check_jpeg(unsigned char *jpeg, int width, int height, int depth); |
61 |
|
62 |
static int __init splash_setup(char *options) |
63 |
{ |
64 |
if(!strncmp("silent", options, 6)) { |
65 |
printk(KERN_INFO "bootsplash: silent mode.\n"); |
66 |
splash_usesilent = 1; |
67 |
/* skip "silent," */ |
68 |
if (strlen(options) == 6) |
69 |
return 0; |
70 |
options += 7; |
71 |
} |
72 |
if(!strncmp("verbose", options, 7)) { |
73 |
printk(KERN_INFO "bootsplash: verbose mode.\n"); |
74 |
splash_usesilent = 0; |
75 |
return 0; |
76 |
} |
77 |
splash_default = simple_strtoul(options, NULL, 0); |
78 |
return 0; |
79 |
} |
80 |
|
81 |
__setup("splash=", splash_setup); |
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 |
unsigned int stipple[32], sti, stin, stinn, stixs, stixe, stiys, stiye; |
126 |
int xs, xe, ys, ye, xo, yo; |
127 |
|
128 |
if (num == 0) |
129 |
return; |
130 |
bufend = buf + num * 12; |
131 |
stipple[0] = 0xffffffff; |
132 |
stin = 1; |
133 |
stinn = 0; |
134 |
stixs = stixe = 0; |
135 |
stiys = stiye = 0; |
136 |
while(buf < bufend) { |
137 |
doblend = 0; |
138 |
buf += boxextract(buf, data1, cols1, &doblend); |
139 |
if (data1[0] == 32767 && data1[1] == 32767) { |
140 |
/* box stipple */ |
141 |
if (stinn == 32) |
142 |
continue; |
143 |
if (stinn == 0) { |
144 |
stixs = data1[2]; |
145 |
stixe = data1[3]; |
146 |
stiys = stiye = 0; |
147 |
} else if (stinn == 4) { |
148 |
stiys = data1[2]; |
149 |
stiye = data1[3]; |
150 |
} |
151 |
stipple[stinn++] = (cols1[ 0] << 24) | (cols1[ 1] << 16) | (cols1[ 2] << 8) | cols1[ 3] ; |
152 |
stipple[stinn++] = (cols1[ 4] << 24) | (cols1[ 5] << 16) | (cols1[ 6] << 8) | cols1[ 7] ; |
153 |
stipple[stinn++] = (cols1[ 8] << 24) | (cols1[ 9] << 16) | (cols1[10] << 8) | cols1[11] ; |
154 |
stipple[stinn++] = (cols1[12] << 24) | (cols1[13] << 16) | (cols1[14] << 8) | cols1[15] ; |
155 |
stin = stinn; |
156 |
continue; |
157 |
} |
158 |
stinn = 0; |
159 |
if (data1[0] > 32767) |
160 |
buf += boxextract(buf, data2, cols2, &doblend); |
161 |
if (data1[0] == 32767 && data1[1] == 32766) { |
162 |
/* box copy */ |
163 |
i = 12 * (short)data1[3]; |
164 |
doblend = 0; |
165 |
i += boxextract(buf + i, data1, cols1, &doblend); |
166 |
if (data1[0] > 32767) |
167 |
boxextract(buf + i, data2, cols2, &doblend); |
168 |
} |
169 |
if (data1[0] == 32767) |
170 |
continue; |
171 |
if (data1[2] > 32767) { |
172 |
if (overpaint) |
173 |
continue; |
174 |
data1[2] = ~data1[2]; |
175 |
} |
176 |
if (data1[3] > 32767) { |
177 |
if (percent == 65536) |
178 |
continue; |
179 |
data1[3] = ~data1[3]; |
180 |
} |
181 |
if (data1[0] > 32767) { |
182 |
data1[0] = ~data1[0]; |
183 |
for (i = 0; i < 4; i++) |
184 |
data1[i] = (data1[i] * (65536 - percent) + data2[i] * percent) >> 16; |
185 |
for (i = 0; i < 16; i++) |
186 |
cols1[i] = (cols1[i] * (65536 - percent) + cols2[i] * percent) >> 16; |
187 |
} |
188 |
*(unsigned int *)cols2 = *(unsigned int *)cols1; |
189 |
a = cols2[3]; |
190 |
if (a == 0 && !doblend) |
191 |
continue; |
192 |
|
193 |
if (stixs >= 32768) { |
194 |
xo = xs = (stixs ^ 65535) + data1[0]; |
195 |
xe = stixe ? stixe + data1[0] : data1[2]; |
196 |
} else if (stixe >= 32768) { |
197 |
xs = stixs ? data1[2] - stixs : data1[0]; |
198 |
xe = data1[2] - (stixe ^ 65535); |
199 |
xo = xe + 1; |
200 |
} else { |
201 |
xo = xs = stixs; |
202 |
xe = stixe ? stixe : data1[2]; |
203 |
} |
204 |
if (stiys >= 32768) { |
205 |
yo = ys = (stiys ^ 65535) + data1[1]; |
206 |
ye = stiye ? stiye + data1[1] : data1[3]; |
207 |
} else if (stiye >= 32768) { |
208 |
ys = stiys ? data1[3] - stiys : data1[1]; |
209 |
ye = data1[3] - (stiye ^ 65535); |
210 |
yo = ye + 1; |
211 |
} else { |
212 |
yo = ys = stiys; |
213 |
ye = stiye ? stiye : data1[3]; |
214 |
} |
215 |
xo = 32 - (xo & 31); |
216 |
yo = stin - (yo % stin); |
217 |
if (xs < data1[0]) |
218 |
xs = data1[0]; |
219 |
if (xe > data1[2]) |
220 |
xe = data1[2]; |
221 |
if (ys < data1[1]) |
222 |
ys = data1[1]; |
223 |
if (ye > data1[3]) |
224 |
ye = data1[3]; |
225 |
|
226 |
for (y = ys; y <= ye; y++) { |
227 |
sti = stipple[(y + yo) % stin]; |
228 |
x = (xs + xo) & 31; |
229 |
if (x) |
230 |
sti = (sti << x) | (sti >> (32 - x)); |
231 |
if (doblend) { |
232 |
if ((p = data1[3] - data1[1]) != 0) |
233 |
p = ((y - data1[1]) << 16) / p; |
234 |
for (i = 0; i < 8; i++) |
235 |
cols2[i + 8] = (cols1[i] * (65536 - p) + cols1[i + 8] * p) >> 16; |
236 |
} |
237 |
add = (xs & 1); |
238 |
add ^= (add ^ y) & 1 ? 1 : 3; /* 2x2 ordered dithering */ |
239 |
picp = (unsigned short *)(pic + xs * 2 + y * bytes); |
240 |
for (x = xs; x <= xe; x++) { |
241 |
if (!(sti & 0x80000000)) { |
242 |
sti <<= 1; |
243 |
picp++; |
244 |
add ^= 3; |
245 |
continue; |
246 |
} |
247 |
sti = (sti << 1) | 1; |
248 |
if (doblend) { |
249 |
if ((p = data1[2] - data1[0]) != 0) |
250 |
p = ((x - data1[0]) << 16) / p; |
251 |
for (i = 0; i < 4; i++) |
252 |
cols2[i] = (cols2[i + 8] * (65536 - p) + cols2[i + 12] * p) >> 16; |
253 |
a = cols2[3]; |
254 |
} |
255 |
r = cols2[0]; |
256 |
g = cols2[1]; |
257 |
b = cols2[2]; |
258 |
if (a != 255) { |
259 |
i = *picp; |
260 |
r = ((i >> 8 & 0xf8) * (255 - a) + r * a) / 255; |
261 |
g = ((i >> 3 & 0xfc) * (255 - a) + g * a) / 255; |
262 |
b = ((i << 3 & 0xf8) * (255 - a) + b * a) / 255; |
263 |
} |
264 |
#define CLAMP(x) ((x) >= 256 ? 255 : (x)) |
265 |
i = ((CLAMP(r + add*2+1) & 0xf8) << 8) | |
266 |
((CLAMP(g + add ) & 0xfc) << 3) | |
267 |
((CLAMP(b + add*2+1) ) >> 3); |
268 |
*picp++ = i; |
269 |
add ^= 3; |
270 |
} |
271 |
} |
272 |
} |
273 |
} |
274 |
|
275 |
static int splash_check_jpeg(unsigned char *jpeg, int width, int height, int depth) |
276 |
{ |
277 |
int size, err; |
278 |
unsigned char *mem; |
279 |
|
280 |
size = ((width + 15) & ~15) * ((height + 15) & ~15) * (depth >> 3); |
281 |
mem = vmalloc(size); |
282 |
if (!mem) { |
283 |
printk(KERN_INFO "bootsplash: no memory for decoded picture.\n"); |
284 |
return -1; |
285 |
} |
286 |
if (!decdata) |
287 |
decdata = vmalloc(sizeof(*decdata)); |
288 |
if ((err = jpeg_decode(jpeg, mem, ((width + 15) & ~15), ((height + 15) & ~15), depth, decdata))) |
289 |
printk(KERN_INFO "bootsplash: error while decompressing picture: %s (%d)\n",jpg_errors[err - 1], err); |
290 |
vfree(mem); |
291 |
return err ? -1 : 0; |
292 |
} |
293 |
|
294 |
static void splash_free(struct vc_data *vc, struct fb_info *info) |
295 |
{ |
296 |
if (!vc->vc_splash_data) |
297 |
return; |
298 |
if (info->silent_screen_base) |
299 |
info->screen_base = info->silent_screen_base; |
300 |
info->silent_screen_base = 0; |
301 |
if (vc->vc_splash_data->splash_silentjpeg) |
302 |
vfree(vc->vc_splash_data->splash_sboxes); |
303 |
vfree(vc->vc_splash_data); |
304 |
vc->vc_splash_data = 0; |
305 |
info->splash_data = 0; |
306 |
} |
307 |
|
308 |
static int splash_mkpenguin(struct splash_data *data, int pxo, int pyo, int pwi, int phe, int pr, int pg, int pb) |
309 |
{ |
310 |
unsigned char *buf; |
311 |
int i; |
312 |
|
313 |
if (pwi ==0 || phe == 0) |
314 |
return 0; |
315 |
buf = (unsigned char *)data + sizeof(*data); |
316 |
pwi += pxo - 1; |
317 |
phe += pyo - 1; |
318 |
*buf++ = pxo; |
319 |
*buf++ = pxo >> 8; |
320 |
*buf++ = pyo; |
321 |
*buf++ = pyo >> 8; |
322 |
*buf++ = pwi; |
323 |
*buf++ = pwi >> 8; |
324 |
*buf++ = phe; |
325 |
*buf++ = phe >> 8; |
326 |
*buf++ = pr; |
327 |
*buf++ = pg; |
328 |
*buf++ = pb; |
329 |
*buf++ = 0; |
330 |
for (i = 0; i < 12; i++, buf++) |
331 |
*buf = buf[-12]; |
332 |
buf[-24] ^= 0xff; |
333 |
buf[-23] ^= 0xff; |
334 |
buf[-1] = 0xff; |
335 |
return 2; |
336 |
} |
337 |
|
338 |
static const int splash_offsets[3][16] = { |
339 |
/* len, unit, size, state, fgcol, col, xo, yo, wi, he |
340 |
boxcnt, ssize, sboxcnt, percent, overok, palcnt */ |
341 |
/* V1 */ |
342 |
{ 20, -1, 16, -1, -1, -1, 8, 10, 12, 14, |
343 |
-1, -1, -1, -1, -1, -1 }, |
344 |
/* V2 */ |
345 |
{ 35, 8, 12, 9, 10, 11, 16, 18, 20, 22, |
346 |
-1, -1, -1, -1, -1, -1 }, |
347 |
/* V3 */ |
348 |
{ 38, 8, 12, 9, 10, 11, 16, 18, 20, 22, |
349 |
24, 28, 32, 34, 36, 37 }, |
350 |
}; |
351 |
|
352 |
#define SPLASH_OFF_LEN offsets[0] |
353 |
#define SPLASH_OFF_UNIT offsets[1] |
354 |
#define SPLASH_OFF_SIZE offsets[2] |
355 |
#define SPLASH_OFF_STATE offsets[3] |
356 |
#define SPLASH_OFF_FGCOL offsets[4] |
357 |
#define SPLASH_OFF_COL offsets[5] |
358 |
#define SPLASH_OFF_XO offsets[6] |
359 |
#define SPLASH_OFF_YO offsets[7] |
360 |
#define SPLASH_OFF_WI offsets[8] |
361 |
#define SPLASH_OFF_HE offsets[9] |
362 |
#define SPLASH_OFF_BOXCNT offsets[10] |
363 |
#define SPLASH_OFF_SSIZE offsets[11] |
364 |
#define SPLASH_OFF_SBOXCNT offsets[12] |
365 |
#define SPLASH_OFF_PERCENT offsets[13] |
366 |
#define SPLASH_OFF_OVEROK offsets[14] |
367 |
#define SPLASH_OFF_PALCNT offsets[15] |
368 |
|
369 |
static inline int splash_getb(unsigned char *pos, int off) |
370 |
{ |
371 |
return off == -1 ? 0 : pos[off]; |
372 |
} |
373 |
|
374 |
static inline int splash_gets(unsigned char *pos, int off) |
375 |
{ |
376 |
return off == -1 ? 0 : pos[off] | pos[off + 1] << 8; |
377 |
} |
378 |
|
379 |
static inline int splash_geti(unsigned char *pos, int off) |
380 |
{ |
381 |
return off == -1 ? 0 : |
382 |
pos[off] | pos[off + 1] << 8 | pos[off + 2] << 16 | pos[off + 3] << 24; |
383 |
} |
384 |
|
385 |
static int splash_getraw(unsigned char *start, unsigned char *end, int *update) |
386 |
{ |
387 |
unsigned char *ndata; |
388 |
int version; |
389 |
int splash_size; |
390 |
int unit; |
391 |
int width, height; |
392 |
int silentsize; |
393 |
int boxcnt; |
394 |
int sboxcnt; |
395 |
int palcnt; |
396 |
int i, len; |
397 |
const int *offsets; |
398 |
struct vc_data *vc; |
399 |
struct fb_info *info; |
400 |
struct splash_data *sd; |
401 |
|
402 |
if (update) |
403 |
*update = -1; |
404 |
|
405 |
if (!update || start[7] < '2' || start[7] > '3' || splash_geti(start, 12) != (int)0xffffffff) |
406 |
printk(KERN_INFO "bootsplash %s: looking for picture...", SPLASH_VERSION); |
407 |
|
408 |
for (ndata = start; ndata < end; ndata++) { |
409 |
if (ndata[0] != 'B' || ndata[1] != 'O' || ndata[2] != 'O' || ndata[3] != 'T') |
410 |
continue; |
411 |
if (ndata[4] != 'S' || ndata[5] != 'P' || ndata[6] != 'L' || ndata[7] < '1' || ndata[7] > '3') |
412 |
continue; |
413 |
version = ndata[7] - '0'; |
414 |
offsets = splash_offsets[version - 1]; |
415 |
len = SPLASH_OFF_LEN; |
416 |
unit = splash_getb(ndata, SPLASH_OFF_UNIT); |
417 |
if (unit >= MAX_NR_CONSOLES) |
418 |
continue; |
419 |
if (unit) { |
420 |
vc_allocate(unit); |
421 |
} |
422 |
vc = vc_cons[unit].d; |
423 |
info = registered_fb[(int)con2fb_map[unit]]; |
424 |
width = info->var.xres; |
425 |
height = info->var.yres; |
426 |
splash_size = splash_geti(ndata, SPLASH_OFF_SIZE); |
427 |
if (splash_size == (int)0xffffffff && version > 1) { |
428 |
if ((sd = vc->vc_splash_data) != 0) { |
429 |
int up = 0; |
430 |
i = splash_getb(ndata, SPLASH_OFF_STATE); |
431 |
if (i != 255) { |
432 |
sd->splash_state = i; |
433 |
up = -1; |
434 |
} |
435 |
i = splash_getb(ndata, SPLASH_OFF_FGCOL); |
436 |
if (i != 255) { |
437 |
sd->splash_fg_color = i; |
438 |
up = -1; |
439 |
} |
440 |
i = splash_getb(ndata, SPLASH_OFF_COL); |
441 |
if (i != 255) { |
442 |
sd->splash_color = i; |
443 |
up = -1; |
444 |
} |
445 |
boxcnt = sboxcnt = 0; |
446 |
if (ndata + len <= end) { |
447 |
boxcnt = splash_gets(ndata, SPLASH_OFF_BOXCNT); |
448 |
sboxcnt = splash_gets(ndata, SPLASH_OFF_SBOXCNT); |
449 |
} |
450 |
if (boxcnt) { |
451 |
i = splash_gets(ndata, len); |
452 |
if (boxcnt + i <= sd->splash_boxcount && ndata + len + 2 + boxcnt * 12 <= end) { |
453 |
|
454 |
if (splash_geti(ndata, len + 2) != 0x7ffd7fff || !memcmp(ndata + len + 2, sd->splash_boxes + i * 12, 8)) { |
455 |
|
456 |
memcpy(sd->splash_boxes + i * 12, ndata + len + 2, boxcnt * 12); |
457 |
up |= 1; |
458 |
} |
459 |
} |
460 |
len += boxcnt * 12 + 2; |
461 |
} |
462 |
if (sboxcnt) { |
463 |
i = splash_gets(ndata, len); |
464 |
if (sboxcnt + i <= sd->splash_sboxcount && ndata + len + 2 + sboxcnt * 12 <= end) { |
465 |
if (splash_geti(ndata, len + 2) != 0x7ffd7fff || !memcmp(ndata + len + 2, sd->splash_sboxes + i * 12, 8)) { |
466 |
memcpy(sd->splash_sboxes + i * 12, ndata + len + 2, sboxcnt * 12); |
467 |
up |= 2; |
468 |
} |
469 |
} |
470 |
} |
471 |
if (update) |
472 |
*update = up; |
473 |
} |
474 |
return unit; |
475 |
} |
476 |
if (splash_size == 0) { |
477 |
printk(KERN_INFO"...found, freeing memory.\n"); |
478 |
if (vc->vc_splash_data) |
479 |
splash_free(vc, info); |
480 |
return unit; |
481 |
} |
482 |
boxcnt = splash_gets(ndata, SPLASH_OFF_BOXCNT); |
483 |
palcnt = 3 * splash_getb(ndata, SPLASH_OFF_PALCNT); |
484 |
if (ndata + len + splash_size > end) { |
485 |
printk(KERN_INFO "...found, but truncated!\n"); |
486 |
return -1; |
487 |
} |
488 |
if (!jpeg_check_size(ndata + len + boxcnt * 12 + palcnt, width, height)) { |
489 |
ndata += len + splash_size - 1; |
490 |
continue; |
491 |
} |
492 |
if (splash_check_jpeg(ndata + len + boxcnt * 12 + palcnt, width, height, info->var.bits_per_pixel)) |
493 |
return -1; |
494 |
silentsize = splash_geti(ndata, SPLASH_OFF_SSIZE); |
495 |
if (silentsize) |
496 |
printk(KERN_INFO" silentjpeg size %d bytes,", silentsize); |
497 |
if (silentsize >= splash_size) { |
498 |
printk(KERN_INFO " bigger than splashsize!\n"); |
499 |
return -1; |
500 |
} |
501 |
splash_size -= silentsize; |
502 |
if (!splash_usesilent) |
503 |
silentsize = 0; |
504 |
else if (height * 2 * info->fix.line_length > info->fix.smem_len) { |
505 |
printk(KERN_INFO " does not fit into framebuffer.\n"); |
506 |
silentsize = 0; |
507 |
} |
508 |
sboxcnt = splash_gets(ndata, SPLASH_OFF_SBOXCNT); |
509 |
if (silentsize) { |
510 |
unsigned char *simage = ndata + len + splash_size + 12 * sboxcnt; |
511 |
if (!jpeg_check_size(simage, width, height) || |
512 |
splash_check_jpeg(simage, width, height, info->var.bits_per_pixel)) { |
513 |
printk(KERN_INFO " error in silent jpeg.\n"); |
514 |
silentsize = 0; |
515 |
} |
516 |
} |
517 |
if (vc->vc_splash_data) |
518 |
splash_free(vc, info); |
519 |
vc->vc_splash_data = sd = vmalloc(sizeof(*sd) + splash_size + (version < 3 ? 2 * 12 : 0)); |
520 |
if (!sd) |
521 |
break; |
522 |
sd->splash_silentjpeg = 0; |
523 |
sd->splash_sboxes = 0; |
524 |
sd->splash_sboxcount = 0; |
525 |
if (silentsize) { |
526 |
sd->splash_silentjpeg = vmalloc(silentsize); |
527 |
if (sd->splash_silentjpeg) { |
528 |
memcpy(sd->splash_silentjpeg, ndata + len + splash_size, silentsize); |
529 |
sd->splash_sboxes = vc->vc_splash_data->splash_silentjpeg; |
530 |
sd->splash_silentjpeg += 12 * sboxcnt; |
531 |
sd->splash_sboxcount = sboxcnt; |
532 |
} |
533 |
} |
534 |
sd->splash_state = splash_getb(ndata, SPLASH_OFF_STATE); |
535 |
sd->splash_fg_color = splash_getb(ndata, SPLASH_OFF_FGCOL); |
536 |
sd->splash_color = splash_getb(ndata, SPLASH_OFF_COL); |
537 |
sd->splash_overpaintok = splash_getb(ndata, SPLASH_OFF_OVEROK); |
538 |
sd->splash_text_xo = splash_gets(ndata, SPLASH_OFF_XO); |
539 |
sd->splash_text_yo = splash_gets(ndata, SPLASH_OFF_YO); |
540 |
sd->splash_text_wi = splash_gets(ndata, SPLASH_OFF_WI); |
541 |
sd->splash_text_he = splash_gets(ndata, SPLASH_OFF_HE); |
542 |
sd->splash_percent = splash_gets(ndata, SPLASH_OFF_PERCENT); |
543 |
if (version == 1) { |
544 |
sd->splash_text_xo *= 8; |
545 |
sd->splash_text_wi *= 8; |
546 |
sd->splash_text_yo *= 16; |
547 |
sd->splash_text_he *= 16; |
548 |
sd->splash_color = (splash_default >> 8) & 0x0f; |
549 |
sd->splash_fg_color = (splash_default >> 4) & 0x0f; |
550 |
sd->splash_state = splash_default & 1; |
551 |
} |
552 |
if (sd->splash_text_xo + sd->splash_text_wi > width || sd->splash_text_yo + sd->splash_text_he > height) { |
553 |
splash_free(vc, info); |
554 |
printk(KERN_INFO " found, but has oversized text area!\n"); |
555 |
return -1; |
556 |
} |
557 |
/* if (!vc_cons[unit].d || info->fbops != &vesafb_ops) { |
558 |
splash_free(vc, info); |
559 |
printk(KERN_INFO " found, but framebuffer can't handle it!\n"); |
560 |
return -1; |
561 |
} */ |
562 |
printk(KERN_INFO "...found (%dx%d, %d bytes, v%d).\n", width, height, splash_size, version); |
563 |
if (version == 1) { |
564 |
printk(KERN_WARNING "bootsplash: Using deprecated v1 header. Updating your splash utility recommended.\n"); |
565 |
printk(KERN_INFO "bootsplash: Find the latest version at http://www.bootsplash.org/\n"); |
566 |
} |
567 |
|
568 |
/* fake penguin box for older formats */ |
569 |
if (version == 1) |
570 |
boxcnt = splash_mkpenguin(sd, sd->splash_text_xo + 10, sd->splash_text_yo + 10, sd->splash_text_wi - 20, sd->splash_text_he - 20, 0xf0, 0xf0, 0xf0); |
571 |
else if (version == 2) |
572 |
boxcnt = splash_mkpenguin(sd, splash_gets(ndata, 24), splash_gets(ndata, 26), splash_gets(ndata, 28), splash_gets(ndata, 30), splash_getb(ndata, 32), splash_getb(ndata, 33), splash_getb(ndata, 34)); |
573 |
|
574 |
memcpy((char *)sd + sizeof(*sd) + (version < 3 ? boxcnt * 12 : 0), ndata + len, splash_size); |
575 |
sd->splash_boxcount = boxcnt; |
576 |
sd->splash_boxes = (unsigned char *)sd + sizeof(*sd); |
577 |
sd->splash_palette = sd->splash_boxes + boxcnt * 12; |
578 |
sd->splash_jpeg = sd->splash_palette + palcnt; |
579 |
sd->splash_palcnt = palcnt / 3; |
580 |
sd->splash_dosilent = sd->splash_silentjpeg != 0; |
581 |
return unit; |
582 |
} |
583 |
printk(KERN_INFO "...no good signature found.\n"); |
584 |
return -1; |
585 |
} |
586 |
|
587 |
int splash_verbose(void) |
588 |
{ |
589 |
struct vc_data *vc; |
590 |
struct fb_info *info; |
591 |
|
592 |
if (!splash_usesilent) |
593 |
return 0; |
594 |
|
595 |
vc = vc_cons[0].d; |
596 |
|
597 |
if (!vc || !vc->vc_splash_data || !vc->vc_splash_data->splash_state) |
598 |
return 0; |
599 |
if (fg_console != vc->vc_num) |
600 |
return 0; |
601 |
if (!vc->vc_splash_data->splash_silentjpeg || !vc->vc_splash_data->splash_dosilent) |
602 |
return 0; |
603 |
vc->vc_splash_data->splash_dosilent = 0; |
604 |
info = registered_fb[(int)con2fb_map[0]]; |
605 |
if (!info->silent_screen_base) |
606 |
return 0; |
607 |
splashcopy(info->silent_screen_base, info->screen_base, info->var.yres, info->var.xres, info->fix.line_length, info->fix.line_length); |
608 |
info->screen_base = info->silent_screen_base; |
609 |
info->silent_screen_base = 0; |
610 |
return 1; |
611 |
} |
612 |
|
613 |
static void splash_off(struct fb_info *info) |
614 |
{ |
615 |
if (info->silent_screen_base) |
616 |
info->screen_base = info->silent_screen_base; |
617 |
info->silent_screen_base = 0; |
618 |
info->splash_data = 0; |
619 |
if (info->splash_pic) |
620 |
vfree(info->splash_pic); |
621 |
info->splash_pic = 0; |
622 |
info->splash_pic_size = 0; |
623 |
} |
624 |
|
625 |
int splash_prepare(struct vc_data *vc, struct fb_info *info) |
626 |
{ |
627 |
int err; |
628 |
int width, height, depth, size, sbytes; |
629 |
|
630 |
if (!vc->vc_splash_data || !vc->vc_splash_data->splash_state) { |
631 |
if (decdata) |
632 |
vfree(decdata); |
633 |
decdata = 0; |
634 |
splash_off(info); |
635 |
return -1; |
636 |
} |
637 |
|
638 |
width = info->var.xres; |
639 |
height = info->var.yres; |
640 |
depth = info->var.bits_per_pixel; |
641 |
if (depth != 16) { /* Other targets might need fixing */ |
642 |
splash_off(info); |
643 |
return -2; |
644 |
} |
645 |
|
646 |
sbytes = ((width + 15) & ~15) * (depth >> 3); |
647 |
size = sbytes * ((height + 15) & ~15); |
648 |
if (size != info->splash_pic_size) |
649 |
splash_off(info); |
650 |
if (!info->splash_pic) |
651 |
info->splash_pic = vmalloc(size); |
652 |
|
653 |
if (!info->splash_pic) { |
654 |
printk(KERN_INFO "bootsplash: not enough memory.\n"); |
655 |
splash_off(info); |
656 |
return -3; |
657 |
} |
658 |
|
659 |
if (!decdata) |
660 |
decdata = vmalloc(sizeof(*decdata)); |
661 |
|
662 |
if (vc->vc_splash_data->splash_silentjpeg && vc->vc_splash_data->splash_dosilent) { |
663 |
/* fill area after framebuffer with other jpeg */ |
664 |
if ((err = jpeg_decode(vc->vc_splash_data->splash_silentjpeg, info->splash_pic, |
665 |
((width + 15) & ~15), ((height + 15) & ~15), depth, decdata))) { |
666 |
printk(KERN_INFO "bootsplash: error while decompressing silent picture: %s (%d)\n", jpg_errors[err - 1], err); |
667 |
if (info->silent_screen_base) |
668 |
info->screen_base = info->silent_screen_base; |
669 |
vc->vc_splash_data->splash_dosilent = 0; |
670 |
} else { |
671 |
if (vc->vc_splash_data->splash_sboxcount) |
672 |
boxit(info->splash_pic, sbytes, vc->vc_splash_data->splash_sboxes, |
673 |
vc->vc_splash_data->splash_sboxcount, vc->vc_splash_data->splash_percent, 0); |
674 |
|
675 |
if (!info->silent_screen_base) |
676 |
info->silent_screen_base = info->screen_base; |
677 |
splashcopy(info->silent_screen_base, info->splash_pic, info->var.yres, info->var.xres, info->fix.line_length, sbytes); |
678 |
info->screen_base = info->silent_screen_base + info->fix.line_length * info->var.yres; |
679 |
} |
680 |
} else if (info->silent_screen_base) |
681 |
info->screen_base = info->silent_screen_base; |
682 |
|
683 |
if ((err = jpeg_decode(vc->vc_splash_data->splash_jpeg, info->splash_pic, |
684 |
((width + 15) & ~15), ((height + 15) & ~15), depth, decdata))) { |
685 |
printk(KERN_INFO "bootsplash: error while decompressing picture: %s (%d) .\n", jpg_errors[err - 1], err); |
686 |
splash_off(info); |
687 |
return -4; |
688 |
} |
689 |
info->splash_pic_size = size; |
690 |
info->splash_bytes = sbytes; |
691 |
if (vc->vc_splash_data->splash_boxcount) |
692 |
boxit(info->splash_pic, sbytes, vc->vc_splash_data->splash_boxes, vc->vc_splash_data->splash_boxcount, vc->vc_splash_data->splash_percent, 0); |
693 |
if (vc->vc_splash_data->splash_state) |
694 |
info->splash_data = vc->vc_splash_data; |
695 |
else |
696 |
splash_off(info); |
697 |
return 0; |
698 |
} |
699 |
|
700 |
|
701 |
#ifdef CONFIG_PROC_FS |
702 |
|
703 |
#include <linux/proc_fs.h> |
704 |
|
705 |
static int splash_read_proc(char *buffer, char **start, off_t offset, int size, |
706 |
int *eof, void *data); |
707 |
static int splash_write_proc(struct file *file, const char *buffer, |
708 |
unsigned long count, void *data); |
709 |
static int splash_status(struct vc_data *vc); |
710 |
static int splash_recolor(struct vc_data *vc); |
711 |
static int splash_proc_register(void); |
712 |
|
713 |
static struct proc_dir_entry *proc_splash; |
714 |
|
715 |
static int splash_recolor(struct vc_data *vc) |
716 |
{ |
717 |
if (!vc->vc_splash_data) |
718 |
return -1; |
719 |
if (!vc->vc_splash_data->splash_state) |
720 |
return 0; |
721 |
con_remap_def_color(vc, vc->vc_splash_data->splash_color << 4 | vc->vc_splash_data->splash_fg_color); |
722 |
if (fg_console == vc->vc_num) { |
723 |
update_region(vc, vc->vc_origin + vc->vc_size_row * vc->vc_top, |
724 |
vc->vc_size_row * (vc->vc_bottom - vc->vc_top) / 2); |
725 |
} |
726 |
return 0; |
727 |
} |
728 |
|
729 |
static int splash_status(struct vc_data *vc) |
730 |
{ |
731 |
struct fb_info *info; |
732 |
printk(KERN_INFO "bootsplash: status on console %d changed to %s\n", vc->vc_num, vc->vc_splash_data && vc->vc_splash_data->splash_state ? "on" : "off"); |
733 |
|
734 |
info = registered_fb[(int) con2fb_map[vc->vc_num]]; |
735 |
if (fg_console == vc->vc_num) |
736 |
splash_prepare(vc, info); |
737 |
if (vc->vc_splash_data && vc->vc_splash_data->splash_state) { |
738 |
con_remap_def_color(vc, vc->vc_splash_data->splash_color << 4 | vc->vc_splash_data->splash_fg_color); |
739 |
/* vc_resize also calls con_switch which resets yscroll */ |
740 |
vc_resize(vc, vc->vc_splash_data->splash_text_wi / vc->vc_font.width, vc->vc_splash_data->splash_text_he / vc->vc_font.height); |
741 |
if (fg_console == vc->vc_num) { |
742 |
update_region(vc, vc->vc_origin + vc->vc_size_row * vc->vc_top, |
743 |
vc->vc_size_row * (vc->vc_bottom - vc->vc_top) / 2); |
744 |
splash_clear_margins(vc->vc_splash_data, vc, info, 0); |
745 |
} |
746 |
} else { |
747 |
/* Switch bootsplash off */ |
748 |
con_remap_def_color(vc, 0x07); |
749 |
vc_resize(vc, info->var.xres / vc->vc_font.width, info->var.yres / vc->vc_font.height); |
750 |
} |
751 |
return 0; |
752 |
} |
753 |
|
754 |
static int splash_read_proc(char *buffer, char **start, off_t offset, int size, |
755 |
int *eof, void *data) |
756 |
{ |
757 |
int len = 0; |
758 |
off_t begin = 0; |
759 |
struct vc_data *vc = vc_cons[0].d; |
760 |
struct fb_info *info = registered_fb[(int)con2fb_map[0]]; |
761 |
int color = vc->vc_splash_data ? vc->vc_splash_data->splash_color << 4 | |
762 |
vc->vc_splash_data->splash_fg_color : splash_default >> 4; |
763 |
int status = vc->vc_splash_data ? vc->vc_splash_data->splash_state & 1 : 0; |
764 |
len += sprintf(buffer + len, "Splash screen v%s (0x%02x, %dx%d%s): %s\n", |
765 |
SPLASH_VERSION, color, info->var.xres, info->var.yres, |
766 |
(vc->vc_splash_data ? vc->vc_splash_data->splash_dosilent : 0)? ", silent" : "", |
767 |
status ? "on" : "off"); |
768 |
if (offset >= begin + len) |
769 |
return 0; |
770 |
|
771 |
*start = buffer + (begin - offset); |
772 |
|
773 |
return (size < begin + len - offset ? size : begin + len - offset); |
774 |
} |
775 |
|
776 |
static int splash_write_proc(struct file *file, const char *buffer, |
777 |
unsigned long count, void *data) |
778 |
{ |
779 |
int new, unit; |
780 |
struct vc_data *vc; |
781 |
|
782 |
if (!buffer || !splash_default) |
783 |
return count; |
784 |
|
785 |
acquire_console_sem(); |
786 |
if (!strncmp(buffer, "show", 4) || !strncmp(buffer, "hide", 4)) { |
787 |
int pe, oldpe; |
788 |
|
789 |
vc = vc_cons[0].d; |
790 |
if (buffer[4] == ' ' && buffer[5] == 'p') |
791 |
pe = 0; |
792 |
else if (buffer[4] == '\n') |
793 |
pe = 65535; |
794 |
else |
795 |
pe = simple_strtoul(buffer + 5, NULL, 0); |
796 |
if (pe < 0) |
797 |
pe = 0; |
798 |
if (pe > 65535) |
799 |
pe = 65535; |
800 |
if (*buffer == 'h') |
801 |
pe = 65535 - pe; |
802 |
pe += pe > 32767; |
803 |
if (vc->vc_splash_data && vc->vc_splash_data->splash_percent != pe) { |
804 |
struct fb_info *info; |
805 |
struct fbcon_ops *ops; |
806 |
|
807 |
oldpe = vc->vc_splash_data->splash_percent; |
808 |
vc->vc_splash_data->splash_percent = pe; |
809 |
if (fg_console != 0 || !vc->vc_splash_data->splash_state) { |
810 |
release_console_sem(); |
811 |
return count; |
812 |
} |
813 |
info = registered_fb[(int) con2fb_map[vc->vc_num]]; |
814 |
ops = info->fbcon_par; |
815 |
if (ops->blank_state) { |
816 |
release_console_sem(); |
817 |
return count; |
818 |
} |
819 |
if (!vc->vc_splash_data->splash_overpaintok || pe == 65536 || pe < oldpe) { |
820 |
if (splash_hasinter(vc->vc_splash_data->splash_boxes, vc->vc_splash_data->splash_boxcount)) |
821 |
splash_status(vc); |
822 |
else |
823 |
splash_prepare(vc, info); |
824 |
} else { |
825 |
if (vc->vc_splash_data->splash_silentjpeg && vc->vc_splash_data->splash_dosilent && info->silent_screen_base) |
826 |
boxit(info->silent_screen_base, info->fix.line_length, vc->vc_splash_data->splash_sboxes, vc->vc_splash_data->splash_sboxcount, vc->vc_splash_data->splash_percent, 1); |
827 |
boxit(info->screen_base, info->fix.line_length, vc->vc_splash_data->splash_boxes, vc->vc_splash_data->splash_boxcount, vc->vc_splash_data->splash_percent, 1); |
828 |
} |
829 |
} |
830 |
release_console_sem(); |
831 |
return count; |
832 |
} |
833 |
if (!strncmp(buffer,"silent\n",7) || !strncmp(buffer,"verbose\n",8)) { |
834 |
vc = vc_cons[0].d; |
835 |
if (vc->vc_splash_data && vc->vc_splash_data->splash_silentjpeg) { |
836 |
if (vc->vc_splash_data->splash_dosilent != (buffer[0] == 's')) { |
837 |
vc->vc_splash_data->splash_dosilent = buffer[0] == 's'; |
838 |
splash_status(vc); |
839 |
} |
840 |
} |
841 |
release_console_sem(); |
842 |
return count; |
843 |
} |
844 |
if (!strncmp(buffer,"freesilent\n",11)) { |
845 |
vc = vc_cons[0].d; |
846 |
if (vc->vc_splash_data && vc->vc_splash_data->splash_silentjpeg) { |
847 |
printk(KERN_INFO "bootsplash: freeing silent jpeg\n"); |
848 |
vc->vc_splash_data->splash_silentjpeg = 0; |
849 |
vfree(vc->vc_splash_data->splash_sboxes); |
850 |
vc->vc_splash_data->splash_sboxes = 0; |
851 |
vc->vc_splash_data->splash_sboxcount = 0; |
852 |
if (vc->vc_splash_data->splash_dosilent) |
853 |
splash_status(vc); |
854 |
vc->vc_splash_data->splash_dosilent = 0; |
855 |
} |
856 |
release_console_sem(); |
857 |
return count; |
858 |
} |
859 |
|
860 |
if (!strncmp(buffer, "BOOTSPL", 7)) { |
861 |
int up = -1; |
862 |
unit = splash_getraw((unsigned char *)buffer, (unsigned char *)buffer + count, &up); |
863 |
if (unit >= 0) { |
864 |
vc = vc_cons[unit].d; |
865 |
if (up == -1) |
866 |
splash_status(vc); |
867 |
else { |
868 |
struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; |
869 |
struct fbcon_ops *ops = info->fbcon_par; |
870 |
if (ops->blank_state) |
871 |
up = 0; |
872 |
if ((up & 2) != 0 && vc->vc_splash_data->splash_silentjpeg && vc->vc_splash_data->splash_dosilent && info->silent_screen_base) |
873 |
boxit(info->silent_screen_base, info->fix.line_length, vc->vc_splash_data->splash_sboxes, vc->vc_splash_data->splash_sboxcount, vc->vc_splash_data->splash_percent, 1); |
874 |
if ((up & 1) != 0) |
875 |
boxit(info->screen_base, info->fix.line_length, vc->vc_splash_data->splash_boxes, vc->vc_splash_data->splash_boxcount, vc->vc_splash_data->splash_percent, 1); |
876 |
} |
877 |
} |
878 |
release_console_sem(); |
879 |
return count; |
880 |
} |
881 |
vc = vc_cons[0].d; |
882 |
if (!vc->vc_splash_data) { |
883 |
release_console_sem(); |
884 |
return count; |
885 |
} |
886 |
if (buffer[0] == 't') { |
887 |
vc->vc_splash_data->splash_state ^= 1; |
888 |
splash_status(vc); |
889 |
release_console_sem(); |
890 |
return count; |
891 |
} |
892 |
new = simple_strtoul(buffer, NULL, 0); |
893 |
if (new > 1) { |
894 |
/* expert user */ |
895 |
vc->vc_splash_data->splash_color = new >> 8 & 0xff; |
896 |
vc->vc_splash_data->splash_fg_color = new >> 4 & 0x0f; |
897 |
} |
898 |
if ((new & 1) == vc->vc_splash_data->splash_state) |
899 |
splash_recolor(vc); |
900 |
else { |
901 |
vc->vc_splash_data->splash_state = new & 1; |
902 |
splash_status(vc); |
903 |
} |
904 |
release_console_sem(); |
905 |
return count; |
906 |
} |
907 |
|
908 |
static int splash_proc_register(void) |
909 |
{ |
910 |
if ((proc_splash = create_proc_entry("splash", 0, 0))) { |
911 |
proc_splash->read_proc = splash_read_proc; |
912 |
proc_splash->write_proc = splash_write_proc; |
913 |
return 0; |
914 |
} |
915 |
return 1; |
916 |
} |
917 |
|
918 |
# if 0 |
919 |
static int splash_proc_unregister(void) |
920 |
{ |
921 |
if (proc_splash) |
922 |
remove_proc_entry("splash", 0); |
923 |
return 0; |
924 |
} |
925 |
# endif |
926 |
#endif /* CONFIG_PROC_FS */ |
927 |
|
928 |
void splash_init(void) |
929 |
{ |
930 |
struct fb_info *info; |
931 |
struct vc_data *vc; |
932 |
int isramfs = 1; |
933 |
int fd; |
934 |
int len; |
935 |
int max_len = 1024*1024*2; |
936 |
char *mem; |
937 |
|
938 |
if (splash_registered) |
939 |
return; |
940 |
vc = vc_cons[0].d; |
941 |
info = registered_fb[0]; |
942 |
if (!vc || !info || info->var.bits_per_pixel != 16) |
943 |
return; |
944 |
#ifdef CONFIG_PROC_FS |
945 |
splash_proc_register(); |
946 |
#endif |
947 |
splash_registered = 1; |
948 |
if (vc->vc_splash_data) |
949 |
return; |
950 |
if ((fd = sys_open("/bootsplash", O_RDONLY, 0)) < 0) { |
951 |
isramfs = 0; |
952 |
fd = sys_open("/initrd.image", O_RDONLY, 0); |
953 |
} |
954 |
if (fd < 0) |
955 |
return; |
956 |
if ((len = (int)sys_lseek(fd, (off_t)0, 2)) <= 0) { |
957 |
sys_close(fd); |
958 |
return; |
959 |
} |
960 |
/* Don't look for more than the last 2MB */ |
961 |
if (len > max_len) { |
962 |
printk( KERN_INFO "bootsplash: scanning last %dMB of initrd for signature\n", |
963 |
max_len>>20); |
964 |
sys_lseek(fd, (off_t)(len - max_len), 0); |
965 |
len = max_len; |
966 |
} else { |
967 |
sys_lseek(fd, (off_t)0, 0); |
968 |
} |
969 |
|
970 |
mem = vmalloc(len); |
971 |
if (mem) { |
972 |
acquire_console_sem(); |
973 |
if ((int)sys_read(fd, mem, len) == len && splash_getraw((unsigned char *)mem, (unsigned char *)mem + len, (int *)0) == 0 && vc->vc_splash_data) |
974 |
vc->vc_splash_data->splash_state = splash_default & 1; |
975 |
release_console_sem(); |
976 |
vfree(mem); |
977 |
} |
978 |
sys_close(fd); |
979 |
if (isramfs) |
980 |
sys_unlink("/bootsplash"); |
981 |
return; |
982 |
} |
983 |
|