|
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 |
|