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