]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | From: mls@suse.de |
2 | Subject: Bootsplash for current kernel | |
3 | Patch-mainline: no | |
4 | References: none | |
5 | ||
6 | Better support for other VTs. Don't change percent or silent status | |
7 | when installing a new jpeg. Provide splash_set_percent function. | |
8 | ||
9 | Signed-off-by: mls@suse.de | |
10 | ||
11 | --- | |
12 | drivers/char/keyboard.c | 9 | |
13 | drivers/char/n_tty.c | 9 | |
14 | drivers/char/vt.c | 25 | |
15 | drivers/video/Kconfig | 4 | |
16 | drivers/video/Makefile | 1 | |
17 | drivers/video/bootsplash/Kconfig | 17 | |
18 | drivers/video/bootsplash/Makefile | 5 | |
19 | drivers/video/bootsplash/bootsplash.c | 1017 ++++++++++++++++++++++++++++++++++ | |
20 | drivers/video/bootsplash/bootsplash.h | 44 + | |
21 | drivers/video/bootsplash/decode-jpg.c | 957 +++++++++++++++++++++++++++++++ | |
22 | drivers/video/bootsplash/decode-jpg.h | 35 + | |
23 | drivers/video/bootsplash/render.c | 328 ++++++++++ | |
24 | drivers/video/console/bitblit.c | 39 + | |
25 | drivers/video/console/fbcon.c | 53 + | |
26 | drivers/video/console/fbcon.h | 28 | |
27 | drivers/video/vesafb.c | 8 | |
28 | include/linux/console_struct.h | 3 | |
29 | include/linux/fb.h | 8 | |
30 | kernel/panic.c | 12 | |
31 | 19 files changed, 2601 insertions(+), 1 deletion(-) | |
32 | ||
33 | --- a/drivers/char/keyboard.c | |
34 | +++ b/drivers/char/keyboard.c | |
35 | @@ -1180,6 +1180,15 @@ static void kbd_keycode(unsigned int key | |
36 | if (keycode < BTN_MISC && printk_ratelimit()) | |
37 | printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode); | |
38 | ||
39 | +#ifdef CONFIG_BOOTSPLASH | |
40 | + /* This code has to be redone for some non-x86 platforms */ | |
41 | + if (down == 1 && (keycode == 0x3c || keycode == 0x01)) { /* F2 and ESC on PC keyboard */ | |
42 | + extern int splash_verbose(void); | |
43 | + if (splash_verbose()) | |
44 | + return; | |
45 | + } | |
46 | +#endif | |
47 | + | |
48 | #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ | |
49 | if (keycode == KEY_SYSRQ && (sysrq_down || (down == 1 && sysrq_alt))) { | |
50 | if (!sysrq_down) { | |
51 | --- a/drivers/char/n_tty.c | |
52 | +++ b/drivers/char/n_tty.c | |
53 | @@ -1325,6 +1325,15 @@ do_it_again: | |
54 | tty->minimum_to_wake = (minimum - (b - buf)); | |
55 | ||
56 | if (!input_available_p(tty, 0)) { | |
57 | +#ifdef CONFIG_BOOTSPLASH | |
58 | + if (file->f_dentry->d_inode->i_rdev == MKDEV(TTY_MAJOR,0) || | |
59 | + file->f_dentry->d_inode->i_rdev == MKDEV(TTY_MAJOR,1) || | |
60 | + file->f_dentry->d_inode->i_rdev == MKDEV(TTYAUX_MAJOR,0) || | |
61 | + file->f_dentry->d_inode->i_rdev == MKDEV(TTYAUX_MAJOR,1)) { | |
62 | + extern int splash_verbose(void); | |
63 | + (void)splash_verbose(); | |
64 | + } | |
65 | +#endif | |
66 | if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) { | |
67 | retval = -EIO; | |
68 | break; | |
69 | --- a/drivers/char/vt.c | |
70 | +++ b/drivers/char/vt.c | |
71 | @@ -4092,6 +4092,31 @@ void vcs_scr_writew(struct vc_data *vc, | |
72 | } | |
73 | } | |
74 | ||
75 | +#ifdef CONFIG_BOOTSPLASH | |
76 | +void con_remap_def_color(struct vc_data *vc, int new_color) | |
77 | +{ | |
78 | + unsigned short *sbuf = vc->vc_screenbuf; | |
79 | + unsigned c, len = vc->vc_screenbuf_size >> 1; | |
80 | + int old_color; | |
81 | + | |
82 | + if (sbuf) { | |
83 | + old_color = vc->vc_def_color << 8; | |
84 | + new_color <<= 8; | |
85 | + while(len--) { | |
86 | + c = *sbuf; | |
87 | + if (((c ^ old_color) & 0xf000) == 0) | |
88 | + *sbuf ^= (old_color ^ new_color) & 0xf000; | |
89 | + if (((c ^ old_color) & 0x0f00) == 0) | |
90 | + *sbuf ^= (old_color ^ new_color) & 0x0f00; | |
91 | + sbuf++; | |
92 | + } | |
93 | + new_color >>= 8; | |
94 | + } | |
95 | + vc->vc_def_color = vc->vc_color = new_color; | |
96 | + update_attr(vc); | |
97 | +} | |
98 | +#endif | |
99 | + | |
100 | /* | |
101 | * Visible symbols for modules | |
102 | */ | |
103 | --- /dev/null | |
104 | +++ b/drivers/video/bootsplash/bootsplash.c | |
105 | @@ -0,0 +1,1017 @@ | |
106 | +/* | |
107 | + * linux/drivers/video/bootsplash/bootsplash.c - | |
108 | + * splash screen handling functions. | |
109 | + * | |
110 | + * (w) 2001-2004 by Volker Poplawski, <volker@poplawski.de>, | |
111 | + * Stefan Reinauer, <stepan@suse.de>, | |
112 | + * Steffen Winterfeldt, <snwint@suse.de>, | |
113 | + * Michael Schroeder <mls@suse.de> | |
114 | + * | |
115 | + * Ideas & SuSE screen work by Ken Wimer, <wimer@suse.de> | |
116 | + * | |
117 | + * For more information on this code check http://www.bootsplash.org/ | |
118 | + */ | |
119 | + | |
120 | +#include <linux/module.h> | |
121 | +#include <linux/types.h> | |
122 | +#include <linux/fb.h> | |
123 | +#include <linux/vt_kern.h> | |
124 | +#include <linux/vmalloc.h> | |
125 | +#include <linux/unistd.h> | |
126 | +#include <linux/syscalls.h> | |
127 | + | |
128 | +#include <asm/irq.h> | |
129 | +#include <asm/system.h> | |
130 | + | |
131 | +#include "../console/fbcon.h" | |
132 | +#include "bootsplash.h" | |
133 | +#include "decode-jpg.h" | |
134 | + | |
135 | +extern struct fb_ops vesafb_ops; | |
136 | +extern signed char con2fb_map[MAX_NR_CONSOLES]; | |
137 | + | |
138 | +#define SPLASH_VERSION "3.1.6-2004/03/31" | |
139 | + | |
140 | +/* These errors have to match fbcon-jpegdec.h */ | |
141 | +static unsigned char *jpg_errors[] = { | |
142 | + "no SOI found", | |
143 | + "not 8 bit", | |
144 | + "height mismatch", | |
145 | + "width mismatch", | |
146 | + "bad width or height", | |
147 | + "too many COMPPs", | |
148 | + "illegal HV", | |
149 | + "quant table selector", | |
150 | + "picture is not YCBCR 221111", | |
151 | + "unknow CID in scan", | |
152 | + "dct not sequential", | |
153 | + "wrong marker", | |
154 | + "no EOI", | |
155 | + "bad tables", | |
156 | + "depth mismatch" | |
157 | +}; | |
158 | + | |
159 | +static struct jpeg_decdata *decdata = 0; /* private decoder data */ | |
160 | + | |
161 | +static int splash_registered = 0; | |
162 | +static int splash_usesilent = 0; /* shall we display the silentjpeg? */ | |
163 | +int splash_default = 0xf01; | |
164 | + | |
165 | +static int splash_check_jpeg(unsigned char *jpeg, int width, int height, int depth); | |
166 | + | |
167 | +static int __init splash_setup(char *options) | |
168 | +{ | |
169 | + if(!strncmp("silent", options, 6)) { | |
170 | + printk(KERN_INFO "bootsplash: silent mode.\n"); | |
171 | + splash_usesilent = 1; | |
172 | + /* skip "silent," */ | |
173 | + if (strlen(options) == 6) | |
174 | + return 0; | |
175 | + options += 7; | |
176 | + } | |
177 | + if(!strncmp("verbose", options, 7)) { | |
178 | + printk(KERN_INFO "bootsplash: verbose mode.\n"); | |
179 | + splash_usesilent = 0; | |
180 | + return 0; | |
181 | + } | |
182 | + splash_default = simple_strtoul(options, NULL, 0); | |
183 | + return 0; | |
184 | +} | |
185 | + | |
186 | +__setup("splash=", splash_setup); | |
187 | + | |
188 | + | |
189 | +static int splash_hasinter(unsigned char *buf, int num) | |
190 | +{ | |
191 | + unsigned char *bufend = buf + num * 12; | |
192 | + while(buf < bufend) { | |
193 | + if (buf[1] > 127) /* inter? */ | |
194 | + return 1; | |
195 | + buf += buf[3] > 127 ? 24 : 12; /* blend? */ | |
196 | + } | |
197 | + return 0; | |
198 | +} | |
199 | + | |
200 | +static int boxextract(unsigned char *buf, unsigned short *dp, unsigned char *cols, int *blendp) | |
201 | +{ | |
202 | + dp[0] = buf[0] | buf[1] << 8; | |
203 | + dp[1] = buf[2] | buf[3] << 8; | |
204 | + dp[2] = buf[4] | buf[5] << 8; | |
205 | + dp[3] = buf[6] | buf[7] << 8; | |
206 | + *(unsigned int *)(cols + 0) = | |
207 | + *(unsigned int *)(cols + 4) = | |
208 | + *(unsigned int *)(cols + 8) = | |
209 | + *(unsigned int *)(cols + 12) = *(unsigned int *)(buf + 8); | |
210 | + if (dp[1] > 32767) { | |
211 | + dp[1] = ~dp[1]; | |
212 | + *(unsigned int *)(cols + 4) = *(unsigned int *)(buf + 12); | |
213 | + *(unsigned int *)(cols + 8) = *(unsigned int *)(buf + 16); | |
214 | + *(unsigned int *)(cols + 12) = *(unsigned int *)(buf + 20); | |
215 | + *blendp = 1; | |
216 | + return 24; | |
217 | + } | |
218 | + return 12; | |
219 | +} | |
220 | + | |
221 | +static void boxit(unsigned char *pic, int bytes, unsigned char *buf, int num, int percent, int overpaint) | |
222 | +{ | |
223 | + int x, y, i, p, doblend, r, g, b, a, add; | |
224 | + unsigned short data1[4]; | |
225 | + unsigned char cols1[16]; | |
226 | + unsigned short data2[4]; | |
227 | + unsigned char cols2[16]; | |
228 | + unsigned char *bufend; | |
229 | + unsigned short *picp; | |
230 | + unsigned int stipple[32], sti, stin, stinn, stixs, stixe, stiys, stiye; | |
231 | + int xs, xe, ys, ye, xo, yo; | |
232 | + | |
233 | + if (num == 0) | |
234 | + return; | |
235 | + bufend = buf + num * 12; | |
236 | + stipple[0] = 0xffffffff; | |
237 | + stin = 1; | |
238 | + stinn = 0; | |
239 | + stixs = stixe = 0; | |
240 | + stiys = stiye = 0; | |
241 | + while(buf < bufend) { | |
242 | + doblend = 0; | |
243 | + buf += boxextract(buf, data1, cols1, &doblend); | |
244 | + if (data1[0] == 32767 && data1[1] == 32767) { | |
245 | + /* box stipple */ | |
246 | + if (stinn == 32) | |
247 | + continue; | |
248 | + if (stinn == 0) { | |
249 | + stixs = data1[2]; | |
250 | + stixe = data1[3]; | |
251 | + stiys = stiye = 0; | |
252 | + } else if (stinn == 4) { | |
253 | + stiys = data1[2]; | |
254 | + stiye = data1[3]; | |
255 | + } | |
256 | + stipple[stinn++] = (cols1[ 0] << 24) | (cols1[ 1] << 16) | (cols1[ 2] << 8) | cols1[ 3] ; | |
257 | + stipple[stinn++] = (cols1[ 4] << 24) | (cols1[ 5] << 16) | (cols1[ 6] << 8) | cols1[ 7] ; | |
258 | + stipple[stinn++] = (cols1[ 8] << 24) | (cols1[ 9] << 16) | (cols1[10] << 8) | cols1[11] ; | |
259 | + stipple[stinn++] = (cols1[12] << 24) | (cols1[13] << 16) | (cols1[14] << 8) | cols1[15] ; | |
260 | + stin = stinn; | |
261 | + continue; | |
262 | + } | |
263 | + stinn = 0; | |
264 | + if (data1[0] > 32767) | |
265 | + buf += boxextract(buf, data2, cols2, &doblend); | |
266 | + if (data1[0] == 32767 && data1[1] == 32766) { | |
267 | + /* box copy */ | |
268 | + i = 12 * (short)data1[3]; | |
269 | + doblend = 0; | |
270 | + i += boxextract(buf + i, data1, cols1, &doblend); | |
271 | + if (data1[0] > 32767) | |
272 | + boxextract(buf + i, data2, cols2, &doblend); | |
273 | + } | |
274 | + if (data1[0] == 32767) | |
275 | + continue; | |
276 | + if (data1[2] > 32767) { | |
277 | + if (overpaint) | |
278 | + continue; | |
279 | + data1[2] = ~data1[2]; | |
280 | + } | |
281 | + if (data1[3] > 32767) { | |
282 | + if (percent == 65536) | |
283 | + continue; | |
284 | + data1[3] = ~data1[3]; | |
285 | + } | |
286 | + if (data1[0] > 32767) { | |
287 | + data1[0] = ~data1[0]; | |
288 | + for (i = 0; i < 4; i++) | |
289 | + data1[i] = (data1[i] * (65536 - percent) + data2[i] * percent) >> 16; | |
290 | + for (i = 0; i < 16; i++) | |
291 | + cols1[i] = (cols1[i] * (65536 - percent) + cols2[i] * percent) >> 16; | |
292 | + } | |
293 | + *(unsigned int *)cols2 = *(unsigned int *)cols1; | |
294 | + a = cols2[3]; | |
295 | + if (a == 0 && !doblend) | |
296 | + continue; | |
297 | + | |
298 | + if (stixs >= 32768) { | |
299 | + xo = xs = (stixs ^ 65535) + data1[0]; | |
300 | + xe = stixe ? stixe + data1[0] : data1[2]; | |
301 | + } else if (stixe >= 32768) { | |
302 | + xs = stixs ? data1[2] - stixs : data1[0]; | |
303 | + xe = data1[2] - (stixe ^ 65535); | |
304 | + xo = xe + 1; | |
305 | + } else { | |
306 | + xo = xs = stixs; | |
307 | + xe = stixe ? stixe : data1[2]; | |
308 | + } | |
309 | + if (stiys >= 32768) { | |
310 | + yo = ys = (stiys ^ 65535) + data1[1]; | |
311 | + ye = stiye ? stiye + data1[1] : data1[3]; | |
312 | + } else if (stiye >= 32768) { | |
313 | + ys = stiys ? data1[3] - stiys : data1[1]; | |
314 | + ye = data1[3] - (stiye ^ 65535); | |
315 | + yo = ye + 1; | |
316 | + } else { | |
317 | + yo = ys = stiys; | |
318 | + ye = stiye ? stiye : data1[3]; | |
319 | + } | |
320 | + xo = 32 - (xo & 31); | |
321 | + yo = stin - (yo % stin); | |
322 | + if (xs < data1[0]) | |
323 | + xs = data1[0]; | |
324 | + if (xe > data1[2]) | |
325 | + xe = data1[2]; | |
326 | + if (ys < data1[1]) | |
327 | + ys = data1[1]; | |
328 | + if (ye > data1[3]) | |
329 | + ye = data1[3]; | |
330 | + | |
331 | + for (y = ys; y <= ye; y++) { | |
332 | + sti = stipple[(y + yo) % stin]; | |
333 | + x = (xs + xo) & 31; | |
334 | + if (x) | |
335 | + sti = (sti << x) | (sti >> (32 - x)); | |
336 | + if (doblend) { | |
337 | + if ((p = data1[3] - data1[1]) != 0) | |
338 | + p = ((y - data1[1]) << 16) / p; | |
339 | + for (i = 0; i < 8; i++) | |
340 | + cols2[i + 8] = (cols1[i] * (65536 - p) + cols1[i + 8] * p) >> 16; | |
341 | + } | |
342 | + add = (xs & 1); | |
343 | + add ^= (add ^ y) & 1 ? 1 : 3; /* 2x2 ordered dithering */ | |
344 | + picp = (unsigned short *)(pic + xs * 2 + y * bytes); | |
345 | + for (x = xs; x <= xe; x++) { | |
346 | + if (!(sti & 0x80000000)) { | |
347 | + sti <<= 1; | |
348 | + picp++; | |
349 | + add ^= 3; | |
350 | + continue; | |
351 | + } | |
352 | + sti = (sti << 1) | 1; | |
353 | + if (doblend) { | |
354 | + if ((p = data1[2] - data1[0]) != 0) | |
355 | + p = ((x - data1[0]) << 16) / p; | |
356 | + for (i = 0; i < 4; i++) | |
357 | + cols2[i] = (cols2[i + 8] * (65536 - p) + cols2[i + 12] * p) >> 16; | |
358 | + a = cols2[3]; | |
359 | + } | |
360 | + r = cols2[0]; | |
361 | + g = cols2[1]; | |
362 | + b = cols2[2]; | |
363 | + if (a != 255) { | |
364 | + i = *picp; | |
365 | + r = ((i >> 8 & 0xf8) * (255 - a) + r * a) / 255; | |
366 | + g = ((i >> 3 & 0xfc) * (255 - a) + g * a) / 255; | |
367 | + b = ((i << 3 & 0xf8) * (255 - a) + b * a) / 255; | |
368 | + } | |
369 | + #define CLAMP(x) ((x) >= 256 ? 255 : (x)) | |
370 | + i = ((CLAMP(r + add*2+1) & 0xf8) << 8) | | |
371 | + ((CLAMP(g + add ) & 0xfc) << 3) | | |
372 | + ((CLAMP(b + add*2+1) ) >> 3); | |
373 | + *picp++ = i; | |
374 | + add ^= 3; | |
375 | + } | |
376 | + } | |
377 | + } | |
378 | +} | |
379 | + | |
380 | +static int splash_check_jpeg(unsigned char *jpeg, int width, int height, int depth) | |
381 | +{ | |
382 | + int size, err; | |
383 | + unsigned char *mem; | |
384 | + | |
385 | + size = ((width + 15) & ~15) * ((height + 15) & ~15) * (depth >> 3); | |
386 | + mem = vmalloc(size); | |
387 | + if (!mem) { | |
388 | + printk(KERN_INFO "bootsplash: no memory for decoded picture.\n"); | |
389 | + return -1; | |
390 | + } | |
391 | + if (!decdata) | |
392 | + decdata = vmalloc(sizeof(*decdata)); | |
393 | + if ((err = jpeg_decode(jpeg, mem, ((width + 15) & ~15), ((height + 15) & ~15), depth, decdata))) | |
394 | + printk(KERN_INFO "bootsplash: error while decompressing picture: %s (%d)\n",jpg_errors[err - 1], err); | |
395 | + vfree(mem); | |
396 | + return err ? -1 : 0; | |
397 | +} | |
398 | + | |
399 | +static void splash_free(struct vc_data *vc, struct fb_info *info) | |
400 | +{ | |
401 | + if (!vc->vc_splash_data) | |
402 | + return; | |
403 | + if (info->silent_screen_base) | |
404 | + info->screen_base = info->silent_screen_base; | |
405 | + info->silent_screen_base = 0; | |
406 | + if (vc->vc_splash_data->splash_silentjpeg) | |
407 | + vfree(vc->vc_splash_data->splash_sboxes); | |
408 | + vfree(vc->vc_splash_data); | |
409 | + vc->vc_splash_data = 0; | |
410 | + info->splash_data = 0; | |
411 | +} | |
412 | + | |
413 | +static int splash_mkpenguin(struct splash_data *data, int pxo, int pyo, int pwi, int phe, int pr, int pg, int pb) | |
414 | +{ | |
415 | + unsigned char *buf; | |
416 | + int i; | |
417 | + | |
418 | + if (pwi ==0 || phe == 0) | |
419 | + return 0; | |
420 | + buf = (unsigned char *)data + sizeof(*data); | |
421 | + pwi += pxo - 1; | |
422 | + phe += pyo - 1; | |
423 | + *buf++ = pxo; | |
424 | + *buf++ = pxo >> 8; | |
425 | + *buf++ = pyo; | |
426 | + *buf++ = pyo >> 8; | |
427 | + *buf++ = pwi; | |
428 | + *buf++ = pwi >> 8; | |
429 | + *buf++ = phe; | |
430 | + *buf++ = phe >> 8; | |
431 | + *buf++ = pr; | |
432 | + *buf++ = pg; | |
433 | + *buf++ = pb; | |
434 | + *buf++ = 0; | |
435 | + for (i = 0; i < 12; i++, buf++) | |
436 | + *buf = buf[-12]; | |
437 | + buf[-24] ^= 0xff; | |
438 | + buf[-23] ^= 0xff; | |
439 | + buf[-1] = 0xff; | |
440 | + return 2; | |
441 | +} | |
442 | + | |
443 | +static const int splash_offsets[3][16] = { | |
444 | + /* len, unit, size, state, fgcol, col, xo, yo, wi, he | |
445 | + boxcnt, ssize, sboxcnt, percent, overok, palcnt */ | |
446 | + /* V1 */ | |
447 | + { 20, -1, 16, -1, -1, -1, 8, 10, 12, 14, | |
448 | + -1, -1, -1, -1, -1, -1 }, | |
449 | + /* V2 */ | |
450 | + { 35, 8, 12, 9, 10, 11, 16, 18, 20, 22, | |
451 | + -1, -1, -1, -1, -1, -1 }, | |
452 | + /* V3 */ | |
453 | + { 38, 8, 12, 9, 10, 11, 16, 18, 20, 22, | |
454 | + 24, 28, 32, 34, 36, 37 }, | |
455 | +}; | |
456 | + | |
457 | +#define SPLASH_OFF_LEN offsets[0] | |
458 | +#define SPLASH_OFF_UNIT offsets[1] | |
459 | +#define SPLASH_OFF_SIZE offsets[2] | |
460 | +#define SPLASH_OFF_STATE offsets[3] | |
461 | +#define SPLASH_OFF_FGCOL offsets[4] | |
462 | +#define SPLASH_OFF_COL offsets[5] | |
463 | +#define SPLASH_OFF_XO offsets[6] | |
464 | +#define SPLASH_OFF_YO offsets[7] | |
465 | +#define SPLASH_OFF_WI offsets[8] | |
466 | +#define SPLASH_OFF_HE offsets[9] | |
467 | +#define SPLASH_OFF_BOXCNT offsets[10] | |
468 | +#define SPLASH_OFF_SSIZE offsets[11] | |
469 | +#define SPLASH_OFF_SBOXCNT offsets[12] | |
470 | +#define SPLASH_OFF_PERCENT offsets[13] | |
471 | +#define SPLASH_OFF_OVEROK offsets[14] | |
472 | +#define SPLASH_OFF_PALCNT offsets[15] | |
473 | + | |
474 | +static inline int splash_getb(unsigned char *pos, int off) | |
475 | +{ | |
476 | + return off == -1 ? 0 : pos[off]; | |
477 | +} | |
478 | + | |
479 | +static inline int splash_gets(unsigned char *pos, int off) | |
480 | +{ | |
481 | + return off == -1 ? 0 : pos[off] | pos[off + 1] << 8; | |
482 | +} | |
483 | + | |
484 | +static inline int splash_geti(unsigned char *pos, int off) | |
485 | +{ | |
486 | + return off == -1 ? 0 : | |
487 | + pos[off] | pos[off + 1] << 8 | pos[off + 2] << 16 | pos[off + 3] << 24; | |
488 | +} | |
489 | + | |
490 | +static int splash_getraw(unsigned char *start, unsigned char *end, int *update) | |
491 | +{ | |
492 | + unsigned char *ndata; | |
493 | + int version; | |
494 | + int splash_size; | |
495 | + int unit; | |
496 | + int width, height; | |
497 | + int silentsize; | |
498 | + int boxcnt; | |
499 | + int sboxcnt; | |
500 | + int palcnt; | |
501 | + int i, len; | |
502 | + const int *offsets; | |
503 | + struct vc_data *vc; | |
504 | + struct fb_info *info; | |
505 | + struct splash_data *sd; | |
506 | + int oldpercent, oldsilent; | |
507 | + | |
508 | + if (update) | |
509 | + *update = -1; | |
510 | + | |
511 | + if (!update || start[7] < '2' || start[7] > '3' || splash_geti(start, 12) != (int)0xffffffff) | |
512 | + printk(KERN_INFO "bootsplash %s: looking for picture...\n", SPLASH_VERSION); | |
513 | + | |
514 | + for (ndata = start; ndata < end; ndata++) { | |
515 | + if (ndata[0] != 'B' || ndata[1] != 'O' || ndata[2] != 'O' || ndata[3] != 'T') | |
516 | + continue; | |
517 | + if (ndata[4] != 'S' || ndata[5] != 'P' || ndata[6] != 'L' || ndata[7] < '1' || ndata[7] > '3') | |
518 | + continue; | |
519 | + version = ndata[7] - '0'; | |
520 | + offsets = splash_offsets[version - 1]; | |
521 | + len = SPLASH_OFF_LEN; | |
522 | + unit = splash_getb(ndata, SPLASH_OFF_UNIT); | |
523 | + if (unit >= MAX_NR_CONSOLES) | |
524 | + continue; | |
525 | + if (unit) { | |
526 | + vc_allocate(unit); | |
527 | + } | |
528 | + vc = vc_cons[unit].d; | |
529 | + info = registered_fb[(int)con2fb_map[unit]]; | |
530 | + width = info->var.xres; | |
531 | + height = info->var.yres; | |
532 | + splash_size = splash_geti(ndata, SPLASH_OFF_SIZE); | |
533 | + if (splash_size == (int)0xffffffff && version > 1) { | |
534 | + if ((sd = vc->vc_splash_data) != 0) { | |
535 | + int up = 0; | |
536 | + i = splash_getb(ndata, SPLASH_OFF_STATE); | |
537 | + if (i != 255) { | |
538 | + sd->splash_state = i; | |
539 | + up = -1; | |
540 | + } | |
541 | + i = splash_getb(ndata, SPLASH_OFF_FGCOL); | |
542 | + if (i != 255) { | |
543 | + sd->splash_fg_color = i; | |
544 | + up = -1; | |
545 | + } | |
546 | + i = splash_getb(ndata, SPLASH_OFF_COL); | |
547 | + if (i != 255) { | |
548 | + sd->splash_color = i; | |
549 | + up = -1; | |
550 | + } | |
551 | + boxcnt = sboxcnt = 0; | |
552 | + if (ndata + len <= end) { | |
553 | + boxcnt = splash_gets(ndata, SPLASH_OFF_BOXCNT); | |
554 | + sboxcnt = splash_gets(ndata, SPLASH_OFF_SBOXCNT); | |
555 | + } | |
556 | + if (boxcnt) { | |
557 | + i = splash_gets(ndata, len); | |
558 | + if (boxcnt + i <= sd->splash_boxcount && ndata + len + 2 + boxcnt * 12 <= end) { | |
559 | + | |
560 | + if (splash_geti(ndata, len + 2) != 0x7ffd7fff || !memcmp(ndata + len + 2, sd->splash_boxes + i * 12, 8)) { | |
561 | + | |
562 | + memcpy(sd->splash_boxes + i * 12, ndata + len + 2, boxcnt * 12); | |
563 | + up |= 1; | |
564 | + } | |
565 | + } | |
566 | + len += boxcnt * 12 + 2; | |
567 | + } | |
568 | + if (sboxcnt) { | |
569 | + i = splash_gets(ndata, len); | |
570 | + if (sboxcnt + i <= sd->splash_sboxcount && ndata + len + 2 + sboxcnt * 12 <= end) { | |
571 | + if (splash_geti(ndata, len + 2) != 0x7ffd7fff || !memcmp(ndata + len + 2, sd->splash_sboxes + i * 12, 8)) { | |
572 | + memcpy(sd->splash_sboxes + i * 12, ndata + len + 2, sboxcnt * 12); | |
573 | + up |= 2; | |
574 | + } | |
575 | + } | |
576 | + } | |
577 | + if (update) | |
578 | + *update = up; | |
579 | + } | |
580 | + return unit; | |
581 | + } | |
582 | + if (splash_size == 0) { | |
583 | + printk(KERN_INFO "bootsplash: ...found, freeing memory.\n"); | |
584 | + if (vc->vc_splash_data) | |
585 | + splash_free(vc, info); | |
586 | + return unit; | |
587 | + } | |
588 | + boxcnt = splash_gets(ndata, SPLASH_OFF_BOXCNT); | |
589 | + palcnt = 3 * splash_getb(ndata, SPLASH_OFF_PALCNT); | |
590 | + if (ndata + len + splash_size > end) { | |
591 | + printk(KERN_ERR "bootsplash: ...found, but truncated!\n"); | |
592 | + return -1; | |
593 | + } | |
594 | + if (!jpeg_check_size(ndata + len + boxcnt * 12 + palcnt, width, height)) { | |
595 | + ndata += len + splash_size - 1; | |
596 | + continue; | |
597 | + } | |
598 | + if (splash_check_jpeg(ndata + len + boxcnt * 12 + palcnt, width, height, info->var.bits_per_pixel)) | |
599 | + return -1; | |
600 | + silentsize = splash_geti(ndata, SPLASH_OFF_SSIZE); | |
601 | + if (silentsize) | |
602 | + printk(KERN_INFO "bootsplash: silentjpeg size %d bytes\n", silentsize); | |
603 | + if (silentsize >= splash_size) { | |
604 | + printk(KERN_ERR "bootsplash: bigger than splashsize!\n"); | |
605 | + return -1; | |
606 | + } | |
607 | + splash_size -= silentsize; | |
608 | + if (!splash_usesilent) | |
609 | + silentsize = 0; | |
610 | + else if (height * 2 * info->fix.line_length > info->fix.smem_len) { | |
611 | + printk(KERN_WARNING "bootsplash: does not fit into framebuffer.\n"); | |
612 | + silentsize = 0; | |
613 | + } | |
614 | + sboxcnt = splash_gets(ndata, SPLASH_OFF_SBOXCNT); | |
615 | + if (silentsize) { | |
616 | + unsigned char *simage = ndata + len + splash_size + 12 * sboxcnt; | |
617 | + if (!jpeg_check_size(simage, width, height) || | |
618 | + splash_check_jpeg(simage, width, height, info->var.bits_per_pixel)) { | |
619 | + printk(KERN_WARNING "bootsplash: error in silent jpeg.\n"); | |
620 | + silentsize = 0; | |
621 | + } | |
622 | + } | |
623 | + oldpercent = -1; | |
624 | + oldsilent = -1; | |
625 | + if (vc->vc_splash_data) { | |
626 | + oldpercent = vc->vc_splash_data->splash_percent; | |
627 | + oldsilent = vc->vc_splash_data->splash_dosilent; | |
628 | + splash_free(vc, info); | |
629 | + } | |
630 | + vc->vc_splash_data = sd = vmalloc(sizeof(*sd) + splash_size + (version < 3 ? 2 * 12 : 0)); | |
631 | + if (!sd) | |
632 | + break; | |
633 | + sd->splash_silentjpeg = 0; | |
634 | + sd->splash_sboxes = 0; | |
635 | + sd->splash_sboxcount = 0; | |
636 | + if (silentsize) { | |
637 | + sd->splash_silentjpeg = vmalloc(silentsize); | |
638 | + if (sd->splash_silentjpeg) { | |
639 | + memcpy(sd->splash_silentjpeg, ndata + len + splash_size, silentsize); | |
640 | + sd->splash_sboxes = vc->vc_splash_data->splash_silentjpeg; | |
641 | + sd->splash_silentjpeg += 12 * sboxcnt; | |
642 | + sd->splash_sboxcount = sboxcnt; | |
643 | + } | |
644 | + } | |
645 | + sd->splash_state = splash_getb(ndata, SPLASH_OFF_STATE); | |
646 | + sd->splash_fg_color = splash_getb(ndata, SPLASH_OFF_FGCOL); | |
647 | + sd->splash_color = splash_getb(ndata, SPLASH_OFF_COL); | |
648 | + sd->splash_overpaintok = splash_getb(ndata, SPLASH_OFF_OVEROK); | |
649 | + sd->splash_text_xo = splash_gets(ndata, SPLASH_OFF_XO); | |
650 | + sd->splash_text_yo = splash_gets(ndata, SPLASH_OFF_YO); | |
651 | + sd->splash_text_wi = splash_gets(ndata, SPLASH_OFF_WI); | |
652 | + sd->splash_text_he = splash_gets(ndata, SPLASH_OFF_HE); | |
653 | + sd->splash_percent = oldpercent == -1 ? splash_gets(ndata, SPLASH_OFF_PERCENT) : oldpercent; | |
654 | + if (version == 1) { | |
655 | + sd->splash_text_xo *= 8; | |
656 | + sd->splash_text_wi *= 8; | |
657 | + sd->splash_text_yo *= 16; | |
658 | + sd->splash_text_he *= 16; | |
659 | + sd->splash_color = (splash_default >> 8) & 0x0f; | |
660 | + sd->splash_fg_color = (splash_default >> 4) & 0x0f; | |
661 | + sd->splash_state = splash_default & 1; | |
662 | + } | |
663 | + if (sd->splash_text_xo + sd->splash_text_wi > width || sd->splash_text_yo + sd->splash_text_he > height) { | |
664 | + splash_free(vc, info); | |
665 | + printk(KERN_ERR "bootsplash: found, but has oversized text area!\n"); | |
666 | + return -1; | |
667 | + } | |
668 | + if (!vc_cons[unit].d || info->fbops->fb_imageblit != cfb_imageblit) { | |
669 | + splash_free(vc, info); | |
670 | + printk(KERN_ERR "bootsplash: found, but framebuffer can't handle it!\n"); | |
671 | + return -1; | |
672 | + } | |
673 | + printk(KERN_INFO "bootsplash: ...found (%dx%d, %d bytes, v%d).\n", width, height, splash_size, version); | |
674 | + if (version == 1) { | |
675 | + printk(KERN_WARNING "bootsplash: Using deprecated v1 header. Updating your splash utility recommended.\n"); | |
676 | + printk(KERN_INFO "bootsplash: Find the latest version at http://www.bootsplash.org/\n"); | |
677 | + } | |
678 | + | |
679 | + /* fake penguin box for older formats */ | |
680 | + if (version == 1) | |
681 | + 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); | |
682 | + else if (version == 2) | |
683 | + 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)); | |
684 | + | |
685 | + memcpy((char *)sd + sizeof(*sd) + (version < 3 ? boxcnt * 12 : 0), ndata + len, splash_size); | |
686 | + sd->splash_boxcount = boxcnt; | |
687 | + sd->splash_boxes = (unsigned char *)sd + sizeof(*sd); | |
688 | + sd->splash_palette = sd->splash_boxes + boxcnt * 12; | |
689 | + sd->splash_jpeg = sd->splash_palette + palcnt; | |
690 | + sd->splash_palcnt = palcnt / 3; | |
691 | + sd->splash_dosilent = sd->splash_silentjpeg != 0 ? (oldsilent == -1 ? 1 : oldsilent) : 0; | |
692 | + return unit; | |
693 | + } | |
694 | + printk(KERN_ERR "bootsplash: ...no good signature found.\n"); | |
695 | + return -1; | |
696 | +} | |
697 | + | |
698 | +int splash_verbose(void) | |
699 | +{ | |
700 | + struct vc_data *vc; | |
701 | + struct fb_info *info; | |
702 | + | |
703 | + if (!splash_usesilent) | |
704 | + return 0; | |
705 | + | |
706 | + vc = vc_cons[0].d; | |
707 | + | |
708 | + if (!vc || !vc->vc_splash_data || !vc->vc_splash_data->splash_state) | |
709 | + return 0; | |
710 | + if (fg_console != vc->vc_num) | |
711 | + return 0; | |
712 | + if (!vc->vc_splash_data->splash_silentjpeg || !vc->vc_splash_data->splash_dosilent) | |
713 | + return 0; | |
714 | + vc->vc_splash_data->splash_dosilent = 0; | |
715 | + info = registered_fb[(int)con2fb_map[0]]; | |
716 | + if (!info->silent_screen_base) | |
717 | + return 0; | |
718 | + splashcopy(info->silent_screen_base, info->screen_base, info->var.yres, info->var.xres, info->fix.line_length, info->fix.line_length); | |
719 | + info->screen_base = info->silent_screen_base; | |
720 | + info->silent_screen_base = 0; | |
721 | + return 1; | |
722 | +} | |
723 | + | |
724 | +static void splash_off(struct fb_info *info) | |
725 | +{ | |
726 | + if (info->silent_screen_base) | |
727 | + info->screen_base = info->silent_screen_base; | |
728 | + info->silent_screen_base = 0; | |
729 | + info->splash_data = 0; | |
730 | + if (info->splash_pic) | |
731 | + vfree(info->splash_pic); | |
732 | + info->splash_pic = 0; | |
733 | + info->splash_pic_size = 0; | |
734 | +} | |
735 | + | |
736 | +int splash_prepare(struct vc_data *vc, struct fb_info *info) | |
737 | +{ | |
738 | + int err; | |
739 | + int width, height, depth, size, sbytes; | |
740 | + | |
741 | + if (!vc->vc_splash_data || !vc->vc_splash_data->splash_state) { | |
742 | + if (decdata) | |
743 | + vfree(decdata); | |
744 | + decdata = 0; | |
745 | + splash_off(info); | |
746 | + return -1; | |
747 | + } | |
748 | + | |
749 | + width = info->var.xres; | |
750 | + height = info->var.yres; | |
751 | + depth = info->var.bits_per_pixel; | |
752 | + if (depth != 16) { /* Other targets might need fixing */ | |
753 | + splash_off(info); | |
754 | + return -2; | |
755 | + } | |
756 | + | |
757 | + sbytes = ((width + 15) & ~15) * (depth >> 3); | |
758 | + size = sbytes * ((height + 15) & ~15); | |
759 | + if (size != info->splash_pic_size) | |
760 | + splash_off(info); | |
761 | + if (!info->splash_pic) | |
762 | + info->splash_pic = vmalloc(size); | |
763 | + | |
764 | + if (!info->splash_pic) { | |
765 | + printk(KERN_INFO "bootsplash: not enough memory.\n"); | |
766 | + splash_off(info); | |
767 | + return -3; | |
768 | + } | |
769 | + | |
770 | + if (!decdata) | |
771 | + decdata = vmalloc(sizeof(*decdata)); | |
772 | + | |
773 | + if (vc->vc_splash_data->splash_silentjpeg && vc->vc_splash_data->splash_dosilent) { | |
774 | + /* fill area after framebuffer with other jpeg */ | |
775 | + if ((err = jpeg_decode(vc->vc_splash_data->splash_silentjpeg, info->splash_pic, | |
776 | + ((width + 15) & ~15), ((height + 15) & ~15), depth, decdata))) { | |
777 | + printk(KERN_INFO "bootsplash: error while decompressing silent picture: %s (%d)\n", jpg_errors[err - 1], err); | |
778 | + if (info->silent_screen_base) | |
779 | + info->screen_base = info->silent_screen_base; | |
780 | + vc->vc_splash_data->splash_dosilent = 0; | |
781 | + } else { | |
782 | + if (vc->vc_splash_data->splash_sboxcount) | |
783 | + boxit(info->splash_pic, sbytes, vc->vc_splash_data->splash_sboxes, | |
784 | + vc->vc_splash_data->splash_sboxcount, vc->vc_splash_data->splash_percent, 0); | |
785 | + | |
786 | + if (!info->silent_screen_base) | |
787 | + info->silent_screen_base = info->screen_base; | |
788 | + splashcopy(info->silent_screen_base, info->splash_pic, info->var.yres, info->var.xres, info->fix.line_length, sbytes); | |
789 | + info->screen_base = info->silent_screen_base + info->fix.line_length * info->var.yres; | |
790 | + } | |
791 | + } else if (info->silent_screen_base) | |
792 | + info->screen_base = info->silent_screen_base; | |
793 | + | |
794 | + if ((err = jpeg_decode(vc->vc_splash_data->splash_jpeg, info->splash_pic, | |
795 | + ((width + 15) & ~15), ((height + 15) & ~15), depth, decdata))) { | |
796 | + printk(KERN_INFO "bootsplash: error while decompressing picture: %s (%d) .\n", jpg_errors[err - 1], err); | |
797 | + splash_off(info); | |
798 | + return -4; | |
799 | + } | |
800 | + info->splash_pic_size = size; | |
801 | + info->splash_bytes = sbytes; | |
802 | + if (vc->vc_splash_data->splash_boxcount) | |
803 | + boxit(info->splash_pic, sbytes, vc->vc_splash_data->splash_boxes, vc->vc_splash_data->splash_boxcount, vc->vc_splash_data->splash_percent, 0); | |
804 | + if (vc->vc_splash_data->splash_state) | |
805 | + info->splash_data = vc->vc_splash_data; | |
806 | + else | |
807 | + splash_off(info); | |
808 | + return 0; | |
809 | +} | |
810 | + | |
811 | + | |
812 | +#ifdef CONFIG_PROC_FS | |
813 | + | |
814 | +#include <linux/proc_fs.h> | |
815 | + | |
816 | +static int splash_read_proc(char *buffer, char **start, off_t offset, int size, | |
817 | + int *eof, void *data); | |
818 | +static int splash_write_proc(struct file *file, const char *buffer, | |
819 | + unsigned long count, void *data); | |
820 | +static int splash_status(struct vc_data *vc); | |
821 | +static int splash_recolor(struct vc_data *vc); | |
822 | +static int splash_proc_register(void); | |
823 | + | |
824 | +static struct proc_dir_entry *proc_splash; | |
825 | + | |
826 | +static int splash_recolor(struct vc_data *vc) | |
827 | +{ | |
828 | + if (!vc->vc_splash_data) | |
829 | + return -1; | |
830 | + if (!vc->vc_splash_data->splash_state) | |
831 | + return 0; | |
832 | + con_remap_def_color(vc, vc->vc_splash_data->splash_color << 4 | vc->vc_splash_data->splash_fg_color); | |
833 | + if (fg_console == vc->vc_num) { | |
834 | + update_region(vc, | |
835 | + vc->vc_origin + vc->vc_size_row * vc->vc_top, | |
836 | + vc->vc_size_row * (vc->vc_bottom - vc->vc_top) / 2); | |
837 | + } | |
838 | + return 0; | |
839 | +} | |
840 | + | |
841 | +static int splash_status(struct vc_data *vc) | |
842 | +{ | |
843 | + struct fb_info *info; | |
844 | + 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"); | |
845 | + | |
846 | + info = registered_fb[(int) con2fb_map[vc->vc_num]]; | |
847 | + if (fg_console == vc->vc_num) | |
848 | + splash_prepare(vc, info); | |
849 | + if (vc->vc_splash_data && vc->vc_splash_data->splash_state) { | |
850 | + con_remap_def_color(vc, vc->vc_splash_data->splash_color << 4 | vc->vc_splash_data->splash_fg_color); | |
851 | + /* vc_resize also calls con_switch which resets yscroll */ | |
852 | + 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); | |
853 | + if (fg_console == vc->vc_num) { | |
854 | + update_region(vc, | |
855 | + vc->vc_origin + vc->vc_size_row * vc->vc_top, | |
856 | + vc->vc_size_row * (vc->vc_bottom - vc->vc_top) / 2); | |
857 | + splash_clear_margins(vc->vc_splash_data, vc, info, 0); | |
858 | + } | |
859 | + } else { | |
860 | + /* Switch bootsplash off */ | |
861 | + con_remap_def_color(vc, 0x07); | |
862 | + vc_resize(vc, info->var.xres / vc->vc_font.width, info->var.yres / vc->vc_font.height); | |
863 | + } | |
864 | + return 0; | |
865 | +} | |
866 | + | |
867 | +static int splash_read_proc(char *buffer, char **start, off_t offset, int size, | |
868 | + int *eof, void *data) | |
869 | +{ | |
870 | + int len = 0; | |
871 | + off_t begin = 0; | |
872 | + struct vc_data *vc = vc_cons[0].d; | |
873 | + struct fb_info *info = registered_fb[(int)con2fb_map[0]]; | |
874 | + int color = vc->vc_splash_data ? vc->vc_splash_data->splash_color << 4 | | |
875 | + vc->vc_splash_data->splash_fg_color : splash_default >> 4; | |
876 | + int status = vc->vc_splash_data ? vc->vc_splash_data->splash_state & 1 : 0; | |
877 | + len += sprintf(buffer + len, "Splash screen v%s (0x%02x, %dx%d%s): %s\n", | |
878 | + SPLASH_VERSION, color, info->var.xres, info->var.yres, | |
879 | + (vc->vc_splash_data ? vc->vc_splash_data->splash_dosilent : 0)? ", silent" : "", | |
880 | + status ? "on" : "off"); | |
881 | + if (offset >= begin + len) | |
882 | + return 0; | |
883 | + | |
884 | + *start = buffer + (begin - offset); | |
885 | + | |
886 | + return (size < begin + len - offset ? size : begin + len - offset); | |
887 | +} | |
888 | + | |
889 | +void splash_set_percent(struct vc_data *vc, int pe) | |
890 | +{ | |
891 | + struct fb_info *info; | |
892 | + struct fbcon_ops *ops; | |
893 | + int oldpe; | |
894 | + | |
895 | + if (pe < 0) | |
896 | + pe = 0; | |
897 | + if (pe > 65535) | |
898 | + pe = 65535; | |
899 | + pe += pe > 32767;; | |
900 | + | |
901 | + if (!vc->vc_splash_data || vc->vc_splash_data->splash_percent == pe) | |
902 | + return; | |
903 | + | |
904 | + oldpe = vc->vc_splash_data->splash_percent; | |
905 | + vc->vc_splash_data->splash_percent = pe; | |
906 | + if (fg_console != vc->vc_num || !vc->vc_splash_data->splash_state) { | |
907 | + return; | |
908 | + } | |
909 | + info = registered_fb[(int) con2fb_map[vc->vc_num]]; | |
910 | + ops = info->fbcon_par; | |
911 | + if (ops->blank_state) | |
912 | + return; | |
913 | + if (!vc->vc_splash_data->splash_overpaintok || pe == 65536 || pe < oldpe) { | |
914 | + if (splash_hasinter(vc->vc_splash_data->splash_boxes, vc->vc_splash_data->splash_boxcount)) | |
915 | + splash_status(vc); | |
916 | + else | |
917 | + splash_prepare(vc, info); | |
918 | + } else { | |
919 | + if (vc->vc_splash_data->splash_silentjpeg && vc->vc_splash_data->splash_dosilent && info->silent_screen_base) | |
920 | + 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); | |
921 | + 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); | |
922 | + } | |
923 | +} | |
924 | + | |
925 | +static int splash_write_proc(struct file *file, const char *buffer, | |
926 | + unsigned long count, void *data) | |
927 | +{ | |
928 | + int new, unit; | |
929 | + struct vc_data *vc; | |
930 | + | |
931 | + if (!buffer || !splash_default) | |
932 | + return count; | |
933 | + | |
934 | + acquire_console_sem(); | |
935 | + unit = 0; | |
936 | + if (buffer[0] == '@' && buffer[1] >= '0' && buffer[1] <= '9') { | |
937 | + unit = buffer[1] - '0'; | |
938 | + buffer += 2; | |
939 | + if (*buffer >= '0' && *buffer <= '9') { | |
940 | + unit = unit * 10 + *buffer - '0'; | |
941 | + buffer++; | |
942 | + } | |
943 | + if (*buffer == ' ') | |
944 | + buffer++; | |
945 | + if (unit >= MAX_NR_CONSOLES || !vc_cons[unit].d) { | |
946 | + release_console_sem(); | |
947 | + return count; | |
948 | + } | |
949 | + } | |
950 | + vc = vc_cons[unit].d; | |
951 | + if (!strncmp(buffer, "redraw", 6)) { | |
952 | + splash_status(vc); | |
953 | + release_console_sem(); | |
954 | + return count; | |
955 | + } | |
956 | + if (!strncmp(buffer, "show", 4) || !strncmp(buffer, "hide", 4)) { | |
957 | + int pe; | |
958 | + | |
959 | + if (buffer[4] == ' ' && buffer[5] == 'p') | |
960 | + pe = 0; | |
961 | + else if (buffer[4] == '\n') | |
962 | + pe = 65535; | |
963 | + else | |
964 | + pe = simple_strtoul(buffer + 5, NULL, 0); | |
965 | + if (pe < 0) | |
966 | + pe = 0; | |
967 | + if (pe > 65535) | |
968 | + pe = 65535; | |
969 | + if (*buffer == 'h') | |
970 | + pe = 65535 - pe; | |
971 | + splash_set_percent(vc, pe); | |
972 | + release_console_sem(); | |
973 | + return count; | |
974 | + } | |
975 | + if (!strncmp(buffer,"silent\n",7) || !strncmp(buffer,"verbose\n",8)) { | |
976 | + if (vc->vc_splash_data && vc->vc_splash_data->splash_silentjpeg) { | |
977 | + if (vc->vc_splash_data->splash_dosilent != (buffer[0] == 's')) { | |
978 | + vc->vc_splash_data->splash_dosilent = buffer[0] == 's'; | |
979 | + splash_status(vc); | |
980 | + } | |
981 | + } | |
982 | + release_console_sem(); | |
983 | + return count; | |
984 | + } | |
985 | + if (!strncmp(buffer,"freesilent\n",11)) { | |
986 | + if (vc->vc_splash_data && vc->vc_splash_data->splash_silentjpeg) { | |
987 | + printk(KERN_INFO "bootsplash: freeing silent jpeg\n"); | |
988 | + vc->vc_splash_data->splash_silentjpeg = 0; | |
989 | + vfree(vc->vc_splash_data->splash_sboxes); | |
990 | + vc->vc_splash_data->splash_sboxes = 0; | |
991 | + vc->vc_splash_data->splash_sboxcount = 0; | |
992 | + if (vc->vc_splash_data->splash_dosilent) | |
993 | + splash_status(vc); | |
994 | + vc->vc_splash_data->splash_dosilent = 0; | |
995 | + } | |
996 | + release_console_sem(); | |
997 | + return count; | |
998 | + } | |
999 | + | |
1000 | + if (!strncmp(buffer, "BOOTSPL", 7)) { | |
1001 | + int up = -1; | |
1002 | + unit = splash_getraw((unsigned char *)buffer, (unsigned char *)buffer + count, &up); | |
1003 | + if (unit >= 0) { | |
1004 | + vc = vc_cons[unit].d; | |
1005 | + if (up == -1) | |
1006 | + splash_status(vc); | |
1007 | + else { | |
1008 | + struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; | |
1009 | + struct fbcon_ops *ops = info->fbcon_par; | |
1010 | + if (ops->blank_state) | |
1011 | + up = 0; | |
1012 | + if ((up & 2) != 0 && vc->vc_splash_data->splash_silentjpeg && vc->vc_splash_data->splash_dosilent && info->silent_screen_base) | |
1013 | + 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); | |
1014 | + if ((up & 1) != 0) | |
1015 | + 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); | |
1016 | + } | |
1017 | + } | |
1018 | + release_console_sem(); | |
1019 | + return count; | |
1020 | + } | |
1021 | + if (!vc->vc_splash_data) { | |
1022 | + release_console_sem(); | |
1023 | + return count; | |
1024 | + } | |
1025 | + if (buffer[0] == 't') { | |
1026 | + vc->vc_splash_data->splash_state ^= 1; | |
1027 | + splash_status(vc); | |
1028 | + release_console_sem(); | |
1029 | + return count; | |
1030 | + } | |
1031 | + new = simple_strtoul(buffer, NULL, 0); | |
1032 | + if (new > 1) { | |
1033 | + /* expert user */ | |
1034 | + vc->vc_splash_data->splash_color = new >> 8 & 0xff; | |
1035 | + vc->vc_splash_data->splash_fg_color = new >> 4 & 0x0f; | |
1036 | + } | |
1037 | + if ((new & 1) == vc->vc_splash_data->splash_state) | |
1038 | + splash_recolor(vc); | |
1039 | + else { | |
1040 | + vc->vc_splash_data->splash_state = new & 1; | |
1041 | + splash_status(vc); | |
1042 | + } | |
1043 | + release_console_sem(); | |
1044 | + return count; | |
1045 | +} | |
1046 | + | |
1047 | +static int splash_proc_register(void) | |
1048 | +{ | |
1049 | + if ((proc_splash = create_proc_entry("splash", 0, 0))) { | |
1050 | + proc_splash->read_proc = splash_read_proc; | |
1051 | + proc_splash->write_proc = splash_write_proc; | |
1052 | + return 0; | |
1053 | + } | |
1054 | + return 1; | |
1055 | +} | |
1056 | + | |
1057 | +# if 0 | |
1058 | +static int splash_proc_unregister(void) | |
1059 | +{ | |
1060 | + if (proc_splash) | |
1061 | + remove_proc_entry("splash", 0); | |
1062 | + return 0; | |
1063 | +} | |
1064 | +# endif | |
1065 | +#endif /* CONFIG_PROC_FS */ | |
1066 | + | |
1067 | +void splash_init(void) | |
1068 | +{ | |
1069 | + struct fb_info *info; | |
1070 | + struct vc_data *vc; | |
1071 | + int isramfs = 1; | |
1072 | + int fd; | |
1073 | + int len; | |
1074 | + int max_len = 1024*1024*2; | |
1075 | + char *mem; | |
1076 | + | |
1077 | + if (splash_registered) | |
1078 | + return; | |
1079 | + vc = vc_cons[0].d; | |
1080 | + info = registered_fb[0]; | |
1081 | + if (!vc || !info || info->var.bits_per_pixel != 16) | |
1082 | + return; | |
1083 | +#ifdef CONFIG_PROC_FS | |
1084 | + splash_proc_register(); | |
1085 | +#endif | |
1086 | + splash_registered = 1; | |
1087 | + if (vc->vc_splash_data) | |
1088 | + return; | |
1089 | + if ((fd = sys_open("/bootsplash", O_RDONLY, 0)) < 0) { | |
1090 | + isramfs = 0; | |
1091 | + fd = sys_open("/initrd.image", O_RDONLY, 0); | |
1092 | + } | |
1093 | + if (fd < 0) | |
1094 | + return; | |
1095 | + if ((len = (int)sys_lseek(fd, (off_t)0, 2)) <= 0) { | |
1096 | + sys_close(fd); | |
1097 | + return; | |
1098 | + } | |
1099 | + /* Don't look for more than the last 2MB */ | |
1100 | + if (len > max_len) { | |
1101 | + printk( KERN_INFO "bootsplash: scanning last %dMB of initrd for signature\n", | |
1102 | + max_len>>20); | |
1103 | + sys_lseek(fd, (off_t)(len - max_len), 0); | |
1104 | + len = max_len; | |
1105 | + } else { | |
1106 | + sys_lseek(fd, (off_t)0, 0); | |
1107 | + } | |
1108 | + | |
1109 | + mem = vmalloc(len); | |
1110 | + if (mem) { | |
1111 | + acquire_console_sem(); | |
1112 | + if ((int)sys_read(fd, mem, len) == len && splash_getraw((unsigned char *)mem, (unsigned char *)mem + len, (int *)0) == 0 && vc->vc_splash_data) | |
1113 | + vc->vc_splash_data->splash_state = splash_default & 1; | |
1114 | + release_console_sem(); | |
1115 | + vfree(mem); | |
1116 | + } | |
1117 | + sys_close(fd); | |
1118 | + if (isramfs) | |
1119 | + sys_unlink("/bootsplash"); | |
1120 | + return; | |
1121 | +} | |
1122 | + | |
1123 | --- /dev/null | |
1124 | +++ b/drivers/video/bootsplash/bootsplash.h | |
1125 | @@ -0,0 +1,44 @@ | |
1126 | +/* | |
1127 | + * linux/drivers/video/bootsplash/bootsplash.h - splash screen definition. | |
1128 | + * | |
1129 | + * (w) 2001-2003 by Volker Poplawski, <volker@poplawski.de> | |
1130 | + * Stefan Reinauer, <stepan@suse.de> | |
1131 | + * | |
1132 | + * | |
1133 | + * idea and SuSE screen work by Ken Wimer, <wimer@suse.de> | |
1134 | + */ | |
1135 | + | |
1136 | +#ifndef __BOOTSPLASH_H | |
1137 | +#define __BOOTSPLASH_H | |
1138 | + | |
1139 | +struct fb_info; | |
1140 | + | |
1141 | +/* splash.c */ | |
1142 | +extern int splash_prepare(struct vc_data *, struct fb_info *); | |
1143 | +extern void splash_init(void); | |
1144 | + | |
1145 | +/* splash_render.c */ | |
1146 | +extern void splash_putcs(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, | |
1147 | + const unsigned short *s, int count, int ypos, int xpos); | |
1148 | +extern void splash_putc(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, | |
1149 | + int c, int ypos, int xpos); | |
1150 | +extern void splashcopy(u8 *dst, u8 *src, int height, int width, int dstbytes, int srcbytes); | |
1151 | +extern void splash_clear(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, int sy, | |
1152 | + int sx, int height, int width); | |
1153 | +extern void splash_bmove(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, int sy, | |
1154 | + int sx, int dy, int dx, int height, int width); | |
1155 | +extern void splash_clear_margins(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, | |
1156 | + int bottom_only); | |
1157 | +extern int splash_cursor(struct splash_data *sd, struct fb_info *info, struct fb_cursor *cursor); | |
1158 | +extern void splash_bmove_redraw(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, | |
1159 | + int y, int sx, int dx, int width); | |
1160 | +extern void splash_blank(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, | |
1161 | + int blank); | |
1162 | + | |
1163 | +/* vt.c */ | |
1164 | +extern void con_remap_def_color(struct vc_data *vc, int new_color); | |
1165 | + | |
1166 | +extern void acquire_console_sem(void); | |
1167 | +extern void release_console_sem(void); | |
1168 | + | |
1169 | +#endif | |
1170 | --- /dev/null | |
1171 | +++ b/drivers/video/bootsplash/decode-jpg.c | |
1172 | @@ -0,0 +1,957 @@ | |
1173 | +/* | |
1174 | + * linux/drivers/video/bootsplash/decode-jpg.c - a tiny jpeg decoder. | |
1175 | + * | |
1176 | + * (w) August 2001 by Michael Schroeder, <mls@suse.de> | |
1177 | + * | |
1178 | + */ | |
1179 | + | |
1180 | +#include <linux/string.h> | |
1181 | +#include <asm/byteorder.h> | |
1182 | + | |
1183 | +#include "decode-jpg.h" | |
1184 | + | |
1185 | +#define ISHIFT 11 | |
1186 | + | |
1187 | +#define IFIX(a) ((int)((a) * (1 << ISHIFT) + .5)) | |
1188 | +#define IMULT(a, b) (((a) * (b)) >> ISHIFT) | |
1189 | +#define ITOINT(a) ((a) >> ISHIFT) | |
1190 | + | |
1191 | +#ifndef __P | |
1192 | +# define __P(x) x | |
1193 | +#endif | |
1194 | + | |
1195 | +/* special markers */ | |
1196 | +#define M_BADHUFF -1 | |
1197 | +#define M_EOF 0x80 | |
1198 | + | |
1199 | +struct in { | |
1200 | + unsigned char *p; | |
1201 | + unsigned int bits; | |
1202 | + int left; | |
1203 | + int marker; | |
1204 | + | |
1205 | + int (*func) __P((void *)); | |
1206 | + void *data; | |
1207 | +}; | |
1208 | + | |
1209 | +/*********************************/ | |
1210 | +struct dec_hufftbl; | |
1211 | +struct enc_hufftbl; | |
1212 | + | |
1213 | +union hufftblp { | |
1214 | + struct dec_hufftbl *dhuff; | |
1215 | + struct enc_hufftbl *ehuff; | |
1216 | +}; | |
1217 | + | |
1218 | +struct scan { | |
1219 | + int dc; /* old dc value */ | |
1220 | + | |
1221 | + union hufftblp hudc; | |
1222 | + union hufftblp huac; | |
1223 | + int next; /* when to switch to next scan */ | |
1224 | + | |
1225 | + int cid; /* component id */ | |
1226 | + int hv; /* horiz/vert, copied from comp */ | |
1227 | + int tq; /* quant tbl, copied from comp */ | |
1228 | +}; | |
1229 | + | |
1230 | +/*********************************/ | |
1231 | + | |
1232 | +#define DECBITS 10 /* seems to be the optimum */ | |
1233 | + | |
1234 | +struct dec_hufftbl { | |
1235 | + int maxcode[17]; | |
1236 | + int valptr[16]; | |
1237 | + unsigned char vals[256]; | |
1238 | + unsigned int llvals[1 << DECBITS]; | |
1239 | +}; | |
1240 | + | |
1241 | +static void decode_mcus __P((struct in *, int *, int, struct scan *, int *)); | |
1242 | +static int dec_readmarker __P((struct in *)); | |
1243 | +static void dec_makehuff __P((struct dec_hufftbl *, int *, unsigned char *)); | |
1244 | + | |
1245 | +static void setinput __P((struct in *, unsigned char *)); | |
1246 | +/*********************************/ | |
1247 | + | |
1248 | +#undef PREC | |
1249 | +#define PREC int | |
1250 | + | |
1251 | +static void idctqtab __P((unsigned char *, PREC *)); | |
1252 | +static void idct __P((int *, int *, PREC *, PREC, int)); | |
1253 | +static void scaleidctqtab __P((PREC *, PREC)); | |
1254 | + | |
1255 | +/*********************************/ | |
1256 | + | |
1257 | +static void initcol __P((PREC[][64])); | |
1258 | + | |
1259 | +static void col221111 __P((int *, unsigned char *, int)); | |
1260 | +static void col221111_16 __P((int *, unsigned char *, int)); | |
1261 | + | |
1262 | +/*********************************/ | |
1263 | + | |
1264 | +#define M_SOI 0xd8 | |
1265 | +#define M_APP0 0xe0 | |
1266 | +#define M_DQT 0xdb | |
1267 | +#define M_SOF0 0xc0 | |
1268 | +#define M_DHT 0xc4 | |
1269 | +#define M_DRI 0xdd | |
1270 | +#define M_SOS 0xda | |
1271 | +#define M_RST0 0xd0 | |
1272 | +#define M_EOI 0xd9 | |
1273 | +#define M_COM 0xfe | |
1274 | + | |
1275 | +static unsigned char *datap; | |
1276 | + | |
1277 | +static int getbyte(void) | |
1278 | +{ | |
1279 | + return *datap++; | |
1280 | +} | |
1281 | + | |
1282 | +static int getword(void) | |
1283 | +{ | |
1284 | + int c1, c2; | |
1285 | + c1 = *datap++; | |
1286 | + c2 = *datap++; | |
1287 | + return c1 << 8 | c2; | |
1288 | +} | |
1289 | + | |
1290 | +struct comp { | |
1291 | + int cid; | |
1292 | + int hv; | |
1293 | + int tq; | |
1294 | +}; | |
1295 | + | |
1296 | +#define MAXCOMP 4 | |
1297 | +struct jpginfo { | |
1298 | + int nc; /* number of components */ | |
1299 | + int ns; /* number of scans */ | |
1300 | + int dri; /* restart interval */ | |
1301 | + int nm; /* mcus til next marker */ | |
1302 | + int rm; /* next restart marker */ | |
1303 | +}; | |
1304 | + | |
1305 | +static struct jpginfo info; | |
1306 | +static struct comp comps[MAXCOMP]; | |
1307 | + | |
1308 | +static struct scan dscans[MAXCOMP]; | |
1309 | + | |
1310 | +static unsigned char quant[4][64]; | |
1311 | + | |
1312 | +static struct dec_hufftbl dhuff[4]; | |
1313 | + | |
1314 | +#define dec_huffdc (dhuff + 0) | |
1315 | +#define dec_huffac (dhuff + 2) | |
1316 | + | |
1317 | +static struct in in; | |
1318 | + | |
1319 | +static int readtables(int till) | |
1320 | +{ | |
1321 | + int m, l, i, j, lq, pq, tq; | |
1322 | + int tc, th, tt; | |
1323 | + | |
1324 | + for (;;) { | |
1325 | + if (getbyte() != 0xff) | |
1326 | + return -1; | |
1327 | + if ((m = getbyte()) == till) | |
1328 | + break; | |
1329 | + | |
1330 | + switch (m) { | |
1331 | + case 0xc2: | |
1332 | + return 0; | |
1333 | + | |
1334 | + case M_DQT: | |
1335 | + lq = getword(); | |
1336 | + while (lq > 2) { | |
1337 | + pq = getbyte(); | |
1338 | + tq = pq & 15; | |
1339 | + if (tq > 3) | |
1340 | + return -1; | |
1341 | + pq >>= 4; | |
1342 | + if (pq != 0) | |
1343 | + return -1; | |
1344 | + for (i = 0; i < 64; i++) | |
1345 | + quant[tq][i] = getbyte(); | |
1346 | + lq -= 64 + 1; | |
1347 | + } | |
1348 | + break; | |
1349 | + | |
1350 | + case M_DHT: | |
1351 | + l = getword(); | |
1352 | + while (l > 2) { | |
1353 | + int hufflen[16], k; | |
1354 | + unsigned char huffvals[256]; | |
1355 | + | |
1356 | + tc = getbyte(); | |
1357 | + th = tc & 15; | |
1358 | + tc >>= 4; | |
1359 | + tt = tc * 2 + th; | |
1360 | + if (tc > 1 || th > 1) | |
1361 | + return -1; | |
1362 | + for (i = 0; i < 16; i++) | |
1363 | + hufflen[i] = getbyte(); | |
1364 | + l -= 1 + 16; | |
1365 | + k = 0; | |
1366 | + for (i = 0; i < 16; i++) { | |
1367 | + for (j = 0; j < hufflen[i]; j++) | |
1368 | + huffvals[k++] = getbyte(); | |
1369 | + l -= hufflen[i]; | |
1370 | + } | |
1371 | + dec_makehuff(dhuff + tt, hufflen, | |
1372 | + huffvals); | |
1373 | + } | |
1374 | + break; | |
1375 | + | |
1376 | + case M_DRI: | |
1377 | + l = getword(); | |
1378 | + info.dri = getword(); | |
1379 | + break; | |
1380 | + | |
1381 | + default: | |
1382 | + l = getword(); | |
1383 | + while (l-- > 2) | |
1384 | + getbyte(); | |
1385 | + break; | |
1386 | + } | |
1387 | + } | |
1388 | + return 0; | |
1389 | +} | |
1390 | + | |
1391 | +static void dec_initscans(void) | |
1392 | +{ | |
1393 | + int i; | |
1394 | + | |
1395 | + info.nm = info.dri + 1; | |
1396 | + info.rm = M_RST0; | |
1397 | + for (i = 0; i < info.ns; i++) | |
1398 | + dscans[i].dc = 0; | |
1399 | +} | |
1400 | + | |
1401 | +static int dec_checkmarker(void) | |
1402 | +{ | |
1403 | + int i; | |
1404 | + | |
1405 | + if (dec_readmarker(&in) != info.rm) | |
1406 | + return -1; | |
1407 | + info.nm = info.dri; | |
1408 | + info.rm = (info.rm + 1) & ~0x08; | |
1409 | + for (i = 0; i < info.ns; i++) | |
1410 | + dscans[i].dc = 0; | |
1411 | + return 0; | |
1412 | +} | |
1413 | + | |
1414 | +int jpeg_check_size(unsigned char *buf, int width, int height) | |
1415 | +{ | |
1416 | + datap = buf; | |
1417 | + getbyte(); | |
1418 | + getbyte(); | |
1419 | + readtables(M_SOF0); | |
1420 | + getword(); | |
1421 | + getbyte(); | |
1422 | + if (height != getword() || width != getword()) | |
1423 | + return 0; | |
1424 | + return 1; | |
1425 | +} | |
1426 | + | |
1427 | +int jpeg_decode(buf, pic, width, height, depth, decdata) | |
1428 | +unsigned char *buf, *pic; | |
1429 | +int width, height, depth; | |
1430 | +struct jpeg_decdata *decdata; | |
1431 | +{ | |
1432 | + int i, j, m, tac, tdc; | |
1433 | + int mcusx, mcusy, mx, my; | |
1434 | + int max[6]; | |
1435 | + | |
1436 | + if (!decdata || !buf || !pic) | |
1437 | + return -1; | |
1438 | + datap = buf; | |
1439 | + if (getbyte() != 0xff) | |
1440 | + return ERR_NO_SOI; | |
1441 | + if (getbyte() != M_SOI) | |
1442 | + return ERR_NO_SOI; | |
1443 | + if (readtables(M_SOF0)) | |
1444 | + return ERR_BAD_TABLES; | |
1445 | + getword(); | |
1446 | + i = getbyte(); | |
1447 | + if (i != 8) | |
1448 | + return ERR_NOT_8BIT; | |
1449 | + if (((getword() + 15) & ~15) != height) | |
1450 | + return ERR_HEIGHT_MISMATCH; | |
1451 | + if (((getword() + 15) & ~15) != width) | |
1452 | + return ERR_WIDTH_MISMATCH; | |
1453 | + if ((height & 15) || (width & 15)) | |
1454 | + return ERR_BAD_WIDTH_OR_HEIGHT; | |
1455 | + info.nc = getbyte(); | |
1456 | + if (info.nc > MAXCOMP) | |
1457 | + return ERR_TOO_MANY_COMPPS; | |
1458 | + for (i = 0; i < info.nc; i++) { | |
1459 | + int h, v; | |
1460 | + comps[i].cid = getbyte(); | |
1461 | + comps[i].hv = getbyte(); | |
1462 | + v = comps[i].hv & 15; | |
1463 | + h = comps[i].hv >> 4; | |
1464 | + comps[i].tq = getbyte(); | |
1465 | + if (h > 3 || v > 3) | |
1466 | + return ERR_ILLEGAL_HV; | |
1467 | + if (comps[i].tq > 3) | |
1468 | + return ERR_QUANT_TABLE_SELECTOR; | |
1469 | + } | |
1470 | + if (readtables(M_SOS)) | |
1471 | + return ERR_BAD_TABLES; | |
1472 | + getword(); | |
1473 | + info.ns = getbyte(); | |
1474 | + if (info.ns != 3) | |
1475 | + return ERR_NOT_YCBCR_221111; | |
1476 | + for (i = 0; i < 3; i++) { | |
1477 | + dscans[i].cid = getbyte(); | |
1478 | + tdc = getbyte(); | |
1479 | + tac = tdc & 15; | |
1480 | + tdc >>= 4; | |
1481 | + if (tdc > 1 || tac > 1) | |
1482 | + return ERR_QUANT_TABLE_SELECTOR; | |
1483 | + for (j = 0; j < info.nc; j++) | |
1484 | + if (comps[j].cid == dscans[i].cid) | |
1485 | + break; | |
1486 | + if (j == info.nc) | |
1487 | + return ERR_UNKNOWN_CID_IN_SCAN; | |
1488 | + dscans[i].hv = comps[j].hv; | |
1489 | + dscans[i].tq = comps[j].tq; | |
1490 | + dscans[i].hudc.dhuff = dec_huffdc + tdc; | |
1491 | + dscans[i].huac.dhuff = dec_huffac + tac; | |
1492 | + } | |
1493 | + | |
1494 | + i = getbyte(); | |
1495 | + j = getbyte(); | |
1496 | + m = getbyte(); | |
1497 | + | |
1498 | + if (i != 0 || j != 63 || m != 0) | |
1499 | + return ERR_NOT_SEQUENTIAL_DCT; | |
1500 | + | |
1501 | + if (dscans[0].cid != 1 || dscans[1].cid != 2 || dscans[2].cid != 3) | |
1502 | + return ERR_NOT_YCBCR_221111; | |
1503 | + | |
1504 | + if (dscans[0].hv != 0x22 || dscans[1].hv != 0x11 || dscans[2].hv != 0x11) | |
1505 | + return ERR_NOT_YCBCR_221111; | |
1506 | + | |
1507 | + mcusx = width >> 4; | |
1508 | + mcusy = height >> 4; | |
1509 | + | |
1510 | + | |
1511 | + idctqtab(quant[dscans[0].tq], decdata->dquant[0]); | |
1512 | + idctqtab(quant[dscans[1].tq], decdata->dquant[1]); | |
1513 | + idctqtab(quant[dscans[2].tq], decdata->dquant[2]); | |
1514 | + initcol(decdata->dquant); | |
1515 | + setinput(&in, datap); | |
1516 | + | |
1517 | +#if 0 | |
1518 | + /* landing zone */ | |
1519 | + img[len] = 0; | |
1520 | + img[len + 1] = 0xff; | |
1521 | + img[len + 2] = M_EOF; | |
1522 | +#endif | |
1523 | + | |
1524 | + dec_initscans(); | |
1525 | + | |
1526 | + dscans[0].next = 6 - 4; | |
1527 | + dscans[1].next = 6 - 4 - 1; | |
1528 | + dscans[2].next = 6 - 4 - 1 - 1; /* 411 encoding */ | |
1529 | + for (my = 0; my < mcusy; my++) { | |
1530 | + for (mx = 0; mx < mcusx; mx++) { | |
1531 | + if (info.dri && !--info.nm) | |
1532 | + if (dec_checkmarker()) | |
1533 | + return ERR_WRONG_MARKER; | |
1534 | + | |
1535 | + decode_mcus(&in, decdata->dcts, 6, dscans, max); | |
1536 | + idct(decdata->dcts, decdata->out, decdata->dquant[0], IFIX(128.5), max[0]); | |
1537 | + idct(decdata->dcts + 64, decdata->out + 64, decdata->dquant[0], IFIX(128.5), max[1]); | |
1538 | + idct(decdata->dcts + 128, decdata->out + 128, decdata->dquant[0], IFIX(128.5), max[2]); | |
1539 | + idct(decdata->dcts + 192, decdata->out + 192, decdata->dquant[0], IFIX(128.5), max[3]); | |
1540 | + idct(decdata->dcts + 256, decdata->out + 256, decdata->dquant[1], IFIX(0.5), max[4]); | |
1541 | + idct(decdata->dcts + 320, decdata->out + 320, decdata->dquant[2], IFIX(0.5), max[5]); | |
1542 | + | |
1543 | + switch (depth) { | |
1544 | + case 24: | |
1545 | + col221111(decdata->out, pic + (my * 16 * mcusx + mx) * 16 * 3, mcusx * 16 * 3); | |
1546 | + break; | |
1547 | + case 16: | |
1548 | + col221111_16(decdata->out, pic + (my * 16 * mcusx + mx) * (16 * 2), mcusx * (16 * 2)); | |
1549 | + break; | |
1550 | + default: | |
1551 | + return ERR_DEPTH_MISMATCH; | |
1552 | + break; | |
1553 | + } | |
1554 | + } | |
1555 | + } | |
1556 | + | |
1557 | + m = dec_readmarker(&in); | |
1558 | + if (m != M_EOI) | |
1559 | + return ERR_NO_EOI; | |
1560 | + | |
1561 | + return 0; | |
1562 | +} | |
1563 | + | |
1564 | +/****************************************************************/ | |
1565 | +/************** huffman decoder ***************/ | |
1566 | +/****************************************************************/ | |
1567 | + | |
1568 | +static int fillbits __P((struct in *, int, unsigned int)); | |
1569 | +static int dec_rec2 | |
1570 | +__P((struct in *, struct dec_hufftbl *, int *, int, int)); | |
1571 | + | |
1572 | +static void setinput(in, p) | |
1573 | +struct in *in; | |
1574 | +unsigned char *p; | |
1575 | +{ | |
1576 | + in->p = p; | |
1577 | + in->left = 0; | |
1578 | + in->bits = 0; | |
1579 | + in->marker = 0; | |
1580 | +} | |
1581 | + | |
1582 | +static int fillbits(in, le, bi) | |
1583 | +struct in *in; | |
1584 | +int le; | |
1585 | +unsigned int bi; | |
1586 | +{ | |
1587 | + int b, m; | |
1588 | + | |
1589 | + if (in->marker) { | |
1590 | + if (le <= 16) | |
1591 | + in->bits = bi << 16, le += 16; | |
1592 | + return le; | |
1593 | + } | |
1594 | + while (le <= 24) { | |
1595 | + b = *in->p++; | |
1596 | + if (b == 0xff && (m = *in->p++) != 0) { | |
1597 | + if (m == M_EOF) { | |
1598 | + if (in->func && (m = in->func(in->data)) == 0) | |
1599 | + continue; | |
1600 | + } | |
1601 | + in->marker = m; | |
1602 | + if (le <= 16) | |
1603 | + bi = bi << 16, le += 16; | |
1604 | + break; | |
1605 | + } | |
1606 | + bi = bi << 8 | b; | |
1607 | + le += 8; | |
1608 | + } | |
1609 | + in->bits = bi; /* tmp... 2 return values needed */ | |
1610 | + return le; | |
1611 | +} | |
1612 | + | |
1613 | +static int dec_readmarker(in) | |
1614 | +struct in *in; | |
1615 | +{ | |
1616 | + int m; | |
1617 | + | |
1618 | + in->left = fillbits(in, in->left, in->bits); | |
1619 | + if ((m = in->marker) == 0) | |
1620 | + return 0; | |
1621 | + in->left = 0; | |
1622 | + in->marker = 0; | |
1623 | + return m; | |
1624 | +} | |
1625 | + | |
1626 | +#define LEBI_DCL int le, bi | |
1627 | +#define LEBI_GET(in) (le = in->left, bi = in->bits) | |
1628 | +#define LEBI_PUT(in) (in->left = le, in->bits = bi) | |
1629 | + | |
1630 | +#define GETBITS(in, n) ( \ | |
1631 | + (le < (n) ? le = fillbits(in, le, bi), bi = in->bits : 0), \ | |
1632 | + (le -= (n)), \ | |
1633 | + bi >> le & ((1 << (n)) - 1) \ | |
1634 | +) | |
1635 | + | |
1636 | +#define UNGETBITS(in, n) ( \ | |
1637 | + le += (n) \ | |
1638 | +) | |
1639 | + | |
1640 | + | |
1641 | +static int dec_rec2(in, hu, runp, c, i) | |
1642 | +struct in *in; | |
1643 | +struct dec_hufftbl *hu; | |
1644 | +int *runp; | |
1645 | +int c, i; | |
1646 | +{ | |
1647 | + LEBI_DCL; | |
1648 | + | |
1649 | + LEBI_GET(in); | |
1650 | + if (i) { | |
1651 | + UNGETBITS(in, i & 127); | |
1652 | + *runp = i >> 8 & 15; | |
1653 | + i >>= 16; | |
1654 | + } else { | |
1655 | + for (i = DECBITS; (c = ((c << 1) | GETBITS(in, 1))) >= (hu->maxcode[i]); i++); | |
1656 | + if (i >= 16) { | |
1657 | + in->marker = M_BADHUFF; | |
1658 | + return 0; | |
1659 | + } | |
1660 | + i = hu->vals[hu->valptr[i] + c - hu->maxcode[i - 1] * 2]; | |
1661 | + *runp = i >> 4; | |
1662 | + i &= 15; | |
1663 | + } | |
1664 | + if (i == 0) { /* sigh, 0xf0 is 11 bit */ | |
1665 | + LEBI_PUT(in); | |
1666 | + return 0; | |
1667 | + } | |
1668 | + /* receive part */ | |
1669 | + c = GETBITS(in, i); | |
1670 | + if (c < (1 << (i - 1))) | |
1671 | + c += (-1 << i) + 1; | |
1672 | + LEBI_PUT(in); | |
1673 | + return c; | |
1674 | +} | |
1675 | + | |
1676 | +#define DEC_REC(in, hu, r, i) ( \ | |
1677 | + r = GETBITS(in, DECBITS), \ | |
1678 | + i = hu->llvals[r], \ | |
1679 | + i & 128 ? \ | |
1680 | + ( \ | |
1681 | + UNGETBITS(in, i & 127), \ | |
1682 | + r = i >> 8 & 15, \ | |
1683 | + i >> 16 \ | |
1684 | + ) \ | |
1685 | + : \ | |
1686 | + ( \ | |
1687 | + LEBI_PUT(in), \ | |
1688 | + i = dec_rec2(in, hu, &r, r, i), \ | |
1689 | + LEBI_GET(in), \ | |
1690 | + i \ | |
1691 | + ) \ | |
1692 | +) | |
1693 | + | |
1694 | +static void decode_mcus(in, dct, n, sc, maxp) | |
1695 | +struct in *in; | |
1696 | +int *dct; | |
1697 | +int n; | |
1698 | +struct scan *sc; | |
1699 | +int *maxp; | |
1700 | +{ | |
1701 | + struct dec_hufftbl *hu; | |
1702 | + int i, r, t; | |
1703 | + LEBI_DCL; | |
1704 | + | |
1705 | + memset(dct, 0, n * 64 * sizeof(*dct)); | |
1706 | + LEBI_GET(in); | |
1707 | + while (n-- > 0) { | |
1708 | + hu = sc->hudc.dhuff; | |
1709 | + *dct++ = (sc->dc += DEC_REC(in, hu, r, t)); | |
1710 | + | |
1711 | + hu = sc->huac.dhuff; | |
1712 | + i = 63; | |
1713 | + while (i > 0) { | |
1714 | + t = DEC_REC(in, hu, r, t); | |
1715 | + if (t == 0 && r == 0) { | |
1716 | + dct += i; | |
1717 | + break; | |
1718 | + } | |
1719 | + dct += r; | |
1720 | + *dct++ = t; | |
1721 | + i -= r + 1; | |
1722 | + } | |
1723 | + *maxp++ = 64 - i; | |
1724 | + if (n == sc->next) | |
1725 | + sc++; | |
1726 | + } | |
1727 | + LEBI_PUT(in); | |
1728 | +} | |
1729 | + | |
1730 | +static void dec_makehuff(hu, hufflen, huffvals) | |
1731 | +struct dec_hufftbl *hu; | |
1732 | +int *hufflen; | |
1733 | +unsigned char *huffvals; | |
1734 | +{ | |
1735 | + int code, k, i, j, d, x, c, v; | |
1736 | + for (i = 0; i < (1 << DECBITS); i++) | |
1737 | + hu->llvals[i] = 0; | |
1738 | + | |
1739 | +/* | |
1740 | + * llvals layout: | |
1741 | + * | |
1742 | + * value v already known, run r, backup u bits: | |
1743 | + * vvvvvvvvvvvvvvvv 0000 rrrr 1 uuuuuuu | |
1744 | + * value unknown, size b bits, run r, backup u bits: | |
1745 | + * 000000000000bbbb 0000 rrrr 0 uuuuuuu | |
1746 | + * value and size unknown: | |
1747 | + * 0000000000000000 0000 0000 0 0000000 | |
1748 | + */ | |
1749 | + code = 0; | |
1750 | + k = 0; | |
1751 | + for (i = 0; i < 16; i++, code <<= 1) { /* sizes */ | |
1752 | + hu->valptr[i] = k; | |
1753 | + for (j = 0; j < hufflen[i]; j++) { | |
1754 | + hu->vals[k] = *huffvals++; | |
1755 | + if (i < DECBITS) { | |
1756 | + c = code << (DECBITS - 1 - i); | |
1757 | + v = hu->vals[k] & 0x0f; /* size */ | |
1758 | + for (d = 1 << (DECBITS - 1 - i); --d >= 0;) { | |
1759 | + if (v + i < DECBITS) { /* both fit in table */ | |
1760 | + x = d >> (DECBITS - 1 - v - | |
1761 | + i); | |
1762 | + if (v && x < (1 << (v - 1))) | |
1763 | + x += (-1 << v) + 1; | |
1764 | + x = x << 16 | (hu-> vals[k] & 0xf0) << 4 | | |
1765 | + (DECBITS - (i + 1 + v)) | 128; | |
1766 | + } else | |
1767 | + x = v << 16 | (hu-> vals[k] & 0xf0) << 4 | | |
1768 | + (DECBITS - (i + 1)); | |
1769 | + hu->llvals[c | d] = x; | |
1770 | + } | |
1771 | + } | |
1772 | + code++; | |
1773 | + k++; | |
1774 | + } | |
1775 | + hu->maxcode[i] = code; | |
1776 | + } | |
1777 | + hu->maxcode[16] = 0x20000; /* always terminate decode */ | |
1778 | +} | |
1779 | + | |
1780 | +/****************************************************************/ | |
1781 | +/************** idct ***************/ | |
1782 | +/****************************************************************/ | |
1783 | + | |
1784 | +#define ONE ((PREC)IFIX(1.)) | |
1785 | +#define S2 ((PREC)IFIX(0.382683432)) | |
1786 | +#define C2 ((PREC)IFIX(0.923879532)) | |
1787 | +#define C4 ((PREC)IFIX(0.707106781)) | |
1788 | + | |
1789 | +#define S22 ((PREC)IFIX(2 * 0.382683432)) | |
1790 | +#define C22 ((PREC)IFIX(2 * 0.923879532)) | |
1791 | +#define IC4 ((PREC)IFIX(1 / 0.707106781)) | |
1792 | + | |
1793 | +#define C3IC1 ((PREC)IFIX(0.847759065)) /* c3/c1 */ | |
1794 | +#define C5IC1 ((PREC)IFIX(0.566454497)) /* c5/c1 */ | |
1795 | +#define C7IC1 ((PREC)IFIX(0.198912367)) /* c7/c1 */ | |
1796 | + | |
1797 | +#define XPP(a,b) (t = a + b, b = a - b, a = t) | |
1798 | +#define XMP(a,b) (t = a - b, b = a + b, a = t) | |
1799 | +#define XPM(a,b) (t = a + b, b = b - a, a = t) | |
1800 | + | |
1801 | +#define ROT(a,b,s,c) ( t = IMULT(a + b, s), \ | |
1802 | + a = IMULT(a, c - s) + t, \ | |
1803 | + b = IMULT(b, c + s) - t) | |
1804 | + | |
1805 | +#define IDCT \ | |
1806 | +( \ | |
1807 | + XPP(t0, t1), \ | |
1808 | + XMP(t2, t3), \ | |
1809 | + t2 = IMULT(t2, IC4) - t3, \ | |
1810 | + XPP(t0, t3), \ | |
1811 | + XPP(t1, t2), \ | |
1812 | + XMP(t4, t7), \ | |
1813 | + XPP(t5, t6), \ | |
1814 | + XMP(t5, t7), \ | |
1815 | + t5 = IMULT(t5, IC4), \ | |
1816 | + ROT(t4, t6, S22, C22),\ | |
1817 | + t6 -= t7, \ | |
1818 | + t5 -= t6, \ | |
1819 | + t4 -= t5, \ | |
1820 | + XPP(t0, t7), \ | |
1821 | + XPP(t1, t6), \ | |
1822 | + XPP(t2, t5), \ | |
1823 | + XPP(t3, t4) \ | |
1824 | +) | |
1825 | + | |
1826 | +static unsigned char zig2[64] = { | |
1827 | + 0, 2, 3, 9, 10, 20, 21, 35, | |
1828 | + 14, 16, 25, 31, 39, 46, 50, 57, | |
1829 | + 5, 7, 12, 18, 23, 33, 37, 48, | |
1830 | + 27, 29, 41, 44, 52, 55, 59, 62, | |
1831 | + 15, 26, 30, 40, 45, 51, 56, 58, | |
1832 | + 1, 4, 8, 11, 19, 22, 34, 36, | |
1833 | + 28, 42, 43, 53, 54, 60, 61, 63, | |
1834 | + 6, 13, 17, 24, 32, 38, 47, 49 | |
1835 | +}; | |
1836 | + | |
1837 | +void idct(in, out, quant, off, max) | |
1838 | +int *in; | |
1839 | +int *out; | |
1840 | +PREC *quant; | |
1841 | +PREC off; | |
1842 | +int max; | |
1843 | +{ | |
1844 | + PREC t0, t1, t2, t3, t4, t5, t6, t7, t; | |
1845 | + PREC tmp[64], *tmpp; | |
1846 | + int i, j; | |
1847 | + unsigned char *zig2p; | |
1848 | + | |
1849 | + t0 = off; | |
1850 | + if (max == 1) { | |
1851 | + t0 += in[0] * quant[0]; | |
1852 | + for (i = 0; i < 64; i++) | |
1853 | + out[i] = ITOINT(t0); | |
1854 | + return; | |
1855 | + } | |
1856 | + zig2p = zig2; | |
1857 | + tmpp = tmp; | |
1858 | + for (i = 0; i < 8; i++) { | |
1859 | + j = *zig2p++; | |
1860 | + t0 += in[j] * quant[j]; | |
1861 | + j = *zig2p++; | |
1862 | + t5 = in[j] * quant[j]; | |
1863 | + j = *zig2p++; | |
1864 | + t2 = in[j] * quant[j]; | |
1865 | + j = *zig2p++; | |
1866 | + t7 = in[j] * quant[j]; | |
1867 | + j = *zig2p++; | |
1868 | + t1 = in[j] * quant[j]; | |
1869 | + j = *zig2p++; | |
1870 | + t4 = in[j] * quant[j]; | |
1871 | + j = *zig2p++; | |
1872 | + t3 = in[j] * quant[j]; | |
1873 | + j = *zig2p++; | |
1874 | + t6 = in[j] * quant[j]; | |
1875 | + IDCT; | |
1876 | + tmpp[0 * 8] = t0; | |
1877 | + tmpp[1 * 8] = t1; | |
1878 | + tmpp[2 * 8] = t2; | |
1879 | + tmpp[3 * 8] = t3; | |
1880 | + tmpp[4 * 8] = t4; | |
1881 | + tmpp[5 * 8] = t5; | |
1882 | + tmpp[6 * 8] = t6; | |
1883 | + tmpp[7 * 8] = t7; | |
1884 | + tmpp++; | |
1885 | + t0 = 0; | |
1886 | + } | |
1887 | + for (i = 0; i < 8; i++) { | |
1888 | + t0 = tmp[8 * i + 0]; | |
1889 | + t1 = tmp[8 * i + 1]; | |
1890 | + t2 = tmp[8 * i + 2]; | |
1891 | + t3 = tmp[8 * i + 3]; | |
1892 | + t4 = tmp[8 * i + 4]; | |
1893 | + t5 = tmp[8 * i + 5]; | |
1894 | + t6 = tmp[8 * i + 6]; | |
1895 | + t7 = tmp[8 * i + 7]; | |
1896 | + IDCT; | |
1897 | + out[8 * i + 0] = ITOINT(t0); | |
1898 | + out[8 * i + 1] = ITOINT(t1); | |
1899 | + out[8 * i + 2] = ITOINT(t2); | |
1900 | + out[8 * i + 3] = ITOINT(t3); | |
1901 | + out[8 * i + 4] = ITOINT(t4); | |
1902 | + out[8 * i + 5] = ITOINT(t5); | |
1903 | + out[8 * i + 6] = ITOINT(t6); | |
1904 | + out[8 * i + 7] = ITOINT(t7); | |
1905 | + } | |
1906 | +} | |
1907 | + | |
1908 | +static unsigned char zig[64] = { | |
1909 | + 0, 1, 5, 6, 14, 15, 27, 28, | |
1910 | + 2, 4, 7, 13, 16, 26, 29, 42, | |
1911 | + 3, 8, 12, 17, 25, 30, 41, 43, | |
1912 | + 9, 11, 18, 24, 31, 40, 44, 53, | |
1913 | + 10, 19, 23, 32, 39, 45, 52, 54, | |
1914 | + 20, 22, 33, 38, 46, 51, 55, 60, | |
1915 | + 21, 34, 37, 47, 50, 56, 59, 61, | |
1916 | + 35, 36, 48, 49, 57, 58, 62, 63 | |
1917 | +}; | |
1918 | + | |
1919 | +static PREC aaidct[8] = { | |
1920 | + IFIX(0.3535533906), IFIX(0.4903926402), | |
1921 | + IFIX(0.4619397663), IFIX(0.4157348062), | |
1922 | + IFIX(0.3535533906), IFIX(0.2777851165), | |
1923 | + IFIX(0.1913417162), IFIX(0.0975451610) | |
1924 | +}; | |
1925 | + | |
1926 | + | |
1927 | +static void idctqtab(qin, qout) | |
1928 | +unsigned char *qin; | |
1929 | +PREC *qout; | |
1930 | +{ | |
1931 | + int i, j; | |
1932 | + | |
1933 | + for (i = 0; i < 8; i++) | |
1934 | + for (j = 0; j < 8; j++) | |
1935 | + qout[zig[i * 8 + j]] = qin[zig[i * 8 + j]] * | |
1936 | + IMULT(aaidct[i], aaidct[j]); | |
1937 | +} | |
1938 | + | |
1939 | +static void scaleidctqtab(q, sc) | |
1940 | +PREC *q; | |
1941 | +PREC sc; | |
1942 | +{ | |
1943 | + int i; | |
1944 | + | |
1945 | + for (i = 0; i < 64; i++) | |
1946 | + q[i] = IMULT(q[i], sc); | |
1947 | +} | |
1948 | + | |
1949 | +/****************************************************************/ | |
1950 | +/************** color decoder ***************/ | |
1951 | +/****************************************************************/ | |
1952 | + | |
1953 | +#define ROUND | |
1954 | + | |
1955 | +/* | |
1956 | + * YCbCr Color transformation: | |
1957 | + * | |
1958 | + * y:0..255 Cb:-128..127 Cr:-128..127 | |
1959 | + * | |
1960 | + * R = Y + 1.40200 * Cr | |
1961 | + * G = Y - 0.34414 * Cb - 0.71414 * Cr | |
1962 | + * B = Y + 1.77200 * Cb | |
1963 | + * | |
1964 | + * => | |
1965 | + * Cr *= 1.40200; | |
1966 | + * Cb *= 1.77200; | |
1967 | + * Cg = 0.19421 * Cb + .50937 * Cr; | |
1968 | + * R = Y + Cr; | |
1969 | + * G = Y - Cg; | |
1970 | + * B = Y + Cb; | |
1971 | + * | |
1972 | + * => | |
1973 | + * Cg = (50 * Cb + 130 * Cr + 128) >> 8; | |
1974 | + */ | |
1975 | + | |
1976 | +static void initcol(q) | |
1977 | +PREC q[][64]; | |
1978 | +{ | |
1979 | + scaleidctqtab(q[1], IFIX(1.77200)); | |
1980 | + scaleidctqtab(q[2], IFIX(1.40200)); | |
1981 | +} | |
1982 | + | |
1983 | +/* This is optimized for the stupid sun SUNWspro compiler. */ | |
1984 | +#define STORECLAMP(a,x) \ | |
1985 | +( \ | |
1986 | + (a) = (x), \ | |
1987 | + (unsigned int)(x) >= 256 ? \ | |
1988 | + ((a) = (x) < 0 ? 0 : 255) \ | |
1989 | + : \ | |
1990 | + 0 \ | |
1991 | +) | |
1992 | + | |
1993 | +#define CLAMP(x) ((unsigned int)(x) >= 256 ? ((x) < 0 ? 0 : 255) : (x)) | |
1994 | + | |
1995 | +#ifdef ROUND | |
1996 | + | |
1997 | +#define CBCRCG(yin, xin) \ | |
1998 | +( \ | |
1999 | + cb = outc[0 +yin*8+xin], \ | |
2000 | + cr = outc[64+yin*8+xin], \ | |
2001 | + cg = (50 * cb + 130 * cr + 128) >> 8 \ | |
2002 | +) | |
2003 | + | |
2004 | +#else | |
2005 | + | |
2006 | +#define CBCRCG(yin, xin) \ | |
2007 | +( \ | |
2008 | + cb = outc[0 +yin*8+xin], \ | |
2009 | + cr = outc[64+yin*8+xin], \ | |
2010 | + cg = (3 * cb + 8 * cr) >> 4 \ | |
2011 | +) | |
2012 | + | |
2013 | +#endif | |
2014 | + | |
2015 | +#define PIC(yin, xin, p, xout) \ | |
2016 | +( \ | |
2017 | + y = outy[(yin) * 8 + xin], \ | |
2018 | + STORECLAMP(p[(xout) * 3 + 0], y + cr), \ | |
2019 | + STORECLAMP(p[(xout) * 3 + 1], y - cg), \ | |
2020 | + STORECLAMP(p[(xout) * 3 + 2], y + cb) \ | |
2021 | +) | |
2022 | + | |
2023 | +#ifdef __LITTLE_ENDIAN | |
2024 | +#define PIC_16(yin, xin, p, xout, add) \ | |
2025 | +( \ | |
2026 | + y = outy[(yin) * 8 + xin], \ | |
2027 | + y = ((CLAMP(y + cr + add*2+1) & 0xf8) << 8) | \ | |
2028 | + ((CLAMP(y - cg + add ) & 0xfc) << 3) | \ | |
2029 | + ((CLAMP(y + cb + add*2+1) ) >> 3), \ | |
2030 | + p[(xout) * 2 + 0] = y & 0xff, \ | |
2031 | + p[(xout) * 2 + 1] = y >> 8 \ | |
2032 | +) | |
2033 | +#else | |
2034 | +#ifdef CONFIG_PPC | |
2035 | +#define PIC_16(yin, xin, p, xout, add) \ | |
2036 | +( \ | |
2037 | + y = outy[(yin) * 8 + xin], \ | |
2038 | + y = ((CLAMP(y + cr + add*2+1) & 0xf8) << 7) | \ | |
2039 | + ((CLAMP(y - cg + add*2+1) & 0xf8) << 2) | \ | |
2040 | + ((CLAMP(y + cb + add*2+1) ) >> 3), \ | |
2041 | + p[(xout) * 2 + 0] = y >> 8, \ | |
2042 | + p[(xout) * 2 + 1] = y & 0xff \ | |
2043 | +) | |
2044 | +#else | |
2045 | +#define PIC_16(yin, xin, p, xout, add) \ | |
2046 | +( \ | |
2047 | + y = outy[(yin) * 8 + xin], \ | |
2048 | + y = ((CLAMP(y + cr + add*2+1) & 0xf8) << 8) | \ | |
2049 | + ((CLAMP(y - cg + add ) & 0xfc) << 3) | \ | |
2050 | + ((CLAMP(y + cb + add*2+1) ) >> 3), \ | |
2051 | + p[(xout) * 2 + 0] = y >> 8, \ | |
2052 | + p[(xout) * 2 + 1] = y & 0xff \ | |
2053 | +) | |
2054 | +#endif | |
2055 | +#endif | |
2056 | + | |
2057 | +#define PIC221111(xin) \ | |
2058 | +( \ | |
2059 | + CBCRCG(0, xin), \ | |
2060 | + PIC(xin / 4 * 8 + 0, (xin & 3) * 2 + 0, pic0, xin * 2 + 0), \ | |
2061 | + PIC(xin / 4 * 8 + 0, (xin & 3) * 2 + 1, pic0, xin * 2 + 1), \ | |
2062 | + PIC(xin / 4 * 8 + 1, (xin & 3) * 2 + 0, pic1, xin * 2 + 0), \ | |
2063 | + PIC(xin / 4 * 8 + 1, (xin & 3) * 2 + 1, pic1, xin * 2 + 1) \ | |
2064 | +) | |
2065 | + | |
2066 | +#define PIC221111_16(xin) \ | |
2067 | +( \ | |
2068 | + CBCRCG(0, xin), \ | |
2069 | + PIC_16(xin / 4 * 8 + 0, (xin & 3) * 2 + 0, pic0, xin * 2 + 0, 3), \ | |
2070 | + PIC_16(xin / 4 * 8 + 0, (xin & 3) * 2 + 1, pic0, xin * 2 + 1, 0), \ | |
2071 | + PIC_16(xin / 4 * 8 + 1, (xin & 3) * 2 + 0, pic1, xin * 2 + 0, 1), \ | |
2072 | + PIC_16(xin / 4 * 8 + 1, (xin & 3) * 2 + 1, pic1, xin * 2 + 1, 2) \ | |
2073 | +) | |
2074 | + | |
2075 | +static void col221111(out, pic, width) | |
2076 | +int *out; | |
2077 | +unsigned char *pic; | |
2078 | +int width; | |
2079 | +{ | |
2080 | + int i, j, k; | |
2081 | + unsigned char *pic0, *pic1; | |
2082 | + int *outy, *outc; | |
2083 | + int cr, cg, cb, y; | |
2084 | + | |
2085 | + pic0 = pic; | |
2086 | + pic1 = pic + width; | |
2087 | + outy = out; | |
2088 | + outc = out + 64 * 4; | |
2089 | + for (i = 2; i > 0; i--) { | |
2090 | + for (j = 4; j > 0; j--) { | |
2091 | + for (k = 0; k < 8; k++) { | |
2092 | + PIC221111(k); | |
2093 | + } | |
2094 | + outc += 8; | |
2095 | + outy += 16; | |
2096 | + pic0 += 2 * width; | |
2097 | + pic1 += 2 * width; | |
2098 | + } | |
2099 | + outy += 64 * 2 - 16 * 4; | |
2100 | + } | |
2101 | +} | |
2102 | + | |
2103 | +static void col221111_16(out, pic, width) | |
2104 | +int *out; | |
2105 | +unsigned char *pic; | |
2106 | +int width; | |
2107 | +{ | |
2108 | + int i, j, k; | |
2109 | + unsigned char *pic0, *pic1; | |
2110 | + int *outy, *outc; | |
2111 | + int cr, cg, cb, y; | |
2112 | + | |
2113 | + pic0 = pic; | |
2114 | + pic1 = pic + width; | |
2115 | + outy = out; | |
2116 | + outc = out + 64 * 4; | |
2117 | + for (i = 2; i > 0; i--) { | |
2118 | + for (j = 4; j > 0; j--) { | |
2119 | + for (k = 0; k < 8; k++) { | |
2120 | + PIC221111_16(k); | |
2121 | + } | |
2122 | + outc += 8; | |
2123 | + outy += 16; | |
2124 | + pic0 += 2 * width; | |
2125 | + pic1 += 2 * width; | |
2126 | + } | |
2127 | + outy += 64 * 2 - 16 * 4; | |
2128 | + } | |
2129 | +} | |
2130 | --- /dev/null | |
2131 | +++ b/drivers/video/bootsplash/decode-jpg.h | |
2132 | @@ -0,0 +1,35 @@ | |
2133 | +/* | |
2134 | + * linux/drivers/video/bootsplash/decode-jpg.h - a tiny jpeg decoder. | |
2135 | + * | |
2136 | + * (w) August 2001 by Michael Schroeder, <mls@suse.de> | |
2137 | + */ | |
2138 | + | |
2139 | +#ifndef __DECODE_JPG_H | |
2140 | +#define __DECODE_JPG_H | |
2141 | + | |
2142 | +#define ERR_NO_SOI 1 | |
2143 | +#define ERR_NOT_8BIT 2 | |
2144 | +#define ERR_HEIGHT_MISMATCH 3 | |
2145 | +#define ERR_WIDTH_MISMATCH 4 | |
2146 | +#define ERR_BAD_WIDTH_OR_HEIGHT 5 | |
2147 | +#define ERR_TOO_MANY_COMPPS 6 | |
2148 | +#define ERR_ILLEGAL_HV 7 | |
2149 | +#define ERR_QUANT_TABLE_SELECTOR 8 | |
2150 | +#define ERR_NOT_YCBCR_221111 9 | |
2151 | +#define ERR_UNKNOWN_CID_IN_SCAN 10 | |
2152 | +#define ERR_NOT_SEQUENTIAL_DCT 11 | |
2153 | +#define ERR_WRONG_MARKER 12 | |
2154 | +#define ERR_NO_EOI 13 | |
2155 | +#define ERR_BAD_TABLES 14 | |
2156 | +#define ERR_DEPTH_MISMATCH 15 | |
2157 | + | |
2158 | +struct jpeg_decdata { | |
2159 | + int dcts[6 * 64 + 16]; | |
2160 | + int out[64 * 6]; | |
2161 | + int dquant[3][64]; | |
2162 | +}; | |
2163 | + | |
2164 | +extern int jpeg_decode(unsigned char *, unsigned char *, int, int, int, struct jpeg_decdata *); | |
2165 | +extern int jpeg_check_size(unsigned char *, int, int); | |
2166 | + | |
2167 | +#endif | |
2168 | --- /dev/null | |
2169 | +++ b/drivers/video/bootsplash/Kconfig | |
2170 | @@ -0,0 +1,17 @@ | |
2171 | +# | |
2172 | +# Bootsplash configuration | |
2173 | +# | |
2174 | + | |
2175 | +menu "Bootsplash configuration" | |
2176 | + | |
2177 | +config BOOTSPLASH | |
2178 | + bool "Bootup splash screen" | |
2179 | + depends on FRAMEBUFFER_CONSOLE && FB_VESA | |
2180 | + default n | |
2181 | + ---help--- | |
2182 | + This option enables the Linux bootsplash screen. For more | |
2183 | + information on the bootsplash screen have a look at | |
2184 | + http://www.bootsplash.org/. | |
2185 | + If you are unsure, say N | |
2186 | +endmenu | |
2187 | + | |
2188 | --- /dev/null | |
2189 | +++ b/drivers/video/bootsplash/Makefile | |
2190 | @@ -0,0 +1,5 @@ | |
2191 | +# Makefile for the Linux bootsplash | |
2192 | + | |
2193 | +obj-$(CONFIG_BOOTSPLASH) += bootsplash.o | |
2194 | +obj-$(CONFIG_BOOTSPLASH) += decode-jpg.o | |
2195 | +obj-$(CONFIG_BOOTSPLASH) += render.o | |
2196 | --- /dev/null | |
2197 | +++ b/drivers/video/bootsplash/render.c | |
2198 | @@ -0,0 +1,328 @@ | |
2199 | +/* | |
2200 | + * linux/drivers/video/bootsplash/render.c - splash screen render functions. | |
2201 | + */ | |
2202 | + | |
2203 | +#include <linux/module.h> | |
2204 | +#include <linux/types.h> | |
2205 | +#include <linux/fb.h> | |
2206 | +#include <linux/vt_kern.h> | |
2207 | +#include <linux/selection.h> | |
2208 | +#include <asm/irq.h> | |
2209 | +#include <asm/system.h> | |
2210 | + | |
2211 | +#include "../console/fbcon.h" | |
2212 | +#include "bootsplash.h" | |
2213 | + | |
2214 | +void splash_putcs(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, | |
2215 | + const unsigned short *s, int count, int ypos, int xpos) | |
2216 | +{ | |
2217 | + unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; | |
2218 | + int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; | |
2219 | + int fgshift = (vc->vc_hi_font_mask) ? 9 : 8; | |
2220 | + u8 *src; | |
2221 | + u8 *dst, *splashsrc; | |
2222 | + unsigned int d, x, y; | |
2223 | + u32 dd, fgx, bgx; | |
2224 | + u16 c = scr_readw(s); | |
2225 | + | |
2226 | + int fg_color, bg_color, transparent; | |
2227 | + if (console_blanked) | |
2228 | + return; | |
2229 | + fg_color = attr_fgcol(fgshift, c); | |
2230 | + bg_color = attr_bgcol(bgshift, c); | |
2231 | + transparent = sd->splash_color == bg_color; | |
2232 | + xpos = xpos * vc->vc_font.width + sd->splash_text_xo; | |
2233 | + ypos = ypos * vc->vc_font.height + sd->splash_text_yo; | |
2234 | + splashsrc = (u8 *)(info->splash_pic + ypos * info->splash_bytes + xpos * 2); | |
2235 | + dst = (u8 *)(info->screen_base + ypos * info->fix.line_length + xpos * 2); | |
2236 | + | |
2237 | + fgx = ((u32 *)info->pseudo_palette)[fg_color]; | |
2238 | + if (transparent && sd->splash_color == 15) { | |
2239 | + if (fgx == 0xffea) | |
2240 | + fgx = 0xfe4a; | |
2241 | + else if (fgx == 0x57ea) | |
2242 | + fgx = 0x0540; | |
2243 | + else if (fgx == 0xffff) | |
2244 | + fgx = 0x52aa; | |
2245 | + } | |
2246 | + bgx = ((u32 *)info->pseudo_palette)[bg_color]; | |
2247 | + d = 0; | |
2248 | + | |
2249 | + while (count--) { | |
2250 | + c = scr_readw(s++); | |
2251 | + src = vc->vc_font.data + (c & charmask) * vc->vc_font.height * ((vc->vc_font.width + 7) >> 3); | |
2252 | + | |
2253 | + for (y = 0; y < vc->vc_font.height; y++) { | |
2254 | + for (x = 0; x < vc->vc_font.width; x += 2) { | |
2255 | + if ((x & 7) == 0) | |
2256 | + d = *src++; | |
2257 | + if (d & 0x80) | |
2258 | + dd = fgx; | |
2259 | + else | |
2260 | + dd = transparent ? *(u16 *)splashsrc : bgx; | |
2261 | + splashsrc += 2; | |
2262 | + if (d & 0x40) | |
2263 | + dd |= fgx << 16; | |
2264 | + else | |
2265 | + dd |= (transparent ? *(u16 *)splashsrc : bgx) << 16; | |
2266 | + splashsrc += 2; | |
2267 | + d <<= 2; | |
2268 | + fb_writel(dd, dst); | |
2269 | + dst += 4; | |
2270 | + } | |
2271 | + dst += info->fix.line_length - vc->vc_font.width * 2; | |
2272 | + splashsrc += info->splash_bytes - vc->vc_font.width * 2; | |
2273 | + } | |
2274 | + dst -= info->fix.line_length * vc->vc_font.height - vc->vc_font.width * 2; | |
2275 | + splashsrc -= info->splash_bytes * vc->vc_font.height - vc->vc_font.width * 2; | |
2276 | + } | |
2277 | +} | |
2278 | + | |
2279 | +static void splash_renderc(struct splash_data *sd, struct fb_info *info, int fg_color, int bg_color, u8 *src, int ypos, int xpos, int height, int width) | |
2280 | +{ | |
2281 | + int transparent = sd->splash_color == bg_color; | |
2282 | + u32 dd, fgx, bgx; | |
2283 | + u8 *dst, *splashsrc; | |
2284 | + unsigned int d, x, y; | |
2285 | + | |
2286 | + if (console_blanked) | |
2287 | + return; | |
2288 | + splashsrc = (u8 *)(info->splash_pic + ypos * info->splash_bytes + xpos * 2); | |
2289 | + dst = (u8 *)(info->screen_base + ypos * info->fix.line_length + xpos * 2); | |
2290 | + fgx = ((u32 *)info->pseudo_palette)[fg_color]; | |
2291 | + if (transparent && sd->splash_color == 15) { | |
2292 | + if (fgx == 0xffea) | |
2293 | + fgx = 0xfe4a; | |
2294 | + else if (fgx == 0x57ea) | |
2295 | + fgx = 0x0540; | |
2296 | + else if (fgx == 0xffff) | |
2297 | + fgx = 0x52aa; | |
2298 | + } | |
2299 | + bgx = ((u32 *)info->pseudo_palette)[bg_color]; | |
2300 | + d = 0; | |
2301 | + for (y = 0; y < height; y++) { | |
2302 | + for (x = 0; x < width; x += 2) { | |
2303 | + if ((x & 7) == 0) | |
2304 | + d = *src++; | |
2305 | + if (d & 0x80) | |
2306 | + dd = fgx; | |
2307 | + else | |
2308 | + dd = transparent ? *(u16 *)splashsrc : bgx; | |
2309 | + splashsrc += 2; | |
2310 | + if (d & 0x40) | |
2311 | + dd |= fgx << 16; | |
2312 | + else | |
2313 | + dd |= (transparent ? *(u16 *)splashsrc : bgx) << 16; | |
2314 | + splashsrc += 2; | |
2315 | + d <<= 2; | |
2316 | + fb_writel(dd, dst); | |
2317 | + dst += 4; | |
2318 | + } | |
2319 | + dst += info->fix.line_length - width * 2; | |
2320 | + splashsrc += info->splash_bytes - width * 2; | |
2321 | + } | |
2322 | +} | |
2323 | + | |
2324 | +void splash_putc(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, | |
2325 | + int c, int ypos, int xpos) | |
2326 | +{ | |
2327 | + unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; | |
2328 | + int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; | |
2329 | + int fgshift = (vc->vc_hi_font_mask) ? 9 : 8; | |
2330 | + u8 *src = vc->vc_font.data + (c & charmask) * vc->vc_font.height * ((vc->vc_font.width + 7) >> 3); | |
2331 | + xpos = xpos * vc->vc_font.width + sd->splash_text_xo; | |
2332 | + ypos = ypos * vc->vc_font.height + sd->splash_text_yo; | |
2333 | + splash_renderc(sd, info, attr_fgcol(fgshift, c), attr_bgcol(bgshift, c), src, ypos, xpos, vc->vc_font.height, vc->vc_font.width); | |
2334 | +} | |
2335 | + | |
2336 | +void splashcopy(u8 *dst, u8 *src, int height, int width, int dstbytes, int srcbytes) | |
2337 | +{ | |
2338 | + int i; | |
2339 | + | |
2340 | + while (height-- > 0) { | |
2341 | + u32 *p = (u32 *)dst; | |
2342 | + u32 *q = (u32 *)src; | |
2343 | + for (i=0; i < width/4; i++) { | |
2344 | + fb_writel(*q++,p++); | |
2345 | + fb_writel(*q++,p++); | |
2346 | + } | |
2347 | + if (width & 2) | |
2348 | + fb_writel(*q++,p++); | |
2349 | + if (width & 1) | |
2350 | + fb_writew(*(u16*)q,(u16*)p); | |
2351 | + dst += dstbytes; | |
2352 | + src += srcbytes; | |
2353 | + } | |
2354 | +} | |
2355 | + | |
2356 | +static void splashset(u8 *dst, int height, int width, int dstbytes, u32 bgx) { | |
2357 | + int i; | |
2358 | + | |
2359 | + bgx |= bgx << 16; | |
2360 | + while (height-- > 0) { | |
2361 | + u32 *p = (u32 *)dst; | |
2362 | + for (i=0; i < width/4; i++) { | |
2363 | + fb_writel(bgx,p++); | |
2364 | + fb_writel(bgx,p++); | |
2365 | + } | |
2366 | + if (width & 2) | |
2367 | + fb_writel(bgx,p++); | |
2368 | + if (width & 1) | |
2369 | + fb_writew(bgx,(u16*)p); | |
2370 | + dst += dstbytes; | |
2371 | + } | |
2372 | +} | |
2373 | + | |
2374 | +static void splashfill(struct fb_info *info, int sy, int sx, int height, int width) { | |
2375 | + splashcopy((u8 *)(info->screen_base + sy * info->fix.line_length + sx * 2), (u8 *)(info->splash_pic + sy * info->splash_bytes + sx * 2), height, width, info->fix.line_length, info->splash_bytes); | |
2376 | +} | |
2377 | + | |
2378 | +void splash_clear(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, int sy, | |
2379 | + int sx, int height, int width) | |
2380 | +{ | |
2381 | + int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; | |
2382 | + int bg_color = attr_bgcol_ec(bgshift, vc, info); | |
2383 | + int transparent = sd->splash_color == bg_color; | |
2384 | + u32 bgx; | |
2385 | + u8 *dst; | |
2386 | + | |
2387 | + if (console_blanked) | |
2388 | + return; | |
2389 | + sy = sy * vc->vc_font.height + sd->splash_text_yo; | |
2390 | + sx = sx * vc->vc_font.width + sd->splash_text_xo; | |
2391 | + height *= vc->vc_font.height; | |
2392 | + width *= vc->vc_font.width; | |
2393 | + if (transparent) { | |
2394 | + splashfill(info, sy, sx, height, width); | |
2395 | + return; | |
2396 | + } | |
2397 | + dst = (u8 *)(info->screen_base + sy * info->fix.line_length + sx * 2); | |
2398 | + bgx = ((u32 *)info->pseudo_palette)[bg_color]; | |
2399 | + splashset(dst, height, width, info->fix.line_length, bgx); | |
2400 | +} | |
2401 | + | |
2402 | +void splash_bmove(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, int sy, | |
2403 | + int sx, int dy, int dx, int height, int width) | |
2404 | +{ | |
2405 | + struct fb_copyarea area; | |
2406 | + | |
2407 | + if (console_blanked) | |
2408 | + return; | |
2409 | + area.sx = sx * vc->vc_font.width; | |
2410 | + area.sy = sy * vc->vc_font.height; | |
2411 | + area.dx = dx * vc->vc_font.width; | |
2412 | + area.dy = dy * vc->vc_font.height; | |
2413 | + area.sx += sd->splash_text_xo; | |
2414 | + area.sy += sd->splash_text_yo; | |
2415 | + area.dx += sd->splash_text_xo; | |
2416 | + area.dy += sd->splash_text_yo; | |
2417 | + area.height = height * vc->vc_font.height; | |
2418 | + area.width = width * vc->vc_font.width; | |
2419 | + | |
2420 | + info->fbops->fb_copyarea(info, &area); | |
2421 | +} | |
2422 | + | |
2423 | +void splash_clear_margins(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, | |
2424 | + int bottom_only) | |
2425 | +{ | |
2426 | + unsigned int tw = vc->vc_cols*vc->vc_font.width; | |
2427 | + unsigned int th = vc->vc_rows*vc->vc_font.height; | |
2428 | + | |
2429 | + if (console_blanked) | |
2430 | + return; | |
2431 | + if (!bottom_only) { | |
2432 | + /* top margin */ | |
2433 | + splashfill(info, 0, 0, sd->splash_text_yo, info->var.xres); | |
2434 | + /* left margin */ | |
2435 | + splashfill(info, sd->splash_text_yo, 0, th, sd->splash_text_xo); | |
2436 | + /* right margin */ | |
2437 | + splashfill(info, sd->splash_text_yo, sd->splash_text_xo + tw, th, info->var.xres - sd->splash_text_xo - tw); | |
2438 | + | |
2439 | + } | |
2440 | + splashfill(info, sd->splash_text_yo + th, 0, info->var.yres - sd->splash_text_yo - th, info->var.xres); | |
2441 | +} | |
2442 | + | |
2443 | +int splash_cursor(struct splash_data *sd, struct fb_info *info, struct fb_cursor *cursor) | |
2444 | +{ | |
2445 | + int i; | |
2446 | + unsigned int dsize, s_pitch; | |
2447 | + | |
2448 | + if (info->state != FBINFO_STATE_RUNNING) | |
2449 | + return 0; | |
2450 | + | |
2451 | + s_pitch = (cursor->image.width + 7) >> 3; | |
2452 | + dsize = s_pitch * cursor->image.height; | |
2453 | + if (cursor->enable) { | |
2454 | + switch (cursor->rop) { | |
2455 | + case ROP_XOR: | |
2456 | + for (i = 0; i < dsize; i++) | |
2457 | + info->fb_cursordata[i] = cursor->image.data[i] ^ cursor->mask[i]; | |
2458 | + break; | |
2459 | + case ROP_COPY: | |
2460 | + default: | |
2461 | + for (i = 0; i < dsize; i++) | |
2462 | + info->fb_cursordata[i] = cursor->image.data[i] & cursor->mask[i]; | |
2463 | + break; | |
2464 | + } | |
2465 | + } else if (info->fb_cursordata != cursor->image.data) | |
2466 | + memcpy(info->fb_cursordata, cursor->image.data, dsize); | |
2467 | + cursor->image.data = info->fb_cursordata; | |
2468 | + splash_renderc(sd, info, cursor->image.fg_color, cursor->image.bg_color, (u8 *)info->fb_cursordata, cursor->image.dy + sd->splash_text_yo, cursor->image.dx + sd->splash_text_xo, cursor->image.height, cursor->image.width); | |
2469 | + return 0; | |
2470 | +} | |
2471 | + | |
2472 | +void splash_bmove_redraw(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, int y, int sx, int dx, int width) | |
2473 | +{ | |
2474 | + unsigned short *d = (unsigned short *) (vc->vc_origin + vc->vc_size_row * y + dx * 2); | |
2475 | + unsigned short *s = d + (dx - sx); | |
2476 | + unsigned short *start = d; | |
2477 | + unsigned short *ls = d; | |
2478 | + unsigned short *le = d + width; | |
2479 | + unsigned short c; | |
2480 | + int x = dx; | |
2481 | + unsigned short attr = 1; | |
2482 | + | |
2483 | + if (console_blanked) | |
2484 | + return; | |
2485 | + do { | |
2486 | + c = scr_readw(d); | |
2487 | + if (attr != (c & 0xff00)) { | |
2488 | + attr = c & 0xff00; | |
2489 | + if (d > start) { | |
2490 | + splash_putcs(sd, vc, info, start, d - start, y, x); | |
2491 | + x += d - start; | |
2492 | + start = d; | |
2493 | + } | |
2494 | + } | |
2495 | + if (s >= ls && s < le && c == scr_readw(s)) { | |
2496 | + if (d > start) { | |
2497 | + splash_putcs(sd, vc, info, start, d - start, y, x); | |
2498 | + x += d - start + 1; | |
2499 | + start = d + 1; | |
2500 | + } else { | |
2501 | + x++; | |
2502 | + start++; | |
2503 | + } | |
2504 | + } | |
2505 | + s++; | |
2506 | + d++; | |
2507 | + } while (d < le); | |
2508 | + if (d > start) | |
2509 | + splash_putcs(sd, vc, info, start, d - start, y, x); | |
2510 | +} | |
2511 | + | |
2512 | +void splash_blank(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, int blank) | |
2513 | +{ | |
2514 | + if (blank) { | |
2515 | + if (info->silent_screen_base) | |
2516 | + splashset((u8 *)info->silent_screen_base, info->var.yres, info->var.xres, info->fix.line_length, 0); | |
2517 | + splashset((u8 *)info->screen_base, info->var.yres, info->var.xres, info->fix.line_length, 0); | |
2518 | + } else { | |
2519 | + if (info->silent_screen_base) | |
2520 | + splash_prepare(vc, info); | |
2521 | + splash_clear_margins(vc->vc_splash_data, vc, info, 0); | |
2522 | + /* no longer needed, done in fbcon_blank */ | |
2523 | + /* update_screen(vc->vc_num); */ | |
2524 | + } | |
2525 | +} | |
2526 | + | |
2527 | --- a/drivers/video/console/bitblit.c | |
2528 | +++ b/drivers/video/console/bitblit.c | |
2529 | @@ -17,6 +17,9 @@ | |
2530 | #include <linux/console.h> | |
2531 | #include <asm/types.h> | |
2532 | #include "fbcon.h" | |
2533 | +#ifdef CONFIG_BOOTSPLASH | |
2534 | +#include "../bootsplash/bootsplash.h" | |
2535 | +#endif | |
2536 | ||
2537 | /* | |
2538 | * Accelerated handlers. | |
2539 | @@ -47,6 +50,13 @@ static void bit_bmove(struct vc_data *vc | |
2540 | { | |
2541 | struct fb_copyarea area; | |
2542 | ||
2543 | +#ifdef CONFIG_BOOTSPLASH | |
2544 | + if (info->splash_data) { | |
2545 | + splash_bmove(info->splash_data, vc, info, | |
2546 | + sy, sx, dy, dx, height, width); | |
2547 | + return; | |
2548 | + } | |
2549 | +#endif | |
2550 | area.sx = sx * vc->vc_font.width; | |
2551 | area.sy = sy * vc->vc_font.height; | |
2552 | area.dx = dx * vc->vc_font.width; | |
2553 | @@ -63,6 +73,13 @@ static void bit_clear(struct vc_data *vc | |
2554 | int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; | |
2555 | struct fb_fillrect region; | |
2556 | ||
2557 | +#ifdef CONFIG_BOOTSPLASH | |
2558 | + if (info->splash_data) { | |
2559 | + splash_clear(info->splash_data, vc, info, | |
2560 | + sy, sx, height, width); | |
2561 | + return; | |
2562 | + } | |
2563 | +#endif | |
2564 | region.color = attr_bgcol_ec(bgshift, vc, info); | |
2565 | region.dx = sx * vc->vc_font.width; | |
2566 | region.dy = sy * vc->vc_font.height; | |
2567 | @@ -160,6 +177,13 @@ static void bit_putcs(struct vc_data *vc | |
2568 | image.height = vc->vc_font.height; | |
2569 | image.depth = 1; | |
2570 | ||
2571 | +#ifdef CONFIG_BOOTSPLASH | |
2572 | + if (info->splash_data) { | |
2573 | + splash_putcs(info->splash_data, vc, info, s, count, yy, xx); | |
2574 | + return; | |
2575 | + } | |
2576 | +#endif | |
2577 | + | |
2578 | if (attribute) { | |
2579 | buf = kmalloc(cellsize, GFP_KERNEL); | |
2580 | if (!buf) | |
2581 | @@ -213,6 +237,13 @@ static void bit_clear_margins(struct vc_ | |
2582 | unsigned int bs = info->var.yres - bh; | |
2583 | struct fb_fillrect region; | |
2584 | ||
2585 | +#ifdef CONFIG_BOOTSPLASH | |
2586 | + if (info->splash_data) { | |
2587 | + splash_clear_margins(info->splash_data, vc, info, bottom_only); | |
2588 | + return; | |
2589 | + } | |
2590 | +#endif | |
2591 | + | |
2592 | region.color = attr_bgcol_ec(bgshift, vc, info); | |
2593 | region.rop = ROP_COPY; | |
2594 | ||
2595 | @@ -379,6 +410,14 @@ static void bit_cursor(struct vc_data *v | |
2596 | cursor.image.depth = 1; | |
2597 | cursor.rop = ROP_XOR; | |
2598 | ||
2599 | +#ifdef CONFIG_BOOTSPLASH | |
2600 | + if (info->splash_data) { | |
2601 | + splash_cursor(info->splash_data, info, &cursor); | |
2602 | + ops->cursor_reset = 0; | |
2603 | + return; | |
2604 | + } | |
2605 | +#endif | |
2606 | + | |
2607 | if (info->fbops->fb_cursor) | |
2608 | err = info->fbops->fb_cursor(info, &cursor); | |
2609 | ||
2610 | --- a/drivers/video/console/fbcon.c | |
2611 | +++ b/drivers/video/console/fbcon.c | |
2612 | @@ -90,6 +90,9 @@ | |
2613 | #endif | |
2614 | ||
2615 | #include "fbcon.h" | |
2616 | +#ifdef CONFIG_BOOTSPLASH | |
2617 | +#include "../bootsplash/bootsplash.h" | |
2618 | +#endif | |
2619 | ||
2620 | #ifdef FBCONDEBUG | |
2621 | # define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args) | |
2622 | @@ -105,7 +108,11 @@ enum { | |
2623 | ||
2624 | static struct display fb_display[MAX_NR_CONSOLES]; | |
2625 | ||
2626 | +#ifdef CONFIG_BOOTSPLASH | |
2627 | +signed char con2fb_map[MAX_NR_CONSOLES]; | |
2628 | +#else | |
2629 | static signed char con2fb_map[MAX_NR_CONSOLES]; | |
2630 | +#endif | |
2631 | static signed char con2fb_map_boot[MAX_NR_CONSOLES]; | |
2632 | ||
2633 | static int logo_lines; | |
2634 | @@ -578,6 +585,10 @@ static int fbcon_takeover(int show_logo) | |
2635 | for (i = first_fb_vc; i <= last_fb_vc; i++) | |
2636 | con2fb_map[i] = info_idx; | |
2637 | ||
2638 | +#ifdef CONFIG_BOOTSPLASH | |
2639 | + splash_init(); | |
2640 | +#endif | |
2641 | + | |
2642 | err = take_over_console(&fb_con, first_fb_vc, last_fb_vc, | |
2643 | fbcon_is_default); | |
2644 | ||
2645 | @@ -1180,6 +1191,16 @@ static void fbcon_init(struct vc_data *v | |
2646 | new_rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); | |
2647 | new_cols /= vc->vc_font.width; | |
2648 | new_rows /= vc->vc_font.height; | |
2649 | + | |
2650 | +#ifdef CONFIG_BOOTSPLASH | |
2651 | + if (vc->vc_splash_data && vc->vc_splash_data->splash_state) { | |
2652 | + new_cols = vc->vc_splash_data->splash_text_wi / vc->vc_font.width; | |
2653 | + new_rows = vc->vc_splash_data->splash_text_he / vc->vc_font.height; | |
2654 | + logo = 0; | |
2655 | + con_remap_def_color(vc, vc->vc_splash_data->splash_color << 4 | vc->vc_splash_data->splash_fg_color); | |
2656 | + } | |
2657 | +#endif | |
2658 | + | |
2659 | vc_resize(vc, new_cols, new_rows); | |
2660 | ||
2661 | /* | |
2662 | @@ -1875,6 +1896,10 @@ static int fbcon_scroll(struct vc_data * | |
2663 | fbcon_softback_note(vc, t, count); | |
2664 | if (logo_shown >= 0) | |
2665 | goto redraw_up; | |
2666 | +#ifdef CONFIG_BOOTSPLASH | |
2667 | + if (info->splash_data) | |
2668 | + goto redraw_up; | |
2669 | +#endif | |
2670 | switch (p->scrollmode) { | |
2671 | case SCROLL_MOVE: | |
2672 | fbcon_redraw_blit(vc, info, p, t, b - t - count, | |
2673 | @@ -1966,6 +1991,10 @@ static int fbcon_scroll(struct vc_data * | |
2674 | count = vc->vc_rows; | |
2675 | if (logo_shown >= 0) | |
2676 | goto redraw_down; | |
2677 | +#ifdef CONFIG_BOOTSPLASH | |
2678 | + if (info->splash_data) | |
2679 | + goto redraw_down; | |
2680 | +#endif | |
2681 | switch (p->scrollmode) { | |
2682 | case SCROLL_MOVE: | |
2683 | fbcon_redraw_blit(vc, info, p, b - 1, b - t - count, | |
2684 | @@ -2114,6 +2143,14 @@ static void fbcon_bmove_rec(struct vc_da | |
2685 | } | |
2686 | return; | |
2687 | } | |
2688 | + | |
2689 | +#ifdef CONFIG_BOOTSPLASH | |
2690 | + if (info->splash_data && sy == dy && height == 1) { | |
2691 | + /* must use slower redraw bmove to keep background pic intact */ | |
2692 | + splash_bmove_redraw(info->splash_data, vc, info, sy, sx, dx, width); | |
2693 | + return; | |
2694 | + } | |
2695 | +#endif | |
2696 | ops->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx, | |
2697 | height, width); | |
2698 | } | |
2699 | @@ -2222,6 +2259,10 @@ static int fbcon_switch(struct vc_data * | |
2700 | info = registered_fb[con2fb_map[vc->vc_num]]; | |
2701 | ops = info->fbcon_par; | |
2702 | ||
2703 | +#ifdef CONFIG_BOOTSPLASH | |
2704 | + splash_prepare(vc, info); | |
2705 | +#endif | |
2706 | + | |
2707 | if (softback_top) { | |
2708 | if (softback_lines) | |
2709 | fbcon_set_origin(vc); | |
2710 | @@ -2349,6 +2390,12 @@ static void fbcon_generic_blank(struct v | |
2711 | { | |
2712 | struct fb_event event; | |
2713 | ||
2714 | +#ifdef CONFIG_BOOTSPLASH | |
2715 | + if (info->splash_data) { | |
2716 | + splash_blank(info->splash_data, vc, info, blank); | |
2717 | + return; | |
2718 | + } | |
2719 | +#endif | |
2720 | if (blank) { | |
2721 | unsigned short charmask = vc->vc_hi_font_mask ? | |
2722 | 0x1ff : 0xff; | |
2723 | @@ -2553,6 +2600,12 @@ static int fbcon_do_set_font(struct vc_d | |
2724 | ||
2725 | cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); | |
2726 | rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); | |
2727 | +#ifdef CONFIG_BOOTSPLASH | |
2728 | + if (info->splash_data) { | |
2729 | + cols = info->splash_data->splash_text_wi; | |
2730 | + rows = info->splash_data->splash_text_he; | |
2731 | + } | |
2732 | +#endif | |
2733 | cols /= w; | |
2734 | rows /= h; | |
2735 | vc_resize(vc, cols, rows); | |
2736 | --- a/drivers/video/console/fbcon.h | |
2737 | +++ b/drivers/video/console/fbcon.h | |
2738 | @@ -25,6 +25,34 @@ | |
2739 | * low-level frame buffer device | |
2740 | */ | |
2741 | ||
2742 | +#ifdef CONFIG_BOOTSPLASH | |
2743 | +struct splash_data { | |
2744 | + int splash_state; /* show splash? */ | |
2745 | + int splash_color; /* transparent color */ | |
2746 | + int splash_fg_color; /* foreground color */ | |
2747 | + int splash_width; /* width of image */ | |
2748 | + int splash_height; /* height of image */ | |
2749 | + int splash_text_xo; /* text area origin */ | |
2750 | + int splash_text_yo; | |
2751 | + int splash_text_wi; /* text area size */ | |
2752 | + int splash_text_he; | |
2753 | + int splash_showtext; /* silent/verbose mode */ | |
2754 | + int splash_boxcount; | |
2755 | + int splash_percent; | |
2756 | + int splash_overpaintok; /* is it ok to overpaint boxes */ | |
2757 | + int splash_palcnt; | |
2758 | + char *oldscreen_base; /* pointer to top of virtual screen */ | |
2759 | + unsigned char *splash_boxes; | |
2760 | + unsigned char *splash_jpeg; /* jpeg */ | |
2761 | + unsigned char *splash_palette; /* palette for 8-bit */ | |
2762 | + | |
2763 | + int splash_dosilent; /* show silent jpeg */ | |
2764 | + unsigned char *splash_silentjpeg; | |
2765 | + unsigned char *splash_sboxes; | |
2766 | + int splash_sboxcount; | |
2767 | +}; | |
2768 | +#endif | |
2769 | + | |
2770 | struct display { | |
2771 | /* Filled in by the low-level console driver */ | |
2772 | const u_char *fontdata; | |
2773 | --- a/drivers/video/Kconfig | |
2774 | +++ b/drivers/video/Kconfig | |
2775 | @@ -2054,4 +2054,8 @@ if FB || SGI_NEWPORT_CONSOLE | |
2776 | source "drivers/video/logo/Kconfig" | |
2777 | endif | |
2778 | ||
2779 | +if FB | |
2780 | + source "drivers/video/bootsplash/Kconfig" | |
2781 | +endif | |
2782 | + | |
2783 | endmenu | |
2784 | --- a/drivers/video/Makefile | |
2785 | +++ b/drivers/video/Makefile | |
2786 | @@ -14,6 +14,7 @@ fb-objs := $(f | |
2787 | obj-$(CONFIG_VT) += console/ | |
2788 | obj-$(CONFIG_LOGO) += logo/ | |
2789 | obj-y += backlight/ display/ | |
2790 | +obj-$(CONFIG_BOOTSPLASH) += bootsplash/ | |
2791 | ||
2792 | obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o | |
2793 | obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o | |
2794 | --- a/drivers/video/vesafb.c | |
2795 | +++ b/drivers/video/vesafb.c | |
2796 | @@ -174,7 +174,10 @@ static int vesafb_setcolreg(unsigned reg | |
2797 | return err; | |
2798 | } | |
2799 | ||
2800 | -static struct fb_ops vesafb_ops = { | |
2801 | +#ifndef CONFIG_BOOTSPLASH | |
2802 | +static | |
2803 | +#endif | |
2804 | +struct fb_ops vesafb_ops = { | |
2805 | .owner = THIS_MODULE, | |
2806 | .fb_setcolreg = vesafb_setcolreg, | |
2807 | .fb_pan_display = vesafb_pan_display, | |
2808 | @@ -258,6 +261,9 @@ static int __init vesafb_probe(struct pl | |
2809 | * option to simply use size_total as that | |
2810 | * wastes plenty of kernel address space. */ | |
2811 | size_remap = size_vmode * 2; | |
2812 | +#ifdef CONFIG_BOOTSPLASH | |
2813 | + size_remap *= 2; /* some more for the images */ | |
2814 | +#endif | |
2815 | if (vram_remap) | |
2816 | size_remap = vram_remap * 1024 * 1024; | |
2817 | if (size_remap < size_vmode) | |
2818 | --- a/include/linux/console_struct.h | |
2819 | +++ b/include/linux/console_struct.h | |
2820 | @@ -107,6 +107,9 @@ struct vc_data { | |
2821 | struct vc_data **vc_display_fg; /* [!] Ptr to var holding fg console for this display */ | |
2822 | unsigned long vc_uni_pagedir; | |
2823 | unsigned long *vc_uni_pagedir_loc; /* [!] Location of uni_pagedir variable for this console */ | |
2824 | +#ifdef CONFIG_BOOTSPLASH | |
2825 | + struct splash_data *vc_splash_data; | |
2826 | +#endif | |
2827 | /* additional information is in vt_kern.h */ | |
2828 | }; | |
2829 | ||
2830 | --- a/include/linux/fb.h | |
2831 | +++ b/include/linux/fb.h | |
2832 | @@ -849,6 +849,14 @@ struct fb_info { | |
2833 | void *fbcon_par; /* fbcon use-only private area */ | |
2834 | /* From here on everything is device dependent */ | |
2835 | void *par; | |
2836 | +#ifdef CONFIG_BOOTSPLASH | |
2837 | + struct splash_data *splash_data; | |
2838 | + unsigned char *splash_pic; | |
2839 | + int splash_pic_size; | |
2840 | + int splash_bytes; | |
2841 | + char *silent_screen_base; /* real screen base */ | |
2842 | + char fb_cursordata[64]; | |
2843 | +#endif | |
2844 | }; | |
2845 | ||
2846 | #ifdef MODULE | |
2847 | --- a/kernel/panic.c | |
2848 | +++ b/kernel/panic.c | |
2849 | @@ -109,6 +109,12 @@ NORET_TYPE void panic(const char * fmt, | |
2850 | * We can't use the "normal" timers since we just panicked.. | |
2851 | */ | |
2852 | printk(KERN_EMERG "Rebooting in %d seconds..",panic_timeout); | |
2853 | +#ifdef CONFIG_BOOTSPLASH | |
2854 | + { | |
2855 | + extern int splash_verbose(void); | |
2856 | + (void)splash_verbose(); | |
2857 | + } | |
2858 | +#endif | |
2859 | for (i = 0; i < panic_timeout*1000; ) { | |
2860 | touch_nmi_watchdog(); | |
2861 | i += panic_blink(i); | |
2862 | @@ -133,6 +139,12 @@ NORET_TYPE void panic(const char * fmt, | |
2863 | disabled_wait(caller); | |
2864 | #endif | |
2865 | local_irq_enable(); | |
2866 | +#ifdef CONFIG_BOOTSPLASH | |
2867 | + { | |
2868 | + extern int splash_verbose(void); | |
2869 | + (void)splash_verbose(); | |
2870 | + } | |
2871 | +#endif | |
2872 | for (i = 0;;) { | |
2873 | touch_softlockup_watchdog(); | |
2874 | i += panic_blink(i); |